Why Not Canvas2D?
Canvas2D is everywhere. Every browser has it. No build step. No WASM. Just draw.
So why aren't we using it for production?
We are—for the demos in this series. But for a professional vector editor? Canvas2D hits walls.
What Canvas2D Does Well
Simplicity. Drawing a rectangle:
ctx.fillStyle = 'red';
ctx.fillRect(10, 10, 100, 50);
Done. No initialization, no context loss handling, no shader compilation.
Wide support. Works in every browser since 2010.
Text rendering. Canvas2D gets text right. Font loading, measurement, baseline alignment—all handled.
Good enough for many apps. Simple games, charts, basic drawing tools. Canvas2D excels.
Where It Falls Apart
Missing Blend Modes
Canvas2D has globalCompositeOperation. Twelve options:
ctx.globalCompositeOperation = 'multiply';
Photoshop has 27 blend modes. Figma uses many of them. Where's Linear Burn? Color Dodge? Subtract?
Not in Canvas2D.
Workaround: Implement in shaders (requires WebGL) or do pixel manipulation (slow).
No Clip Effects
You can clip paths. You cannot:
- Apply blur to just the clipped area
- Add shadow to a clipped shape
- Composite clipped content with blend modes
Figma's layer effects require all three.
Performance Cliff
Canvas2D is immediate mode. Every frame, redraw everything.
10 objects? Fine. 100 objects? Tolerable. 1,000 objects with effects? Slideshow.
// Every frame
function draw() {
ctx.clearRect(0, 0, width, height);
for (const obj of objects) {
drawObject(ctx, obj); // CPU-bound loop
}
}
The GPU sits idle while JavaScript crunches.
No GPU Texture Caching
Draw a complex shape once. Move it. Canvas2D redraws it from scratch.
WebGL/Skia can cache the rasterized result in GPU memory. Move the texture. 60fps, no sweat.
Canvas2D has no such concept.
Stroke Limitations
Remember dashes? Canvas2D has them:
ctx.setLineDash([10, 5]);
But:
- No per-segment dash patterns
- No dash offset animation without full redraw
- No variable-width strokes
- No stroke alignment (center only)
For Figma-style strokes, we'd implement everything manually anyway.
Filter Bottleneck
Canvas2D has filter:
ctx.filter = 'blur(4px)';
Sounds good. Reality:
- Applies to everything you draw after
- Can't blur just one layer's edge
- Performance tanks with complex filters
- Shadow + blur + blend = exponential slowdown
No Off-Thread Rendering
JavaScript is single-threaded. Canvas2D rendering blocks UI.
WebGL can offload to GPU while JavaScript continues. OffscreenCanvas helps but has limited adoption. Worker + Canvas2D loses context on postMessage.
For large canvases, main thread freezes during render.
When Canvas2D Makes Sense
Prototyping. Get ideas working fast.
Simple tools. Basic shapes, no effects.
Educational content. These demos work in Canvas2D because we keep them simple.
Compatibility priority. When IE11 support matters (it shouldn't, but sometimes it does).
When to Move Beyond
Professional features. Blend modes, effects, masks.
Performance requirements. 1000+ objects, 60fps.
Complex compositions. Nested groups with mixed blend modes.
Production rendering. Export quality, frame capture, video encoding.
The Migration Path
Start with Canvas2D. Prototype, learn, iterate.
When you hit the walls—and you will—migrate to:
- WebGL directly: Maximum control, maximum work
- CanvasKit/Skia: Figma-level features, WASM bundle size
- WebGPU: Future-proof, still maturing
We chose Skia/CanvasKit. It has everything Canvas2D doesn't, wrapped in a usable API.
Summary
Canvas2D is the gateway. Use it to learn. Use it to prototype.
But don't mistake the gateway for the destination. When you need:
- All blend modes
- GPU acceleration
- Effect compositing
- Professional performance
Canvas2D won't get you there.
The demos in this series run on Canvas2D. The production renderer doesn't. That's the lesson.