quickdraw ships an MIT infinite-canvas engine where every edit is a diff
The MIT-licensed infinite-canvas whiteboard SDK. An open-source tldraw alternative — no license fee, free for commercial use. React, React Native, and plain JS.
At a glance
- What is it?
- A JavaScript whiteboard SDK from quickdrawjs that positions itself against tldraw on licence cost, with zero runtime dependencies and three packages for web, React and React Native. The diff based data model is the part worth stealing; the release history is two versions old.
- Who is it for?
- Quickdraw is worth an afternoon if you need a whiteboard embedded in a React or React Native product and tldraw's licence fee is the blocker, because the MIT terms are real, the badge removal is one prop, and the diff model means you can write your own sync layer in a dozen lines instead of adopting someone else's.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 7, 2026, and from our analysis. They are not legal advice.
Editorial analysis
watermark: false is the entire licensing story
The pitch is cost. The stated reason the project exists is that embedding a whiteboard should not cost thousands of dollars a year, and the claim is that Quickdraw is MIT with no license key, no fees and no strings, free for commercial products. In practice the licence question resolves to a single prop. A small Made with Quickdraw badge sits in the corner of the board by default, and passing `watermark={false}` removes it. The documentation is explicit that turning it off is free and legal, with no license key, no signup and no phone-home, and asks only for the credit. That is an unusually clean arrangement compared with the commercial SDKs it positions against, and it means the decision you face at integration time is a branding one, not a procurement one. The same page links a documentation site, a hosted demo board and the three npm packages, so the defaults can be inspected before anything is installed.
Three packages, and core ships as unbuilt ESM
The monorepo publishes three packages. `@quickdrawjs/core` is the framework-free engine plus toolbar for any web page, `@quickdrawjs/react` wraps it as a `<Quickdraw />` component with hooks, and `@quickdrawjs/react-native` is a WebView component with a typed bridge. Core carries zero runtime dependencies and is plain ESM that runs in any modern browser with no build step, which is why the root `build` script in package.json targets only `@quickdrawjs/react-native`. The React package is where the framework-specific props live, so a plain-JS integration never sees them. There is also a hosted board at app.tryquickdraw.com built from the same `createQuickdraw()` call your own page makes, which is the quickest way to see what the defaults look like before you write any code. Repository layout is plain enough to navigate: `packages/` holds the three engines, `tests/` and `vitest.config.mjs` hold the test run, `docs/` holds the guides, and `tsconfig.json` covers the whole workspace. The plain-JS entry point stays minimal, taking only a container element.
Every mutation is a diff over immutable records
The data model is the part of this SDK worth copying into your own projects. The document is a flat map of immutable records, every mutation runs inside a transaction, and each transaction emits one diff:
{ added: { [id]: record }, removed: { [id]: record }, updated: { [id]: [from, to] } }One shape then does four jobs. Persistence is `store.getSnapshot()` and `store.loadSnapshot(snap)` as plain JSON round-trips. History stores undo entries as diffs composed per gesture, with `invertDiff` and `composeDiff` exported rather than hidden. Audit and recording come free, since logging the diff stream lets you replay a drawing stroke by stroke. Most interesting is sync, where `store.applyDiff(diff, 'remote')` on arrival keeps remote changes out of local undo history, which is what stops collaborative undo from corrupting itself. The diff is JSON safe by construction, which is what lets it travel over any transport without a serialisation layer on either side. A complete client is two lines:
store.listen((diff) => socket.send(JSON.stringify(diff)), { source: 'user' })
socket.onmessage = (e) => store.applyDiff(JSON.parse(e.data), 'remote')Palm rejection flips the input model once a stylus appears
Input handling is where a whiteboard either feels right or does not, and Quickdraw makes two decisions worth knowing. Pressure ink varies stroke width with stylus pressure, or with velocity for mouse users, so tapered strokes need no pressure hardware. Palm rejection is conditional rather than a setting: once a stylus has been seen, fingers stop drawing and steer the camera instead. That ordering means the behaviour flips mid session rather than being configured up front. The tool inventory is deliberately small: seven shapes with a seeded hand drawn wobble, four fill styles, editable labels, arrows with draggable bend, text, sticky notes, a highlighter that soaks into the paper and glows on dark boards, and a laser pointer that is ephemeral and never saved. Twelve named colours resolve per theme, with light and dark switching from the board menu. Selection covers click, shift-click and marquee, followed by move, resize, rotate, duplicate, reorder and full keyboard nudging. Undo is one entry per gesture however many low level events it took, and clearing the whole board is undoable rather than final.
The toolbar sheds tools as the frame narrows, or you replace it
The floating toolbar is responsive by shedding tools as the frame gets narrow, and there is a second path: hide it and build your own from the headless API. The imperative surface is small and specific. `ref.current.editor.setTool('draw')` switches tools and `ref.current.editor.store.undo()` reaches the store directly, and the React props cover the rest: `snapshot` loads a serialized document, `autoFit` fits content on mount and resize, `onChange` hands you every document change along with the editor, and `onSave` intercepts the toolbar PNG export so you can upload the blob instead of letting the browser download it. Grid backdrops cover plain, ruled lines, notebook rules, dots, crosses and isometric, with `lines` as the default, and spacing adapts to the zoom level and fades in rather than popping. Images can be pasted, dropped or picked, are auto-downscaled and stored inside the document rather than pushed anywhere. PNG export covers the whole board or just the selection, on paper or on a transparent background. Keyboard coverage is broad: `V` and `1` for select, `H` or held Space for hand, `D` or `P` or `B` to draw, `I` highlight, `E` eraser, `K` laser, `G` `R` `O` for shape, rectangle and ellipse, `T` and `N` for text and sticky note, bracket keys for z-order, `⇧1` and `⇧0` for zoom to fit and zoom reset.
React Native runs the engine as one HTML string in a WebView
The React Native package takes a different route from the web packages. It needs `react-native-webview` alongside itself, and the engine ships inside the package as a single self contained HTML string. That has two consequences worth planning for: there is no network call at runtime, so the board works offline, and Apple Pencil pressure with palm rejection comes along without separate native work. The bridge is typed, and the ref exposes document and export operations directly.
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 }}
/>The commented lines in the documentation show `board.current.getSnapshot()` and `board.current.exportPng({ scale: 2 })`, so a native app can pull the same JSON document and render a higher resolution PNG out of the same board. Because the engine ships whole rather than being reimplemented natively, the mobile path inherits the same tool set, themes and pressure handling as the web build, and `style={{ flex: 1 }}` is all the layout a screen needs.
Two releases in two days, and a workspace list that skips examples/vanilla
The version story is young. Two releases exist: v0.1.0 on 2026-07-31 and v0.1.1 on 2026-08-01, the latter titled around bendable lines, which matches the draggable arrow bend in the tool list. The repository is not archived and the last push to main was on 2026-10-01, so work continued after the tag, but there is no 1.0 and no changelog entry beyond that point in the visible history. The monorepo root is a private package at version 0.1.0 with workspaces covering `packages/*`, `examples/react-demo`, `examples/sync` and `apps/*`, which leaves the `examples/vanilla/` directory sitting outside any workspace. The root `test` script chains `vitest run` with a second run inside `quickdraw-sync-example`, and publishing runs three separate `npm publish` calls for core, react and react native. Development dependencies are React 19, React DOM 19, TypeScript 5.8, vitest 3, jsdom, esbuild and Testing Library, and esbuild is the only entry granted lifecycle script permission in the root package.
Editorial conclusion
Quickdraw is worth an afternoon if you need a whiteboard embedded in a React or React Native product and tldraw's licence fee is the blocker, because the MIT terms are real, the badge removal is one prop, and the diff model means you can write your own sync layer in a dozen lines instead of adopting someone else's. It is not yet a safe default for a product surface that needs breadth: only two versions have shipped, v0.1.0 on 2026-07-31 and v0.1.1 on 2026-08-01, the last push was 2026-10-01, and the tool inventory in the README is finite and small next to what tldraw users expect. Before committing, check which drawing tools your users will miss, read what `applyDiff` does with a remote conflict, and decide whether shipping the corner badge is acceptable to your brand.
Frequently asked questions
Is quickdraw really free for commercial use?
Yes. The project is MIT licensed with no license key and no fees, and it describes itself as free for any use including commercial products. A Made with Quickdraw badge sits in the board corner by default, and passing watermark={false} removes it with no license key, no signup and no phone-home.
Which npm packages does quickdraw publish?
Three: @quickdrawjs/core, a framework-free engine with toolbar for any web page; @quickdrawjs/react, a Quickdraw component with hooks; and @quickdrawjs/react-native, a WebView component with a typed bridge. The core package has zero runtime dependencies and ships as plain ESM with no build step.
How does quickdraw handle collaborative editing?
Every mutation runs in a transaction and emits a diff of added, removed and updated records. You ship user diffs to peers with store.listen and apply incoming ones with store.applyDiff(diff, 'remote'), and remote diffs are kept out of local undo history so collaborative undo behaves. Undo entries are diffs composed per gesture.
Does quickdraw work in React Native?
Yes, through @quickdrawjs/react-native, which needs react-native-webview alongside it. The engine ships inside the package as a single self contained HTML string, so there is no network call and the board works offline, with Apple Pencil pressure and palm rejection included. The ref exposes getSnapshot and exportPng.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/quickdrawjs-quickdraw)