diff --git a/tests/fileformats/gif/newtons_cradle.png b/tests/fileformats/gif/newtons_cradle.png
new file mode 100644
index 0000000..bddc25a
Binary files /dev/null and b/tests/fileformats/gif/newtons_cradle.png differ
diff --git a/tests/test_contexts.nim b/tests/test_contexts.nim
index e2cd7dd..c547c16 100644
--- a/tests/test_contexts.nim
+++ b/tests/test_contexts.nim
@@ -1,4 +1,4 @@
-import chroma, pixie, utils
+import chroma, pixie, xrays
 
 block:
   let ctx = newContext(newImage(300, 160))
@@ -17,7 +17,7 @@ block:
 
   ctx.clearRect(10, 10, 120, 100)
 
-  ctx.image.diffVs("tests/contexts/clearRect_1.png")
+  ctx.image.xray("tests/contexts/clearRect_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -34,7 +34,7 @@ block:
   ctx.lineTo(120, 120)
   ctx.stroke()
 
-  ctx.image.diffVs("tests/contexts/beginPath_1.png")
+  ctx.image.xray("tests/contexts/beginPath_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -46,7 +46,7 @@ block:
   ctx.lineTo(280, 120)
   ctx.stroke()
 
-  ctx.image.diffVs("tests/contexts/moveTo_1.png")
+  ctx.image.xray("tests/contexts/moveTo_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -63,7 +63,7 @@ block:
   ctx.fillStyle = "green"
   ctx.fill(region, EvenOdd)
 
-  ctx.image.diffVs("tests/contexts/fill_1.png")
+  ctx.image.xray("tests/contexts/fill_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -71,7 +71,7 @@ block:
   ctx.rect(10, 10, 150, 100)
   ctx.stroke()
 
-  ctx.image.diffVs("tests/contexts/stroke_1.png")
+  ctx.image.xray("tests/contexts/stroke_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -94,7 +94,7 @@ block:
   ctx.lineTo(280, 140)
   ctx.stroke()
 
-  ctx.image.diffVs("tests/contexts/stroke_2.png")
+  ctx.image.xray("tests/contexts/stroke_2.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -112,7 +112,7 @@ block:
   ctx.stroke()
   ctx.fill()
 
-  ctx.image.diffVs("tests/contexts/stroke_3.png")
+  ctx.image.xray("tests/contexts/stroke_3.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -124,7 +124,7 @@ block:
   ctx.closePath()
   ctx.stroke()
 
-  ctx.image.diffVs("tests/contexts/closePath_1.png")
+  ctx.image.xray("tests/contexts/closePath_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -140,7 +140,7 @@ block:
   ctx.bezierCurveTo(cp1, cp2, to)
   ctx.stroke()
 
-  ctx.image.diffVs("tests/contexts/bezierCurveTo_1.png")
+  ctx.image.xray("tests/contexts/bezierCurveTo_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -150,7 +150,7 @@ block:
   ctx.bezierCurveTo(120, 160, 180, 10, 220, 140)
   ctx.stroke()
 
-  ctx.image.diffVs("tests/contexts/bezierCurveTo_2.png")
+  ctx.image.xray("tests/contexts/bezierCurveTo_2.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -159,7 +159,7 @@ block:
   ctx.quadraticCurveTo(230, 30, 50, 100)
   ctx.stroke()
 
-  ctx.image.diffVs("tests/contexts/quadracticCurveTo_1.png")
+  ctx.image.xray("tests/contexts/quadracticCurveTo_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -169,7 +169,7 @@ block:
   ctx.quadraticCurveTo(230, 150, 250, 20)
   ctx.stroke()
 
-  ctx.image.diffVs("tests/contexts/quadracticCurveTo_2.png")
+  ctx.image.xray("tests/contexts/quadracticCurveTo_2.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -178,7 +178,7 @@ block:
   ctx.ellipse(100, 75, 75, 50)
   ctx.stroke()
 
-  ctx.image.diffVs("tests/contexts/ellipse_1.png")
+  ctx.image.xray("tests/contexts/ellipse_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -186,7 +186,7 @@ block:
   ctx.strokeStyle = "green"
   ctx.strokeRect(20, 10, 160, 100)
 
-  ctx.image.diffVs("tests/contexts/strokeRect_1.png")
+  ctx.image.xray("tests/contexts/strokeRect_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -196,7 +196,7 @@ block:
   ctx.strokeStyle = "#38f"
   ctx.strokeRect(30, 30, 160, 90)
 
-  ctx.image.diffVs("tests/contexts/strokeRect_2.png")
+  ctx.image.xray("tests/contexts/strokeRect_2.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -204,7 +204,7 @@ block:
   ctx.setTransform(mat3(1, 0.2, 0, 0.8, 1, 0, 0, 0, 1))
   ctx.fillRect(0, 0, 100, 100)
 
-  ctx.image.diffVs("tests/contexts/setTransform_1.png")
+  ctx.image.xray("tests/contexts/setTransform_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -212,7 +212,7 @@ block:
   ctx.setTransform(mat3(1, 0.2, 0, 0.8, 1, 0, 0, 0, 1))
   ctx.fillRect(0, 0, 100, 100)
 
-  ctx.image.diffVs("tests/contexts/resetTransform_1.png")
+  ctx.image.xray("tests/contexts/resetTransform_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -220,7 +220,7 @@ block:
   ctx.rotate(45 * PI / 180)
   ctx.fillRect(60, 0, 100, 30)
 
-  ctx.image.diffVs("tests/contexts/resetTransform_1.png")
+  ctx.image.xray("tests/contexts/resetTransform_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -235,7 +235,7 @@ block:
   ctx.fillRect(40, 40, 50, 20)
   ctx.fillRect(40, 90, 50, 20)
 
-  ctx.image.diffVs("tests/contexts/resetTransform_2.png")
+  ctx.image.xray("tests/contexts/resetTransform_2.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -249,7 +249,7 @@ block:
   ctx.fillStyle = "gray"
   ctx.fillRect(0, 0, 80, 80)
 
-  ctx.image.diffVs("tests/contexts/translate_1.png")
+  ctx.image.xray("tests/contexts/translate_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -263,7 +263,7 @@ block:
   ctx.fillStyle = "gray"
   ctx.fillRect(10, 10, 8, 20)
 
-  ctx.image.diffVs("tests/contexts/scale_1.png")
+  ctx.image.xray("tests/contexts/scale_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -275,7 +275,7 @@ block:
   ctx.fillStyle = "red"
   ctx.fillRect(100, 0, 80, 20)
 
-  ctx.image.diffVs("tests/contexts/rotate_1.png")
+  ctx.image.xray("tests/contexts/rotate_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -288,7 +288,7 @@ block:
 
   ctx.fillText("Hello world", 50, 90)
 
-  ctx.image.diffVs("tests/contexts/fillText_1.png")
+  ctx.image.xray("tests/contexts/fillText_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -298,7 +298,7 @@ block:
 
   ctx.strokeText("Hello world", 50, 90)
 
-  ctx.image.diffVs("tests/contexts/strokeText_1.png")
+  ctx.image.xray("tests/contexts/strokeText_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -312,7 +312,7 @@ block:
 
   ctx.fillRect(150, 40, 100, 100)
 
-  ctx.image.diffVs("tests/contexts/save_1.png")
+  ctx.image.xray("tests/contexts/save_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -326,7 +326,7 @@ block:
   ctx.fillStyle = "orange"
   ctx.fillRect(0, 0, 100, 100)
 
-  ctx.image.diffVs("tests/contexts/clip_1.png")
+  ctx.image.xray("tests/contexts/clip_1.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -343,7 +343,7 @@ block:
   ctx.fillStyle = "orange"
   ctx.fillRect(0, 0, 100, 100)
 
-  ctx.image.diffVs("tests/contexts/clip_1b.png")
+  ctx.image.xray("tests/contexts/clip_1b.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -364,7 +364,7 @@ block:
   ctx.fillStyle = "blue"
   ctx.fillRect(0, 0, ctx.image.width.float32, ctx.image.height.float32)
 
-  ctx.image.diffVs("tests/contexts/clip_1c.png")
+  ctx.image.xray("tests/contexts/clip_1c.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -385,7 +385,7 @@ block:
 
   ctx.restore()
 
-  ctx.image.diffVs("tests/contexts/clip_1d.png")
+  ctx.image.xray("tests/contexts/clip_1d.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -409,7 +409,7 @@ block:
   ctx.fillStyle = "blue"
   ctx.fillRect(0, 0, ctx.image.width.float32, ctx.image.height.float32)
 
-  ctx.image.diffVs("tests/contexts/clip_1e.png")
+  ctx.image.xray("tests/contexts/clip_1e.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -433,7 +433,7 @@ block:
 
   ctx.restore() # Pop the layer
 
-  ctx.image.diffVs("tests/contexts/clip_1f.png")
+  ctx.image.xray("tests/contexts/clip_1f.png")
 
 block:
   let ctx = newContext(newImage(300, 150))
@@ -446,7 +446,7 @@ block:
   ctx.fillStyle = "blue"
   ctx.fillRect(0, 0, ctx.image.width.float32, ctx.image.height.float32)
 
-  ctx.image.diffVs("tests/contexts/clip_2.png")
+  ctx.image.xray("tests/contexts/clip_2.png")
 
 block:
   let image = newImage(300, 150)
@@ -464,7 +464,7 @@ block:
   ctx.fillStyle = "blue"
   ctx.fillRect(0, 0, ctx.image.width.float32, ctx.image.height.float32)
 
-  image.diffVs("tests/contexts/clip_3.png")
+  image.xray("tests/contexts/clip_3.png")
 
 block:
   let image = newImage(300, 150)
@@ -485,7 +485,7 @@ block:
 
   ctx.restore()
 
-  image.diffVs("tests/contexts/clip_text.png")
+  image.xray("tests/contexts/clip_text.png")
 
 block:
   let ctx = newContext(100, 100)
@@ -517,7 +517,7 @@ block:
   drawDashedLine(@[20.float32, 3, 3, 3, 3, 3, 3, 3])
   drawDashedLine(@[12.float32, 3, 3])
 
-  image.diffVs("tests/contexts/setLineDash_1.png")
+  image.xray("tests/contexts/setLineDash_1.png")
 
 block:
   let
@@ -534,7 +534,7 @@ block:
 
   ctx.fillRect(10, 10, 100, 100)
 
-  image.diffVs("tests/contexts/blendmode_1.png")
+  image.xray("tests/contexts/blendmode_1.png")
 
 block:
   let
@@ -551,7 +551,7 @@ block:
   ctx.fillStyle = "red"
   ctx.fillRect(50, 50, 100, 100)
 
-  image.diffVs("tests/contexts/globalAlpha_1.png")
+  image.xray("tests/contexts/globalAlpha_1.png")
 
 block:
   let
@@ -560,7 +560,7 @@ block:
     testImage = readImage("tests/images/pip1.png")
   ctx.drawImage(testImage, 0, 0)
   ctx.drawImage(testImage, 30, 30)
-  image.diffVs("tests/contexts/draw_image.png")
+  image.xray("tests/contexts/draw_image.png")
 
 block:
   let
@@ -570,7 +570,7 @@ block:
   ctx.translate(30, 30)
   ctx.drawImage(testImage, -30, -30)
   ctx.drawImage(testImage, 0, 0)
-  image.diffVs("tests/contexts/draw_image_translated.png")
+  image.xray("tests/contexts/draw_image_translated.png")
 
 block:
   let
@@ -581,7 +581,7 @@ block:
   ctx.drawImage(testImage, 0, 0)
   ctx.scale(0.25, 0.25)
   ctx.drawImage(testImage, 0, 0)
-  image.diffVs("tests/contexts/draw_image_scaled.png")
+  image.xray("tests/contexts/draw_image_scaled.png")
 
 block:
   let
@@ -589,7 +589,7 @@ block:
     ctx = newContext(image)
     testImage = readImage("tests/images/pip1.png")
   ctx.drawImage(testImage, 30, 30, 20, 20)
-  image.diffVs("tests/contexts/draw_image_self_scaled.png")
+  image.xray("tests/contexts/draw_image_self_scaled.png")
 
 block:
   let
@@ -597,7 +597,7 @@ block:
     ctx = newContext(image)
     rhino = readImage("tests/images/rhino.png")
   ctx.drawImage(rhino, 33, 71, 104, 124, 21, 20, 87, 104)
-  image.diffVs("tests/contexts/draw_image_rhino.png")
+  image.xray("tests/contexts/draw_image_rhino.png")
 
 block:
   let
@@ -605,7 +605,7 @@ block:
     ctx = newContext(image)
     rhino = readImage("tests/images/rhino.png")
   ctx.drawImage(rhino, rect(33, 71, 104, 124), rect(21, 20, 87, 104))
-  image.diffVs("tests/contexts/draw_image_rhino2.png")
+  image.xray("tests/contexts/draw_image_rhino2.png")
 
 block:
   let
@@ -643,7 +643,7 @@ block:
   ctx.fillStyle.color = color(0, 0, 1, 1)
   ctx.restore()
   ctx.fillRect(0, 0, ctx.image.width.float32, ctx.image.height.float32)
-  ctx.image.diffVs("tests/contexts/paintSaveRestore.png")
+  ctx.image.xray("tests/contexts/paintSaveRestore.png")
 
 block:
   # From https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/textBaseline
@@ -674,4 +674,4 @@ block:
     ctx.stroke()
     ctx.fillText("Abcdefghijklmnop (" & $baseline & ")", 0, y)
 
-  ctx.image.diffVs("tests/contexts/textBaseline_1.png")
+  ctx.image.xray("tests/contexts/textBaseline_1.png")
diff --git a/tests/test_fonts.nim b/tests/test_fonts.nim
index 759d190..632b94b 100644
--- a/tests/test_fonts.nim
+++ b/tests/test_fonts.nim
@@ -1,4 +1,4 @@
-import os, pixie, pixie/fileformats/png, strformat, unicode, utils
+import os, pixie, pixie/fileformats/png, strformat, unicode, xrays
 
 proc wh(image: Image): Vec2 =
   ## Return with and height as a size vector.
@@ -25,7 +25,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "fill")
 
-  image.diffVs("tests/fonts/masters/image_fill.png")
+  image.xray("tests/fonts/masters/image_fill.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -34,7 +34,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.strokeText(font, "stroke")
 
-  image.diffVs("tests/fonts/masters/image_stroke.png")
+  image.xray("tests/fonts/masters/image_stroke.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -42,7 +42,7 @@ block:
   let mask = newMask(200, 100)
   mask.fillText(font, "fill")
 
-  mask.diffVs("tests/fonts/masters/mask_fill.png")
+  mask.xray("tests/fonts/masters/mask_fill.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -50,7 +50,7 @@ block:
   let mask = newMask(200, 100)
   mask.strokeText(font, "stroke")
 
-  mask.diffVs("tests/fonts/masters/mask_stroke.png")
+  mask.xray("tests/fonts/masters/mask_stroke.png")
 
 block:
   # SVG Fonts have no masters
@@ -59,35 +59,35 @@ block:
     font.size = 48
     let mask = newMask(200, 100)
     mask.fillText(font, "Changa")
-    mask.diffVs("tests/fonts/svg_changa.png")
+    mask.xray("tests/fonts/svg_changa.png")
 
   block:
     var font = readFont("tests/fonts/DejaVuSans.svg")
     font.size = 48
     let mask = newMask(200, 100)
     mask.fillText(font, "Deja vu ")
-    mask.diffVs("tests/fonts/svg_dejavu.png")
+    mask.xray("tests/fonts/svg_dejavu.png")
 
   block:
     var font = readFont("tests/fonts/IBMPlexSans-Regular.svg")
     font.size = 48
     let mask = newMask(200, 100)
     mask.fillText(font, "IBM ")
-    mask.diffVs("tests/fonts/svg_ibm.png")
+    mask.xray("tests/fonts/svg_ibm.png")
 
   block:
     var font = readFont("tests/fonts/Moon-Bold.svg")
     font.size = 48
     let mask = newMask(200, 100)
     mask.fillText(font, "Moon ")
-    mask.diffVs("tests/fonts/svg_moon.png")
+    mask.xray("tests/fonts/svg_moon.png")
 
   block:
     var font = readFont("tests/fonts/Ubuntu.svg")
     font.size = 48
     let mask = newMask(200, 100)
     mask.fillText(font, "Ubuntu ")
-    mask.diffVs("tests/fonts/svg_ubuntu.png")
+    mask.xray("tests/fonts/svg_ubuntu.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -97,7 +97,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "asdf")
 
-  image.diffVs("tests/fonts/masters/basic1.png")
+  image.xray("tests/fonts/masters/basic1.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -107,7 +107,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "A cow")
 
-  image.diffVs("tests/fonts/masters/basic2.png")
+  image.xray("tests/fonts/masters/basic2.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -117,7 +117,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "A bit of text HERE")
 
-  image.diffVs("tests/fonts/masters/basic3.png")
+  image.xray("tests/fonts/masters/basic3.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -128,7 +128,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "Line height")
 
-  image.diffVs("tests/fonts/masters/basic4.png")
+  image.xray("tests/fonts/masters/basic4.png")
 
 block:
   var font = readFont("tests/fonts/Ubuntu-Regular_1.ttf")
@@ -138,7 +138,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "Another font")
 
-  image.diffVs("tests/fonts/masters/basic5.png")
+  image.xray("tests/fonts/masters/basic5.png")
 
 block:
   var font = readFont("tests/fonts/Aclonica-Regular_1.ttf")
@@ -148,7 +148,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "Different font")
 
-  image.diffVs("tests/fonts/masters/basic6.png")
+  image.xray("tests/fonts/masters/basic6.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -161,7 +161,7 @@ block:
     font, "Second line", translate(vec2(0, font.defaultLineHeight))
   )
 
-  image.diffVs("tests/fonts/masters/basic7.png")
+  image.xray("tests/fonts/masters/basic7.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -175,7 +175,7 @@ block:
     bounds = vec2(200, 0)
   )
 
-  image.diffVs("tests/fonts/masters/basic8.png")
+  image.xray("tests/fonts/masters/basic8.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -189,7 +189,7 @@ block:
     bounds = vec2(100, 0)
   )
 
-  image.diffVs("tests/fonts/masters/basic8b.png")
+  image.xray("tests/fonts/masters/basic8b.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -203,7 +203,7 @@ block:
     bounds = vec2(200, 0)
   )
 
-  image.diffVs("tests/fonts/masters/basic9.png")
+  image.xray("tests/fonts/masters/basic9.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -218,7 +218,7 @@ block:
     hAlign = RightAlign
   )
 
-  image.diffVs("tests/fonts/masters/basic10.png")
+  image.xray("tests/fonts/masters/basic10.png")
 
 const
   paragraph = "ShehadcometotheconclusionthatyoucouldtellalotaboutapersonbytheirearsThewaytheystuckoutandthesizeoftheearlobescouldgiveyou"
@@ -241,7 +241,7 @@ block:
     )
 
     let name = if i > 0: &"paragraph1_{i + 1}" else: "paragraph1"
-    image.diffVs(&"tests/fonts/masters/{name}.png")
+    image.xray(&"tests/fonts/masters/{name}.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -259,7 +259,7 @@ block:
     )
 
     let name = if i > 0: &"paragraph1_nokern_{i + 1}" else: "paragraph1_nokern"
-    image.diffVs(&"tests/fonts/masters/{name}.png")
+    image.xray(&"tests/fonts/masters/{name}.png")
 
 block:
   var font = readFont("tests/fonts/Ubuntu-Regular_1.ttf")
@@ -276,7 +276,7 @@ block:
     )
 
     let name = if i > 0: &"paragraph2_{i + 1}" else: "paragraph2"
-    image.diffVs(&"tests/fonts/masters/{name}.png")
+    image.xray(&"tests/fonts/masters/{name}.png")
 
 block:
   var font = readFont("tests/fonts/Ubuntu-Regular_1.ttf")
@@ -294,7 +294,7 @@ block:
     )
 
     let name = if i > 0: &"paragraph2_nokern_{i + 1}" else: "paragraph2_nokern"
-    image.diffVs(&"tests/fonts/masters/{name}.png")
+    image.xray(&"tests/fonts/masters/{name}.png")
 
 block:
   var font = readFont("tests/fonts/IBMPlexSans-Regular_2.ttf")
@@ -311,7 +311,7 @@ block:
     )
 
     let name = if i > 0: &"paragraph3_{i + 1}" else: "paragraph3"
-    image.diffVs(&"tests/fonts/masters/{name}.png")
+    image.xray(&"tests/fonts/masters/{name}.png")
 
 block:
   var font = readFont("tests/fonts/IBMPlexSans-Regular_2.ttf")
@@ -329,7 +329,7 @@ block:
     )
 
     let name = if i > 0: &"paragraph3_nokern_{i + 1}" else: "paragraph3_nokern"
-    image.diffVs(&"tests/fonts/masters/{name}.png")
+    image.xray(&"tests/fonts/masters/{name}.png")
 
 block:
   var font = readFont("tests/fonts/NotoSans-Regular_4.ttf")
@@ -346,7 +346,7 @@ block:
     )
 
     let name = if i > 0: &"paragraph4_{i + 1}" else: "paragraph4"
-    image.diffVs(&"tests/fonts/masters/{name}.png")
+    image.xray(&"tests/fonts/masters/{name}.png")
 
 block:
   var font = readFont("tests/fonts/NotoSans-Regular_4.ttf")
@@ -364,7 +364,7 @@ block:
     )
 
     let name = if i > 0: &"paragraph4_nokern_{i + 1}" else: "paragraph4_nokern"
-    image.diffVs(&"tests/fonts/masters/{name}.png")
+    image.xray(&"tests/fonts/masters/{name}.png")
 
 block:
   var font = readFont("tests/fonts/Pacifico-Regular_4.ttf")
@@ -381,7 +381,7 @@ block:
     )
 
     let name = if i > 0: &"paragraph5_{i + 1}" else: "paragraph5"
-    image.diffVs(&"tests/fonts/masters/{name}.png")
+    image.xray(&"tests/fonts/masters/{name}.png")
 
 block:
   var font = readFont("tests/fonts/Pacifico-Regular_4.ttf")
@@ -399,7 +399,7 @@ block:
     )
 
     let name = if i > 0: &"paragraph5_nokern_{i + 1}" else: "paragraph5_nokern"
-    image.diffVs(&"tests/fonts/masters/{name}.png")
+    image.xray(&"tests/fonts/masters/{name}.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -413,7 +413,7 @@ block:
     bounds = image.wh
   )
 
-  image.diffVs("tests/fonts/masters/huge1.png")
+  image.xray("tests/fonts/masters/huge1.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -428,7 +428,7 @@ block:
     bounds = image.wh
   )
 
-  image.diffVs("tests/fonts/masters/huge1_nokern.png")
+  image.xray("tests/fonts/masters/huge1_nokern.png")
 
 block:
   var font = readFont("tests/fonts/Ubuntu-Regular_1.ttf")
@@ -442,7 +442,7 @@ block:
     bounds = image.wh
   )
 
-  image.diffVs("tests/fonts/masters/huge2.png")
+  image.xray("tests/fonts/masters/huge2.png")
 
 block:
   var font = readFont("tests/fonts/Ubuntu-Regular_1.ttf")
@@ -457,7 +457,7 @@ block:
     bounds = image.wh
   )
 
-  image.diffVs("tests/fonts/masters/huge2_nokern.png")
+  image.xray("tests/fonts/masters/huge2_nokern.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -471,7 +471,7 @@ block:
     bounds = image.wh
   )
 
-  image.diffVs("tests/fonts/masters/huge3.png")
+  image.xray("tests/fonts/masters/huge3.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -486,7 +486,7 @@ block:
     bounds = image.wh
   )
 
-  image.diffVs("tests/fonts/masters/huge3_nokern.png")
+  image.xray("tests/fonts/masters/huge3_nokern.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -500,7 +500,7 @@ block:
     bounds = image.wh
   )
 
-  image.diffVs("tests/fonts/masters/pairs1.png")
+  image.xray("tests/fonts/masters/pairs1.png")
 
 block:
   var font = readFont("tests/fonts/Ubuntu-Regular_1.ttf")
@@ -514,7 +514,7 @@ block:
     bounds = image.wh
   )
 
-  image.diffVs("tests/fonts/masters/pairs2.png")
+  image.xray("tests/fonts/masters/pairs2.png")
 
 block:
   var font = readFont("tests/fonts/IBMPlexSans-Regular_2.ttf")
@@ -528,7 +528,7 @@ block:
     bounds = image.wh
   )
 
-  image.diffVs("tests/fonts/masters/pairs3.png")
+  image.xray("tests/fonts/masters/pairs3.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -548,7 +548,7 @@ Seventh line""",
     bounds = image.wh
   )
 
-  image.diffVs("tests/fonts/masters/lines1.png")
+  image.xray("tests/fonts/masters/lines1.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -567,7 +567,7 @@ Fifth line""",
     bounds = image.wh
   )
 
-  image.diffVs("tests/fonts/masters/lines2.png")
+  image.xray("tests/fonts/masters/lines2.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -648,7 +648,7 @@ block:
     vAlign = BottomAlign
   )
 
-  image.diffVs("tests/fonts/masters/alignments.png")
+  image.xray("tests/fonts/masters/alignments.png")
 
 block:
   var font = readFont("tests/fonts/IBMPlexSans-Regular_2.ttf")
@@ -667,7 +667,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "Text")
 
-  image.diffVs("tests/fonts/masters/image_paint_fill.png")
+  image.xray("tests/fonts/masters/image_paint_fill.png")
 
 block:
   var font1 = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -692,14 +692,14 @@ block:
 
   image.fillText(arrangement)
 
-  image.diffVs("tests/fonts/masters/spans1.png")
+  image.xray("tests/fonts/masters/spans1.png")
 
   let ctx = newContext(image)
   ctx.fillStyle = rgba(127, 127, 127, 127)
   for i, rect in arrangement.selectionRects:
     ctx.fillRect(rect)
 
-  image.diffVs("tests/fonts/masters/selection_rects1.png")
+  image.xray("tests/fonts/masters/selection_rects1.png")
 
 block:
   var font1 = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -724,14 +724,14 @@ block:
 
   image.fillText(arrangement)
 
-  image.diffVs("tests/fonts/masters/spans2.png")
+  image.xray("tests/fonts/masters/spans2.png")
 
   let ctx = newContext(image)
   ctx.fillStyle = rgba(127, 127, 127, 127)
   for i, rect in arrangement.selectionRects:
     ctx.fillRect(rect)
 
-  image.diffVs("tests/fonts/masters/selection_rects2.png")
+  image.xray("tests/fonts/masters/selection_rects2.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -751,7 +751,7 @@ block:
   for i, rect in arrangement.selectionRects:
     ctx.fillRect(rect)
 
-  image.diffVs("tests/fonts/masters/selection_rects3.png")
+  image.xray("tests/fonts/masters/selection_rects3.png")
 
 block:
   let
@@ -813,7 +813,7 @@ block:
 
   image.fillText(arrangement)
 
-  image.diffVs("tests/fonts/masters/spans4.png")
+  image.xray("tests/fonts/masters/spans4.png")
 
 block:
   let ubuntu = readTypeface("tests/fonts/Ubuntu-Regular_1.ttf")
@@ -847,7 +847,7 @@ block:
 
   image.fillText(arrangement, translate(vec2(20, 20)))
 
-  image.diffVs("tests/fonts/masters/spans5.png")
+  image.xray("tests/fonts/masters/spans5.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -862,7 +862,7 @@ block:
     bounds = vec2(200, 0)
   )
 
-  image.diffVs("tests/fonts/masters/underline1.png")
+  image.xray("tests/fonts/masters/underline1.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -878,7 +878,7 @@ block:
     bounds = vec2(200, 0)
   )
 
-  image.diffVs("tests/fonts/masters/underline2.png")
+  image.xray("tests/fonts/masters/underline2.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -893,7 +893,7 @@ block:
     bounds = vec2(200, 0)
   )
 
-  image.diffVs("tests/fonts/masters/underline3.png")
+  image.xray("tests/fonts/masters/underline3.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -908,7 +908,7 @@ block:
     bounds = vec2(200, 0)
   )
 
-  image.diffVs("tests/fonts/masters/strikethrough1.png")
+  image.xray("tests/fonts/masters/strikethrough1.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -924,7 +924,7 @@ block:
     bounds = vec2(200, 0)
   )
 
-  image.diffVs("tests/fonts/masters/strikethrough2.png")
+  image.xray("tests/fonts/masters/strikethrough2.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -939,7 +939,7 @@ block:
     bounds = vec2(200, 0)
   )
 
-  image.diffVs("tests/fonts/masters/strikethrough3.png")
+  image.xray("tests/fonts/masters/strikethrough3.png")
 
 block:
   let ubuntu = readTypeface("tests/fonts/Ubuntu-Regular_1.ttf")
@@ -986,7 +986,7 @@ block:
 
   image.fillText(arrangement, translate(vec2(20, 20)))
 
-  image.diffVs("tests/fonts/masters/spans6.png")
+  image.xray("tests/fonts/masters/spans6.png")
 
 block:
 
@@ -1023,7 +1023,7 @@ block:
   # Enable this to show how text is drawing directly
   # image.fillText(arrangement, translate(vec2(40, 170)))
 
-  image.diffVs("tests/fonts/masters/spans7.png")
+  image.xray("tests/fonts/masters/spans7.png")
 
 block:
   var font = readFont("tests/fonts/Roboto-Regular_1.ttf")
@@ -1043,7 +1043,7 @@ block:
     bounds = vec2(200, 0)
   )
 
-  image.diffVs("tests/fonts/masters/paints1.png")
+  image.xray("tests/fonts/masters/paints1.png")
 
 block:
   var typeface = readTypeface("tests/fonts/Roboto-Regular_1.ttf")
@@ -1056,7 +1056,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "Grumpy wizards make toxic brew for the evil Queen and Jack.")
 
-  image.diffVs("tests/fonts/masters/cff.png")
+  image.xray("tests/fonts/masters/cff.png")
 
 block:
   var font = readFont("tests/fonts/NotoSansJP-Regular.ttf")
@@ -1065,7 +1065,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "仰コソ会票カク帰了ノ終準港みせス議徳モチタ提請ルまつ力路お")
 
-  image.diffVs("tests/fonts/masters/cff_jp.png")
+  image.xray("tests/fonts/masters/cff_jp.png")
 
 block:
   var font = readFont("tests/fonts/Inter-Regular.ttf")
@@ -1075,7 +1075,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "Grumpy wizards make toxic brew for the evil Queen and Jack.")
 
-  image.diffVs("tests/fonts/masters/cff_underline.png")
+  image.xray("tests/fonts/masters/cff_underline.png")
 
 block:
   var font = readFont("tests/fonts/Inter-Regular.ttf")
@@ -1085,7 +1085,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "Grumpy wizards make toxic brew for the evil Queen and Jack.")
 
-  image.diffVs("tests/fonts/masters/cff_strikethrough.png")
+  image.xray("tests/fonts/masters/cff_strikethrough.png")
 
 block:
   var font = readFont("tests/fonts/Inter-Regular.ttf")
@@ -1096,7 +1096,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "Grumpy ウィザード make 有毒な醸造 for the 悪い女王 and Jack.")
 
-  image.diffVs("tests/fonts/masters/fallback.png")
+  image.xray("tests/fonts/masters/fallback.png")
 
 block:
   let
@@ -1119,7 +1119,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "Grumpy ウィザード make 有毒な醸造 for the 悪い女王 and Jack.")
 
-  image.diffVs("tests/fonts/masters/fallback2.png")
+  image.xray("tests/fonts/masters/fallback2.png")
 
 block:
   var font = readFont("tests/fonts/Inter-Regular.ttf")
@@ -1129,7 +1129,7 @@ block:
   image.fill(rgba(255, 255, 255, 255))
   image.fillText(font, "This[]Advance!")
 
-  image.diffVs("tests/fonts/masters/tofu_advance.png")
+  image.xray("tests/fonts/masters/tofu_advance.png")
 
 block:
   let image = newImage(200, 200)
@@ -1187,7 +1187,7 @@ block:
       transform = translate(vec2(0, 60))
   )
 
-  image.diffVs("tests/fonts/masters/customlineheight.png")
+  image.xray("tests/fonts/masters/customlineheight.png")
 
 block:
   var font = readTypefaces("tests/fonts/PTSans.ttc")[0].newFont
diff --git a/tests/test_gif.nim b/tests/test_gif.nim
index 65d9d3c..85a1b24 100644
--- a/tests/test_gif.nim
+++ b/tests/test_gif.nim
@@ -1,11 +1,11 @@
-import pixie, pixie/fileformats/gif, utils
+import pixie, pixie/fileformats/gif, xrays
 
 block:
   let
     path = "tests/fileformats/gif/3x5.gif"
     image = readImage(path)
     dimensions = decodeGifDimensions(readFile(path))
-  image.diffVs("tests/fileformats/gif/3x5.png")
+  image.xray("tests/fileformats/gif/3x5.png")
   doAssert image.width == dimensions.width
   doAssert image.height == dimensions.height
 
@@ -14,7 +14,7 @@ block:
     path = "tests/fileformats/gif/audrey.gif"
     image = readImage(path)
     dimensions = decodeGifDimensions(readFile(path))
-  image.diffVs("tests/fileformats/gif/audrey.png")
+  image.xray("tests/fileformats/gif/audrey.png")
   doAssert image.width == dimensions.width
   doAssert image.height == dimensions.height
 
@@ -23,7 +23,7 @@ block:
     path = "tests/fileformats/gif/sunflower.gif"
     image = readImage(path)
     dimensions = decodeGifDimensions(readFile(path))
-  image.diffVs("tests/fileformats/gif/sunflower.png")
+  image.xray("tests/fileformats/gif/sunflower.png")
   doAssert image.width == dimensions.width
   doAssert image.height == dimensions.height
 
@@ -32,13 +32,13 @@ block:
     path = "tests/fileformats/gif/sunflower.gif"
     image = readImage(path)
     dimensions = decodeGifDimensions(readFile(path))
-  image.diffVs("tests/fileformats/gif/sunflower.png")
+  image.xray("tests/fileformats/gif/sunflower.png")
   doAssert image.width == dimensions.width
   doAssert image.height == dimensions.height
 
 block:
   let img4 = readImage("tests/fileformats/gif/newtons_cradle.gif")
-  img4.diffVs("tests/fileformats/gif/newtons_cradle.png")
+  img4.xray("tests/fileformats/gif/newtons_cradle.png")
 
   let animatedGif =
     decodeGif(readFile("tests/fileformats/gif/newtons_cradle.gif"))
diff --git a/tests/test_images.nim b/tests/test_images.nim
index b74e32d..9351af0 100644
--- a/tests/test_images.nim
+++ b/tests/test_images.nim
@@ -1,4 +1,4 @@
-import chroma, pixie, pixie/internal, vmath, utils
+import chroma, pixie, pixie/internal, vmath, xrays
 
 block:
   let image = newImage(10, 10)
@@ -45,77 +45,77 @@ block:
 
   a.draw(b)
 
-  a.diffVs("tests/images/flipped1.png")
+  a.xray("tests/images/flipped1.png")
   a.flipVertical()
-  a.diffVs("tests/images/flipped2.png")
+  a.xray("tests/images/flipped2.png")
   a.flipHorizontal()
-  a.diffVs("tests/images/flipped3.png")
+  a.xray("tests/images/flipped3.png")
 
 block:
   let
     a = readImage("tests/images/flipped1.png")
     b = a.superImage(-10, 0, 20, 20)
-  b.diffVs("tests/images/superimage1.png")
+  b.xray("tests/images/superimage1.png")
 
 block:
   let
     a = readImage("tests/images/flipped1.png")
     b = a.superImage(-10, -10, 20, 20)
-  b.diffVs("tests/images/superimage2.png")
+  b.xray("tests/images/superimage2.png")
 
 block:
   let
     a = readImage("tests/images/flipped1.png")
     b = a.superImage(90, 0, 120, 120)
-  b.diffVs("tests/images/superimage3.png")
+  b.xray("tests/images/superimage3.png")
 
 block:
   let
     a = readImage("tests/images/flipped1.png")
     b = a.superImage(90, 90, 120, 120)
-  b.diffVs("tests/images/superimage4.png")
+  b.xray("tests/images/superimage4.png")
 
 block:
   let
     a = readImage("tests/images/flipped1.png")
     b = a.superImage(-10, -10, 120, 120)
-  b.diffVs("tests/images/superimage5.png")
+  b.xray("tests/images/superimage5.png")
 
 block:
   let
     a = readImage("tests/images/flipped1.png")
     b = a.superImage(45, 45, 20, 20)
-  b.diffVs("tests/images/superimage6.png")
+  b.xray("tests/images/superimage6.png")
 
 block:
   let
     a = readImage("tests/images/flipped1.png")
     b = a.minifyBy2()
-  b.diffVs("tests/images/minifiedBy2.png")
+  b.xray("tests/images/minifiedBy2.png")
 
 block:
   let
     a = readImage("tests/images/minifiedBy2.png")
     b = a.magnifyBy2()
-  b.diffVs("tests/images/magnifiedBy2.png")
+  b.xray("tests/images/magnifiedBy2.png")
 
 block:
   let
     a = readImage("tests/images/flipped1.png")
     b = a.minifyBy2(2)
-  b.diffVs("tests/images/minifiedBy4.png")
+  b.xray("tests/images/minifiedBy4.png")
 
 block:
   let
     a = readImage("tests/images/minifiedBy4.png")
     b = a.magnifyBy2(2)
-  b.diffVs("tests/images/magnifiedBy4.png")
+  b.xray("tests/images/magnifiedBy4.png")
 
 block:
   let
     a = readImage("tests/fileformats/png/mandrill.png")
     b = a.minifyBy2()
-  b.diffVs("tests/images/minifiedMandrill.png")
+  b.xray("tests/images/minifiedMandrill.png")
 
 block:
   let a = newImage(100, 100)
@@ -129,7 +129,7 @@ block:
   ctx.image.fill(rgba(0, 0, 0, 255))
   ctx.fillRect(rect(25, 25, 50, 50), )
   ctx.image.blur(20)
-  ctx.image.diffVs("tests/images/imageblur20.png")
+  ctx.image.xray("tests/images/imageblur20.png")
 
 block:
   let ctx = newContext(100, 100)
@@ -137,7 +137,7 @@ block:
   ctx.image.fill(rgba(0, 0, 0, 255))
   ctx.fillRect(rect(25, 25, 50, 50))
   ctx.image.blur(20, rgba(0, 0, 0, 255))
-  ctx.image.diffVs("tests/images/imageblur20oob.png")
+  ctx.image.xray("tests/images/imageblur20oob.png")
 
 block: # Test conversion between image and mask
   let
@@ -163,7 +163,7 @@ block:
   let image = newImage(100, 100)
   image.fillPath(p, rgba(255, 0, 0, 255))
 
-  newImage(newMask(image)).diffVs("tests/images/mask2image.png")
+  newImage(newMask(image)).xray("tests/images/mask2image.png")
 
 block:
   let image = newImage(100, 100)
diff --git a/tests/test_images_draw.nim b/tests/test_images_draw.nim
index 6380107..c2d99f1 100644
--- a/tests/test_images_draw.nim
+++ b/tests/test_images_draw.nim
@@ -1,4 +1,4 @@
-import pixie, strformat, utils
+import pixie, strformat, xrays
 
 block:
   let
@@ -8,7 +8,7 @@ block:
   b.fill(rgba(0, 255, 0, 255))
 
   a.draw(b, translate(vec2(250, 250)))
-  a.diffVs("tests/images/rotate0.png")
+  a.xray("tests/images/rotate0.png")
 
 block:
   let
@@ -18,7 +18,7 @@ block:
   b.fill(rgba(0, 255, 0, 255))
 
   a.draw(b, translate(vec2(250, 250)) * rotate(90 * PI.float32 / 180))
-  a.diffVs("tests/images/rotate90.png")
+  a.xray("tests/images/rotate90.png")
 
 block:
   let
@@ -28,7 +28,7 @@ block:
   b.fill(rgba(0, 255, 0, 255))
 
   a.draw(b, translate(vec2(250, 250)) * rotate(180 * PI.float32 / 180))
-  a.diffVs("tests/images/rotate180.png")
+  a.xray("tests/images/rotate180.png")
 
 block:
   let
@@ -38,7 +38,7 @@ block:
   b.fill(rgba(0, 255, 0, 255))
 
   a.draw(b, translate(vec2(250, 250)) * rotate(270 * PI.float32 / 180))
-  a.diffVs("tests/images/rotate270.png")
+  a.xray("tests/images/rotate270.png")
 
 block:
   let
@@ -48,14 +48,14 @@ block:
   b.fill(rgba(0, 255, 0, 255))
 
   a.draw(b, translate(vec2(250, 250)) * rotate(360 * PI.float32 / 180))
-  a.diffVs("tests/images/rotate360.png")
+  a.xray("tests/images/rotate360.png")
 
 block:
   let ctx = newContext(100, 100)
   ctx.fillStyle = rgba(255, 255, 0, 255)
   ctx.image.fill(rgba(0, 255, 255, 255))
   ctx.fillRect(rect(vec2(10, 10), vec2(30, 30)))
-  ctx.image.diffVs("tests/images/drawRect.png")
+  ctx.image.xray("tests/images/drawRect.png")
 
 block:
   let ctx = newContext(100, 100)
@@ -63,14 +63,14 @@ block:
   ctx.lineWidth = 10
   ctx.image.fill(rgba(0, 255, 255, 255))
   ctx.strokeRect(rect(vec2(10, 10), vec2(30, 30)))
-  ctx.image.diffVs("tests/images/strokeRect.png")
+  ctx.image.xray("tests/images/strokeRect.png")
 
 block:
   let ctx = newContext(100, 100)
   ctx.fillStyle = rgba(255, 255, 0, 255)
   ctx.image.fill(rgba(0, 255, 255, 255))
   ctx.fillRoundedRect(rect(vec2(10, 10), vec2(30, 30)), 10)
-  ctx.image.diffVs("tests/images/drawRoundedRect.png")
+  ctx.image.xray("tests/images/drawRoundedRect.png")
 
 block:
   let ctx = newContext(100, 100)
@@ -78,7 +78,7 @@ block:
   ctx.lineWidth = 10
   ctx.image.fill(rgba(0, 255, 255, 255))
   ctx.strokeRoundedRect(rect(vec2(10, 10), vec2(30, 30)), 10)
-  ctx.image.diffVs("tests/images/strokeRoundedRect.png")
+  ctx.image.xray("tests/images/strokeRoundedRect.png")
 
 block:
   let ctx = newContext(100, 100)
@@ -86,14 +86,14 @@ block:
   ctx.lineWidth = 10
   ctx.image.fill(rgba(0, 255, 255, 255))
   ctx.strokeSegment(segment(vec2(10, 10), vec2(90, 90)))
-  ctx.image.diffVs("tests/images/drawSegment.png")
+  ctx.image.xray("tests/images/drawSegment.png")
 
 block:
   let ctx = newContext(100, 100)
   ctx.fillStyle = rgba(255, 255, 0, 255)
   ctx.image.fill(rgba(0, 255, 255, 255))
   ctx.fillEllipse(vec2(50, 50), 25, 25)
-  ctx.image.diffVs("tests/images/drawEllipse.png")
+  ctx.image.xray("tests/images/drawEllipse.png")
 
 block:
   let ctx = newContext(100, 100)
@@ -101,14 +101,14 @@ block:
   ctx.lineWidth = 10
   ctx.image.fill(rgba(0, 255, 255, 255))
   ctx.strokeEllipse(vec2(50, 50), 25, 25)
-  ctx.image.diffVs("tests/images/strokeEllipse.png")
+  ctx.image.xray("tests/images/strokeEllipse.png")
 
 block:
   let ctx = newContext(100, 100)
   ctx.fillStyle = rgba(255, 255, 0, 255)
   ctx.image.fill(rgba(0, 255, 255, 255))
   ctx.fillPolygon(vec2(50, 50), 30, 6)
-  ctx.image.diffVs("tests/images/drawPolygon.png")
+  ctx.image.xray("tests/images/drawPolygon.png")
 
 block:
   let ctx = newContext(100, 100)
@@ -116,7 +116,7 @@ block:
   ctx.lineWidth = 10
   ctx.image.fill(rgba(0, 255, 255, 255))
   ctx.strokePolygon(vec2(50, 50), 30, 6)
-  ctx.image.diffVs("tests/images/strokePolygon.png")
+  ctx.image.xray("tests/images/strokePolygon.png")
 
 block:
   let
@@ -126,7 +126,7 @@ block:
   b.fill(rgba(0, 255, 0, 255))
 
   a.draw(b, translate(vec2(250, 250)) * scale(vec2(0.5, 0.5)))
-  a.diffVs("tests/images/scaleHalf.png")
+  a.xray("tests/images/scaleHalf.png")
 
 block:
   let
@@ -135,7 +135,7 @@ block:
   a.fill(rgba(255, 255, 255, 255))
   b.fill(rgbx(0, 0, 0, 255))
   a.draw(b, translate(vec2(0.5, 0.5)))
-  a.diffVs("tests/images/masters/smooth1.png")
+  a.xray("tests/images/masters/smooth1.png")
 
 block:
   let
@@ -144,7 +144,7 @@ block:
   a.fill(rgba(255, 255, 255, 255))
   b.fill(rgbx(0, 0, 0, 255))
   a.draw(b, translate(vec2(0, 50)) * rotate(45.toRadians))
-  a.diffVs("tests/images/masters/smooth2.png")
+  a.xray("tests/images/masters/smooth2.png")
 
 block:
   let
@@ -153,7 +153,7 @@ block:
   a.fill(rgba(255, 255, 255, 255))
   b.fill(rgba(0, 0, 0, 255))
   a.draw(b, translate(vec2(25.2, 25)))
-  a.diffVs("tests/images/masters/smooth3.png")
+  a.xray("tests/images/masters/smooth3.png")
 
 block:
   let
@@ -162,7 +162,7 @@ block:
   a.fill(rgba(255, 255, 255, 255))
   b.fill(rgba(0, 0, 0, 255))
   a.draw(b, translate(vec2(25.2, 25.6)))
-  a.diffVs("tests/images/masters/smooth4.png")
+  a.xray("tests/images/masters/smooth4.png")
 
 block:
   let
@@ -172,7 +172,7 @@ block:
   b.fill(rgbx(255, 0, 0, 255))
   let m = translate(vec2(50, 50)) * rotate(30.toRadians)
   a.draw(b, m)
-  a.diffVs("tests/images/masters/smooth5.png")
+  a.xray("tests/images/masters/smooth5.png")
 
 block:
   let
@@ -181,7 +181,7 @@ block:
   a.fill(rgba(255, 255, 255, 255))
   let m = translate(vec2(50, 50)) * rotate(30.toRadians)
   a.draw(b, m)
-  a.diffVs("tests/images/masters/smooth6.png")
+  a.xray("tests/images/masters/smooth6.png")
 
 block:
   let
@@ -190,7 +190,7 @@ block:
   a.fill(rgba(255, 255, 255, 255))
   let m = translate(vec2(50, 50)) * rotate(30.toRadians) * scale(vec2(0.1, 0.1))
   a.draw(b, m)
-  a.diffVs("tests/images/masters/smooth7.png")
+  a.xray("tests/images/masters/smooth7.png")
 
 block:
   let
@@ -199,7 +199,7 @@ block:
   a.fill(rgba(255, 255, 255, 255))
   let m = scale(vec2(2, 2))
   a.draw(b, m)
-  a.diffVs("tests/images/masters/smooth8.png")
+  a.xray("tests/images/masters/smooth8.png")
 
 block:
   let
@@ -208,7 +208,7 @@ block:
   a.fill(rgba(255, 255, 255, 255))
   let m = translate(vec2(1, 1)) * scale(vec2(2, 2))
   a.draw(b, m)
-  a.diffVs("tests/images/masters/smooth9.png")
+  a.xray("tests/images/masters/smooth9.png")
 
 block:
   let
@@ -217,7 +217,7 @@ block:
   a.fill(rgba(255, 255, 255, 255))
   let m = translate(vec2(0.5, 0.5)) * scale(vec2(2, 2))
   a.draw(b, m)
-  a.diffVs("tests/images/masters/smooth10.png")
+  a.xray("tests/images/masters/smooth10.png")
 
 block:
   let
@@ -228,7 +228,7 @@ block:
     rotate(-15.toRadians) *
     scale(vec2(263.86/40, 263.86/40))
   a.draw(b, m)
-  a.diffVs("tests/images/masters/smooth11.png")
+  a.xray("tests/images/masters/smooth11.png")
 
 block:
   let
@@ -240,7 +240,7 @@ block:
   a.draw(b, m * translate(vec2(-40, 0)))
   a.draw(b, m * translate(vec2(-40, -40)))
   a.draw(b, m * translate(vec2(0, -40)))
-  a.diffVs("tests/images/masters/smooth12.png")
+  a.xray("tests/images/masters/smooth12.png")
 
 block:
   let
@@ -249,19 +249,19 @@ block:
   a.fill(rgba(255, 255, 255, 255))
   b.fill(rgba(0, 0, 0, 255))
   a.draw(b, scale(vec2(0.5, 0.5)))
-  a.diffVs("tests/images/masters/minify_odd.png")
+  a.xray("tests/images/masters/minify_odd.png")
 
 block:
   let
     rock = readImage("tests/images/rock.png")
     minified = rock.minifyBy2()
-  minified.diffVs("tests/images/masters/rock_minified.png")
+  minified.xray("tests/images/masters/rock_minified.png")
 
 block:
   let
     rock = readImage("tests/images/rock.png")
     minified = rock.minifyBy2(2)
-  minified.diffVs("tests/images/masters/rock_minified2.png")
+  minified.xray("tests/images/masters/rock_minified2.png")
 
 block:
   let pathStr = """
@@ -278,7 +278,7 @@ block:
   strokeImage.strokePath(pathStr, color(1, 1, 1, 1), strokeWidth = 4)
   image.draw(strokeImage)
 
-  image.diffVs("tests/images/fillOptimization.png")
+  image.xray("tests/images/fillOptimization.png")
   doAssert image[10, 10] == rgbx(255, 127, 63, 255)
 
 block:
@@ -306,4 +306,4 @@ block:
 
     a.draw(b, translate(translation))
 
-  a.diffVs("tests/images/fillOptimization2.png")
+  a.xray("tests/images/fillOptimization2.png")
diff --git a/tests/test_masks.nim b/tests/test_masks.nim
index 4dc7fef..a48c02b 100644
--- a/tests/test_masks.nim
+++ b/tests/test_masks.nim
@@ -1,4 +1,4 @@
-import pixie, utils
+import pixie, xrays
 
 block:
   let mask = newMask(100, 100)
@@ -34,13 +34,13 @@ block:
 
   doAssert minified.width == 50 and minified.height == 50
 
-  minified.diffVs("tests/masks/maskMinified.png")
+  minified.xray("tests/masks/maskMinified.png")
 
 block:
   let
     a = readImage("tests/masks/maskMinified.png")
     b = a.magnifyBy2()
-  b.diffVs("tests/masks/maskMagnified.png")
+  b.xray("tests/masks/maskMagnified.png")
 
 block:
   let image = newImage(100, 100)
@@ -53,7 +53,7 @@ block:
   mask.fillPath(path)
 
   image.draw(mask)
-  image.diffVs("tests/masks/circleMask.png")
+  image.xray("tests/masks/circleMask.png")
 
 block:
   let a = newMask(100, 100)
@@ -66,7 +66,7 @@ block:
   b.fillPath(path)
 
   a.draw(b)
-  a.diffVs("tests/masks/maskedMask.png")
+  a.xray("tests/masks/maskedMask.png")
 
 block:
   let a = newMask(100, 100)
@@ -79,7 +79,7 @@ block:
   b.fillPath(path, rgba(0, 0, 0, 255))
 
   a.draw(b)
-  a.diffVs("tests/masks/imageMaskedMask.png")
+  a.xray("tests/masks/imageMaskedMask.png")
 
 block:
   let path = newPath()
@@ -90,7 +90,7 @@ block:
 
   a.spread(10)
 
-  a.diffVs("tests/masks/spread.png")
+  a.xray("tests/masks/spread.png")
 
 block:
   let path = newPath()
@@ -101,7 +101,7 @@ block:
 
   a.spread(-5)
 
-  a.diffVs("tests/masks/negativeSpread.png")
+  a.xray("tests/masks/negativeSpread.png")
 
 block:
   let mask = newMask(100, 100)
@@ -112,7 +112,7 @@ block:
   mask.fillPath(path)
   mask.ceil()
 
-  mask.diffVs("tests/masks/circleMaskSharpened.png")
+  mask.xray("tests/masks/circleMaskSharpened.png")
 
 block:
   let path = newPath()
@@ -120,7 +120,7 @@ block:
 
   let mask = newMask(100, 100)
   mask.fillPath(path)
-  mask.diffVs("tests/masks/drawRect.png")
+  mask.xray("tests/masks/drawRect.png")
 
 block:
   let path = newPath()
@@ -128,7 +128,7 @@ block:
 
   let mask = newMask(100, 100)
   mask.strokePath(path, strokeWidth = 10)
-  mask.diffVs("tests/masks/strokeRect.png")
+  mask.xray("tests/masks/strokeRect.png")
 
 block:
   let path = newPath()
@@ -136,14 +136,14 @@ block:
 
   let mask = newMask(100, 100)
   mask.fillPath(path)
-  mask.diffVs("tests/masks/drawRoundedRect.png")
+  mask.xray("tests/masks/drawRoundedRect.png")
 
 block:
   let path = newPath()
   path.roundedRect(rect(vec2(10, 10), vec2(30, 30)), 10, 10, 10, 10)
   let mask = newMask(100, 100)
   mask.strokePath(path, strokeWidth = 10)
-  mask.diffVs("tests/masks/strokeRoundedRect.png")
+  mask.xray("tests/masks/strokeRoundedRect.png")
 
 block:
   let path = newPath()
@@ -152,7 +152,7 @@ block:
 
   let mask = newMask(100, 100)
   mask.strokePath(path, strokeWidth = 10)
-  mask.diffVs("tests/masks/drawSegment.png")
+  mask.xray("tests/masks/drawSegment.png")
 
 block:
   let path = newPath()
@@ -160,7 +160,7 @@ block:
 
   let mask = newMask(100, 100)
   mask.fillPath(path)
-  mask.diffVs("tests/masks/drawEllipse.png")
+  mask.xray("tests/masks/drawEllipse.png")
 
 block:
   let path = newPath()
@@ -168,7 +168,7 @@ block:
 
   let mask = newMask(100, 100)
   mask.strokePath(path, strokeWidth = 10)
-  mask.diffVs("tests/masks/strokeEllipse.png")
+  mask.xray("tests/masks/strokeEllipse.png")
 
 block:
   let path = newPath()
@@ -176,7 +176,7 @@ block:
 
   let mask = newMask(100, 100)
   mask.fillPath(path)
-  mask.diffVs("tests/masks/drawPolygon.png")
+  mask.xray("tests/masks/drawPolygon.png")
 
 block:
   let path = newPath()
@@ -184,7 +184,7 @@ block:
 
   let mask = newMask(100, 100)
   mask.strokepath(path, strokeWidth = 10)
-  mask.diffVs("tests/masks/strokePolygon.png")
+  mask.xray("tests/masks/strokePolygon.png")
 
 block:
   let path = newPath()
@@ -193,7 +193,7 @@ block:
   let mask = newMask(100, 100)
   mask.fillpath(path)
   mask.blur(20)
-  mask.diffVs("tests/images/maskblur20.png")
+  mask.xray("tests/images/maskblur20.png")
 
 block:
   let path = newPath()
@@ -204,7 +204,7 @@ block:
   mask.blur(25)
 
   let minified = mask.minifyBy2()
-  minified.diffVs("tests/masks/minifiedBlur.png")
+  minified.xray("tests/masks/minifiedBlur.png")
 
 block:
   let path = newPath()
@@ -214,4 +214,4 @@ block:
   mask.fillPath(path)
 
   let magnified = mask.magnifyBy2()
-  magnified.diffVs("tests/masks/drawPolygonMagnified.png")
+  magnified.xray("tests/masks/drawPolygonMagnified.png")
diff --git a/tests/test_paints.nim b/tests/test_paints.nim
index 1dfcc9f..ebc649c 100644
--- a/tests/test_paints.nim
+++ b/tests/test_paints.nim
@@ -1,4 +1,4 @@
-import chroma, pixie, vmath, utils
+import chroma, pixie, vmath, xrays
 
 const heartShape = """
     M 10,30
@@ -14,7 +14,7 @@ block:
     heartShape,
     rgba(255, 0, 0, 255)
   )
-  image.diffVs("tests/paths/paintSolid.png")
+  image.xray("tests/paths/paintSolid.png")
 
 block:
   let paint = newPaint(ImagePaint)
@@ -23,7 +23,7 @@ block:
 
   let image = newImage(100, 100)
   image.fillPath(heartShape, paint)
-  image.diffVs("tests/paths/paintImage.png")
+  image.xray("tests/paths/paintImage.png")
 
 block:
   let paint = newPaint(ImagePaint)
@@ -33,7 +33,7 @@ block:
 
   let image = newImage(100, 100)
   image.fillPath(heartShape, paint)
-  image.diffVs("tests/paths/paintImageOpacity.png")
+  image.xray("tests/paths/paintImageOpacity.png")
 
 block:
   let paint = newPaint(TiledImagePaint)
@@ -42,7 +42,7 @@ block:
 
   let image = newImage(100, 100)
   image.fillPath(heartShape, paint)
-  image.diffVs("tests/paths/paintImageTiled.png")
+  image.xray("tests/paths/paintImageTiled.png")
 
 block:
   let paint = newPaint(TiledImagePaint)
@@ -52,7 +52,7 @@ block:
 
   let image = newImage(100, 100)
   image.fillPath(heartShape, paint)
-  image.diffVs("tests/paths/paintImageTiledOpacity.png")
+  image.xray("tests/paths/paintImageTiledOpacity.png")
 
 block:
   let paint = newPaint(LinearGradientPaint)
@@ -67,7 +67,7 @@ block:
 
   let image = newImage(100, 100)
   image.fillPath(heartShape, paint)
-  image.diffVs("tests/paths/gradientLinear.png")
+  image.xray("tests/paths/gradientLinear.png")
 
 block:
   let paint = newPaint(LinearGradientPaint)
@@ -82,7 +82,7 @@ block:
 
   let image = newImage(100, 100)
   image.fillPath(heartShape, paint)
-  image.diffVs("tests/paths/gradientLinear2.png")
+  image.xray("tests/paths/gradientLinear2.png")
 
 block:
   let paint = newPaint(RadialGradientPaint)
@@ -98,7 +98,7 @@ block:
 
   let image = newImage(100, 100)
   image.fillPath(heartShape, paint)
-  image.diffVs("tests/paths/gradientRadial.png")
+  image.xray("tests/paths/gradientRadial.png")
 
 block:
   let paint = newPaint(AngularGradientPaint)
@@ -114,7 +114,7 @@ block:
 
   let image = newImage(100, 100)
   image.fillPath(heartShape, paint)
-  image.diffVs("tests/paths/gradientAngular.png")
+  image.xray("tests/paths/gradientAngular.png")
 
 block:
   let paint = newPaint(AngularGradientPaint)
@@ -131,4 +131,4 @@ block:
 
   let image = newImage(100, 100)
   image.fillPath(heartShape, paint)
-  image.diffVs("tests/paths/gradientAngularOpacity.png")
+  image.xray("tests/paths/gradientAngularOpacity.png")
diff --git a/tests/test_paths.nim b/tests/test_paths.nim
index 464dcd3..d452846 100644
--- a/tests/test_paths.nim
+++ b/tests/test_paths.nim
@@ -1,4 +1,4 @@
-import chroma, pixie, pixie/fileformats/png, strformat, utils
+import chroma, pixie, pixie/fileformats/png, strformat, xrays
 
 block:
   let pathStr = """
@@ -54,7 +54,7 @@ block:
     pathStr = "M 10 10 L 90 90"
     color = rgba(255, 0, 0, 255)
   image.strokePath(pathStr, color, strokeWidth = 10)
-  image.diffVs("tests/paths/pathStroke1.png")
+  image.xray("tests/paths/pathStroke1.png")
 
 block:
   let
@@ -62,7 +62,7 @@ block:
     pathStr = "M 10 10 L 50 60 90 90"
     color = rgba(255, 0, 0, 255)
   image.strokePath(pathStr, color, strokeWidth = 10)
-  image.diffVs("tests/paths/pathStroke2.png")
+  image.xray("tests/paths/pathStroke2.png")
 
 block:
   let image = newImage(100, 100)
@@ -71,7 +71,7 @@ block:
     rgba(255, 255, 0, 255),
     strokeWidth = 10
   )
-  image.diffVs("tests/paths/pathStroke3.png")
+  image.xray("tests/paths/pathStroke3.png")
 
 block:
   let
@@ -79,7 +79,7 @@ block:
     pathStr = "M 10 10 H 90 V 90 H 10 L 10 10"
     color = rgba(0, 0, 0, 255)
   image.fillPath(pathStr, color)
-  image.diffVs("tests/paths/pathBlackRectangle.png")
+  image.xray("tests/paths/pathBlackRectangle.png")
 
 block:
   let
@@ -87,7 +87,7 @@ block:
     pathStr = "M 10 10 H 90 V 90 H 10 Z"
     color = rgba(0, 0, 0, 255)
   image.fillPath(parsePath(pathStr), color)
-  image.diffVs("tests/paths/pathBlackRectangleZ.png")
+  image.xray("tests/paths/pathBlackRectangleZ.png")
 
 block:
   let image = newImage(100, 100)
@@ -95,7 +95,7 @@ block:
     "M 10 10 H 90 V 90 H 10 L 10 10",
     rgba(255, 255, 0, 255)
   )
-  image.diffVs("tests/paths/pathYellowRectangle.png")
+  image.xray("tests/paths/pathYellowRectangle.png")
 
 block:
   let path = newPath()
@@ -107,7 +107,7 @@ block:
 
   let image = newImage(100, 100)
   image.fillPath(path, rgba(255, 0, 0, 255))
-  image.diffVs("tests/paths/pathRedRectangle.png")
+  image.xray("tests/paths/pathRedRectangle.png")
 
 block:
   let image = newImage(100, 100)
@@ -115,7 +115,7 @@ block:
     "M30 60 A 20 20 0 0 0 90 60 L 30 60",
     parseHtmlColor("#FC427B").rgba
   )
-  image.diffVs("tests/paths/pathBottomArc.png")
+  image.xray("tests/paths/pathBottomArc.png")
 
 block:
   let image = newImage(100, 100)
@@ -129,7 +129,7 @@ block:
     """,
     parseHtmlColor("#FC427B").rgba
   )
-  image.diffVs("tests/paths/pathHeart.png")
+  image.xray("tests/paths/pathHeart.png")
 
 block:
   let image = newImage(100, 100)
@@ -137,7 +137,7 @@ block:
     "M 20 50 A 20 10 45 1 1 80 50 L 20 50",
     parseHtmlColor("#FC427B").rgba
   )
-  image.diffVs("tests/paths/pathRotatedArc.png")
+  image.xray("tests/paths/pathRotatedArc.png")
 
 block:
   let image = newImage(100, 100)
@@ -145,7 +145,7 @@ block:
     "M 0 50 A 50 50 0 0 0 50 0 L 50 50 L 0 50",
     parseHtmlColor("#FC427B").rgba
   )
-  image.diffVs("tests/paths/pathInvertedCornerArc.png")
+  image.xray("tests/paths/pathInvertedCornerArc.png")
 
 block:
   let image = newImage(100, 100)
@@ -153,7 +153,7 @@ block:
     "M 0 50 A 50 50 0 0 1 50 0 L 50 50 L 0 50",
     parseHtmlColor("#FC427B").rgba
   )
-  image.diffVs("tests/paths/pathCornerArc.png")
+  image.xray("tests/paths/pathCornerArc.png")
 
 # block:
 #   let
@@ -170,14 +170,14 @@ block:
 #   path.arcTo(x, y + h, x, y, r)
 #   path.arcTo(x, y, x + w, y, r)
 #   image.fillPath(path, rgba(255, 0, 0, 255))
-#   image.diffVs("tests/paths/pathRoundRect.png")
+#   image.xray("tests/paths/pathRoundRect.png")
 
 block:
   let
     mask = newMask(100, 100)
     pathStr = "M 10 10 H 90 V 90 H 10 L 10 10"
   mask.fillPath(pathStr)
-  mask.diffVs("tests/paths/pathRectangleMask.png")
+  mask.xray("tests/paths/pathRectangleMask.png")
 
 # block:
 #   let
@@ -206,7 +206,7 @@ block:
   image.strokePath(p, rgba(0, 255, 0, 255), scale(vec2(200, 200)),
       strokeWidth = 0.01)
 
-  image.diffVs("tests/paths/pixelScale.png")
+  image.xray("tests/paths/pixelScale.png")
 
 block:
   let
@@ -217,7 +217,7 @@ block:
     path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, RoundCap, RoundJoin
   )
 
-  image.diffVs("tests/paths/boxRound.png")
+  image.xray("tests/paths/boxRound.png")
 
 block:
   let
@@ -228,7 +228,7 @@ block:
     path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, RoundCap, BevelJoin
   )
 
-  image.diffVs("tests/paths/boxBevel.png")
+  image.xray("tests/paths/boxBevel.png")
 
 block:
   let
@@ -239,7 +239,7 @@ block:
     path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, RoundCap, MiterJoin
   )
 
-  image.diffVs("tests/paths/boxMiter.png")
+  image.xray("tests/paths/boxMiter.png")
 
 block:
   let
@@ -250,7 +250,7 @@ block:
     path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, ButtCap, BevelJoin
   )
 
-  image.diffVs("tests/paths/ButtCap.png")
+  image.xray("tests/paths/ButtCap.png")
 
 block:
   let
@@ -261,7 +261,7 @@ block:
     path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, RoundCap, BevelJoin
   )
 
-  image.diffVs("tests/paths/RoundCap.png")
+  image.xray("tests/paths/RoundCap.png")
 
 block:
   let
@@ -272,7 +272,7 @@ block:
     path, rgba(0, 0, 0, 255), translate(vec2(10, 10)), 10, SquareCap, BevelJoin
   )
 
-  image.diffVs("tests/paths/SquareCap.png")
+  image.xray("tests/paths/SquareCap.png")
 
 block:
   let
@@ -309,7 +309,7 @@ block:
     dashes = @[1.float32, 2, 3, 4, 5, 6, 7, 8, 9]
   )
 
-  image.diffVs("tests/paths/dashes.png")
+  image.xray("tests/paths/dashes.png")
 
 block:
   proc miterTest(angle, limit: float32) =
@@ -326,7 +326,7 @@ block:
       path, rgba(0, 0, 0, 255), translate(vec2(30, 30)), 8, ButtCap, MiterJoin,
       miterLimit = limit
     )
