An infinite canvas for drawing, collaboration, and creative coding.
Documentation · Downloads · Getting Started
Drawfinity is a free, open-source drawing app with an infinite canvas. Use pressure-sensitive brushes to sketch, write Lua scripts to generate geometric art with turtle graphics, or draw together in real-time with friends. Runs as a native desktop app on Linux, macOS, and Windows.
- Infinite canvas — pan and zoom without limits, with momentum and smooth log-space zoom
- Turtle graphics — write Lua scripts to generate spirals, fractals, and geometric art
- Real-time collaboration — draw together in shared rooms with conflict-free sync
- Cross-platform — native desktop app on Linux, macOS, and Windows via Tauri v2
Drawfinity comes with a brush tool offering four presets, an eraser, and four shape tools for quick geometry.
| Preset | Width | Pressure | Opacity | Use case |
|---|---|---|---|---|
| Pen | 2px | Constant | Full | Technical drawing |
| Pencil | 1.5px | Responsive | Pressure-based | Sketching |
| Marker | 8px | Low sensitivity | Full | Bold strokes |
| Highlighter | 16px | Constant | 30% | Overlay marking |
Shape tools: Rectangle (R), Ellipse (O), Polygon (P), and Star (S). Each supports pressure-sensitive stroke width.
Open the turtle panel with Ctrl+` and write Lua scripts to drive a virtual turtle across the canvas. Built-in examples include spirals, fractal trees, and recursive snowflakes — a great way to explore creative coding.
-- Draw a square
for i = 1, 4 do
forward(100)
right(90)
endSee the Turtle Graphics documentation for the full API reference.
Press Ctrl+K to open the connection panel, enter a server URL and room ID, and start drawing with others. All changes sync instantly and conflict-free via Yjs CRDTs — everyone can draw at the same time without issues.
- Bookmarks — save and recall camera positions (
Ctrl+Bto open panel,Ctrl+Dto quick-add) - Momentum panning — flick the canvas and it glides with inertia
- Smooth zoom — scroll wheel, trackpad pinch, or
Ctrl+=/Ctrl+-with animation - Dot grid — toggle a reference grid with
Ctrl+'
![]() Infinite canvas drawing |
![]() Turtle graphics scripting |
![]() Shape tools |
![]() Real-time collaboration |
Grab the latest release for your platform from the GitHub Releases page:
| Platform | Desktop App | Server |
|---|---|---|
| Linux | .deb, .rpm, .AppImage |
drawfinity-server-linux-amd64 |
| macOS | .dmg (Apple Silicon) |
drawfinity-server-macos-arm64 |
| Windows | .msi, .exe |
drawfinity-server-windows-amd64.exe |
Download the desktop app, install it, and you're drawing in seconds. The server binary is optional — only needed if you want to host your own collaboration rooms.
See the Downloads page for detailed installation instructions per platform.
If you prefer to build from source, pick whichever path suits you:
If you have Docker and Docker Compose, one command gets everything running — the collaboration server and the frontend:
make upOpen http://localhost:1420 in your browser and start drawing. Use make logs to watch output, make restart to rebuild, and make down to stop.
Start both the server and frontend locally:
make devThis launches the collaboration server on port 8080 and Vite on port 1420. Stop everything with make stop.
For the full native experience with file save/load and tablet support:
make tauriThis starts Tauri in dev mode with hot-reload. For a production build: npm run tauri build.
| Platform | Format | Location |
|---|---|---|
| Linux | .deb, .rpm, Binary |
src-tauri/target/release/bundle/ |
| macOS | .dmg, .app |
src-tauri/target/release/bundle/ |
| Windows | .msi, .exe |
src-tauri/target/release/bundle/ |
If you just want to sketch without a server:
npm run devOpen http://localhost:1420. Drawings are saved to localStorage (no collaboration in this mode).
Prerequisites & platform dependencies
- Node.js (v18+)
- Rust (stable toolchain) — needed for the collaboration server and Tauri desktop builds
Linux (Debian/Ubuntu)
sudo apt install libwebkit2gtk-4.1-dev libgtk-3-dev libayatana-appindicator3-dev librsvg2-devLinux (Arch/Manjaro)
sudo pacman -S webkit2gtk-4.1 gtk3 libayatana-appindicator librsvgmacOS
xcode-select --installWindows
- Visual Studio Build Tools with the C++ workload
- WebView2 runtime (pre-installed on Windows 10 1803+ and Windows 11)
Run make help to see all targets. Here's the full list organized by category:
| Category | Target | Description |
|---|---|---|
| Docker | up |
Start server + frontend via Docker Compose |
down |
Stop and remove containers | |
restart |
Restart everything | |
logs |
Tail logs from all services | |
logs-server |
Tail server logs only | |
logs-frontend |
Tail frontend logs only | |
| Local Dev | dev |
Start server + frontend locally (no Docker) |
stop |
Stop local dev processes | |
server |
Start only the collaboration server | |
frontend |
Start only the frontend dev server | |
tauri |
Start Tauri desktop app in dev mode | |
| Testing | test |
Run all frontend tests |
test-watch |
Run frontend tests in watch mode | |
test-server |
Run server tests | |
test-all |
Run all tests (frontend + server) | |
typecheck |
TypeScript type check | |
| Building | build |
Production build (frontend only) |
build-tauri |
Production Tauri desktop build | |
build-server |
Production server build | |
build-all |
Build frontend + server | |
| Cleanup | clean |
Remove build artifacts |
clean-docker |
Remove Docker containers, images, and volumes | |
clean-all |
Remove everything (build artifacts + Docker) |
Drawfinity ships with a lightweight Rust collaboration server. It acts as a WebSocket relay — clients connect to a room, and the server broadcasts Yjs CRDT updates between them. Room state is persisted to disk so rooms survive server restarts.
make server
# or: cd server && cargo runThe server listens on port 8080 by default. Override with CLI flags or environment variables:
# CLI flags
cargo run -- --port 9090 --data-dir /path/to/storage
# Environment variables
DRAWFINITY_PORT=9090 DRAWFINITY_DATA_DIR=/path/to/storage cargo runmake up # Docker Compose — starts server + frontend
# or
docker compose upGET http://localhost:8080/health
Returns 200 OK when the server is ready. Useful for load-balancer probes or uptime monitors.
- Press
Ctrl+Kto open the connection panel - Enter the server URL (default:
ws://localhost:8080) - Enter or generate a room ID
- Click Connect
Multiple clients in the same room see each other's strokes in real time — all changes are conflict-free via Yjs CRDTs.
| Input | Action |
|---|---|
| Left click + drag | Draw |
B |
Brush tool |
E |
Eraser tool |
R |
Rectangle shape tool |
O |
Ellipse shape tool |
P |
Polygon shape tool |
S |
Star shape tool |
1–4 |
Select brush preset (Pen, Pencil, Marker, Highlighter) |
[ / ] |
Decrease / increase brush size |
| Input | Action |
|---|---|
| Middle mouse drag | Pan |
Space + drag |
Pan mode |
G |
Toggle pan/zoom tool |
| Scroll wheel | Zoom (discrete steps) |
| Trackpad pinch | Zoom (continuous) |
Ctrl+= / Ctrl+- |
Animated zoom in/out |
Ctrl+0 |
Reset zoom to 100% |
| Input | Action |
|---|---|
Ctrl+K |
Toggle connection panel |
Ctrl+B |
Toggle bookmark panel |
Ctrl+D |
Quick-add bookmark |
Ctrl+, |
Toggle settings panel |
Ctrl+` |
Toggle turtle graphics panel |
Ctrl+' |
Toggle dot grid |
F3 |
Toggle FPS counter |
| Input | Action |
|---|---|
Ctrl+Z / Ctrl+Shift+Z |
Undo / Redo |
Ctrl+Shift+E |
Export PNG |
Ctrl+W |
Return to home screen |
Escape |
Return to home screen |
src/ # TypeScript frontend
├── main.ts # App entry point and render loop
├── camera/ # Infinite pan/zoom with momentum
├── canvas/ # CanvasApp — full drawing canvas lifecycle
├── crdt/ # Yjs CRDT document and undo manager
├── input/ # Pointer capture, stroke smoothing, shape capture
├── model/ # Stroke and document type definitions
├── persistence/ # Tauri file I/O and auto-save
├── renderer/ # WebGL2 rendering pipeline
├── sync/ # WebSocket collaboration (y-websocket)
├── tools/ # Brush presets, eraser, shape tools, tool manager
├── turtle/ # Lua turtle graphics runtime and drawing
├── ui/ # Toolbar, connection panel, cursors, FPS
└── user/ # User preferences and profile
server/ # Rust collaboration server
├── src/main.rs # Axum HTTP + WebSocket server
├── src/room.rs # Room management and broadcast
├── src/ws.rs # WebSocket handler
└── src/persistence.rs # Room state persistence
src-tauri/ # Tauri desktop wrapper configuration
make test # All 716 tests (~5s)
make test-watch # Watch mode
make test-server # Server tests only
make test-all # Frontend + server testsmake typecheckmake clean # Remove build artifacts
make clean-docker # Remove Docker containers, images, and volumes
make clean-all # Remove everything (build artifacts + Docker)See the Makefile reference for all available targets.
- Frontend: TypeScript, Vite, WebGL2 (raw shaders, no framework)
- Desktop: Tauri v2 (Rust + WebKitGTK/WebView2)
- Data sync: Yjs CRDTs with y-websocket provider
- Server: Rust, Axum, Tokio
- Rendering: Triangle strip geometry, spatial indexing (grid-based), Douglas-Peucker LOD, vertex caching, batched draw calls
- Persistence: Binary Yjs state encoding via Tauri plugin-fs
Pressure data is read from PointerEvent.pressure and works with:
- Wacom tablets on all platforms
- Windows Ink via WebView2
- Mouse input defaults to 0.5 pressure, so all brush presets work without a stylus
- AppImage builds may fail on some Linux distributions — use
.deb/.rpmpackages or run the binary directly - WebKitGTK cache staleness (Linux): if the UI shows stale content after code changes, run
npm run clean:cache - macOS code signing: unsigned builds work locally but require signing for distribution
See the Cross-platform notes for detailed platform notes.
Drawfinity is developed and managed with Maestro orchestrating multiple Claude Code agents working in parallel. Maestro coordinates the planning, implementation, and review of features across the full stack — from the WebGL renderer to the Rust collaboration server.
This project is licensed under the MIT License.




