Drawspell's web client, built with TanStack React Start and Vite. It renders the multiplayer board UI, manages client-side state, and connects to the realtime PartyServer. Path: apps/web.
- Owns the UI, routing, and client-side stores (
src/store,src/components,src/routes). - Manages client sync setup (Yjs provider + intent socket) and local overlays.
- Fetches card data from Scryfall and caches it locally.
- Does not apply authoritative game rules or permissions; that happens in
apps/server.
- Routes:
/and/rooms/$sessionId(seesrc/routes). - Invite tokens are accepted via query params
gt(player) andst(spectator) on the game route (seesrc/lib/partyKitToken.ts). - PartyServer message types used by the client are defined in
src/partykit/messages.ts.
Run these from apps/web (or prefix with bun run --cwd apps/web from the repo root):
bun run dev
bun run build
bun run build:staging
bun run build:production
bun run preview
bun run test
bun run typecheck
bun run cf-typegen
bun run deploy
bun run deploy:staging- Drawspell web/server origins are resolved from
@mtg/shared/constants/hostsusingimport.meta.env.VITE_ENV. VITE_PUBLIC_POSTHOG_KEYandVITE_PUBLIC_POSTHOG_HOST: public analytics build vars loaded fromapps/web/.env*.JOIN_TOKEN_SECRET: required runtime secret for issuing join tokens. Must match the secret used byapps/server. Set it withwrangler secret put JOIN_TOKEN_SECRETfor production andapps/web/.dev.varsfor local dev.- Worker runtime deploy config lives in
wrangler.jsonc.VITE_ENVis injected from Vite mode for browser code and also set in Cloudflare worker vars.
- src/routes/index.tsx
- src/routes/rooms.$sessionId.tsx
- src/components/game/board/MultiplayerBoardView.tsx
- src/hooks/game/multiplayer-sync/sessionResources.ts
- src/store/gameStore.ts
- src/services/deck-import/
- src/services/scryfall/scryfallCache.ts
- src/partykit/messages.ts
bun run test (Vitest; config in vitest.config.ts).