-    image.diffVs(&"tests/paths/miterLimit_{angle.int}deg_{limit:0.2f}num.png")
+    image.xray(&"tests/paths/miterLimit_{angle.int}deg_{limit:0.2f}num.png")
 
   miterTest(10, 2)
   miterTest(145, 2)
@@ -343,7 +343,7 @@ block:
     path = parsePath("M0 0 L0 0 L60 0 L60 60 L0 60")
   image.fill(rgba(255, 255, 255, 255))
   image.fillPath(path, rgba(127, 127, 127, 255))
-  image.diffVs("tests/paths/selfclosing.png")
+  image.xray("tests/paths/selfclosing.png")
 
 # Potential error cases, ensure they do not crash
 
@@ -398,7 +398,7 @@ block:
     "M 30 30 H 80 V 80 H 30 z",
     paint
   )
-  image.diffVs("tests/paths/rectExcludeMask.png")
+  image.xray("tests/paths/rectExcludeMask.png")
 
 block:
   let image = newImage(100, 100)
@@ -415,7 +415,7 @@ block:
     "M 30.1 30.1 H 80.1 V 80.1 H 30.1 z",
     paint
   )
-  image.diffVs("tests/paths/rectExcludeMaskAA.png")
+  image.xray("tests/paths/rectExcludeMaskAA.png")
 
 block:
   let image = newImage(100, 100)
@@ -432,7 +432,7 @@ block:
     "M 30 30 H 80 V 80 H 30 z",
     paint
   )
-  image.diffVs("tests/paths/rectMask.png")
+  image.xray("tests/paths/rectMask.png")
 
 block:
   let image = newImage(100, 100)
@@ -449,7 +449,7 @@ block:
     "M 30.1 30.1 H 80.1 V 80.1 H 30.1 z",
     paint
   )
-  image.diffVs("tests/paths/rectMaskAA.png")
+  image.xray("tests/paths/rectMaskAA.png")
 
 block:
   let image = newImage(100, 100)
@@ -467,13 +467,13 @@ block:
     paint,
     strokeWidth = 10
   )
-  image.diffVs("tests/paths/rectMaskStroke.png")
+  image.xray("tests/paths/rectMaskStroke.png")
 
 block:
   let mask = newMask(100, 100)
   mask.fillPath("M 10 10 H 60 V 60 H 10 z")
   mask.fillPath("M 30 30 H 80 V 80 H 30 z", blendMode = ExcludeMaskBlend)
-  mask.diffVs("tests/paths/maskRectExcludeMask.png")
+  mask.xray("tests/paths/maskRectExcludeMask.png")
 
 block:
   let mask = newMask(100, 100)
@@ -482,19 +482,19 @@ block:
     "M 30.1 30.1 H 80.1 V 80.1 H 30.1 z",
     blendMode = ExcludeMaskBlend
   )
