The MIT-licensed infinite-canvas whiteboard SDK. Drop a complete, polished drawing surface into your React, React Native, or plain-JS app — free for any use, including commercial products, forever. An open-source alternative to tldraw with no license fee.
Website · Try the app · npm · Docs · Contributing · Changelog
The hosted app at app.tryquickdraw.com — the same board createQuickdraw() drops into your page.
Quickdraw exists because embedding a whiteboard shouldn't cost thousands of
dollars a year. Quickdraw is MIT: no license key, no fees, no strings. A small
"Made with Quickdraw" badge sits in the board's corner by default; keeping it
helps people find the project, and turning it off is free, legal, and one line
— watermark: false, no license key, no signup, no phone-home. We just
appreciate the credit.
A simple, joyful drawing experience:
- Pressure ink — a freehand pen whose width breathes with stylus pressure, or with velocity for mouse users; strokes taper like a real pen
- Highlighter that soaks into the paper (and glows on dark boards)
- Shapes — rectangle, ellipse, triangle, diamond, hexagon, star — with a seeded hand-drawn wobble, four fill styles, and editable labels
- Arrows with draggable bend, lines, text, sticky notes
- Images — paste, drag-drop, or pick; auto-downscaled and stored in-document
- Laser pointer for presenting (ephemeral, never saved)
- Selection — click, shift-click, marquee; move, resize, rotate, duplicate, reorder; full keyboard nudging
- Infinite canvas — pan, wheel zoom, two-finger pinch, zoom-to-fit
- Palm rejection — once a stylus is seen, fingers steer the camera and the pen draws
- Undo/redo — one entry per gesture, however many events it took
- Light & dark themes, twelve named colors that resolve per theme, and a theme switch built into the board menu
- Grid backdrops — ruled lines or dotted intersections, spacing that adapts to the zoom and fades in rather than popping
- PNG export — whole board or selection, on paper or transparent
- A responsive floating toolbar that sheds tools gracefully as the frame narrows — or hide it and build your own from the headless API
- Real-time sync built into the data model — every change emits a JSON-safe diff you can ship over any transport
Zero runtime dependencies. The core is plain ESM that runs in any modern browser without a build step.
| Package | For | |
|---|---|---|
@quickdrawjs/core |
Any web page or framework | framework-free engine + toolbar |
@quickdrawjs/react |
React apps | <Quickdraw /> component + hooks |
@quickdrawjs/react-native |
React Native / Expo apps | WebView component + typed bridge |
npm install @quickdrawjs/reactimport { Quickdraw } from '@quickdrawjs/react'
import '@quickdrawjs/core/quickdraw.css'
export default function App() {
return (
<div style={{ position: 'fixed', inset: 0 }}>
<Quickdraw theme="light" grid="lines" watermark={false} />
{/* the "Made with Quickdraw" badge is on by default;
watermark={false} removes it — free, no strings */}
</div>
)
}Persistence, imperative control, custom chrome:
const ref = useRef(null)
<Quickdraw
ref={ref}
snapshot={saved} // load a serialized document
autoFit // fit content on mount/resize
onChange={(diff, source, editor) => // every document change
save(editor.store.getSnapshot())}
onSave={(blob) => upload(blob)} // intercept toolbar PNG export
/>
ref.current.editor.setTool('draw')
ref.current.editor.store.undo()npm install @quickdrawjs/coreimport { createQuickdraw } from '@quickdrawjs/core'
import '@quickdrawjs/core/quickdraw.css'
const board = createQuickdraw({ container: document.getElementById('board') })
board.editor.store.listen((diff) => console.log('changed', diff))npm install @quickdrawjs/react-native react-native-webviewimport { Quickdraw } from '@quickdrawjs/react-native'
<Quickdraw
ref={board}
theme="dark"
onChange={(diff) => sync(diff)}
style={{ flex: 1 }}
/>
// const snapshot = await board.current.getSnapshot()
// const png = await board.current.exportPng({ scale: 2 })The engine ships inside the package as a single self-contained HTML string — no network, works offline, Apple Pencil pressure and palm rejection included.
The document is a flat map of immutable records. Every mutation happens in a transaction and emits a diff:
{ added: { [id]: record }, removed: { [id]: record }, updated: { [id]: [from, to] } }That one shape powers everything:
- Persistence —
store.getSnapshot()/store.loadSnapshot(snap)are plain JSON round-trips - Sync — ship user diffs to peers,
store.applyDiff(diff, 'remote')on arrival; remote diffs never pollute local undo history, so collaborative undo behaves - History — undo entries are diffs, composed per gesture;
invertDiffandcomposeDiffare exported - Audit / recording — log the diff stream and you can replay a drawing stroke by stroke
// a complete sync client
store.listen((diff) => socket.send(JSON.stringify(diff)), { source: 'user' })
socket.onmessage = (e) => store.applyDiff(JSON.parse(e.data), 'remote')V / 1 |
Select |
H |
Hand (or hold Space) |
D / P / B |
Draw |
I |
Highlight |
E |
Eraser |
K |
Laser |
A / L |
Arrow / Line |
G, R, O |
Shape / rectangle / ellipse |
T / N |
Text / sticky note |
⌘Z / ⇧⌘Z |
Undo / redo |
⌘A ⌘C ⌘X ⌘V ⌘D |
Select all, copy, cut, paste, duplicate |
] / [ |
Bring to front / send to back |
Arrows (+Shift) |
Nudge selection |
⇧1 / ⇧0 |
Zoom to fit / reset zoom |
⌘+ / ⌘− |
Zoom in / out |
⌫ / ⇧⌘⌫ |
Delete selection / clear the board (undoable) |
Enter / Esc |
Edit text / done |
packages/core @quickdrawjs/core — the engine (plain ESM, zero deps)
packages/react @quickdrawjs/react
packages/react-native @quickdrawjs/react-native
examples/vanilla no-build-step example (open via any static server)
examples/react-demo vite playground (npm run dev)
Development:
npm install # workspace install
npm test # vitest — engine, React bindings, RN bridge
npm run dev # react demo at localhost:5173
npm run build # bundle the RN WebView page
npm run typecheck # validate the published type declarationsQuickdraw is young. What it doesn't have yet: a first-party multiplayer server (the diff-based store is sync-ready — you bring the transport), layers, frames, or rich text. The full roadmap lives in issue #1 — comment there if the missing feature that sent you back to a paid SDK is on it (or isn't).
Projects and products built on Quickdraw. Shipped something? Add it here — edit this table and open a PR (one row, alphabetical, ≤ 15-word description; see the showcase guidelines).
| Project | Description |
|---|---|
| tryquickdraw.com/app | The official free whiteboard app — no account, autosaves locally. |
| Your project here | Add yours → |
Quickdraw is MIT-licensed with no paid tier — sponsors are what keep it that way. Sponsors get their logo on the website and here:
No sponsors yet — your logo could be the first.
Quickdraw is free forever — no license fees, no upsell. If it saves you one, a star is how other developers find it.
Regenerated every night by a scheduled workflow — same data as the chart on the website.
Quickdraw is open to contributions from everyone — bug reports, features,
docs, examples. Start with CONTRIBUTING.md, browse
good first issue,
or open a discussion
if you're not sure where a change belongs. We follow the
Contributor Covenant.
MIT. Use it, ship it, sell what you build with it.