An infinite-canvas sketchbook for thinking, drawing, diagramming, and planning. Local-first, offline, single-user. See slate-prd.md for the full product spec.
Built entirely on MIT-licensed open source — no tldraw, no Excalidraw:
| Concern | Library |
|---|---|
| Ink (variable-width pressure strokes) | perfect-freehand |
| Hand-drawn "sketchy" shape rendering | roughjs |
| Spatial index (culling, hit-testing, snapping) | rbush (R-tree) |
| Persistence | Dexie over IndexedDB |
| Markdown notes | marked |
| UI state | Zustand |
| Chrome / panels | React 18 + Vite + TypeScript |
| Offline / installable | vite-plugin-pwa |
The canvas engine itself is hand-rolled (src/engine/): a scene-graph document store with a reversible command model (one write path feeding undo, autosave, and a future CRDT sync layer), a two-layer Canvas2D renderer (static scene + live overlay so ink never repaints the world), viewport culling via the R-tree, Path2D caching per stroke, and far-zoom LOD.
npm install
npm run dev # http://localhost:5173
npm run build # production PWA in dist/Headless browser test scenarios live in scripts/*.mjs (Playwright); they expect the dev server on port 5180: npm run dev -- --port 5180, then e.g. node scripts/smoke.mjs.
-
Draw:
P, then pick Fine / Pen / Pencil / Marker / Brush in the style bar, with size, smoothing and opacity sliders. Trackpad and mouse get velocity-based width; a stylus gets real pressure.Eis a stroke eraser. -
Navigate: two-finger scroll pans, pinch (or
⌘+scroll) zooms at the cursor,Space-drag orHpans,⇧1zoom-to-fit,⇧2zoom-to-selection,⌘0reset. The minimap (bottom-left) is clickable. -
Tools:
Vselect ·Eeraser ·Rrect ·Oellipse ·Ddiamond ·Lline ·Cconnector/arrow ·Ssticky ·Ttext ·Fframe ·Iicon library. The toolbar is movable — drag the⋮⋮grip (double-click it to reset).
- Shapes have fill/stroke/dash controls, square or rounded corners, and a Sketchy mode (hand-drawn roughjs borders, Excalidraw-style).
-
Connectors (
C) magnetically attach to any object and land exactly on its edge; they re-route live when things move (straight / elbow / curved, arrowheads togglable). Lines (L) are the same minus arrowheads. - Drag a selected line's endpoint handles to re-angle or re-attach it; hold
⇧while dragging for 15° angle snapping. - The Attach / Free toggle in the line/connector style bar stops endpoints from sticking to shapes (for grids and interior lines); holding
⌥while drawing does the same as a one-off.
-
Tplaces text; double-click empty canvas does too; double-click any shape or sticky to label it.Enteredits the selected object. - Font picker (Sans / Serif / Elegant / Futura / Hand / Mono — native macOS stacks, fully offline) and a 12–96px size dropdown for visual hierarchy.
-
Iopens Iconland: ~290 stroke-style vector icons in 20 searchable categories (arrows, UI, design, engineering, AI/ML, data, product, geometric shapes, symbols, science…). Icons are recolorable and have an adjustable stroke width. - Select anything and hit ⊕ Save to store it as a reusable component; place copies from the "My components" section of the tray on any board (right-click a component to delete it).
-
⌘Ggroup /⌘⇧Gungroup,⌘Llock,⌘[/⌘]z-order, align/distribute buttons on multi-selection,⌘Dduplicate, arrow keys nudge. -
Frames (
F) are named regions: everything inside moves with the frame, the⧈button in the top bar jumps to any frame, frames rename from the style bar, and each frame exports as its own PNG from the Export menu. - Smart alignment guides appear while dragging; toggle snapping with the
⌖button.
- The home screen lists boards with thumbnails; boards rename, duplicate, pin and delete. Everything autosaves to IndexedDB continuously — no save button.
- 🗒 Notes opens a collapsible per-board markdown side panel (write/preview).
- Export PNG (1×/2×) / SVG of the board, selection or a frame, plus full-fidelity
.slatebackup files that re-import from the home screen. Paste or drag-drop images straight onto the canvas; pasted text becomes a text object. - Custom colors: the dashed + swatch in any palette opens the system color wheel; picked colors are saved across sessions (right-click a swatch to remove).