Skip to content

hansy/drawspell

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

422 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Drawspell monorepo

What this repo is

Drawspell (drawspell.space) is a multiplayer tabletop for Magic: The Gathering cards, with realtime shared state and deck import powered by Scryfall card data. The web client renders the board and handles client-side state, while the backend runs a PartyServer/Cloudflare Durable Object that hosts the Yjs document and per-room tokens. Both apps live under apps/ and communicate over PartyKit/PartyServer WebSockets.

Architecture at a glance

flowchart LR
  Web["apps/web<br/>TanStack React Start (Vite)"] -->|WebSocket: Yjs sync + intents| Server["apps/server<br/>PartyServer (Durable Object)"]
  Discord["apps/discord<br/>Cloudflare Worker (Discord Interactions)"] -->|Service Binding `SERVER`| Server
  Web -->|HTTPS| Scryfall["Scryfall API"]
  Discord -->|Discord REST API| DiscordApi["Discord API"]
  Server --> DO[(Durable Object storage)]
Loading
  • Web app (apps/web): UI, routing, and client-side state; connects to PartyServer for sync; fetches Scryfall card data.
  • Realtime server (apps/server): PartyServer runtime; applies intents to the Yjs document; manages hidden state and room tokens in Durable Object storage.
  • Discord worker (apps/discord): verifies slash-command interactions, provisions rooms via server binding, and sends DM invite links.
  • Shared types: server imports types from apps/web/src/types (see apps/server/src/domain/types.ts).
  • External services: Scryfall API for card metadata; Discord API for interactions/DMs; Cloudflare Workers + Durable Objects for hosting.

Repo structure

Path Description
apps/web Web client (TanStack React Start + Vite). See apps/web/README.md.
apps/server PartyServer backend (Cloudflare Workers + Durable Objects). See apps/server/README.md.
apps/discord Discord Interactions worker for /drawspell create. See apps/discord/README.md.

Getting started