-  mask.diffVs("tests/paths/maskRectExcludeMaskAA.png")
+  mask.xray("tests/paths/maskRectExcludeMaskAA.png")
 
 block:
   let mask = newMask(100, 100)
   mask.fillPath("M 10 10 H 60 V 60 H 10 z")
   mask.fillPath("M 30 30 H 80 V 80 H 30 z", blendMode = MaskBlend)
-  mask.diffVs("tests/paths/maskRectMask.png")
+  mask.xray("tests/paths/maskRectMask.png")
 
 block:
   let mask = newMask(100, 100)
   mask.fillPath("M 10.1 10.1 H 60.1 V 60.1 H 10.1 z")
   mask.fillPath("M 30.1 30.1 H 80.1 V 80.1 H 30.1 z", blendMode = MaskBlend)
-  mask.diffVs("tests/paths/maskRectMaskAA.png")
+  mask.xray("tests/paths/maskRectMaskAA.png")
 
 block:
   let mask = newMask(100, 100)
@@ -504,7 +504,7 @@ block:
     strokeWidth = 10,
     blendMode = MaskBlend
   )
-  mask.diffVs("tests/paths/maskStrokeRectMask.png")
+  mask.xray("tests/paths/maskStrokeRectMask.png")
 
 block:
   var
@@ -531,7 +531,7 @@ block:
       else:
         ctx.stroke()
 
