An Infinite Canvas Tutorial
Online App | Self-Deployment Guide
My free course in Gumroad . Feel free to rate!
What is an Infinite Canvas? The term "infinite" in infinitecanvas is described as follows:
High scalability. Users can freely organize content structures in a non-linear fashion.
Zooming. Emulates the "zoom in" to get an overview and "zoom out" to observe details as in the real world.
Direct manipulation. Provides intuitive editing capabilities for basic shapes, including moving, grouping, and modifying styles.
The infinitecanvas showcases numerous examples ranging from design tools to creative boards, including some well-known products such as: Figma , Modyfi , Motiff , rnote , tldraw , excalidraw and so on.
As a front-end developer, I am very interested in the rendering technologies involved. Although tldraw, excalidraw, and others generally use more user-friendly technologies like Canvas2D/SVG, there are also many editors and design tools in the JS and Rust ecosystems that use more low-level rendering technologies for 2D graphics with GPU acceleration to achieve better performance and experience:
Figma uses a tile-based rendering engine written in C++, compiled into WASM and then calls WebGL and WebGPU for rendering.
Motiff also uses a tile-based rendering engine with WebGL.
Modyfi uses wgpu from the Rust ecosystem, also compiled into WASM and then calls WebGL2 for rendering.
Zed uses GPUI to render rectangles, shadows, text, images, and other UI elements.
Vello and xilem experimentally use Compute Shader for 2D rendering.
Therefore, in this tutorial, I hope to implement the following features:
Use @antv/g-device-api as a hardware abstraction layer, supporting WebGL1/2 and WebGPU.
Use Becsy to implement high-performance, highly scalable systems based on the ECS architecture.
Use SDF (Signed Distance Field) rendering for circles, ellipses, rectangles, etc.
GPU-accelerated text and Bezier curve rendering.
Use rough.js to support hand-drawn styles.
Use CRDT (Conflict-free Replicated Data Type) to support collaborative Yjs .
Referencing mapbox and Figma , attempt to use tile-based rendering.
I hope to rewrite the rendering part of the canvas with Rust in the future, but the current project completion is still relatively low:
wgpu is a very reliable hardware abstraction layer, which can even implement the backend for piet .
Shaders can basically be reused.
Hand-drawn styles can use rough-rs .
y-crdt is the Rust implementation of Yjs .
Let's get started!
The course project uses pnpm workspace, so you need to install pnpm first.
After entering the course directory, run Vite devserver:
cd packages/lesson_001
pnpm run dev
Or you can run the site locally:
pnpm run build
cd packages/site
pnpm run dev
If you want to use it in your own project, you can refer to:
Lesson 1 - Initialize canvas π
A hardware abstraction layer based on WebGL1/2 and WebGPU.
Canvas API design.
Implementing a simple plugin system.
Implementing a rendering plugin based on the hardware abstraction layer.
Lesson 2 - Draw a circle π
Adding shapes to the canvas.
Drawing a circle using SDF.
Anti Aliasing.
Dirty flag design pattern.
Lesson 3 - Scene graph and transform π
Transformations. Make shapes support pan, zoom, rotate, and skew transformations.
Scene graph.
What is a Camera?
Projection transformation.
Camera transformation.
Camera animation. Using Landmark transition between different camera states.
Drawing straight lines using Line Geometry or screen-space techniques.
Drawing dots grid.
Drawing wireframe for Geometry.
Grid
Wireframe
Lesson 6 - Event system π
Implement an event system compatible with DOM Event API.
How to pick a circle.
Implement a drag-and-drop plugin based on our event system.
Support for pinch zoom gestures.
Developing Web UI with Lit and Shoelace
Implementing a canvas component
Implementing a zoom toolbar component
Implementing a dark theme
I18n with Lit localization
Lesson 8 - Optimize performance π
What is a draw call
Reducing draw calls with culling
Reducing draw calls by combining batches
Using spatial indexing to improve pickup efficiency
Lesson 9 - Draw ellipse and rectangle π
How to derive the SDF representation of an ellipse or rounded rectangle
Render drop-shadow and inner shadow for SDF
How to determine if a point is inside an ellipse or rounded rectangle
Drop Shadow
Inner Shadow
Lesson 10 - Import and export images π
Exporting canvas content to PNG, JPEG and SVG formats
Rendering images in the canvas
Extending the capabilities of SVG, using stroke-alignment as an example
Lesson 11 - Test and server-side rendering π
Jest-based test environment setup, including local and CI environments
Using unit tests to improve code coverage
Visual regression testing
Server-side rendering based on headless-gl, targets WebGL1
E2E testing base on Playwright, targets WebGL2 & WebGPU
E2E UI testing
Browser Compatibility Test based on BrowserStack
Render in WebWorker
Lesson 12 - Draw polyline π
Why not just use gl.LINES?
Building Mesh in the CPU or Shader
Building segments, caps and joints, antialiasing, and drawing dashed lines in shader
How to calculate its bounding box?
Lesson 13 - Draw path and sketchy style π
Experimenting with SDF
Trying to draw fills using some triangulating methods and strokes using polylines
Support earcut and libtess.js two triangulation schemes
Handle holes in the path correctly
Support fillRule property
Draw some hand-drawn shapes
Path and rough shapes
Fill rule
Lesson 14 - Canvas mode and auxiliary UI π
Implement zIndex and sizeAttenuation
Add more canvas modes, e.g. move and select and shapes
Lesson 15 - Text rendering π
What's TextMetrics and how to get it in server and browser side
What's shaping? Implement letterSpacing and kerning
Paragraph layout
Auto wordbreak
BiDi, arabic shaping included
Handle clusters
Support text-align
How to generate SDF atlas and use it to draw
How to use ESDT and MSDF to improve text rendering quality
How to draw bitmap font
How to draw emoji
Render text with SDF atlas
Bitmap font, emoji, BiDi and clusters
Lesson 16 - Text advanced features π
Using Bezier curves to render text, shaping with OpenType and Harfbuzz
Render TeX math
Text stroke, decoration, dropshadow and text along path
Physical text rendering
Load web font with web font loader
Shaping TeX with MathJax
Physical text
Text decoration
Text stroke
Lesson 17 - Gradient and Pattern π
Use CanvasGradient to implement gradients
Imperative. Create textures using the Device API
Declarative. Supports CSS gradient syntax: linear-gradient, radial-gradient, conic-gradient
Use Shoelace to implement gradient configuration panel
Use Shader to implement Mesh Gradient
Simulate random
Value Noise and Gradient Noise
Voronoi, FBM and Domain Warping
Server-side rendering in AWS lambda function
Export SVG
Use CanvasPattern to implement repeating patterns
Linear, Radial, Conic Gradient
Mesh Gradient
Lesson 18 - Refactor with ECS π
What is ECS architecture
Using ECS architecture to refactor the application with Becsy
Using Spectrum to implement UIs instead of shoelace
Top nav and zoom toolbar
Layers and properties panels
Implement a simple history system, including undo and redo
Lesson 20 - Collaboration π
Implement collaboration through CRDT
Using Loro / Yjs and BroadcastChannel to simulate collaboration on localhost
Using liveblocks to implement collaborative editing between servers and multiple clients
End-to-end encrypted CRDTs
Awareness & Presence: multiplayer cursors and comments
BroadcastChannel with Loro or Yjs
Liveblocks as backend
Multiplayer cursors
Comments
Lesson 21 - Transformer π
Resize, lock aspect ratio and centered scaling
Rotate and change the rotation origin
Nudge shapes with arrow key
Rotate anchor
Resize anchor
Line transformer
Lesson 22 - VectorNetwork π
Limitations of SVG Path
What is VectorNetwork
Analyze d3-tree, d3-flextree and @antv/hierarchy
D3 flextree
Mindmap
Lesson 24 - Context menu and clipboard π
How to implement context menu with Spectrum
Adjust z-index with bring forward and send back
Writes and reads clipboard content, supports pasting serialized graphics, non-vector images, SVG and plain text
Drag-and-drop import of image files from file systems and pages
Context menu
Drag'n'drop image
Lesson 25 - Draw rect mode and brush π
Draw shapes mode: draw rect, ellipse, line and arrow with dragging
Pencil mode, including freehand
Brush mode
Eraser tool, try to support non-atomic effect
Laser pointer tool for presentation
Draw rect mode
Draw arrow
Brush
Pencil tool
Pencil tool with freehand
Eraser
Lesson 26 - Selection tools π
Single and multi-selection with Shift keypress
Marquee selection
Lasso tool
Marquee selection
Lasso selection
Lesson 27 - Snap and alignment π
Snap to pixel grid
Snap to objects, display snap points & gap lines
Snap to pixel grid
Snap to objects
Lesson 28 - Integrating with AI π
Use chatbox
Use Nano banana to edit image, e.g remove background
Use SAM with ONNX WebGPU runtime in WebWorker
Use Qwen-Image-Layered to decompose an image into multiple layers
Use UpscalerJS to upscale an image to 2X
Use chatbox
Remove background
Use SAM with ONNX WebGPU runtime in WebWorker
Decompose into layers with Qwen-Image-Layered
Upscale image with UpscalerJS
Lesson 29 - Embedding HTML content π
Create HTML container and sync camera with CSS transform
Paste URL, display with bookmark and iframe
Paste HTML content
Export to image
VS Code snippet
Embeded YouTube
Lesson 30 - Image processing and render graph π
Image processing, including brightness, noise, etc.
The design concept and implementation of Render graph
Use FXAA render pass
Image processing
Lesson 31 - Bindings between shapes π
Analyze the data-structure design in excalidraw, tldraw, drawio and g6
Perimeter algorithm, including rectangle and ellipse
Routing rules
Bindings
Orth Connector
Lesson 32 - Text to diagram π
Parse Mermaid and render in our canvas
Parse D2 and render in our canvas
Parse draw.io and render in our canvas
Mermaid flowchart
D2 flowchart
Draw.io flowchart
Lesson 33 - Layout engine π
Implement Flexbox layout with Yoga
AlignItems & JustifyContent
Gap
Flex Basis, Grow, and Shrink
Min/Max Width and Height
Gap
AlignItems & JustifyContent
Lesson 34 - Frame and clip π
Implement clip and mask effect with stencil buffer
Crop an image
Non-atomic eraser
Crop an image
Brush with eraser