diff --git a/README.md b/README.md
index 53be7ab..cd591af 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,7 @@ let
   pos = vec2(50, 50)
   wh = vec2(100, 100)
 
-image.drawRect(rect(pos, wh), rgba(255, 0, 0, 255))
+image.fillRect(rect(pos, wh), rgba(255, 0, 0, 255))
 ```
 ![example output](examples/square.png)
 
@@ -42,7 +42,7 @@ let
   stop = vec2(175, 175)
   color = parseHtmlColor("#FF5C00").rgba
 
-image.drawSegment(segment(start, stop), color, strokeWidth = 10)
+image.strokeSegment(segment(start, stop), color, strokeWidth = 10)
 ```
 ![example output](examples/line.png)
 
@@ -54,7 +54,7 @@ let
   wh = vec2(100, 100)
   r = 25.0
 
-image.drawRoundedRect(rect(pos, wh), r, rgba(0, 255, 0, 255))
+image.fillRoundedRect(rect(pos, wh), r, rgba(0, 255, 0, 255))
 ```
 ![example output](examples/rounded_rectangle.png)
 
@@ -79,19 +79,21 @@ image.fillPath(
 [examples/shadow.nim](examples/shadow.nim)
 ```nim
 let polygonImage = newImage(200, 200)
-polygonImage.drawPolygon(
+polygonImage.fillPolygon(
   vec2(100, 100),
   70,
   sides = 8,
   rgba(255, 255, 255, 255)
 )
 
-image.draw(polygonImage.shadow(
+let shadow = polygonImage.shadow(
   offset = vec2(2, 2),
   spread = 2,
   blur = 10,
   color = rgba(0, 0, 0, 200)
-))
+)
+
+image.draw(shadow)
 image.draw(polygonImage)
 ```
 ![example output](examples/shadow.png)
@@ -100,7 +102,7 @@ image.draw(polygonImage)
 [examples/blur.nim](examples/blur.nim)
 ```nim
 let mask = newMask(200, 200)
-mask.drawPolygon(vec2(100, 100), 70, sides = 6)
+mask.fillPolygon(vec2(100, 100), 70, sides = 6)
 
 blur.blur(20)
 blur.draw(mask, blendMode = bmMask)
diff --git a/examples/blur.nim b/examples/blur.nim
index e9889fd..16d34b5 100644
--- a/examples/blur.nim
+++ b/examples/blur.nim
@@ -8,7 +8,7 @@ let
 image.fill(rgba(255, 255, 255, 255))
 
 let mask = newMask(200, 200)
-mask.drawPolygon(vec2(100, 100), 70, sides = 6)
+mask.fillPolygon(vec2(100, 100), 70, sides = 6)
 
 blur.blur(20)
 blur.draw(mask, blendMode = bmMask)
diff --git a/examples/line.nim b/examples/line.nim
index 3a03e23..24f9b76 100644
--- a/examples/line.nim
+++ b/examples/line.nim
@@ -8,6 +8,6 @@ let
   stop = vec2(175, 175)
   color = parseHtmlColor("#FF5C00").rgba
 
-image.drawSegment(segment(start, stop), color, strokeWidth = 10)
+image.strokeSegment(segment(start, stop), color, strokeWidth = 10)
 
 image.writeFile("examples/line.png")
diff --git a/examples/rounded_rectangle.nim b/examples/rounded_rectangle.nim
index 776fb6d..79bc160 100644
--- a/examples/rounded_rectangle.nim
+++ b/examples/rounded_rectangle.nim
@@ -8,6 +8,6 @@ let
   wh = vec2(100, 100)
   r = 25.0
 
-image.drawRoundedRect(rect(pos, wh), r, rgba(0, 255, 0, 255))
+image.fillRoundedRect(rect(pos, wh), r, rgba(0, 255, 0, 255))
 
 image.writeFile("examples/rounded_rectangle.png")
diff --git a/examples/shadow.nim b/examples/shadow.nim
index 52c0d33..399ab9b 100644
--- a/examples/shadow.nim
+++ b/examples/shadow.nim
@@ -4,19 +4,21 @@ let image = newImage(200, 200)
 image.fill(rgba(255, 255, 255, 255))
 
 let polygonImage = newImage(200, 200)
-polygonImage.drawPolygon(
+polygonImage.fillPolygon(
   vec2(100, 100),
   70,
   sides = 8,
   rgba(255, 255, 255, 255)
 )
 
-image.draw(polygonImage.shadow(
+let shadow = polygonImage.shadow(
   offset = vec2(2, 2),
   spread = 2,
   blur = 10,
   color = rgba(0, 0, 0, 200)
-))
+)
+
+image.draw(shadow)
 image.draw(polygonImage)
 
 image.writeFile("examples/shadow.png")
diff --git a/examples/square.nim b/examples/square.nim
index 578007c..1942f17 100644
--- a/examples/square.nim
+++ b/examples/square.nim
@@ -7,6 +7,6 @@ let
   pos = vec2(50, 50)
   wh = vec2(100, 100)
 
-image.drawRect(rect(pos, wh), rgba(255, 0, 0, 255))
+image.fillRect(rect(pos, wh), rgba(255, 0, 0, 255))
 
 image.writeFile("examples/square.png")
diff --git a/src/pixie.nim b/src/pixie.nim
index f8b4caf..35d1971 100644
--- a/src/pixie.nim
+++ b/src/pixie.nim
@@ -50,51 +50,95 @@ proc writeFile*(image: Image, filePath: string) =
       raise newException(PixieError, "Unsupported image file extension")
   image.writeFile(filePath, fileformat)
 
-proc drawRect*(
-  image: Image, rect: Rect, color: ColorRGBA, blendMode = bmNormal
-) =
+proc fillRect*(image: Image, rect: Rect, color: ColorRGBA) =
   var path: Path
   path.rect(rect)
-  image.fillPath(path, color, wrNonZero, blendMode)
+  image.fillPath(path, color)
 
-proc drawRect*(mask: Mask, rect: Rect) =
+proc fillRect*(mask: Mask, rect: Rect) =
   var path: Path
   path.rect(rect)
   mask.fillPath(path)
 
-proc drawRoundedRect*(
+proc strokeRect*(
+  image: Image, rect: Rect, color: ColorRGBA, strokeWidth = 1.0
+) =
+  var path: Path
+  path.rect(rect)
+  image.strokePath(path, color, strokeWidth)
+
+proc strokeRect*(mask: Mask, rect: Rect, strokeWidth = 1.0) =
+  var path: Path
+  path.rect(rect)
+  mask.strokePath(path, strokeWidth)
+
+proc fillRoundedRect*(
+  image: Image,
+  rect: Rect,
+  nw, ne, se, sw: float32,
+  color: ColorRGBA
+) =
+  var path: Path
+  path.roundedRect(rect, nw, ne, se, sw)
+  image.fillPath(path, color)
+
+proc fillRoundedRect*(
+  image: Image,
+  rect: Rect,
+  radius: float32,
+  color: ColorRGBA
+) =
+  var path: Path
+  path.roundedRect(rect, radius, radius, radius, radius)
+  image.fillPath(path, color)
+
+proc fillRoundedRect*(mask: Mask, rect: Rect, nw, ne, se, sw: float32) =
+  var path: Path
+  path.roundedRect(rect, nw, ne, se, sw)
+  mask.fillPath(path)
+
+proc fillRoundedRect*(mask: Mask, rect: Rect, radius: float32) =
+  var path: Path
+  path.roundedRect(rect, radius, radius, radius, radius)
+  mask.fillPath(path)
+
+proc strokeRoundedRect*(
   image: Image,
   rect: Rect,
   nw, ne, se, sw: float32,
   color: ColorRGBA,
-  blendMode = bmNormal
+  strokeWidth = 1.0
 ) =
   var path: Path
   path.roundedRect(rect, nw, ne, se, sw)
-  image.fillPath(path, color, wrNonZero, blendMode)
+  image.strokePath(path, color, strokeWidth)
 
-proc drawRoundedRect*(
+proc strokeRoundedRect*(
   image: Image,
   rect: Rect,
   radius: float32,
   color: ColorRGBA,
-  blendMode = bmNormal
+  strokeWidth = 1.0
 ) =
   var path: Path
   path.roundedRect(rect, radius, radius, radius, radius)
-  image.fillPath(path, color, wrNonZero, blendMode)
+  image.strokePath(path, color, strokeWidth)
 
-proc drawRoundedRect*(mask: Mask, rect: Rect, nw, ne, se, sw: float32) =
+proc strokeRoundedRect*(
+  mask: Mask, rect: Rect, nw, ne, se, sw: float32, strokeWidth = 1.0
+) =
   var path: Path
   path.roundedRect(rect, nw, ne, se, sw)
-  mask.fillPath(path)
+  mask.strokePath(path, strokeWidth)
 
-proc drawRoundedRect*(mask: Mask, rect: Rect, radius: float32) =
+proc strokeRoundedRect*(
+  mask: Mask, rect: Rect, radius: float32, strokeWidth = 1.0
+) =
   var path: Path
   path.roundedRect(rect, radius, radius, radius, radius)
-  mask.fillPath(path)
+  mask.strokePath(path, strokeWidth)
 
-proc drawSegment*(
+proc strokeSegment*(
   image: Image,
   segment: Segment,
   color: ColorRGBA,
@@ -106,13 +150,13 @@ proc drawSegment*(
   path.lineTo(segment.to)
   image.strokePath(path, color, strokeWidth, wrNonZero, blendMode)
 
-proc drawSegment*(mask: Mask, segment: Segment, strokeWidth: float32) =
+proc strokeSegment*(mask: Mask, segment: Segment, strokeWidth: float32) =
   var path: Path
   path.moveTo(segment.at)
   path.lineTo(segment.to)
   mask.strokePath(path, strokeWidth)
 
-proc drawEllipse*(
+proc fillEllipse*(
   image: Image,
   center: Vec2,
   rx, ry: float32,
@@ -123,7 +167,7 @@ proc drawEllipse*(
   path.ellipse(center, rx, ry)
   image.fillPath(path, color, wrNonZero, blendMode)
 
-proc drawEllipse*(
+proc fillEllipse*(
   mask: Mask,
   center: Vec2,
   rx, ry: float32
@@ -132,18 +176,38 @@ proc drawEllipse*(
   path.ellipse(center, rx, ry)
   mask.fillPath(path)
 
-proc drawCircle*(
+proc strokeEllipse*(
+  image: Image,
+  center: Vec2,
+  rx, ry: float32,
+  color: ColorRGBA,
+  strokeWidth = 1.0
+) =
+  var path: Path
+  path.ellipse(center, rx, ry)
+  image.strokePath(path, color, strokeWidth)
+
+proc strokeEllipse*(
+  mask: Mask,
+  center: Vec2,
+  rx, ry: float32,
+  strokeWidth = 1.0
+) =
+  var path: Path
+  path.ellipse(center, rx, ry)
+  mask.strokePath(path, strokeWidth)
+
+proc fillCircle*(
   image: Image,
   center: Vec2,
   radius: float32,
-  color: ColorRGBA,
-  blendMode = bmNormal
+  color: ColorRGBA
 ) =
   var path: Path
   path.ellipse(center, radius, radius)
-  image.fillPath(path, color, wrNonZero, blendMode)
+  image.fillPath(path, color)
 
-proc drawCircle*(
+proc fillCircle*(
   mask: Mask,
   center: Vec2,
   radius: float32
@@ -152,19 +216,39 @@ proc drawCircle*(
   path.ellipse(center, radius, radius)
   mask.fillPath(path)
 
-proc drawPolygon*(
+proc strokeCircle*(
+  image: Image,
+  center: Vec2,
+  radius: float32,
+  color: ColorRGBA,
+  strokeWidth = 1.0
+) =
+  var path: Path
+  path.ellipse(center, radius, radius)
+  image.fillPath(path, color)
+
+proc strokeCircle*(
+  mask: Mask,
+  center: Vec2,
+  radius: float32,
+  strokeWidth = 1.0
+) =
+  var path: Path
+  path.ellipse(center, radius, radius)
+  mask.fillPath(path)
+
+proc fillPolygon*(
   image: Image,
   pos: Vec2,
   size: float32,
   sides: int,
-  color: ColorRGBA,
-  blendMode = bmNormal
+  color: ColorRGBA
 ) =
   var path: Path
   path.polygon(pos, size, sides)
-  image.fillPath(path, color, wrNonZero, blendMode)
+  image.fillPath(path, color)
 
-proc drawPolygon*(
+proc fillPolygon*(
   mask: Mask,
   pos: Vec2,
   size: float32,
@@ -173,3 +257,26 @@ proc drawPolygon*(
   var path: Path
   path.polygon(pos, size, sides)
   mask.fillPath(path)
+
+proc strokePolygon*(
+  image: Image,
+  pos: Vec2,
+  size: float32,
+  sides: int,
+  color: ColorRGBA,
+  strokeWidth = 1.0
+) =
+  var path: Path
+  path.polygon(pos, size, sides)
+  image.strokePath(path, color, strokeWidth)
+
+proc strokePolygon*(
+  mask: Mask,
+  pos: Vec2,
+  size: float32,
+  sides: int,
+  strokeWidth = 1.0
+) =
+  var path: Path
+  path.polygon(pos, size, sides)
+  mask.strokePath(path, strokeWidth)
diff --git a/tests/images/masks/strokeEllipse.png b/tests/images/masks/strokeEllipse.png
new file mode 100644
index 0000000..872ae6f
Binary files /dev/null and b/tests/images/masks/strokeEllipse.png differ
diff --git a/tests/images/masks/strokePolygon.png b/tests/images/masks/strokePolygon.png
new file mode 100644
index 0000000..9682590
Binary files /dev/null and b/tests/images/masks/strokePolygon.png differ
diff --git a/tests/images/masks/strokeRect.png b/tests/images/masks/strokeRect.png
new file mode 100644
index 0000000..c44294a
Binary files /dev/null and b/tests/images/masks/strokeRect.png differ
diff --git a/tests/images/masks/strokeRoundedRect.png b/tests/images/masks/strokeRoundedRect.png
new file mode 100644
index 0000000..73a2437
Binary files /dev/null and b/tests/images/masks/strokeRoundedRect.png differ
diff --git a/tests/images/strokeEllipse.png b/tests/images/strokeEllipse.png
new file mode 100644
index 0000000..828dd58
Binary files /dev/null and b/tests/images/strokeEllipse.png differ
diff --git a/tests/images/strokePolygon.png b/tests/images/strokePolygon.png
new file mode 100644
index 0000000..f4483df
Binary files /dev/null and b/tests/images/strokePolygon.png differ
diff --git a/tests/images/strokeRect.png b/tests/images/strokeRect.png
new file mode 100644
index 0000000..3d8128a
Binary files /dev/null and b/tests/images/strokeRect.png differ
diff --git a/tests/images/strokeRoundedRect.png b/tests/images/strokeRoundedRect.png
new file mode 100644
index 0000000..d1745c6
Binary files /dev/null and b/tests/images/strokeRoundedRect.png differ
diff --git a/tests/test_images_draw.nim b/tests/test_images_draw.nim
index a553d84..b4d1c99 100644
--- a/tests/test_images_draw.nim
+++ b/tests/test_images_draw.nim
@@ -53,13 +53,19 @@ block:
 block:
   let image = newImage(100, 100)
   image.fill(rgba(0, 255, 255, 255))
-  image.drawRect(rect(vec2(10, 10), vec2(30, 30)), rgba(255, 255, 0, 255))
+  image.fillRect(rect(vec2(10, 10), vec2(30, 30)), rgba(255, 255, 0, 255))
   image.writeFile("tests/images/drawRect.png")
 
 block:
   let image = newImage(100, 100)
   image.fill(rgba(0, 255, 255, 255))
-  image.drawRoundedRect(
+  image.strokeRect(rect(vec2(10, 10), vec2(30, 30)), rgba(255, 255, 0, 255), 10)
+  image.writeFile("tests/images/strokeRect.png")
+
+block:
+  let image = newImage(100, 100)
+  image.fill(rgba(0, 255, 255, 255))
+  image.fillRoundedRect(
     rect(vec2(10, 10), vec2(30, 30)),
     10,
     rgba(255, 255, 0, 255)
@@ -69,7 +75,18 @@ block:
 block:
   let image = newImage(100, 100)
   image.fill(rgba(0, 255, 255, 255))
-  image.drawSegment(
+  image.strokeRoundedRect(
+    rect(vec2(10, 10), vec2(30, 30)),
+    10,
+    rgba(255, 255, 0, 255),
+    10
+  )
+  image.writeFile("tests/images/strokeRoundedRect.png")
+
+block:
+  let image = newImage(100, 100)
+  image.fill(rgba(0, 255, 255, 255))
+  image.strokeSegment(
     segment(vec2(10, 10), vec2(90, 90)),
     rgba(255, 255, 0, 255),
     strokeWidth = 10
@@ -79,7 +96,7 @@ block:
 block:
   let image = newImage(100, 100)
   image.fill(rgba(0, 255, 255, 255))
-  image.drawEllipse(
+  image.fillEllipse(
     vec2(50, 50),
     25,
     25,
@@ -90,10 +107,34 @@ block:
 block:
   let image = newImage(100, 100)
   image.fill(rgba(0, 255, 255, 255))
-  image.drawPolygon(
+  image.strokeEllipse(
+    vec2(50, 50),
+    25,
+    25,
+    rgba(255, 255, 0, 255),
+    10
+  )
+  image.writeFile("tests/images/strokeEllipse.png")
+
+block:
+  let image = newImage(100, 100)
+  image.fill(rgba(0, 255, 255, 255))
+  image.fillPolygon(
     vec2(50, 50),
     30,
     6,
     rgba(255, 255, 0, 255)
   )
   image.writeFile("tests/images/drawPolygon.png")
+
+block:
+  let image = newImage(100, 100)
+  image.fill(rgba(0, 255, 255, 255))
+  image.strokePolygon(
+    vec2(50, 50),
+    30,
+    6,
+    rgba(255, 255, 0, 255),
+    10
+  )
+  image.writeFile("tests/images/strokePolygon.png")
diff --git a/tests/test_masks.nim b/tests/test_masks.nim
index 5818291..1f79c39 100644
--- a/tests/test_masks.nim
+++ b/tests/test_masks.nim
@@ -105,17 +105,27 @@ block:
 
 block:
   let mask = newMask(100, 100)
-  mask.drawRect(rect(vec2(10, 10), vec2(30, 30)))
+  mask.fillRect(rect(vec2(10, 10), vec2(30, 30)))
   writeFile("tests/images/masks/drawRect.png", mask.encodePng())
 
 block:
   let mask = newMask(100, 100)
-  mask.drawRoundedRect(rect(vec2(10, 10), vec2(30, 30)), 10)
+  mask.strokeRect(rect(vec2(10, 10), vec2(30, 30)), 10)
+  writeFile("tests/images/masks/strokeRect.png", mask.encodePng())
+
+block:
+  let mask = newMask(100, 100)
+  mask.fillRoundedRect(rect(vec2(10, 10), vec2(30, 30)), 10)
   writeFile("tests/images/masks/drawRoundedRect.png", mask.encodePng())
 
 block:
   let mask = newMask(100, 100)
-  mask.drawSegment(
+  mask.strokeRoundedRect(rect(vec2(10, 10), vec2(30, 30)), 10, 10)
+  writeFile("tests/images/masks/strokeRoundedRect.png", mask.encodePng())
+
+block:
+  let mask = newMask(100, 100)
+  mask.strokeSegment(
     segment(vec2(10, 10), vec2(90, 90)),
     strokeWidth = 10
   )
@@ -123,10 +133,20 @@ block:
 
 block:
   let mask = newMask(100, 100)
-  mask.drawEllipse(vec2(50, 50), 20, 10)
+  mask.fillEllipse(vec2(50, 50), 20, 10)
   writeFile("tests/images/masks/drawEllipse.png", mask.encodePng())
 
 block:
   let mask = newMask(100, 100)
-  mask.drawPolygon(vec2(50, 50), 30, 6)
+  mask.strokeEllipse(vec2(50, 50), 20, 10, 10)
+  writeFile("tests/images/masks/strokeEllipse.png", mask.encodePng())
+
+block:
+  let mask = newMask(100, 100)
+  mask.fillPolygon(vec2(50, 50), 30, 6)
   writeFile("tests/images/masks/drawPolygon.png", mask.encodePng())
+
+block:
+  let mask = newMask(100, 100)
+  mask.strokePolygon(vec2(50, 50), 30, 6, 10)
+  writeFile("tests/images/masks/strokePolygon.png", mask.encodePng())