-  surface.diffVs("tests/paths/arc.png")
+  surface.xray("tests/paths/arc.png")
 
 block:
   var
@@ -550,7 +550,7 @@ block:
   ctx.lineTo(p2.x, p2.y)
   ctx.stroke()
 
-  surface.diffVs("tests/paths/arcTo1.png")
+  surface.xray("tests/paths/arcTo1.png")
 
 block:
   var
@@ -586,7 +586,7 @@ block:
   ctx.arc(50, 20, 5, 0, 2 * PI) # Control point two
   ctx.fill()
 
-  surface.diffVs("tests/paths/arcTo2.png")
+  surface.xray("tests/paths/arcTo2.png")
 
 block:
   var
@@ -600,7 +600,7 @@ block:
   ctx.lineTo(110, 130)
   ctx.stroke()
 
-  surface.diffVs("tests/paths/arcTo3.png")
+  surface.xray("tests/paths/arcTo3.png")
 
 block:
   let path = newPath()
@@ -651,7 +651,7 @@ block:
   let image = newImage(100, 100)
   image.fillPath(path, paint)
 
-  image.diffVs("tests/paths/opacityFill.png")
+  image.xray("tests/paths/opacityFill.png")
 
 block:
   let path = newPath()
@@ -664,7 +664,7 @@ block:
   let image = newImage(100, 100)
   image.strokePath(path, paint, strokeWidth = 10)
 
