Why Not Raw WebGL?
Maximum control. Maximum performance. Direct GPU access.
WebGL is the foundation. Skia uses it. Every professional 2D renderer uses something like it.
So why not use WebGL directly?
The Appeal
Raw power. The GPU does exactly what you tell it.
No abstraction cost. No library overhead. No framework tax.
Full control. Every shader, every buffer, every draw call—yours.
Maximum performance potential. Nothing between you and the metal (well, the driver).
For 3D games and custom visualizations, WebGL is the right choice.
The Reality Check
Path Tessellation
WebGL draws triangles. Vector graphics are curves.
Bezier curve: GPU triangles:
● /\ /\
/ \ / \/ \
/ \ /__/\__/\
/ \ / \/ \/ \
●───────● ●──────────●
Converting curves to triangles is called tessellation. It's non-trivial:
- Bezier subdivision to polyline
- Polyline to triangle fan/strip
- Handling concave shapes (requires ear clipping or similar)
- Dynamic LOD based on zoom level
- Cache invalidation when paths change
That's weeks of work before you draw one curved line.
Anti-Aliasing
WebGL doesn't anti-alias geometry by default. Raw triangles have jagged edges.
Without AA: With AA:
██████ ▓▓████▓▓
████████ ▓▓██████▓▓
████████ ▓▓██████▓▓
████████ ▓▓██████▓▓
Options:
- MSAA: Works, costs GPU memory, doesn't help with shader effects
- Coverage-based AA: Per-pixel distance calculations in fragment shader
- Pre-filtering: Compute coverage analytically, complex math
Each approach has tradeoffs. Each requires significant shader work.
Text Rendering
Rendering text on GPU is its own field:
Bitmap fonts: Pre-rendered glyphs as textures. Limited resolution, can't scale smoothly.
SDF fonts (Signed Distance Fields): Better scaling, artifacts at extreme sizes, complex toolchain.
Glyph tessellation: Convert fonts to triangles. Expensive setup, complex curves.
Full text shaping: Character positioning, ligatures, kerning, bidirectional text, line breaking.
Figma spent years on text. It's not "just draw some letters."
Blend Modes
WebGL 1 has gl.blendFunc(). Limited options:
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); // Normal
gl.blendFunc(gl.DST_COLOR, gl.ZERO); // Multiply
Where's Color Dodge? Linear Burn? Overlay?
Not in WebGL blend functions.
Solution: Render to texture, sample both layers in shader, compute blend mathematically. That's:
- Extra render passes
- More GPU memory
- Complex shader management
- Slower than hardware blend
Stroke Rendering
Lines in WebGL are limited:
gl.drawArrays(gl.LINES, 0, 2); // 1 pixel wide, no control
Fat lines with caps and joins? Tessellate geometry. That's:
- Compute perpendicular offsets
- Generate quad strips
- Calculate miter/bevel/round joins
- Handle degenerate cases (180° turns, zero-length segments)
- Add cap geometry
Again, weeks of work.
Clipping and Masking
WebGL has stencil buffer. It works. Using it is manual:
gl.enable(gl.STENCIL_TEST);
gl.stencilFunc(gl.ALWAYS, 1, 0xFF);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
// Draw mask
gl.stencilFunc(gl.EQUAL, 1, 0xFF);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP);
// Draw masked content
Now layer masks. Alpha masks. Nested clip groups. Effect ordering.
Each feature: more stencil management, more render passes, more state tracking.
The Development Timeline
Building a production 2D renderer from scratch:
| Feature | Time Estimate |
|---|---|
| Basic shape rendering | 2-4 weeks |
| Path tessellation | 4-6 weeks |
| Anti-aliasing | 2-4 weeks |
| Stroke rendering | 3-5 weeks |
| Text (basic) | 4-8 weeks |
| Text (full shaping) | 3-6 months |
| Blend modes | 2-4 weeks |
| Effects (blur, shadow) | 4-6 weeks |
| Clipping/masking | 2-4 weeks |
| Performance optimization | Ongoing |
Conservative total: 6-12 months for one engineer. And you haven't built the editor yet.
What Skia Provides
Skia is open source. Maintained by Google. Used in Chrome, Android, Flutter.
canvas->drawPath(path, paint); // Just works
Behind that line:
- GPU-accelerated tessellation
- Adaptive LOD
- Quality anti-aliasing
- Cached geometry
- Optimized shaders
- All blend modes
- Full text shaping (via HarfBuzz)
- Effects pipeline
- Years of optimization
CanvasKit wraps Skia for WebAssembly. 2MB download, decades of engineering.
When Raw WebGL Makes Sense
Novel rendering techniques. Research, experimental visualizations.
Extreme optimization. You've profiled, Skia is the bottleneck, you can do better for your specific case.
3D integration. Vector graphics mixed with 3D scenes.
Learning. Understanding GPU rendering from first principles.
Tiny bundle. When 2MB is too much (rare, getting rarer).
The Pragmatic Choice
Build from scratch: 6-12 months minimum. Integrate Skia: 1-2 weeks to productive.
Time saved: 5-11 months.
Those months go into:
- Editor features
- User experience
- Polish
- Shipping
Skia isn't "cheating." It's smart engineering.
Summary
Raw WebGL offers:
- Maximum control
- Maximum performance potential
- Maximum development time
Building everything yourself means building everything yourself:
- Tessellation
- Anti-aliasing
- Text shaping
- Blend modes
- Stroke rendering
- Effect pipeline
Each is months of work.
Skia/CanvasKit delivers all of it, battle-tested, optimized.
Use WebGL directly when you need something Skia can't provide.
For vector editing, that's almost never.
Series Conclusion
We explored why common tools fall short:
- Canvas2D: Missing blend modes, no GPU acceleration
- Fabric.js/Konva: No vector networks, Canvas2D limits
- SVG: DOM overhead at scale
- Raw WebGL: Development time explosion
The answer for professional vector editing: Skia/CanvasKit.
- Full feature set
- GPU acceleration
- Battle-tested code
- Reasonable bundle size
- Active development
The demos in this series use Canvas2D for simplicity. The production renderer uses Skia for capability.
Choose tools that let you ship.