apps/docs/content/starter-kits/shader.mdx
To build with a shader starter kit, run this command in your terminal:
npm create tldraw@latest -- --template shader
Use the shader starter kit to build:
<StarterKitBento type="shader" />The reusable WebGLManager class (src/WebGLManager.ts) creates and manages a WebGL2 context that is synchronized with the tldraw canvas. It owns the render loop and exposes lifecycle hooks—onInitialize(), onUpdate(), onRender(), and onDispose(). Each shader manager can focus on its effect-specific logic while sharing viewport coordination, resolution control, and animation timing. The Minimal, Rainbow, and Shadows examples extend this base class; the Fluid example uses a different architecture with its own simulation system.
The config panel components (src/config-panel/) provide ready-made UI controls for editing shader uniforms. Each panel stores settings in reactive atoms and persists them to localStorage, so your shader parameters survive reloads without extra wiring.
The template ships with four complete demos that follow the same pattern of manager, renderer, config panel, and GLSL files:
src/fluid/) — Navier-Stokes-based flow that turns pointer movement into velocity splats. Includes an in-depth guide.src/rainbow/) — Gradient animation that demonstrates time-based uniforms and color cycling.src/shadow/) — Raymarched shadow effect using signed distance fields derived from canvas geometry.src/minimal/) — Dark-mode-aware solid color shader that makes it easy to start your own effect, with a step-by-step walkthrough.Switch between demos from the example menu next to the style panel to see how different managers plug into the same infrastructure.
A real-time fluid simulation based on Pavel Dobryakov's WebGL fluid implementation. Shape movements create dynamic flows in the simulation.
See: src/fluid/ | Documentation
An animated gradient shader demonstrating time-based effects and uniform management.
See: src/rainbow/
Dynamic shadow casting from tldraw shapes using raymarching and signed distance fields.
See: src/shadow/
A bare-bones template for starting new shader projects. Renders a solid color that adapts to dark mode.
See: src/minimal/ | Documentation
Copy the minimal shader to create a new effect:
cp -r src/minimal src/my-shader
Then update:
config.ts — Define uniforms and UI controls for your shader.fragment.glsl / vertex.glsl — Implement rendering logic.MyShaderManager.ts — Extend WebGLManager and coordinate buffers, uniforms, and lifecycle hooks.MyRenderer.tsx — Mount the manager from React and handle cleanup.MyConfigPanel.tsx — Customize the controls exposed to users.Finally, register the new manager in src/App.tsx.
Each manager can override lifecycle hooks to add render targets, resize behavior, or post-processing passes. Use onInitialize() to set up buffers, textures, and framebuffers; onUpdate() for per-frame uniform updates (such as time, resolution, or editor-driven state); and onRender() to issue draw calls. The base class also exposes helpers for handling pixel density and canvas resizes.
Every manager receives the live tldraw editor instance, which lets you:
editor.getCurrentPageShapes().editor.store.listen().editor.getCamera().editor.pageToViewport().editor.inputs.getCurrentScreenPoint().See src/fluid/FluidManager.ts for a full example of mixing editor state with GPU simulation.
For multi-user shader environments, see the Multiplayer Starter Kit. To create custom shapes with advanced geometry and rendering, see Shape Utilities. For working with tldraw's reactive state system and event handling, see Editor State Management.
If you build something great, please share it with us in our #show-and-tell channel on Discord. We want to see what you've built!