A theater card game about sitting patrons in the correct spots. Are you the best usher that can make the play a success or will the noisy kids ruin it for everyone?
Seat patrons strategically to earn victory points. Different patron types have special placement rules and synergies!
📖 Read the full Rule Book — covers all patrons, traits, theaters, and scoring in detail.
# Run the development server
deno task dev
# Open http://localhost:8080 in your browser- Start — Click the number of players on the title screen
- Player Setup — Choose human or AI for each slot, pick AI difficulty, and select player colors
- Select a Theater — Click a theater board to select it, or hit Random Theater
- On your turn:
- Draw a new card from the lobby (known) or deck (blind).
- Select — Click a card from your hand (bottom of screen)
- Place — Click an empty seat in the theater grid to place that patron
- Score — The game ends after 12 turns.
| Type | Strategy |
|---|---|
| Patron | Worth 3 VP anywhere. |
| VIP | 3 VP base; +2 VP in front rows. Adjacent Kids or Noisy nullify the bonus. |
| Lovebirds | 1 VP alone; +3 if horizontally paired. +2 VP in back row. |
| Kid | 1 VP uncapped; 4 VP when capped by Teachers, on both sides of a row or column! |
| Teacher | 3 VP base; +1 VP per capped Kid this Teacher caps. |
| Critic | 3 VP base; +2 VP in an aisle seat. Noisy neighbors nullify the bonus. |
| Friend | 3 VP base; +1 VP per adjacent Friend. |
Traits can be applied to any patron type, adding unique bonuses or penalties.
| Trait | Effect |
|---|---|
| Bespectacled | +2 VP unless seated on the back row. |
| Tall | Patron directly behind this seat gets −2 VP. |
| Short | +2 VP if no one in front; −3 VP if a Tall patron is in front. |
| Noisy | Each adjacent patron (any type) gets −1 VP. |
- Full Deck — 56 cards with 7 patron types and 4 secondary traits
- Lobby System — Draw from a public pool of known patrons or the blind deck
- Card Hand — Hand of 2 cards per turn with visual selection and speech-bubble tooltips
- Hot seat support — Pass-and-play with hand passing screen
- Card Placement — Click a seat to place the selected patron with animated feedback
- Scoring Engine — VIP front-row bonuses, Teacher/Kid capping, Lovebird pairing, Critic aisle multipliers, adjacency debuffs, and all trait interactions
- Victory Points Display — Running score during gameplay, toggleable in settings
- Opponent view — See what the other users are up to by cliking the names in the score panel
- 3 Difficulty Levels — Easy and Medium mix exploration with scoring heuristics. Hard uses deterministic exhaustive first-seat search with one-card lookahead; in 2-player games it draws blind first before evaluating the second draw.
- Player Setup Screen — Choose human or AI per slot, pick difficulty, and swap player colors with a color picker
- Seamless Integration — AI turns auto-play with pacing delays; robot emoji marks AI players on the scoreboard
- 8 Unique Theaters — Each with its own layout, background art, and house rule:
- The Grand Empress — 5×4 grid - no special scoring
- The Blackbox — Compact 4×4 intimate space, with middle aile
- The Opera House — Features isolated Royal Box seats with crown tags
- The Promenade — 5x4 grid but the aisles are staggered inside
- The Amphitheater — Expanding rows (3→4→5→6), narrow front to wide back
- The Dinner Playhouse — Table-style seating with gaps between groups
- The Ziegfeld Runway — T-shaped stage extension splits the theater into left/right houses
- The Rotunda — 5×5 hollow ring, theater-in-the-round (16 seats, no back row)
- Theater Selection Screen — Preview thumbnails with zoom animation and random theater option
- Seat Label System — Front row, back row, aisle, and Royal Box seats are tagged and scored automatically per layout
- 1920s Art Deco Aesthetic — Gold and deep purple palette throughout
- Custom Patron Art — Unique card art for all patron types and traits
- Theater Backgrounds — Hand-crafted AI-generated art for each venue
- Art Deco Seat Tags — Crown tags for Royal Boxes, gold borders for aisle seats, visible walkway strips between sections
- House Rule Reminder — Active house rule stays visible in the HUD all game
Note: Yes the art is AI-generated but a lot of thought went into the cohesive theme, style, abiance and look and feel of the patrons and the theaters. If I ever get to print this game I will 100% get an artist to redo all of it from scratch.
- Title Screen — Animated logo with fullscreen toggle
- Boot Screen — Asset preloader with progress bar
- End Game Screen — Winner announcement, per-type scoring breakdown, and play-again option
- Responsive Scaling — DPR-aware, adapts to viewport aspect ratio, works on mobile
- Able to cycle through opponents theater during play and at the end game screen
- On mobile when discarding a card show the tooltip and confirm the action to prevent misclicks
- Undo & Confirm turn prompts before passing to the next player
- Pure Scoring Engine — No Phaser dependency, fully unit-tested (158 tests)
- Pure AI Engine — No Phaser dependency, fully unit-tested
- Modular Scenes — Boot → Title → Theater Selection → Game → End Game
- Reusable Components — Shared Button, Card, and SpeechBubble objects
- CI Pipeline — Type-check, lint, and test in one command
- Runtime: Deno — Modern JavaScript runtime with built-in TypeScript support
- Bundler: Vite 5 — Fast HMR and builds
- Language: JavaScript with JSDoc — Type-safe JS without compilation
- Engine: Phaser 3 — Popular 2D game framework
All tasks are defined in deno.json and run via deno task <name>:
| Task | Description |
|---|---|
dev |
Start the Vite dev server with HMR |
build |
Production build to dist/ |
preview |
Preview the production build locally |
check |
Type-check JS files (validates JSDoc code blocks too) |
lint |
Lint source files with Deno's built-in linter |
test |
Run all unit tests |
ci |
Run the full CI pipeline sequentially |
analytics:crunch |
Crunch JSONL beacons into SQLite aggregates |
# Run all checks in one command (type-check → lint → test)
deno task ci
# Or run individually
deno task check
deno task lint
deno task testoverture/
├── src/
│ ├── main.js # Game entry point & Phaser config
│ ├── config.js # Layout constants & responsive scaling
│ ├── types.js # Card data, patron types, theater layouts, deck creation
│ ├── scoring.js # Scoring engine — pure functions, no Phaser dependency
│ ├── scoring.test.js # Unit tests for scoring & deck logic
│ ├── ai.js # AI engine — pure functions, no Phaser dependency
│ ├── ai.test.js # Unit tests for AI decision-making
│ ├── settings.js # Runtime game settings
│ ├── scenes/
│ │ ├── BootScene.js # Asset preloader with progress bar
│ │ ├── TitleScene.js # Title screen & player setup
│ │ ├── TheaterSelectionScene.js # Theater picker with previews
│ │ ├── GameScene.js # Main gameplay
│ │ └── EndGameScene.js # Scorecard, winner & play-again
│ └── objects/
│ ├── Button.js # Shared button helper
│ ├── Card.js # Card game object (Container)
│ └── SpeechBubble.js # Tooltip that follows cards
├── index.html # HTML entry point
├── deno.json # Deno config, tasks & import map
├── vite.config.js # Vite configuration
├── docs/
│ ├── GAME_DESIGN.md # Full game design document
│ ├── RULE_BOOK.md # Illustrated rule book for players
│ └── images/ # Screenshots & art for the rule book
└── README.md # This file
The project uses Deno's built-in test runner — no extra test framework needed.
deno task test158 tests passing across scoring.test.js (131 tests) and ai.test.js (27
tests).
Tests live alongside source files and cover:
- All 7 patron types and 4 traits scoring rules across all 8 theater layouts
- Theater-specific mechanics: Royal Box isolation, seat labels, house rules
- Edge cases: empty grids, unknown types, overlapping debuffs, back-row multipliers
- Deck creation: correct card count, patron distribution, and metadata
- AI decision-making: all 3 difficulty levels, card selection, and 2-player discard logic
Both the scoring engine (src/scoring.js) and AI engine (src/ai.js) are
intentionally kept as pure functions with no Phaser dependency, making them
straightforward to test in isolation.
- No audio — Sound effects not yet added
- JSDoc types — All type annotations via JSDoc;
deno task checkvalidates them including code blocks in doc comments
Container runtime now includes analytics ingestion + report endpoints:
POST /api/analytics/beacon— acceptsgame_start/game_endbeacon payloadsGET /api/analytics/report— basic-auth protected HTML report
Default storage paths:
- Raw beacon log:
/app/data/analytics.jsonl - Aggregates DB:
/app/data/analytics.sqlite
Environment variables:
ANALYTICS_BASIC_AUTH_USER(required for report endpoint)ANALYTICS_BASIC_AUTH_PASS(required for report endpoint)ANALYTICS_RATE_LIMIT_PER_MINUTE(default:30)ANALYTICS_MAX_BEACON_BYTES(default:65536)ANALYTICS_JSONL_PATH(default:/app/data/analytics.jsonl)ANALYTICS_DB_PATH(default:/app/data/analytics.sqlite)
Manual crunch command:
deno task analytics:crunch- Game Design Document — Full design spec including planned features and ideas (lobby, play cards, season deck).
- Releases and Rulebook Updates — Publish to itch.io and update the linked rulebook.
- Online Multiplayer — Play with friends remotely
- Play Variants — Different "plays" with special rules
- Audio — Ambient theater sounds and placement effects
Made with Pi coding agent with the help of many different LLMs. Gemini was my main brainstorming partner for game design, theaters and plays and refinement in general. This is not AI Slop™ I have worked very hard for many months to refine the design, test it on spreadsheets and finally I decided I could take on the huge task of making a game. It would not be possible without the help of the LLMs, but I want to be clear that this is a labor of love and I am proud of it.
I hope you enjoy playing it as much as I enjoyed making it!
