13 silent catch handlers replaced with descriptive console.warn logging
across 6 frontend files. No silent error swallowing remains.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Nostr signer: poll for window.nostr up to 3s on mobile (Amber injects
late). Both login() and handleSignerLogin() now wait before failing.
- Mobile TTS: install global one-time click/touch/keydown handler to
auto-unlock AudioContext when fight pages mount. Previously only
triggered by explicit sound toggle, so mobile TTS silently failed.
- Add loading spinners to "I BUILD BOTS" and "I FIGHT MYSELF" buttons.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add sfxModem() — synthesized 56k handshake sound with carrier tones,
data burst, and chirps. Plays instead of TTS for code_golf/hack_battle
rounds and code-detected answers.
- Fix entrance voice overlap: remove duplicate announceDeepIntro() from
robe entrance, add cancelPrevious to entrance-specific voice calls
(girlfriend, bouncer, shopping cart, spotlight, creator) so they
cleanly replace the global intro instead of overlapping.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove .slice(0, 120) truncation from battle log entries and
.slice(0, 60) from speech bubble calls. Increase bubble limits
to 200 chars, 24 chars/line, 8 lines so responses display fully.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
On narrow viewports (<600px), fighters were oversized due to the
desktop scale formula. Use reduced base (1.1) and tier (0.2) scale
factors on mobile while keeping desktop unchanged.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix invisible characters in human mode: init live scene BEFORE starting
challenge polling so entrance plays before first question appears
- Cap creative writing timer to 10s for multiple choice (just tapping buttons)
- Fix TTS reliability: precache priority phrases (Round 1-7, Fight!, K.O.)
all at once instead of in slow batches; prevent duplicate precache runs
- Add 10 vibe-coded narrations (~20% chance): "I was vibe coded into existence"
- Add 15 sweary narrations (~30% chance): raw unhinged fight commentary
- Add sweary draw and retro narrations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Practice button to BotProfilePage for quick sparring
- Fix rate limiter bug: all rateLimit() instances shared one counter map,
causing global and per-route limits to corrupt each other. Each limiter
now gets its own isolated map.
- Replace 8-digit hex colors (#ffd70066) with rgba() in sprite rendering
for mobile browser compatibility (iOS Safari renders them as black boxes)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Mobile nav menu now overlays content (absolute positioning) instead of
pushing it down
- Speech bubbles stay visible for minimum 400ms even when TTS resolves
instantly or fails
- kokoroPlayCached checks audio cache and loads static files even when
Kokoro worker hasn't loaded — fixes TTS not playing on production
- CORS_ORIGIN env now supports comma-separated origins
- Rename "VIDEO REPLAY" to play icon + "REPLAY"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
71 static voice files (9.6MB) for round calls, intros, hype lines,
and challenge announces. These play instantly from file instead of
running Kokoro TTS generation in the browser. Dynamic content
(questions, answers, narrations) still uses Kokoro.
Includes Node.js generation script (scripts/generate-voice-files.mjs)
and modified tts.ts to check static file cache before worker generation.
Static audio works even before Kokoro model finishes loading.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reduces worker generation timeout from 10s to 4s and adds 2s race on
awaitReady so slow Kokoro generation falls back to Web Speech API
quickly instead of stalling the fight.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds await-then-play pattern: audio is pre-generated and cached before
visuals appear, so log text + speech bubble + mouth animation + voice
all fire in the same frame. Prefetches both answers during question
playback for instant transitions. Adds hideSpeechBubble() to dismiss
bubbles when voice ends instead of fixed 5s timer.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sprite generation fallback now preserves archetype and customization
instead of silently reverting to a random character.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix fight replay showing empty scene: validate rounds before playing,
retry loading fight data up to 5 times when rounds are missing
- Add COOP/COEP headers to production server for SharedArrayBuffer
(required by Kokoro TTS WASM threading on mobile)
- Add blob: to scriptSrc/workerSrc CSP for Web Worker support
- Fix mobile character cutoff: raise ground line to 0.82, add
MOBILE_SCALE_CAP (0.55) so fighters never shrink too small
- Add ₿ bitcoin chest badge to all fighter sprites (scales with tier)
- Add sats coin stack on bot profile page proportional to satsWon
- Seed dev tournament with 8 mock bots on startup (dev mode only)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
TTS audioCache now tracks lastAccess timestamp per entry and evicts
the least-recently-used entry when full (was FIFO, deleting commonly
used phrases). Adds 6 new database indexes for bets, bot type/active
filtering, payment status lookups, and tournament entries.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
fontSrc blocked fonts.gstatic.com and styleSrc blocked fonts.googleapis.com,
causing Honk font to fail in production. The chromatic aberration pseudo-elements
then appeared as doubled plain text instead of a styled 3D effect.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Moves 103 lines of choreography selection logic out of FightScene.ts
into a dedicated module. FightScene re-exports for backward compat.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace any[] with GameObj[], fighter: any with Fighter in speech
bubbles, talking anims, showboat system, bow/fistbump/helpup, and
dizzy stars. Fix customization as any casts with ?? undefined.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- fighter: any → Fighter in entrances, morphs, finishers, rounds, types
- any[] → GameObj[] for spawned game objects across all choreography files
- as any cast in particles.ts replaced with closure variables
- Record<string, unknown> for morph sprite opts
- this: any → this: GameObj in basic choreography callback
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Effect functions now accept FightContext | ChoreoContext union type,
eliminating the unsafe cast in rounds.ts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move FightData, FightRound, FightBot, FightArenaInfo types from local
definitions in FightViewer.vue to shared fight/types.ts. Replace `any`
typing in HumanFightPage, FightPage, useFightPolling, and useFightCache
with proper typed interfaces. Fix null-safety guards exposed by typing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace 32 bare setTimeout calls with tracked timeouts across all fight
modules (effects, entrances, finishers, choreographies). All timers are
now registered in cleanupTimers Set and cleared on scene destroy.
Enhanced destroy() to also clean up active speech bubbles and explicitly
destroy all remaining game objects before k.quit().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove 38 unused audio/announce imports from FightScene.ts left over
from the module extraction. All functions are still used by the
extracted modules which import them directly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Split FightScene.ts from 6514 to 3468 lines by extracting four major
subsystems into dedicated modules with factory functions and ChoreoContext.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract 457 choreography functions from FightScene.ts into 11 modular files
under fight/choreography/. ChoreoContext interface bundles all closure deps
(k, effects, SFX) so function bodies remain unchanged. Factory pattern
(createFactories) shares prop system and make* helpers across categories.
Categories: basic (72), ranged (94), silly (80), food (45), weapons (45),
ultimates (41), bitcoin (34), heavy (30), creator (16), plus factories
and index. FightScene.ts reduced from 11,917 to 6,515 lines.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move spawnSparks, spawnBulletHoles, spawnExhaust to fight/particles.ts,
glitchRGB, scanlineGlitch, vhsTracking, dimensionalShift to fight/effects.ts,
and spawnProjectile to fight/projectiles.ts. All accept FightContext as first
param. FightScene.ts reduced by ~180 lines.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Normal wins: winner flex pose with camera flash bursts + confetti rain.
Upset wins (100+ Elo underdog): dramatic zoom on winner with golden
flash. Upset tag shown on win overlay. Wired into FightViewer after
KO/Perfect sequence.
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>
- 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>
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>