Restaurant gamification platform powered by real POS data.
Turn your sales floor into a competitive arena. The Expo connects your Toast POS system to a suite of games played on a back-of-house TV. Your staff doesn't just play a game β they play their shift. Earn coins, redeem prizes, compete across the entire restaurant.
The Expo is a modular game platform. The backend β Toast integration, player profiles, coin economy, prize shop β stays the same. The games are swappable skins that visualize the same sales data in different ways.
Toast POS β Webhook β Game Engine β Active Game β TV + Phones
β
Coin Economy β Prize Shop
Every closed check feeds the current game. Every race/match awards coins. Coins persist across shifts. Players redeem coins for real-world prizes β gift cards, premium section picks, day-off priority, whatever the manager stocks the shop with.
Split-screen 3D racing in a shared world. Each player gets their own camera viewpoint of the same scene β like Mario Kart multiplayer. Position is rank-based (leader out front, others behind by constant gaps). The road scrolls underneath to create forward motion. Score drives speed. Power-ups from dessert sales, big checks, and combo orders. Spinouts from voids and comps.
Race types:
- Dollar Dash β total revenue
- The Coke 500 β soft drink units
- Dessert Derby β most desserts sold
- Check Race β most checks closed
- Item Rush β total items sold
The entire 4-hour shift plays out as a party adventure. No player control β the game plays itself. Your sales drive the party forward through a themed dungeon with rooms, minibosses, and a final boss.
How it works:
- Auto-launches at 5:00 PM when at least 3 players are in the lobby
- One party β everyone on shift fights together
- Sales = damage β every closed check attacks the current enemy
- Desserts heal β upsells power big moments
- Voids backfire β spells misfire, take self-damage
- Comps heal the enemy β you just made the boss stronger
- Pace gate β on a slow night, you literally cannot reach the final boss
State machine: tavern β overland β dungeon_entry β room_1 β miniboss_1 β room_2 β miniboss_2 β treasure β approach β boss_door β boss_fight β victory/defeat
10 themed quests (random selection per shift or manager pick):
- The Tyrant's Feast (Dragon demands filet mignons)
- The Saucier's Curse (Chef Mephisto and the mother sauce horror)
- Grease Trap Abyss (Sentient fryer grievances)
- The Expeditor's Revenge (Ghost haunts the pass)
- Temple of the Lost Receipt (Mirror rooms, voids = wrong path)
- Happy Hour Hellscape (2-for-1 demons)
- The Walk-In Lich (Hot sales burn, cold dishes heal it)
- Siege of Catering Castle (Wave defense)
- The Birthday Wight (300-year birthday party)
- Mount Corkage (Volcano crawl, wine = extinguisher)
Party classes β determined by your BOH partner's role:
| BOH Role | Class | Ability |
|---|---|---|
| Line Cook | Warrior | +20% melee damage from entrees |
| Sous Chef | Mage | Wine bottles do 3Γ AoE damage |
| Dishwasher | Cleric | Void-immune, heals on desserts |
| Prep Cook | Rogue | Appetizers give double-strike |
| Expo | Paladin | Combo bonuses 2Γ |
| (none) | Bard | Jack of all trades |
Presentation:
- Real sprite pack characters (soldier/orc from Tiny RPG pack) with idle/walk/attack/hurt/death animations
- Infernus hellscape tile-based backgrounds per area
- Speech bubbles over characters for party banter and enemy taunts
- Scene cards for area transitions and boss intros
- Live HP bars, buffs (π° Dessert Rush), debuffs (π Cursed)
- Historical pace calculator gates the final boss room
Status: Alpha. The engine, narration, and combat math are working. Client rendering is under active debugging β see
BossRaidErrorBoundary.jsxfor the on-screen crash inspector.
- Fighter β 1v1 bracket tournaments, sales = damage, HP bars
- Battle Royale β lowest seller gets eliminated every 30 minutes, last one standing wins
More game skins can be added without touching the backend. The game engine is decoupled from the renderer.
- One profile per employee β tied to their Toast employee GUID
- Character builder β single anatomical sprite with modular addons (shirt hue, flair emoji, accent color)
- Alias β pick a racing/fighting name that shows up in every game
- 4-digit PIN β log back in between shifts to check balance and redeem prizes
- Persistent coins β earn from every game, spend whenever you want
- React Context (
PlayerProvider) holds session state across routes
- Pre-shift lobby at
/tvshows QR code + joined players + live vote counts - Players scan in, pick their avatar, then vote for tonight's game mode
- Winning game auto-launches when the shift starts
- Votes update in real time via SSE
- Earn coins from game results and achievements
- π₯ 1st place: 100 coins
- π₯ 2nd place: 50 coins
- π₯ 3rd place: 25 coins
- Participation: 10 coins
- Big check ($200+): +10 coins
- First dessert of the race: +5 coins
- Spend coins in the prize shop
- Admin controls prize inventory β custom names, costs, quantities
- Browse available prizes from your phone
- Redeem with one tap
- Track redemption status (pending / fulfilled)
- Manager fulfills redemptions from the admin panel
- Racing mode β Three.js split-screen 3D viewports (hero layout or auto grid)
- Boss Raid mode β 2D sprite scene with tile-based backgrounds, animated characters, speech bubbles, scene cards
- Lobby mode β QR code + joined players + live vote counts
- Automatic mode switching based on active game state
- Error boundary wraps the Boss Raid renderer to surface crashes on-screen + in server logs
- Announcer bar with play-by-play
- Winner podium screen on game end
- Onboarding: Pick your employee β create character β set PIN β done
- During race: Clean pit-board view (position, score, leaderboard)
- During Boss Raid: Persistent adventurer HUD (class, HP, party status, buffs, current target)
- Between games: Shop, history, profile, vote for next game
- Tab nav: π Game | π Shop
- Scan QR to join
- Trash talk engine (30+ pre-made messages)
- Add-to-homescreen (PWA)
- PIN-protected
- Start/stop games (races or Boss Raid)
- Boss Raid controls: pick quest, seed historical pace from Toast, add heroes, force-end run
- Layout mode selector (hero grid vs auto grid)
- Toast POS configuration (client ID, secret, restaurant GUID)
- Webhook URL display for Toast setup
- Prize management β CRUD for gift card inventory
- Redemption fulfillment β mark redemptions as delivered
- Employee sync β pull roster from Toast API
- Live connection stats (TV screens, phones connected)
- Processes Toast order webhooks in real time
- Routes orders to the active game(s) β Shake N Bake and Boss Raid run in parallel when both are configured
- Power-up detection: desserts, big checks ($100+), combos (5+ items), wine bottles
- Spinout detection: voids, comps
- Game-scoped join tokens β new QR per game, dead when game ends
- Historical pace baseline pulled from Toast
/orders/v2/ordersBulk(last 4 shifts same DOW) - BOH partner abilities β pair FOH server with kitchen staff for buffs
FOH server picks a kitchen partner at race start. Each BOH role maps to a D&D class in Boss Raid and gives a buff in Shake N Bake.
| Role | Shake N Bake Ability | Boss Raid Class |
|---|---|---|
| π³ Line Cook | Dessert boost lasts 2Γ longer | Warrior |
| π₯ Sous Chef | Wine/cocktail sales give extra boost | Mage |
| π§Ό Dishwasher | Immune to one void spinout per race | Cleric |
| π₯¬ Prep Cook | Appetizer sales give speed boost | Rogue |
| π’ Expo | Combo bonus at 3 items instead of 5 | Paladin |
| (none) | β | Bard |
Both FOH and BOH share in the coin winnings β kitchen staff gets rewarded too.
| Layer | Technology |
|---|---|
| Backend | Node.js, Express, SQLite (better-sqlite3) |
| Frontend | React 18, Vite |
| 3D Engine | Three.js with FBXLoader (Shake N Bake) |
| 2D Engine | CSS sprite-sheet animation (Boss Raid) |
| Real-time | Server-Sent Events (SSE) |
| Mobile | Progressive Web App (PWA) |
| Deploy | Docker on macvlan (br0) at 192.168.1.40:3005 |
| POS | Toast API (OAuth2, webhooks) |
the-expo/
βββ server/
β βββ index.js # Express entry + debug/tv-error endpoint
β βββ db.js # SQLite schema + queries
β βββ sse.js # SSE client manager
β βββ game-engine.js # Shake N Bake scoring
β βββ toast-auth.js # Toast OAuth token manager
β βββ games/
β β βββ boss-raid/
β β βββ engine.js # State machine, tick loop, pace, buffs
β β βββ encounters.js # Mob pool definitions
β β βββ quests.js # 10 themed dungeons
β β βββ narrator.js # Flavor text generator + banter + taunts
β β βββ classes.js # BOH β class mapping + abilities
β β βββ pace.js # Historical pace calculator
β β βββ routes.js # Boss Raid API endpoints
β βββ middleware/
β β βββ auth.js # PIN + session guards
β βββ routes/
β βββ webhook.js # Toast order receiver (routes to both games)
β βββ races.js # Race CRUD + QR + SSE
β βββ players.js # Registration, profiles
β βββ coins.js # Balance, transactions, redemption
β βββ trashtalk.js # Pre-made message system
β βββ games.js # Game voting + lobby
β βββ admin.js # Admin API (PIN-protected)
βββ client/
β βββ src/
β βββ tv/
β β βββ TVApp.jsx # TV shell β auto-switches modes
β β βββ TVLobby.jsx # Pre-shift voting screen
β β βββ BossRaidTV.jsx # Boss Raid main view
β β βββ BossRaidScene.jsx # Sprite scene + hero/enemy animation
β β βββ BossRaidBackground.jsx # Infernus tile backgrounds per area
β β βββ BossRaidEffects.jsx # Popups, bubbles, scene cards, banners
β β βββ BossRaidErrorBoundary.jsx # On-screen crash inspector
β βββ games/
β β βββ shake-n-bake/ # Racing game mode
β β βββ SplitScreenGame.jsx # Three.js renderer
β β βββ LayoutManager.js # Viewport grid calculator
β β βββ PlayerHUD.jsx # Per-player overlay
β β βββ AnnouncerBar.jsx # Play-by-play ticker
β βββ mobile/ # Phone companion
β β βββ Register.jsx # Multi-step onboarding
β β βββ CharacterBuilder.jsx # Avatar + sprite helpers
β β βββ Dashboard.jsx # Race view (simplified)
β β βββ BossRaidHUD.jsx # Adventurer HUD during raid
β β βββ CoinShop.jsx # Prize shop
β β βββ TrashTalk.jsx # Message sender
β β βββ MobileApp.jsx # Tab navigation
β βββ admin/AdminApp.jsx # Admin panel
β βββ context/PlayerContext.jsx # Persistent player session
β βββ hooks/useSSE.js # SSE subscription hook
βββ public/models/
β βββ characters/
β β βββ char_free/ # Base player avatar (12-layer sprite)
β β βββ tiny_rpg_clean/
β β βββ soldier/ # Hero sprites (idle/walk/attackΓ3/hurt/death)
β β βββ orc/ # Enemy sprites
β βββ tilesets/infernus/ # 639 hellscape tiles for Boss Raid
βββ scripts/
β βββ fetch-assets.sh # Download heavy assets from GH releases
β βββ simulate.js # Fire fake webhooks for local testing
βββ docs/
β βββ toast-api.md # Toast API integration notes
βββ .env.example # Env var template (copy to .env)
βββ Dockerfile # Multi-stage (alpine build + slim runtime)
βββ docker-compose.yml # Portable base compose (localhost)
βββ CLAUDE.md # Dev reference
git clone https://github.com/nullEFFORT/the-expo.git
cd the-expo
./scripts/fetch-assets.shWhy a separate fetch step? Heavy binary assets (3D car models, sprite
sheets, tile packs β ~87 MB) are published as a GitHub Release artifact
instead of being committed to git. The fetch script downloads the bundle
for the pinned version (ASSETS_VERSION in the script) and extracts it
into client/public/models/.
The script will try GITHUB_TOKEN, then the gh CLI, then the token
embedded in the origin remote URL (works for HTTPS clones with credential
helpers). If you bump the asset bundle later, edit ASSETS_VERSION in the
script and re-run it.
cp .env.example .env
# Fill in TOAST_RESTAURANT_GUID, TOAST_CLIENT_ID, TOAST_CLIENT_SECRET, DOMAINcd server && npm install && npm run dev # http://localhost:3005
cd client && npm install && npm run dev # http://localhost:5173docker compose up -d --buildDefault deployment binds to localhost:${PORT}. For Unraid/macvlan setups,
create a docker-compose.override.yml with your br0 network + persistent
data volume (see the example pattern in this repo's CLAUDE.md).
What scripts/fetch-assets.sh puts into client/public/models/:
| Path | Source pack | Used by |
|---|---|---|
MovieCarsSet/ |
MovieCarsSet FBX | Shake N Bake 3D cars |
characters/char_free/ |
Char Free (itch.io) | Player avatars (12-layer sprite) |
characters/tiny_rpg_clean/soldier/ |
Tiny RPG Character Asset Pack v1.03b (free tier) | Boss Raid heroes |
characters/tiny_rpg_clean/orc/ |
Tiny RPG Character Asset Pack v1.03b (free tier) | Boss Raid enemies |
tilesets/infernus/ |
PVGames Infernus (free tier) | Boss Raid hellscape backgrounds |
To swap in your own content: replace files at the paths above and rebuild β the client references them by absolute URL, no config changes needed.
- Get API credentials from Toast Web (Standard API access)
- Enter client ID + secret in admin panel (
/hnic) - Sync employee roster from the admin panel
- Configure Toast to send order webhooks to your
/api/webhook/ordersendpoint - Each closed check fires the active game(s)
GET /api/gamesβ list game modes with vote countsPOST /api/games/voteβ cast vote (session required)GET /api/lobby/playersβ voting lobby rosterGET /api/boss-raid/stateβ current run stateGET /api/boss-raid/questsβ list available questsPOST /api/webhook/ordersβ Toast order receiverPOST /api/webhook/testβ manual order simulation
POST /api/admin/boss-raid/startβ start a run with optionalquestIdanddailySpecialsPOST /api/admin/boss-raid/endβ force-end the current runPOST /api/admin/boss-raid/seed-historyβ pull historical pace from ToastPOST /api/admin/boss-raid/add-heroβ manually add a player to the party
POST /api/debug/tv-errorβ TV client posts React crash reports here; logged todocker logs the-expo
Phase 1: Foundation β
- Toast integration + webhook receiver
- Game engine with power-ups/spinouts
- TV display + mobile companion
- Race-scoped QR code joining
Phase 2: Shake N Bake Polish β
- Three.js 3D rendering with FBX models
- Split-screen shared world
- BOH partner system
- Coin economy + prize shop
- Admin panel with prize management
- Sale pop animations
Phase 3: Player Accounts + Voting β
- Persistent player profiles tied to Toast employee GUIDs
- Manager-triggered employee roster sync
- First-login onboarding: pick employee β character builder β PIN
- PIN login for returning players
- Modular character builder (shirt hue, flair, accent color)
- Pre-shift voting lobby with live SSE updates
Phase 4: Boss Raid π§ (alpha)
- Backend engine, state machine, tick loop
- 10 themed quests + 30+ mob definitions
- Pace calculator with historical baseline
- Sprite-based TV renderer (Tiny RPG pack)
- Infernus tile backgrounds per area
- Speech bubbles and scene cards
- Buffs/debuffs on party cards
- Mob auto-attack with real HP drops
- Slow-pace hole-drop mechanic (visual + engine)
- On-screen error boundary with server-side crash reporting
- [OPEN BUG] Client renders blank after raid start β no heroes on map, screen flashes blank. Error boundary ships crash reports to
/api/debug/tv-error; seedocker logs the-expofor stack traces.
Phase 5: More Games
- Fighter (1v1 tournament bracket)
- Battle Royale (elimination mode)
Phase 6: Multi-Restaurant
- Multiple Toast restaurants per install
- Cross-location tournaments
- Franchise leaderboards
Private. Built for ForkLift Restaurant (Tupelo, MS).
"If you ain't first, you're last." β Ricky Bobby