-  image.diffVs("tests/paths/opacityStroke.png")
+  image.xray("tests/paths/opacityStroke.png")
 
 block:
   let
@@ -672,14 +672,14 @@ block:
     pathStr = "M0 0 L200 200"
     color = rgba(255, 0, 0, 255)
   image.strokePath(pathStr, color, strokeWidth = 10)
-  image.diffVs("tests/paths/pathStroke1Big.png")
+  image.xray("tests/paths/pathStroke1Big.png")
 
 block:
   let
     image = newMask(100, 100)
     pathStr = "M0 0 L200 200"
   image.strokePath(pathStr, strokeWidth = 10)
-  image.diffVs("tests/paths/pathStroke1BigMask.png")
+  image.xray("tests/paths/pathStroke1BigMask.png")
 
 block:
   let
@@ -687,7 +687,7 @@ block:
     pathStr = "M99 99 L999 99 L999 100 L99 100 Z"
     color = rgba(255, 0, 0, 255)
   image.fillPath(pathStr, color)
-  image.diffVs("tests/paths/path1pxCover.png")
+  image.xray("tests/paths/path1pxCover.png")
 
 block:
   let
@@ -695,7 +695,7 @@ block:
     pathStr = "M100 100 L999 100 L999 101 L100 101 Z"
     color = rgba(255, 0, 0, 255)
   image.fillPath(pathStr, color)
