Skip to content

ritza-co/2draw

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

2draw

A Drawful-style party game where teams of two share a canvas: each teammate is locked to one shade of the team colour, no talking allowed — coordinate through the drawing. Then every other team invents lies about what you drew, and everyone votes for the real prompt.

Built on the tldraw SDK with self-hosted tldraw sync (@tldraw/sync-core) running in a plain Node server with SQLite persistence. No Cloudflare required. Destined for 2draw.dwyer.co.za.

How it works

  • Game loop (src/server/game.ts): an in-memory state machine per game — lobby → drawing → (titling → voting → reveal) per drawing → scores. Phases advance lazily: every state poll (and every mutation) calls tick(), which moves the phase when its deadline passes or everyone has acted. No server-side timers. Timings are env-overridable (DRAW_MS, TITLE_MS, VOTE_MS, REVEAL_MS) for testing.
  • Scoring: guess the real prompt = 1000 (+500 to the artists); each player fooled by your lie = 500 to your team.
  • Sync (src/server/rooms.ts): fastify + @tldraw/sync-core. One TLSocketRoom per team per round (game__r2__t0), persisted to SQLite files in .rooms/ — fresh round, fresh room, free canvas reset. Up to 4 teams, using tldraw's dark/light palette pairs (red, blue, green, violet); member 0 draws the dark shade, member 1 the light one.
  • Client (src/client/): polls /api/game/:id/state every 1.5s and renders the matching screen. The canvas locks each player to their shade via setStyleForNextShapes plus a registerBeforeCreateHandler backstop; beforeDelete/beforeChange side effects stop you erasing or moving your partner's strokes. Side-effect handlers check source === 'user' so remote changes pass through untouched. At pens-down the canvas goes read-only and editor.toImage() exports the team drawing as a PNG data URL to the server.
  • Games live in the URL hash: /#some-game-id. No hash → a random game is created. A token in sessionStorage means a refresh keeps your seat.

Co-op mode (3+ players)

A simpler variant for playtesting the core "two people silently coordinating a drawing" mechanic. Two players share a canvas and a secret word (no talking, each locked to one shade); everyone else watches the canvas live and races to type the right guess. Drawers rotate each round so everyone gets a turn. First correct guesser and both drawers score.

Open any hash starting with coop, e.g. http://localhost:5757/#coop-test, in 3+ tabs. Server lives in src/server/coop.ts (/api/coop/:id/...); client in src/client/Coop.tsx. Both modes share the canvas, sync, colour-locking and helpers in src/client/shared.tsx. Phase timings are env-overridable: COOP_DRAW_MS, COOP_REVEAL_MS.

Dev

npm install
npm run dev        # server on :5858, client on :5757

Open http://localhost:5757 in three or more tabs (seats are per browser session, and sessionStorage is per-tab, so every tab is a separate player). You need players on at least two teams to start. For quick testing, shorten the phases:

DRAW_MS=25000 TITLE_MS=20000 VOTE_MS=20000 REVEAL_MS=8000 npm run dev

Production

VITE_TLDRAW_LICENSE_KEY=<your-key> npm run build   # client → dist/
npm start                                          # serves dist/ + sync on :5858

Put a reverse proxy in front for TLS; it must proxy /connect (websocket) and the /api routes. Caddy works with a plain reverse_proxy host:port (it handles ws automatically). Caddy 2.6.x has a websocket bug — use 2.8+.

tldraw license is required on a real domain

tldraw treats localhost/127.0.0.1 as development and renders without a key, but on any production domain it silently refuses to render the editor without a license key (you'll see "A license is required for production deployments" in the console and a blank canvas). Get a key from https://tldraw.dev (free 100-day trial, no card) and pass it via VITE_TLDRAW_LICENSE_KEY at build time — it's wired into <Tldraw licenseKey={...}> in src/client/shared.tsx. Without a key the app only works on localhost.

Deployment notes (2draw.ritzademo.com)

Runs on the shared host oc alongside other Caddy sites. Node 20 (via nvm) under the 2draw.service systemd unit on port 3002; Caddy reverse-proxies 2draw.ritzademo.comlocalhost:3002. Server resilience: a process.on('uncaughtException') guard keeps a single malformed sync message from crashing the whole process, and perMessageDeflate is disabled on the websocket (some proxies drop the compression-accept header). The remaining blocker to a live demo is the tldraw license key above.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors