Tier-selectable practice page at /practice. Fights against classic
bots with dampened Elo. Routes to human fight page or arena based
on bot type.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Large tap-target multiple-choice buttons (min 48px), full-width text
area for creative responses, countdown timer with color shift
(green/yellow/red) and shake animation at <3s, timer progress bar,
correct/wrong feedback flash overlay.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TournamentListPage with status filters, TournamentPage with CSS grid
bracket display, lobby view for open tournaments, champion banner,
live polling for active tournaments. Routes at /tournaments and
/tournament/:id. NavBar link added.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add CacheFirst runtimeCaching rules for Hugging Face model requests
(huggingface.co and cdn-lfs) with 90-day expiration. Add
getKokoroProgress() export to tts.ts for tracking download progress.
Add TTS model download progress bar overlay in FightViewer.vue that
shows during model loading and auto-hides when complete.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document top 5 largest chunks in vite.config.ts. Findings:
- kokoro-js (2.2MB) is in a separate worker chunk, NOT main bundle
- kaplay is tree-shaken into the lazy FightViewer chunk only
- nostr-tools is split across wallet chunks, minimal in main entry
- optimizeDeps.include is dev-only, no production effect
- All routes are properly code-split via dynamic imports
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- useNostr.ts: wrap auto-restore login fetch with AbortController,
abort on logout to cancel in-flight request
- useWallet.ts: wrap localStorage.setItem/removeItem calls in try/catch
for Safari private browsing quota exceptions
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- FightPage.vue: store SSE listener refs in array, removeEventListener
on each before close() in disconnectSSE()
- FightScene.ts: add cleanupTimers Set with trackedInterval/trackedTimeout
helpers; replace key setInterval calls (projectile trails, entrance
flames, talking animation, exhaust effects, dimensional shift, hole
fade) with tracked versions; clear all on scene destroy()
- rate-limit.ts: export cleanupInterval handle for graceful shutdown
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- app.ts: type serveFile context parameter as Hono Context
- bets.ts: replace catch(err: any) with err: unknown + narrowing
- fight-loop.ts: type pickMatchup style as union literal, replace
as any casts with proper result type
- tts-worker.ts: import KokoroTTS type, use ProgressInfo inference
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Define Fighter type alias using Kaplay's GameObj with SpriteComp, PosComp,
ScaleComp, AnchorComp, OpacityComp, ColorComp, RotateComp, and ZComp.
Replace 81 choreography function signatures from (atk: any, def: any, ...)
to (atk: Fighter, def: Fighter, ...). Type loadSpriteWithTimeout opts as
LoadSpriteOpt. Type lines/bands arrays as GameObj[]. Type spawnAfterimages
and cameraZoom fighter params. Add as Fighter casts at k.get() call sites.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Elo-bracket matchmaking: prefer ±200, widen by 100 every 15s of waiting.
Add pickRankedChallenge() that filters to creative/open-ended only, never
multiple choice. Show ranked queue status, wait estimate, and "HARDER
PROMPTS" notice on JoinBoutPage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add GET /api/bots/leaderboard?season=current endpoint. LeaderboardPage
now toggles between "This Season" and "All Time" views. Shows season
name, countdown timer, and top 3 placement badges.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add ZAP WINNER button in FightViewer after fight ends. Server endpoint
POST /api/payments/zap increments zapsReceived on winner bot. Show zap
count on bot profile page. Add zaps_received column with migration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fetch full kind:0 metadata (display_name, about, banner, nip05) from
relays with a 5-min TTL cache. Show Nostr banner, display name, and
NIP-05 on bot profile pages. Expose ownerPubkey in stats API.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BetHistory component shows personal bet history with fight links,
amounts, outcomes, and payouts. P&L summary shows total wagered, total
won, and net sats. Added to BotProfilePage for the bot owner's view.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
BetPanel component with pick-winner buttons, preset amounts (21/100/500/
1000 sats), Cashu token paste, odds display from server, and payout
preview with 5% house cut. Wired into FightCardPage for scheduled fights.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
POST /api/fights/:fightId/react endpoint accepts emoji reactions (fist,
fire, skull, 100, clown), aggregates counts, broadcasts via SSE.
Reaction bar added to FightViewer with floating emoji particles that
rise and fade. Live fight views receive reactions via SSE in real-time.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reverse-chronological activity stream of recent fights showing winner,
KO/decision result, arena, sats, and time ago. Filter by tier and bot
name. Click any fight to watch replay. Added to NavBar as FEED link.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable real-time fight spectating for all live fights (not just human
fights). Multiple spectators can watch simultaneously via SSE. Spectator
count is tracked per-fight and broadcast with every SSE event.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds kokoro-js (82M model, 28 distinct voices) as primary TTS engine with
automatic fallback to speechSynthesis while model loads. All 60+ voice
profiles mapped to real Kokoro voices. Common fight phrases pre-cached
for instant playback.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Music now uses per-track synthStyle for bass/lead/pad/arp instead of
generic synths. Add .pnpm-store and .npmrc to gitignore.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
50%+ of fight time is now physical contact between fighters:
- Brawl exchanges: both fighters close to center, trade 4-13 rapid
blows with sparks at contact point, positional pushing, intensity
scaling. Winner lands 65% of hits.
- Clinch combos: attacker rushes in, grapples at close range for
3-11 sustained hits with defender counter-blocking (30% chance).
Ends with a shove-apart.
- Counter-attacks: after a choreography hit, defender retaliates
with 2-3 quick hits (25% chance on non-final exchanges).
- Exchange count increased from 2-4 to 3-7, scaling with round
number and intensity. Later rounds are longer, more brutal.
- Physical exchange chance: 35-70% per non-final exchange,
increasing with intensity and exchange number.
- Reduced dodge chance (12% vs 15%) for more contact, fewer misses.
- Shorter pauses between exchanges for tighter pacing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Comedy sounds (all procedural Web Audio, no samples):
- Vine Boom, Air Horn (MLG), Bruh, Fart, Record Scratch
- Rubber Chicken, Squeaky Toy, Wet Slap, Bone Crack, Cartoon Run
- Rim Shot (ba dum tss), Slide Whistle Up/Down, Yippee, Ding
- Taco Bell Bong, Windows Error, Meme Thud
- Sad Trombone, Emotional Damage, Dun Dun Dunnnn
- Fail Horn, Price Is Right Fail, Buzzer, Sad Violin
- Mission Failed, Crickets
Wiring:
- Round-end narration: 75% comedy SFX, 25% TTS (was 100% TTS)
- Critical rounds get Emotional Damage, draws get random fail
- Showboat loop: 40% chance of comedy sound punctuation after each
- KO finish: 50% chance of comedy fail sound on loser
- sfxRandomSilly expanded with comedy sounds
- New exports: sfxRandomComedy, sfxRandomFail
Also adds bulletTimeAttack combat choreography + ultimateBulletTimeBarrage
(tier 3+ ultimate) to fight system.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds cinematic bullet-time combat sequence with slow-mo golden projectiles,
afterimage dodge trails, and devastating counter-rush with multi-hit impact.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Creator omni-morph now generates actual sprite sheets for morphed archetypes
- 3 new Creator showboats: bullet time attack, ₿ throne summon, disco dance
- Music: subtle tempo shift (+10 BPM max), longer phrases (8/16/24 bars),
smoother crossfades, less chaotic hi-hat at high intensity
- Server: security headers, body size limit, production error masking,
CORS origin warning, graceful shutdown with drain
- Payments: atomic consume (eliminates SELECT/UPDATE race), release reverts DB
- Fight loop: round events for live TUI, retro displayPrompt
- Frontend: pass pubkey in payment/queue requests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Completely rewrote all 30 showboats with much more walking, jumping,
sprinting back and forth across the arena. Fighters now pace, charge,
leapfrog, zigzag sprint, do backflip retreats, wall-to-wall dashes,
kangaroo hops, shadow box sprints, and girlfriend kiss scenes.
Added 12 Creator-exclusive magical showboats:
- Levitate across screen trailing golden ₿ rain
- Portal teleport (vanish, flash between 3 spots, reappear)
- Massive golden code rain summon (₿01∞⚡⛏ characters)
- ₿ orbit explosion (orbit then burst outward)
- Lightning flight (zigzag with lightning bolts)
- Satoshi meditation (golden aura, bitcoin wisdom quotes)
- Golden tornado (circular path with ₿ trail)
- Laptop hack (type furiously, spawn code chars)
- Bitcoin rain shower (fly across dropping ₿ coins)
- Dimension rift (tear golden portal, step through)
- Golden ascension (rise, glow, slam down with shockwave)
- Phase walk (flicker through opponent's space)
Creator gets magical showboats ~60% of the time. Pause between
showboats shortened to keep the action constant.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fighters now perform random showboating micro-animations while idle
during question reading and opponent's answer — shadow boxing, backflips,
flex poses, moonwalks, ground pounds, air guitar, sumo stomps, and more.
Each showboat uses existing sprite anims (attack/kick/special/win) combined
with Kaplay tweens for position, scale, rotation, sparks, and emote text.
Showboating loops with random variety and pauses between moves.
Flow: both showboat during question → stop the answering bot during their
turn → stop all before fight animation begins.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Unified speakAsync/speakAsyncWithRate into _speakAsyncCore with:
- 500ms startup check: bail immediately if speech won't start (mobile/no gesture)
- 8s safety timeout (down from 15s) to prevent blocking
- iOS-safe keepalive: only do Chrome pause/resume workaround on desktop Chrome
- Immediate bail when no voices loaded
- Sprite loading: 5s timeout per sprite prevents mobile hangs from stuck Image decodes
- Scene creation: 10s timeout in FightViewer so overlay/voice flow continues even if
canvas fails on mobile
- playRound: bail gracefully if fighter sprites missing instead of crashing
- Global audio unlock: first touch/click on site unlocks AudioContext + SpeechSynthesis
- Practice button pre-unlocks audio while still in user gesture context
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TTS fixes:
- Remove 60-char truncation in FightViewer — let speakAnswer handle limits
- Smart truncation at sentence boundaries (period, comma, etc.) up to 200 chars
- Chrome keepalive: periodic pause/resume prevents silent 15s cutoff bug
- Deduplicated cleanup logic in speakAsync/speakAsyncWithRate
Retro mode:
- Simplified challenge prompt from verbose wall of text to clean 3-line format
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace 100vh with 100dvh everywhere (accounts for mobile browser chrome)
- DocsPage: viewport-fixed with tabs pinned, tab content scrolls internally
- BotProfilePage: overflow-hidden outer, internal scroll container
- JoinBoutPage: viewport-fixed with internal overflow scroll
- HumanFightPage: viewport-fixed, flex-1 content area with internal scroll
- All other pages: vh → dvh for correct mobile sizing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DocsPage: escaped \"answer\" inside v-for HTML attribute broke template
parsing causing infinite Vite error loop. Replaced with " entity.
FightScene: three k.text('₿') objects used .angle without k.rotate()
component, causing TS2339 build errors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Every fight now includes one Retro Mode round where bots submit
gamepad combo inputs (↑↓←→ A B). 24 moves across 4 tiers: basic
(always shown), standard (partially revealed), super (must discover),
and ultra (KONAMI CODE for 50 dmg). Discovery bonus gives 1.5x damage.
Includes pixel-art gamepad overlays (P1/P2) with animated button
presses, retro-specific narrations, and mock bot combo responses
scaled by ELO.
Also adds loops/plan.md with 11-phase production hardening roadmap.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds emissive glow bloom, visible pixel grid, cross-hatch background,
scan lines, 3D bevel, and tier-gated energy particles to poster sprites.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fight Card page: dramatic poster background with cross-hatch, spotlights,
vignettes, corner brackets, scan lines; 3D VS orb with punch animation;
selectable undercard with main event always pinned at top
- PosterSprite: high-quality 480px poster frame with 6-pass renderer
(aura, glow, bevel, specular, particles); PixelGlove component
- 12-char bot name limit across all forms and server validation
- Mock bots: all 100 now have diverse archetypes (25 types), 25% human
fighters; seedMockBots updates existing bots on restart
- Leaderboard: inline SpritePreview next to each bot name
- Nostr auth: persistent login, nsec copy button
- Wallet: NWC + Lightning Address, ranked fight flow
- Server: payments, ranked queue, customization endpoint
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Arena page shows small sprite previews next to each bot's name
- Server returns archetype in fights list endpoint
- New /fight-card page with 3D perspective fight poster, neon signs,
animated boxing gloves, fighter bobbing, VS pulse, undercard list
- Added FIGHT CARD to nav bar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add WalletConnect.vue with NWC/LN Address connection states. Add "FIGHT
FOR SATS" button to JoinBoutPage with entry fee payment flow. Show ranked
pot and winner payout in FightPage. Add sats stats and wallet section to
BotProfilePage. Extend BotData interface with satsWon/satsWagered/hasWallet.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Client-side wallet composable with NWC auto-pay, invoice polling,
Cashu token submission, and persistent wallet state. Follows useNostr
pattern with readonly exports and localStorage persistence.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Disconnect and recreate sfxGain in stopAllAudio() so oscillators
and noise buffers stop immediately instead of playing to completion.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- FightViewer: wrap createFightScene in try/catch so scene failures
don't crash every subsequent playRound call
- FightViewer: wait for container to have non-zero dimensions before
creating canvas (prevents 0x0 canvas causing sprite load failures)
- FightViewer: graceful log-only fallback when scene init fails
- FightPage: same dimension-wait and try/catch for initLiveScene
- Fallback canvas dimensions (800x500) when container not yet laid out
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fetches from /api/docs/webhook and renders as a styled tabbed page.
Added /docs route and DOCS nav link.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>