-  image.diffVs("tests/paths/path0pxCover.png")
+  image.xray("tests/paths/path0pxCover.png")
 
 block:
   let image = newImage(200, 200)
@@ -729,7 +729,7 @@ block:
     path.polygon(vec2(50, 50), 30, i)
     let mask = newMask(100, 100)
     mask.fillPath(path)
-    mask.diffVs(&"tests/paths/polygon{i}.png")
+    mask.xray(&"tests/paths/polygon{i}.png")
 
 block:
   let image = newImage(200, 200)
@@ -783,4 +783,4 @@ block:
     color = rgba(0, 0, 0, 255)
   image.fill(rgba(255, 255, 255, 255))
   image.fillPath(pathStr, color)
-  image.diffVs("tests/paths/pathSwish.png")
+  image.xray("tests/paths/pathSwish.png")
diff --git a/tests/test_svg.nim b/tests/test_svg.nim
index d54a97c..6950119 100644
--- a/tests/test_svg.nim
+++ b/tests/test_svg.nim
@@ -1,4 +1,4 @@
-import pixie, pixie/fileformats/svg, strformat, utils
+import pixie, pixie/fileformats/svg, strformat, xrays
 
 const files = [
   "line01",
@@ -19,7 +19,7 @@ const files = [
 
 for file in files:
   let image = readImage(&"tests/fileformats/svg/{file}.svg")
-  image.diffVs(&"tests/fileformats/svg/masters/{file}.png")
+  image.xray(&"tests/fileformats/svg/masters/{file}.png")
 
 block:
   let
@@ -28,4 +28,4 @@ block:
       512, 512
     )
     image = newImage(svg)
-  image.diffVs(&"tests/fileformats/svg/masters/accessibility-outline.png")
+  image.xray(&"tests/fileformats/svg/masters/accessibility-outline.png")
diff --git a/tests/utils.nim b/tests/xrays.nim
similarity index 55%
rename from tests/utils.nim
rename to tests/xrays.nim
index 3f6b1bd..c13f1f9 100644
--- a/tests/utils.nim
+++ b/tests/xrays.nim
@@ -9,27 +9,18 @@ proc makeDirs*(dirs: string) =
       createDir(path)
     path.add "/"
 
-proc diffVs*(image: Image, masterPath: string) =
+proc xray*(image: Image, masterPath: string) =
   let
-    master = readImage(masterPath)
-    (score, xRay) = diff(image, master)
     imagePath = "tmp/generated/" & masterPath
     xRayPath = "tmp/xray/" & masterPath
   makeDirs(imagePath.splitPath.head)
   makeDirs(xRayPath.splitPath.head)
   image.writeFile(imagePath)
+  let
+    master = readImage(masterPath)
+    (score, xRay) = diff(image, master)
   xRay.writeFile(xRayPath)
   echo &"diff {masterPath} -> {score:0.6f}"
 
-proc diffVs*(mask: Mask, masterPath: string) =
-  let
-    master = readImage(masterPath)
-    image = mask.newImage
-    (score, xRay) = diff(image, master)
-    imagePath = "tmp/generated/" & masterPath
-    xRayPath = "tmp/xray/" & masterPath
-  makeDirs(imagePath.splitPath.head)
-  makeDirs(xRayPath.splitPath.head)
-  image.writeFile(imagePath)
-  xRay.writeFile(xRayPath)
-  echo &"diff {masterPath} -> {score:0.6f}"
+proc xray*(mask: Mask, masterPath: string) =
+  mask.newImage.xray(masterPath)