Prereqs

  • Bun 1.2.21 (see package.json#packageManager).

Install

bun install

Commands (from repo root)

Task Command Notes
Dev: web app bun run dev Runs Vite dev server in apps/web.
Dev: server bun run dev:server Runs wrangler dev --env development in apps/server.
Dev: Discord worker bun run dev:discord Runs wrangler dev --env development in apps/discord.
Build bun run build Builds the web app.
Preview bun run preview Builds + previews the web app.
Test bun run test Runs tests for all workspaces.
Typecheck bun run typecheck Runs typechecks for all workspaces.
Deploy: staging (server + web) bun run deploy:staging Deploys dedicated staging workers.
Deploy: staging server bun run deploy:server:staging Deploys drawspell-server-staging.
Deploy: staging web bun run deploy:web:staging Builds with CLOUDFLARE_ENV=staging and deploys drawspell-staging.
Deploy: web bun run deploy:web Deploys apps/web.
Deploy: server bun run deploy:server Deploys apps/server.
Deploy: Discord worker bun run deploy:discord Deploys apps/discord.
Register Discord commands (guild) bun run register:discord:commands -- --guild-id <GUILD_ID> Fast propagation for testing.
Register Discord commands (global) bun run register:discord:commands:global Use after guild validation.
Smoke test: Discord /drawspell create bun run test:discord:smoke Runs TO-01 integration expectation used post-registration.
Cloudflare types (web) bun run cf-typegen Generates Workers types for the web app.
Cloudflare types (discord) bun run --cwd apps/discord cf:typegen Regenerates Discord worker Env types from wrangler.jsonc + .dev.vars.
Lint TBD No lint script is defined in package.json.

Configuration

Environment variables

Name Used by Description Source
VITE_PUBLIC_POSTHOG_KEY apps/web Public PostHog API key used by the web client. apps/web/.env
VITE_PUBLIC_POSTHOG_HOST apps/web Public PostHog host used by the web client. apps/web/.env
JOIN_TOKEN_SECRET apps/web, apps/server HMAC secret for join tokens; must match across web + server workers. Cloudflare secret or local .dev.vars
DISCORD_PUBLIC_KEY apps/discord Discord public key for interaction signature validation. Cloudflare secret or apps/discord/.dev.vars
DISCORD_BOT_TOKEN apps/discord Bot token for DM fanout and command registration. Cloudflare secret or apps/discord/.dev.vars
DISCORD_SERVICE_AUTH_SECRET apps/discord, apps/server Shared secret for internal provisioning auth. Cloudflare secret or .dev.vars in each app
DISCORD_APPLICATION_ID apps/discord registration script Discord application ID used for slash-command registration. Cloudflare secret/env var or apps/discord/.dev.vars
DISCORD_COMMAND_GUILD_ID apps/discord registration script Optional default guild for faster command registration rollout. Local env or shell export
DISCORD_API_BASE_URL apps/discord registration script Optional Discord API base URL override for command registration. Local env
VITE_ENV apps/web Build/runtime environment selector used by the web app to resolve Drawspell hosts. wrangler.jsonc vars or Vite define
NODE_ENV apps/server, apps/discord Runtime environment selector used for server host resolution and Discord-to-server routing. wrangler.jsonc vars

Env files and loading

  • Web: Vite loads .env* files from apps/web during vite build and vite dev.
  • Web: public VITE_* values belong in apps/web/.env*; runtime-only values and secrets belong in apps/web/wrangler.jsonc plus wrangler secret.
  • Server: Durable Object binding rooms is configured in apps/server/wrangler.jsonc; secrets use wrangler secret or apps/server/.dev.vars.
  • Drawspell web/server origins are centralized in packages/shared/src/constants/hosts.ts.
  • apps/web selects hosts with VITE_ENV; apps/server and apps/discord select them with NODE_ENV.
  • Discord: service binding SERVER is configured in apps/discord/wrangler.jsonc; default/prod binds to drawspell-server, and env.development binds to drawspell-server-development for local wrangler dev --env development.
  • Discord command registration script reads exported shell env values only (DISCORD_BOT_TOKEN, DISCORD_APPLICATION_ID, and optional DISCORD_COMMAND_GUILD_ID/DISCORD_API_BASE_URL).
  • Discord worker Env type declarations are generated into apps/discord/worker-configuration.d.ts; rerun bun run --cwd apps/discord cf:typegen when Discord worker vars/bindings or .dev.vars keys change.

Common workflows

Run the full system locally

  1. In one terminal: bun run dev:server
  2. In another terminal: bun run dev
  3. Open the URL printed by Vite and create a game.

Run a single app/package

  • Web only: bun run --cwd apps/web dev
  • Server only: bun run --cwd apps/server dev
  • Discord only: bun run --cwd apps/discord dev

Deployment / operations

  • Staging deploy target is dev branch by convention.
  • Staging deploy command: bun run deploy:staging.
  • Web deploy: bun run deploy:web (config: apps/web/wrangler.jsonc).
  • Server deploy: bun run deploy:server (config: apps/server/wrangler.jsonc, apps/server/partykit.json).
  • Discord deploy: bun run deploy:discord (config: apps/discord/wrangler.jsonc).
  • Slash-command registration workflow: see apps/discord/README.md for guild-first rollout and global rollout commands.
  • Durable Object migrations are defined in apps/server/wrangler.jsonc.
  • CI: TBD (no CI config found in the repo; add one under .github/ or similar).

Performance

See docs/performance-report.md for the latest benchmarks, load scripts, and measurement notes.

Contributing

  • Use Bun for scripts and dependency management.
  • Run bun run test and bun run typecheck before opening a PR.
  • Keep changes scoped and update docs/tests when behavior changes.
  • Formatting/linting: TBD (follow existing file style until a formatter is added).

About

Web-based virtual tabletop

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors