Commit Graph
146 Commits
Author SHA1 Message Date
DorianandClaude Opus 4.6 95ed80335a feat: polling API, HMAC webhook signing, session-only keys, prod audio fix
- Add polling API (GET/POST /api/fights/poll) so bots don't need public URLs
- Add HMAC-SHA256 webhook signing (X-Botfights-Signature header)
- Stop auto-persisting nsec keys — session-only by default with opt-in "Remember on this device"
- Fix production TTS: add wav/mp3/ogg MIME types, /audio/* route, SPA blocklist
- Overhaul docs: mode selector (poll vs webhook), AI-first bot examples, security tab
- Fix duplicate sign-in buttons, login flow bugs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 18:34:22 +00:00
DorianandClaude Opus 4.6 150ce7447d fix: human vs AI fight bugs — CSP for TTS, invisible sprites, fight end sequence
- Allow huggingface.co in CSP connect-src (fixes Kokoro TTS model download)
- Add registerSW.js route (fixes PWA service worker 404)
- Add _resetPositions() safety after entrance (fixes invisible fighters)
- Fight end sequence works without canvas scene (KO/overlays/log always play)
- Pre-fight instructions in battle log for human players
- NIP-55 visibility sync and cleanup handlers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 17:00:20 +00:00
DorianandClaude Opus 4.6 63cc00fcb6 feat: add NIP-55 Android signer support for Amber/Primal login
When window.nostr isn't available (common on mobile Chrome where
extensions can't inject), fall back to NIP-55 nostrsigner: intent
URIs. This opens Amber/Primal directly to sign a NIP-98 event,
then redirects back with the signed event for JWT authentication.

- Build nostrsigner: URI with unsigned NIP-98 event + callback URL
- Process NIP-55 callback on page mount (extract signed event from URL)
- Auto-detect Android to show "SIGN IN WITH AMBER / PRIMAL" label
- Reduced window.nostr polling from 3s to 2s before NIP-55 fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 16:15:16 +00:00
DorianandClaude Opus 4.6 df70f5f093 fix: move BETA badge after green dot in navbar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 15:36:24 +00:00
DorianandClaude Opus 4.6 226d242552 feat: add BETA badge to header logo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 15:33:44 +00:00
DorianandClaude Opus 4.6 6dc50f5d5d feat: move creator pubkey to env, fix mobile TTS + signer, button loaders
Security:
- Move CREATOR_PUBKEY from hardcoded constant to BOTFIGHTS_CREATOR_PUBKEYS
  env var. Shared isCreatorPubkey() in constants.ts used by auth, admin,
  tournaments. Frontend checks authorization via API, not client-side.

Mobile fixes:
- Nostr signer: poll for window.nostr up to 3s (Amber injects late).
- TTS: auto-unlock AudioContext on first user interaction via
  installAutoUnlock() on fight page mount.

UX:
- Add loading spinners to "I BUILD BOTS" and "I FIGHT MYSELF" buttons.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 15:31:58 +00:00
DorianandClaude Opus 4.6 dd3cbdae7f fix: mobile nostr signer detection, mobile TTS auto-unlock, button loaders
- 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>
2026-03-09 14:44:38 +00:00
DorianandClaude Opus 4.6 a98d94d24c feat: 56k modem SFX for code answers, fix crossed entrance voices
- 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>
2026-03-09 14:21:58 +00:00
DorianandClaude Opus 4.6 3a5f473d25 fix: show full text in battle log and speech bubbles
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>
2026-03-09 14:11:02 +00:00
DorianandClaude Opus 4.6 761c01f92f fix: reduce fighter sprite scale on mobile canvas
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>
2026-03-09 13:56:50 +00:00
DorianandClaude Opus 4.6 a2416bbe19 fix: human fight timing, creative timer, TTS reliability, add sweary/vibe narrations
- 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>
2026-03-09 13:50:24 +00:00
DorianandClaude Opus 4.6 3ba05a66b4 feat: NIP-98 + JWT authentication with signer support
Replace insecure raw-pubkey auth with cryptographic NIP-98 signed
requests and server-issued JWT sessions. Logout now fully clears
all state including nsec. Add yellow "Use Nostr Signer" button
for Amber/NIP-07 remote signers.

- Server: JWT middleware (HMAC-SHA256, 24h expiry), NIP-98 verification
- Server: POST /api/auth/nostr/session endpoint
- Frontend: NIP-98 token builder + authFetch wrapper with JWT Bearer
- Frontend: All authenticated API calls use authFetch
- Security: logout clears JWT, pubkey, bot, nsec, and profile pic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:31:25 +00:00
DorianandClaude Opus 4.6 ad96d1158f feat: practice button on profile, fix rate limiter, fix mobile sprite rendering
- 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>
2026-03-09 12:14:07 +00:00
DorianandClaude Opus 4.6 d0f0a84a57 feat: add first-time warning dialog for Fight For Sats
Shows a one-time warning when users first click "Fight For Sats" letting
them know it's vibe coded and to only use small sats amounts. Acknowledged
state persists in localStorage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 12:05:56 +00:00
DorianandClaude Opus 4.6 e6b5aa4b9b fix: mobile menu overlay, speech bubble timing, TTS static file fallback
- 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>
2026-03-09 11:59:18 +00:00
DorianandClaude Opus 4.6 1a7ad74859 fix: prevent FightViewer random resets from concurrent kaplay init
- Guard initScene() with initializingScene flag to prevent concurrent calls
- Don't auto-reinit scene on WebGL context restore during active replay
- Block initScene() after component is destroyed
- Static audio files now play even before Kokoro worker loads
- kokoroSpeak/kokoroSpeakAsync check cache before requiring worker ready

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:58:13 +00:00
DorianandClaude Opus 4.6 52769ab43a feat: ship pre-generated TTS audio files for instant playback
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>
2026-03-09 10:38:44 +00:00
DorianandClaude Opus 4.6 4c17379ad4 fix: harden TTS with 2s await timeout and 4s worker timeout for reliable fallback
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>
2026-03-09 10:18:03 +00:00
DorianandClaude Opus 4.6 cb8a1d50fe feat: sync TTS voice with chat bubbles and battle log for zero-gap playback
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>
2026-03-09 10:15:54 +00:00
DorianandClaude Opus 4.6 e7d1f9b97b fix: update WTF modal description text and increase title/subtitle margins
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:51:53 +00:00
DorianandClaude Opus 4.6 e31d49898b feat: show rejoin link when bot is already in a fight
- Track active fight IDs per bot in orchestrator (Set → Map)
- Return fightId in "already in fight" error responses (409)
- Frontend shows "REJOIN FIGHT" link instead of generic error

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:27:48 +00:00
DorianandClaude Opus 4.6 98e6baccc1 fix: handle canvas context loss with recovery and fallback overlay
Listen for webglcontextlost/restored events on the fight canvas.
Show "recovering" overlay on context loss, re-init scene on restore.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:18:33 +00:00
DorianandClaude Opus 4.6 d459097a7d feat: add WTF explainer modal on home page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:15:37 +00:00
DorianandClaude Opus 4.6 3c32f01aa7 feat: add Retry-After header and countdown timer for rate limits
- Rate limiter returns retryAfterSec in response body + Retry-After header
- Registration rate limits: 10 per 10min (was 15/hour)
- Frontend surfaces retry timer in error messages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:15:30 +00:00
DorianandClaude Opus 4.6 dcd8570ed8 fix: prevent double-tap race conditions and poll leaks in JoinBoutPage
- Don't reset isJoining flags on successful navigation (component unmounts)
- Add onBeforeRouteLeave guard to clean up polling and rate limit timers
- Use handleError with rate limit countdown for all error paths

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 09:12:51 +00:00
DorianandClaude Opus 4.6 b00f52c1e6 fix: add back-button guard and tab-switch re-sync to HumanFightPage
- Warn before navigating away from active fight (beforeRouteLeave)
- Re-poll challenge state when tab becomes visible (visibilitychange)
- Prevents silent forfeit on back-button and stale timer after tab switch

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:41:26 +00:00
DorianandClaude Opus 4.6 0f606cc991 fix: close existing SSE before opening new one (BUG-11)
Prevents duplicate SSE connections when connectSSE is called
without prior disconnect.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:39:36 +00:00
DorianandClaude Opus 4.6 d47be39156 fix: pass archetype and customization in sprite fallback (BUG-10)
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>
2026-03-09 08:39:32 +00:00
DorianandClaude Opus 4.6 c7a1f6cb0b fix: resolve 9 MC bugs in HumanFightPage and useHumanChallenge
- BUG-1: Prevent double-tap by locking phase before async submit
- BUG-2: Submit timeout notification to server when timer expires
- BUG-3: Distinct "TIME'S UP!" visual vs "ANSWER SUBMITTED"
- BUG-4: Track consecutive poll failures, show connection lost banner
- BUG-5: Add A-D / 1-4 keyboard shortcuts for MC choices
- BUG-6: Use choice text as v-for key instead of array index
- BUG-7: Deadline-based timer (250ms tick) prevents drift
- BUG-8: Validate choice is in current choices before submit
- BUG-9: Submit empty timeout instead of random choice on expiry

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:39:27 +00:00
DorianandClaude Opus 4.6 3c95adb545 feat: convert all human fights to multiple choice, remove text input
Creative challenges (roast_battle, creative_writing, meme_war,
code_golf, wrestling_match) now auto-generate multiple choice options
from per-type response pools: 1 good answer + 3 weaker distractors.
The free text input UI is commented out but preserved for future use.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 08:28:22 +00:00
DorianandClaude Opus 4.6 5ee6b6c88c fix: fight restart bug, mobile TTS, character sizing, bitcoin symbols
- 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>
2026-03-09 08:21:16 +00:00
DorianandClaude Opus 4.6 493983ccc0 fix: prevent fight view scrolling on mobile with tab bar
All pages used h-[calc(100dvh-4rem)] which only subtracted the top
navbar but ignored the mobile tab bar's pb-14 bottom padding, causing
content to overflow and scroll. Changed all pages to h-full so they
fill the flex parent (main element) which already handles both the
navbar and tab bar spacing correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 07:57:37 +00:00
DorianandClaude Opus 4.6 7d9b8b1dbf chore: add ESLint with no-floating-promises and no-console rules
Sets up ESLint 10 flat config with @typescript-eslint/no-floating-promises (error)
and no-console (warn, allow warn/error). Fixes all floating promise errors in
server routes, orchestrator reader cleanup, and frontend composables with void operator.
Game engine files get warning-level for intentional fire-and-forget async.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 07:47:43 +00:00
DorianandClaude Opus 4.6 46d560af24 fix: replace TTS FIFO cache with LRU eviction, add database indexes
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>
2026-03-09 07:38:04 +00:00
DorianandClaude Opus 4.6 7b82803868 fix: allow Google Fonts in CSP so 3D announcement font loads in production
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>
2026-03-09 07:18:57 +00:00
DorianandClaude Opus 4.6 b28d0b220e refactor: extract arena renderer and showboat system from FightScene.ts
- drawArenaDecor (1,234 lines) → fight/arena-renderer.ts
- showboat/taunt system (870 lines) → fight/showboats.ts
- FightScene.ts: 3,468 → 1,266 lines (scene setup + orchestration only)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 06:38:46 +00:00
DorianandClaude Opus 4.6 b6033a90e5 refactor: extract pickChoreography to fight/choreography/picker.ts
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>
2026-03-09 06:31:22 +00:00
DorianandClaude Opus 4.6 38d7236be3 refactor: eliminate more any types in FightScene, FightViewer, FightPage
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>
2026-03-09 06:29:09 +00:00
DorianandClaude Opus 4.6 a86d39b982 refactor: replace 97 any types in fight system with Fighter/GameObj
- 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>
2026-03-09 06:26:33 +00:00
DorianandClaude Opus 4.6 81048ff22f fix: make vhsTracking accept ChoreoContext directly, remove as any cast
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>
2026-03-09 06:21:06 +00:00
DorianandClaude Opus 4.6 86bf534f50 fix: type safeColor return in ChoreoContext using Kaplay Color type
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 06:19:55 +00:00
DorianandClaude Opus 4.6 945a776a5a refactor: extract shared FightData interface to fight/types.ts
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>
2026-03-09 06:19:26 +00:00
DorianandClaude Opus 4.6 6e092ee7be feat: offline resilience and connection status
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 00:27:05 +00:00
DorianandClaude Opus 4.6 aca025a360 feat: mobile UX polish with haptics and reduced motion
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 00:23:39 +00:00
DorianandClaude Opus 4.6 8be71e9929 fix: admin and docs bugs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 00:20:00 +00:00
DorianandClaude Opus 4.6 c654ff9f73 feat: interactive bot developer documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 00:18:06 +00:00
DorianandClaude Opus 4.6 2170e9275c feat: admin dashboard for THE CREATOR
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 00:12:36 +00:00
DorianandClaude Opus 4.6 5af5ee1cba perf: adaptive performance mode for mobile
Auto-detect low-end devices (< 4 cores or touch) and reduce visual
complexity: 60% fewer particles, 6 vs 16 speed lines, 15 vs 40 stars,
halved datacenter buildings/racks, skip LED blinking animations,
fewer GPU graveyard chips, reduced afterimages and exhaust particles.

Toggle in fight viewer (LO/HI button), persisted in localStorage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 00:00:48 +00:00
DorianandClaude Opus 4.6 78f83a7520 perf: fight replay memory leak fixes
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>
2026-03-08 23:55:58 +00:00
DorianandClaude Opus 4.6 57703a28ad refactor: remove dead code
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>
2026-03-08 23:46:30 +00:00