CanvasKit: Bringing Skia to the Web (And Its Rough Edges)
The Problem
You want Skia's power. In the browser. Without plugins.
Historically, impossible. Browsers give you HTML Canvas—a simple 2D drawing API that's fine for basic graphics but lacks advanced features. No complex path operations. Limited text shaping. No hardware-accelerated effects.
Then WebAssembly arrived.
What CanvasKit Is
CanvasKit is Skia compiled to WebAssembly (WASM). The entire C++ graphics library, running in your browser at near-native speed.
It exposes Skia's API through JavaScript bindings. You get:
- Full path operations
- Advanced text layout (HarfBuzz, paragraph layout)
- Hardware-accelerated effects
- All blend modes
- Shader support (RuntimeEffect)
- Everything else Skia provides
Download size: ~2.9MB gzipped. That's the entire graphics engine.
Who Uses CanvasKit
Flutter Web: Switched exclusively to CanvasKit renderer. Every Flutter web app uses it.
Shopify: Built react-native-skia with CanvasKit for web support. React Native apps can now use Skia across mobile and web.
AntV (Ant Group): Created @antv/g-canvaskit renderer for their graphics library.
Figma (partially): Uses custom WebGL code primarily, but leverages Skia for specific algorithms.
43+ npm packages: Various frameworks and libraries building on CanvasKit.
The First Failed Attempt: The Fiddle
Official documentation points to https://jsfiddle.skia.org/canvaskit for an online playground.
Problem: It doesn't work. As of 2024, users get 403 Forbidden after Google login. The CanvasKit fiddle has been down intermittently.
The main Skia Fiddle (fiddle.skia.org) works for C++ code, but that's not helpful for web developers trying to learn CanvasKit.
Reality: No working online playground means learning from docs and examples alone. The docs exist, but...
The Documentation Problem
CanvasKit documentation exists at https://skia.org/docs/user/modules/canvaskit/
Here's what's actually there:
- Installation instructions (accurate)
- TypeScript definitions (in the npm package)
- API overview (basic)
- A few code examples (incomplete)
Here's what's missing:
- Memory management best practices (critical!)
- Bundler integration guides (Webpack/Vite have issues)
- Performance considerations (GPU vs CPU paths)
- Complete API reference (you need TypeScript definitions)
- Real-world examples (complex shapes, animations)
The documentation assumes you know Skia's C++ API and can translate. If you don't, good luck.
What the Docs Don't Tell You: Memory Management
Critical rule: Objects created with new or Make* methods must be deleted manually.
const paint = new CanvasKit.Paint();
// ... use paint ...
paint.delete(); // MUST call this
JavaScript's garbage collector does not clean up WASM memory. Forget to delete, memory leaks forever (until page reload).
The mistake everyone makes: Creating paths/paints inside render loops without deleting them. 100 frames = 100 leaked objects.
We'll cover proper patterns in the interactive examples.
Bundler Integration Hell
Webpack Issues
- WASM support is experimental
- Need to copy
canvaskit.wasmto build directory manually - "Can't resolve 'fs'" errors require config changes
- No official guide for Webpack 5
Vite Issues
- Development mode renames
CanvasKitInittoCanvasKitInit2(completely wrong) - Importing WASM from node_modules fails
- Need custom import solutions
- Build vs dev mode behave differently
The Reality
Most CanvasKit projects include a webpack.config.js or vite.config.js with cryptic workarounds. Copy-paste and pray.
React Native Skia: Shopify's Approach
Shopify built react-native-skia to bring Skia to React Native. For web support, it uses CanvasKit.
Key insight: They wrapped CanvasKit in a declarative API. Instead of imperative draw calls, you describe what to draw:
<Canvas>
<Rect x={0} y={0} width={256} height={256} color="blue" />
</Canvas>
The library handles:
- Memory management (automatic deletion)
- Render loops
- Platform differences (native Skia vs CanvasKit)
This is not a CanvasKit fork. It's a high-level API that uses CanvasKit for web and native Skia for mobile.
Worth considering if you're building in React.
Who Actually Uses CanvasKit Directly
Flutter: No choice, it's the renderer.
Custom renderers: Building design tools, canvas apps, visualization libraries.
Performance-critical apps: Need GPU acceleration HTML Canvas can't provide.
Cross-platform tools: Want identical rendering on web and desktop (via Skia).
Most developers: Use a framework on top (Flutter, react-native-skia, AntV).
The Advantages (Why We Chose It)
1. Real GPU Acceleration
CanvasKit uses WebGL/WebGPU. Complex paths render fast. Effects are hardware-accelerated. HTML Canvas can't compete.
2. Feature Parity
Need custom blend modes? Advanced text? Path boolean operations? CanvasKit has it. Canvas API doesn't.
3. Identical Rendering
Skia on desktop + CanvasKit on web = pixel-perfect match. Critical for design tools.
4. Control
Low-level API means no magic. You control clipping, layers, GPU resources. When you need performance, this matters.
The Disadvantages (Why It's Painful)
1. Size
2.9MB gzipped is significant. Your bundle is instantly larger. First load is slower.
2. Learning Curve
Not HTML Canvas. Not SVG. It's Skia's API, translated to JavaScript. Expect weeks of learning.
3. Memory Management
Manual deletion or memory leaks. No escaping it.
4. Debugging
Errors in WASM are cryptic. Stack traces are useless. console.log() is your friend.
5. Bundler Hell
Every build tool needs custom configuration. Expect half a day fighting Webpack/Vite.
Interactive Examples (Planned for This Series)
We're building interactive examples you can run in your browser:
Example 1: "Hello Rectangle"
What it shows: Basic CanvasKit setup, creating a surface, drawing a rectangle Memory lesson: Proper paint creation and deletion ~50 lines of code
Example 2: "Animating a Circle"
What it shows: Render loop, requestAnimationFrame integration, transform matrices Memory lesson: Reusing paint objects vs creating new ones ~100 lines of code
Example 3: "Path Operations"
What it shows: Creating paths, combining them (union/intersect), stroking vs filling Memory lesson: When to delete paths, when to reuse them ~150 lines of code
Example 4: "Text Rendering"
What it shows: Font loading, text shaping, paragraph layout Memory lesson: Font and paragraph object lifetimes ~200 lines of code
Example 5: "Layers and Effects"
What it shows: saveLayer(), blur effects, blend modes Memory lesson: Layer stack management, filter ownership ~200 lines of code
Each example will be fully interactive with editable code and live output. We'll highlight the lines where memory management matters.
When to Use CanvasKit
Use CanvasKit when:
- You need features HTML Canvas lacks
- GPU performance is critical
- Cross-platform rendering consistency matters
- You're building a design/graphics tool
- 2.9MB download is acceptable
Don't use CanvasKit when:
- HTML Canvas is sufficient
- Bundle size is critical
- Simple 2D drawing is all you need
- You can't invest time learning it
The Reality Check
CanvasKit brings Skia's power to the web. But it's not polished. Documentation is sparse. Bundler integration is messy. Memory management is manual.
We spent months learning this. We hit every edge case. We wrote workarounds for everything.
This series documents what actually works. Not what the docs say. What survives production.
Next article: Why we couldn't use Skia's Path API for Figma-style vector networks.
Key Resources
- CanvasKit docs: https://skia.org/docs/user/modules/canvaskit/
- npm package: https://npmjs.com/package/canvaskit-wasm
- TypeScript definitions: Included in package at
types/ - Shopify react-native-skia: https://shopify.github.io/react-native-skia/
- Flutter Web renderer docs: Flutter's CanvasKit usage
Read next: Why We Can't Use Skia's Path API