§13.3: Display "Narrated" badge on enriched matches in bot profile
recent matches section, matching the match list page behavior.
- Add enriched badge rendering to renderMatchItem() in bot-profile.ts
- Add .enriched-badge CSS style (pink/magenta color to match
playlist category styling)
The index builder already sets the Enriched flag via isMatchEnriched()
which checks R2 for commentary file existence. The match list page
(matches.ts) already displays this badge.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Virtual list tracks expanded row heights for correct spacer calculations.
Leaderboard mobile cards use event delegation so toggles work inside lazy
sections. Mobile card details animate with max-height instead of display
toggle. Reduced-motion rules cover all expand/collapse patterns.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Implement double-buffered canvas cross-fade when switching between
dots, Voronoi territory, and influence gradient views. Old layer fades
out while new layer fades in with ease-in-out cubic easing over 400ms.
Respects prefers-reduced-motion by snapping instantly when set.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three perceived-performance features:
- Preload on hover: internal links prefetch target JSON data after 150ms
hover debounce using <link rel=prefetch>. Touch events prefetch
immediately.
- Skeleton screens: every async page shows a shimmer-animated placeholder
matching the final content layout (leaderboard rows, bot profile card,
replay canvas, playlist grid, etc.) instead of generic "Loading..." text.
- Instant back-cache: back/forward navigation restores scroll position and
cached HTML from an in-memory LRU cache (8 pages), making back navigation
0ms.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- POST /api/register: bot registration with URL + shared secret validation
- GET /api/job: worker polls for next pending match job (authenticated)
- POST /api/job/:id/result: worker submits match result (winner, replay JSON)
- GET /api/replay/🆔 serve replay JSON from R2 warm cache (falls back to B2)
- GET /api/bot/🆔 bot profile JSON (rating, elo, record, metadata)
- GET /api/bots: leaderboard snapshot with pagination
- POST /api/ui-feedback: accept Agentation UI feedback
Authentication via Bearer token (worker API key). Shared secrets encrypted
with AES-256-GCM using ACB_ENCRYPTION_KEY.