White-label trading card game built for both humans and ElizaOS agents. Embedded as iframe in the milaidy Electron app. Agents stream gameplay via retake.tv.
| Layer | Tech |
|---|---|
| Runtime | Bun 1.3.5 |
| Frontend | Vite 6 + React 19.2 + React Router 7 |
| Styling | Tailwind CSS 4 |
| Backend | Convex 1.31.6 (white-label components) |
| Auth | Privy 3.12 |
| State | Zustand 5.0 |
| Animation | Framer Motion 12 |
| UI | Radix UI + custom zine components |
| AI Agents | ElizaOS 1.7.2 |
| Streaming | retake.tv |
Important
Use Bun Exclusively This project uses Bun for everything.
- Install:
bun install - Run:
bun run <script> - Add:
bun add <package> - Do NOT use:
npm,yarn, orpnpm.
# Install dependencies
bun install
# Start development (Convex + Web)
bun run dev
# Or run individually:
bun run dev:convex # Backend only
bun run dev:web # Frontend only (port 3334)
bun run dev:rpg # RPG frontend (port 3340)Set these environment variables before enabling Telegram inline + Mini App gameplay:
# Convex runtime
TELEGRAM_BOT_TOKEN=123456:your_bot_token
TELEGRAM_WEBHOOK_SECRET=your_random_secret
TELEGRAM_BOT_USERNAME=YourBot
TELEGRAM_WEB_APP_URL=https://your-web-app.example/ # used for Games launch URLs
# Optional but recommended: direct mini app links (works even if Main Mini App isn't enabled yet)
TELEGRAM_MINIAPP_SHORT_NAME=your_mini_app_short_name
# Optional: Telegram Games API
TELEGRAM_GAME_SHORT_NAME=your_game_short_name
# Web runtime
VITE_TELEGRAM_BOT_USERNAME=YourBot
VITE_TELEGRAM_MINIAPP_SHORT_NAME=your_mini_app_short_name
VITE_TELEGRAM_GAME_SHORT_NAME=your_game_short_nameBotFather checklist:
- Enable inline mode:
/setinline - Set Menu Button URL:
/mybots-> Bot Settings -> Menu Button - Configure Main Mini App:
/mybots-> Bot Settings -> Configure Mini App (enables?startapp=links) - (Optional) Create a Direct Mini App short name:
/newapp(use fort.me/<bot>/<short_name>?startapp=...) - (Optional) Create a Game:
/newgame(setTELEGRAM_GAME_SHORT_NAME)
Webhook setup:
curl -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/setWebhook" \
-H "Content-Type: application/json" \
-d '{
"url":"https://<your-convex-site>/api/telegram/webhook",
"secret_token":"'"${TELEGRAM_WEBHOOK_SECRET}"'"
}'LTCG-v2/
├── convex/ # Convex backend (host layer)
├── apps/rpg-web/ # RPG creator + library + session UI
├── packages/
│ ├── engine/ # Pure TS game engine
│ ├── rpg-engine/ # Deterministic RPG engine + dice runtime
│ ├── rpg-worlds/ # RPG world manifests + flagship world bundles
│ ├── rpg-render/ # 2D renderer + optional 3D adapter contracts
│ ├── rpg-agents/ # Agent seat policies and safety helpers
│ ├── plugin-rpg/ # ElizaOS RPG plugin
│ ├── plugin-ltcg/ # ElizaOS plugin
│ ├── lunchtable-tcg-cards/ # Card inventory + decks
│ ├── lunchtable-tcg-match/ # Event-sourced matches
│ └── lunchtable-tcg-story/ # Story mode progression
├── apps/web/ # Frontend (Vite + React SPA)
└── docs/ # Architecture + agent docs
- Setup guide:
docs/integrations/discord-activity.md - Required client env:
VITE_DISCORD_CLIENT_ID - Required server env for OAuth code exchange:
DISCORD_CLIENT_SECRET - Required server env for interactions verification:
DISCORD_PUBLIC_KEY - Optional client env for URL mappings:
VITE_DISCORD_URL_MAPPINGS - Discord mobile deep-link path:
/_discord/join - Discord interactions endpoint:
/api/interactions
- Manifest file:
apps/web/public/soundtrack.in - Agent-readable endpoint:
GET /api/soundtrack(optional?context=play) - Plugin env (optional):
LTCG_SOUNDTRACK_API_URL=https://your-app.com/api/soundtrack
soundtrack.in supports:
- Playlist sections like
[landing],[play],[story],[watch],[default] - SFX section
[sfx]with key/value pairs likeattack=/audio/sfx/attack.wav
Landing context is shuffled automatically; other contexts loop in order.
A vice-themed trading card game with 6 archetypes:
- Dropout (Red) - Aggro
- Prep (Blue) - Midrange
- Geek (Yellow) - Combo
- Freak (Purple) - Chaos
- Nerd (Green) - Control
- Goodie Two-Shoes (White) - Attrition
# Run tests
bun run test # Watch mode
bun run test:once # Single runProprietary - All rights reserved.