Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions .claude/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@
"runtimeArgs": [
"run",
"dev",
"--workspace=quickdraw-website",
"--",
"--port",
"4399"
"--workspace=quickdraw-website"
],
"port": 4399
"port": 4399,
"autoPort": true
},
{
"name": "app",
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Quickdraw

[![CI](https://github.com/nmndwivedi/quickdraw/actions/workflows/ci.yml/badge.svg)](https://github.com/nmndwivedi/quickdraw/actions/workflows/ci.yml)
[![npm](https://img.shields.io/npm/v/@quickdrawjs/core?label=%40quickdrawjs%2Fcore)](https://www.npmjs.com/package/@quickdrawjs/core)
[![npm: @quickdrawjs/core](https://img.shields.io/npm/v/@quickdrawjs/core?label=%40quickdrawjs%2Fcore&logo=npm)](https://www.npmjs.com/package/@quickdrawjs/core)
[![npm: @quickdrawjs/react](https://img.shields.io/npm/v/@quickdrawjs/react?label=%40quickdrawjs%2Freact&logo=npm)](https://www.npmjs.com/package/@quickdrawjs/react)
[![npm: @quickdrawjs/react-native](https://img.shields.io/npm/v/@quickdrawjs/react-native?label=%40quickdrawjs%2Freact-native&logo=npm)](https://www.npmjs.com/package/@quickdrawjs/react-native)
[![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

**The MIT-licensed infinite-canvas whiteboard SDK.** Drop a complete,
Expand Down
2 changes: 1 addition & 1 deletion apps/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"@quickdrawjs/core": "^0.1.3"
"@quickdrawjs/core": "^0.2.0"
},
"devDependencies": {
"vite": "^6.3.0"
Expand Down
2 changes: 1 addition & 1 deletion apps/app/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const theme = localStorage.getItem(THEME_KEY) || (prefersDark ? 'dark' : 'light'
const board = createQuickdraw({
container: document.getElementById('board'),
theme,
grid: 'dots',
grid: 'lines',
})

const { editor } = board
Expand Down
10 changes: 10 additions & 0 deletions apps/docs/app/brand.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ html.light aside {
--nextra-bg: 250, 248, 244;
}

/* npm mark in the navbar, matching the GitHub icon's hover feel */
.qd-npm-link {
display: flex;
align-items: center;
transition: opacity 0.15s;
}
.qd-npm-link:hover {
opacity: 0.75;
}

/* slightly rounder code blocks, matching the marketing site */
.nextra-code pre {
border-radius: 12px;
Expand Down
73 changes: 62 additions & 11 deletions apps/docs/app/layout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,77 @@ const logo = (
</span>
)

// npm's wordmark, sized to sit next to Nextra's 24px GitHub icon.
const npmLink = (
<a
href="https://www.npmjs.com/package/@quickdrawjs/react"
target="_blank"
rel="noreferrer"
aria-label="Quickdraw on npm"
title="@quickdrawjs/react on npm"
className="qd-npm-link"
>
<svg width="26" height="26" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M0 7.334v8h6.666v1.332H12v-1.332h12v-8H0zm6.666 6.664H5.334v-4H3.999v4H1.335V8.667h5.331v5.331zm4 0v1.336H8.001V8.667h5.334v5.332h-2.669v-.001zm12.001 0h-1.33v-4h-1.336v4h-1.335v-4h-1.33v4h-2.671V8.667h8.002v5.331zM10.665 10H12v2.667h-1.335V10z" />
</svg>
</a>
)

const navbar = (
<Navbar
logo={logo}
logoLink="https://tryquickdraw.com"
projectLink="https://github.com/nmndwivedi/quickdraw"
/>
>
{npmLink}
</Navbar>
)

const footerLink = { textDecoration: 'underline' }

// One <span> so the whole line is a single flex item of Nextra's footer and
// wraps as ordinary text instead of one child per row.
const footer = (
<Footer>
MIT licensed. Built in the open —{' '}
<a
href="https://github.com/nmndwivedi/quickdraw"
target="_blank"
rel="noreferrer"
style={{ textDecoration: 'underline' }}
>
contributions welcome
</a>
.
<span>
MIT licensed. Built in the open —{' '}
<a
href="https://github.com/nmndwivedi/quickdraw"
target="_blank"
rel="noreferrer"
style={footerLink}
>
contributions welcome
</a>
. On npm:{' '}
<a
href="https://www.npmjs.com/package/@quickdrawjs/core"
target="_blank"
rel="noreferrer"
style={footerLink}
>
@quickdrawjs/core
</a>
,{' '}
<a
href="https://www.npmjs.com/package/@quickdrawjs/react"
target="_blank"
rel="noreferrer"
style={footerLink}
>
@quickdrawjs/react
</a>
,{' '}
<a
href="https://www.npmjs.com/package/@quickdrawjs/react-native"
target="_blank"
rel="noreferrer"
style={footerLink}
>
@quickdrawjs/react-native
</a>
.
</span>
</Footer>
)

Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/core.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Returns `{ editor, ui, destroy }`.
| --- | --- | --- | --- |
| `container` | `HTMLElement` | required | The board fills it |
| `theme` | `'light' \| 'dark'` | `'light'` | |
| `grid` | `'none' \| 'lines' \| 'dots'` | `'none'` | |
| `grid` | `'none' \| 'lines' \| 'ruled' \| 'dots' \| 'crosses' \| 'iso'` | `'lines'` | |
| `readonly` | `boolean` | `false` | View-only board |
| `hideUi` | `boolean` | `false` | No toolbar — [headless](/docs/headless/) |
| `themeToggle` / `gridControl` | `boolean` | `true` | Board-menu switches |
Expand Down
6 changes: 3 additions & 3 deletions apps/docs/content/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ three packages:

| Package | For |
| --- | --- |
| `@quickdrawjs/react` | React apps — a `<Quickdraw />` component |
| `@quickdrawjs/react-native` | React Native / Expo — a WebView component with a typed bridge |
| `@quickdrawjs/core` | Any web page — framework-free, zero dependencies |
| [`@quickdrawjs/react`](https://www.npmjs.com/package/@quickdrawjs/react) | React apps — a `<Quickdraw />` component |
| [`@quickdrawjs/react-native`](https://www.npmjs.com/package/@quickdrawjs/react-native) | React Native / Expo — a WebView component with a typed bridge |
| [`@quickdrawjs/core`](https://www.npmjs.com/package/@quickdrawjs/core) | Any web page — framework-free, zero dependencies |

Every board comes complete: pressure ink, highlighter, shapes with editable
labels, arrows, lines, text, sticky notes, images, laser pointer, selection,
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/react-native.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default function Board() {
| Prop | Type | Default | |
| --- | --- | --- | --- |
| `theme` | `'light' \| 'dark'` | `'light'` | Live-switchable |
| `grid` | `'none' \| 'lines' \| 'dots'` | `'none'` | Live-switchable |
| `grid` | `'none' \| 'lines' \| 'ruled' \| 'dots' \| 'crosses' \| 'iso'` | `'lines'` | Live-switchable |
| `readonly` | `boolean` | `false` | Lock input |
| `hideUi` | `boolean` | `false` | Hide the toolbar |
| `themeToggle` / `gridControl` | `boolean` | `true` | Board-menu switches |
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/content/react.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ real dimensions.
| Prop | Type | Default | |
| --- | --- | --- | --- |
| `theme` | `'light' \| 'dark'` | `'light'` | Live-switchable |
| `grid` | `'none' \| 'lines' \| 'dots'` | `'none'` | The backdrop; live-switchable |
| `grid` | `'none' \| 'lines' \| 'ruled' \| 'dots' \| 'crosses' \| 'iso'` | `'lines'` | The backdrop; live-switchable |
| `readonly` | `boolean` | `false` | Lock input (also hides the toolbar) |
| `hideUi` | `boolean` | `false` | Hide the stock toolbar — [bring your own](/docs/headless/) |
| `themeToggle` | `boolean` | `true` | Show the theme switch in the board menu |
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/content/theming.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ and a glow on dark ones.

## Grids

Three backdrops: bare paper, ruled lines, or dotted intersections.
Six backdrops: bare paper, grid lines, ruled notebook lines, dotted intersections, blueprint crosses, or an isometric weave.

```js
editor.setGrid('dots') // 'none' | 'lines' | 'dots'
editor.setGrid('dots') // 'none' | 'lines' | 'ruled' | 'dots' | 'crosses' | 'iso'
editor.on('grid', sync)
```

Expand Down
2 changes: 1 addition & 1 deletion apps/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
},
"dependencies": {
"@astrojs/sitemap": "^3.3.0",
"@quickdrawjs/core": "^0.1.3",
"@quickdrawjs/core": "^0.2.0",
"astro": "^5.7.0"
}
}
90 changes: 88 additions & 2 deletions apps/website/src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,24 @@ const features = [
</div>
<div class="board-frame">
<div id="hero-board" aria-label="Live Quickdraw whiteboard — draw here"></div>
<div id="hero-hint" aria-hidden="true">
<div class="hint-stage">
<div class="hint-doodle-wrap">
<svg class="hint-doodle" viewBox="0 0 220 90" width="220" height="90" fill="none" aria-hidden="true">
<path
class="hint-squiggle"
pathLength="1"
d="M18 62 C 40 18, 62 18, 78 50 C 92 78, 110 78, 124 50 C 138 22, 158 22, 172 44 C 182 60, 194 62, 204 52"
stroke="var(--accent, #e8590c)" stroke-width="4" stroke-linecap="round" />
</svg>
<svg class="hint-hand" viewBox="0 0 24 24" width="34" height="34" fill="none" stroke="var(--ink, #1c1b18)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" fill="rgba(255,255,255,0.92)"/>
<path d="m15 5 4 4"/>
</svg>
</div>
<span class="hint-pill">Draw something!</span>
</div>
</div>
</div>
</section>

Expand Down Expand Up @@ -198,7 +216,7 @@ const features = [
import '@quickdrawjs/core/quickdraw.css'

export default function Board() {
return <Quickdraw theme="light" grid="dots" />
return <Quickdraw theme="light" grid="lines" />
}`}</code></pre>
</div>
<div class="qs-pane" data-qs-pane="js">
Expand Down Expand Up @@ -312,12 +330,19 @@ createQuickdraw({

const container = document.getElementById('hero-board')
if (container) {
const board = createQuickdraw({ container, theme: 'light', grid: 'dots' })
const board = createQuickdraw({ container, theme: 'light', grid: 'lines' })
const { store } = board.editor
const saved = sessionStorage.getItem('qd-hero')
if (saved) {
try { store.loadSnapshot(JSON.parse(saved), 'remote') } catch {}
}
// "draw something" nudge: only over an untouched board, gone at first touch
const hint = document.getElementById('hero-hint')
if (hint) {
const hide = () => hint.classList.add('off')
if (store.shapes().length > 0) hide()
else container.addEventListener('pointerdown', hide, { once: true })
}
let t
store.listen(() => {
clearTimeout(t)
Expand Down Expand Up @@ -413,6 +438,67 @@ createQuickdraw({
box-shadow: 0 24px 60px -28px rgba(28, 27, 24, 0.28);
overflow: hidden; background: #fff;
}
#hero-hint {
position: absolute; inset: 0; z-index: 5;
display: flex; align-items: center; justify-content: center;
pointer-events: none;
}
#hero-hint.off { display: none; }
.hint-stage {
position: relative;
display: flex; flex-direction: column; align-items: center; gap: 2px;
}
/* the wrap is exactly the SVG's box, so the hand's offset-path (element
coordinates) and the squiggle (SVG viewBox) share one origin */
.hint-doodle-wrap { position: relative; width: 220px; height: 90px; }
.hint-doodle { overflow: visible; display: block; }
.hint-squiggle {
stroke-dasharray: 1;
stroke-dashoffset: 1;
animation: hint-draw 3.2s ease-in-out infinite;
}
.hint-hand {
position: absolute; top: 0; left: 0;
/* same curve as .hint-squiggle, so the pencil tip rides the line */
offset-path: path('M18 62 C 40 18, 62 18, 78 50 C 92 78, 110 78, 124 50 C 138 22, 158 22, 172 44 C 182 60, 194 62, 204 52');
offset-rotate: 0deg;
/* offset-path anchors the glyph CENTER to the curve (Chrome has no
offset-anchor), so shift the box until the pencil tip — bottom-left
of the glyph — is what touches the line */
transform: translate(14px, -14px);
animation: hint-trace 3.2s ease-in-out infinite;
filter: drop-shadow(0 3px 4px rgba(28, 27, 24, 0.25));
}
@supports not (offset-path: path('M0 0 L1 1')) {
.hint-hand { display: none; }
}
.hint-pill {
display: inline-flex; align-items: center; gap: 8px;
padding: 9px 16px; border-radius: 999px;
background: rgba(255, 255, 255, 0.9);
border: 1.5px dashed color-mix(in srgb, var(--accent) 55%, transparent);
box-shadow: 0 10px 26px -14px rgba(28, 27, 24, 0.35);
backdrop-filter: blur(4px);
color: var(--ink); font-weight: 600; font-size: 14.5px;
}
/* line and pen share the same fade window (74–90%) so they vanish together */
@keyframes hint-draw {
0% { stroke-dashoffset: 1; opacity: 1; }
62% { stroke-dashoffset: 0; opacity: 1; }
74% { stroke-dashoffset: 0; opacity: 1; }
90%, 100% { stroke-dashoffset: 0; opacity: 0; }
}
@keyframes hint-trace {
0% { offset-distance: 0%; opacity: 0; }
6% { opacity: 1; }
62% { offset-distance: 100%; opacity: 1; }
74% { offset-distance: 100%; opacity: 1; }
90%, 100% { offset-distance: 100%; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.hint-squiggle { animation: none; stroke-dashoffset: 0; }
.hint-hand { animation: none; offset-distance: 100%; }
}

.features .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: 18px; }
.card {
Expand Down
14 changes: 7 additions & 7 deletions docs/star-history-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 4 additions & 3 deletions docs/star-history.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"repo": "nmndwivedi/quickdraw",
"stars": 19,
"stars": 20,
"createdAt": "2026-07-31T22:22:15Z",
"generatedAt": "2026-08-02T10:40:48.779Z",
"generatedAt": "2026-08-02T12:23:29.848Z",
"starredAt": [
"2026-08-01T01:18:08Z",
"2026-08-01T05:46:50Z",
Expand All @@ -22,6 +22,7 @@
"2026-08-02T06:42:06Z",
"2026-08-02T08:48:12Z",
"2026-08-02T09:13:33Z",
"2026-08-02T09:35:30Z"
"2026-08-02T09:35:30Z",
"2026-08-02T11:39:14Z"
]
}
Loading
Loading