commits
Preview config is branch-specific and should only live in worktrees,
not on master.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Set emoji size to 28px, fine-tune position offset
- Show only most recent emoji per stone, skip reactions without emoji
- Add hover shrink animation (0.3s ease to 80%) for interactivity hint
- Click an emoji to rewind board history to that move
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When "All Reactions" mode is toggled, reaction emojis are overlaid
directly on the stones they reference, making it easy to see which
moves received reactions at a glance.
- Add reactionOverlay prop to Board component
- Compute overlay data mapping move reactions to stone coordinates
- Position emojis with drop shadow for visibility on both stone colors
- Show up to 3 unique emojis per stone, with +N count for more
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add custom DID resolvers for Cloudflare Workers (did:plc and did:web)
- Simplify db.ts to D1-only (removes better-sqlite3 for Workers compatibility)
- Remove dotenv dependency from hooks (not needed in Cloudflare)
- Pass platform context to OAuth endpoints for env var access
- Add deploy script and npm run deploy command
- Add backfill script to sync games from UFOS/Constellation to D1
- Configure D1 database binding in wrangler.toml
- Set PUBLIC_BASE_URL to go.sky.boo
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Auth routes now pass event.platform to getOAuthClient so environment
variables can be read from Cloudflare's platform.env in production.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Document all completed features including reactions
- List testing checklist
- Document known issues and workarounds
- Add next steps for deployment
- Status: Ready for testing
- Document all OAuth API fixes
- Document local development fallbacks
- Document ESM/CommonJS module fixes
- Add development setup instructions
- Update to use generateClientAssertionKey from @atcute/oauth-crypto
- Fix detection of existing keys to ignore commented lines
- Successfully generates EC keys for OAuth
- Add try-catch around database initialization
- Verify Kysely instance has selectFrom method before returning
- Add detailed error logging
- Return cached instance when available
- Use createRequire from module to enable CommonJS require in ESM
- Keep getDb synchronous to avoid breaking all callers
- Fix 'require is not defined' error in local development
- Add dotenv back for local development
- Database falls back to better-sqlite3 when D1 not available
- OAuth falls back to MemoryStore when KV not available
- Create .env file with local development settings
- Support hybrid local/production deployment
- Remove importJwkKey which no longer exists in v1.1.0
- Parse PRIVATE_KEY_JWK directly as JSON and provide as ClientAssertionPrivateJwk array
- Update imports to use ClientAssertionPrivateJwk type
Add no-cache headers to prevent stale data after structure changes.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Server now returns pre-filtered activeGames, waitingGames, completedGames
- Removed double filtering (server filtered, then client re-filtered)
- Client now uses server's pre-filtered arrays directly
- Keeps player_two inference from moves for backward compatibility
This fixes games showing in wrong sections due to filtering mismatch.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
During migration to on-protocol, many active games lack complete
Constellation data and are misclassified as 'waiting'. Using loose
filter (status != completed) until migration is complete.
TODO: Revert to strict filter (status === active) after migration.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changed filter from 'status != completed' to 'status === active'.
This prevents games waiting for players from appearing in Current Games.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Prevent errors when resolving null DIDs to handles.
Returns 'Unknown' for null DIDs instead of crashing.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Check that action_count > 0 before determining if it's user's turn.
This prevents board preview loading issues for games that haven't started.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Replace database status with client-side derived status based on PDS data
- Game page now computes status from moves, resigns, and scores
- Homepage fetches backlinks from Constellation for moves, passes, resigns
- Fix Constellation API response handling (use 'records' not 'backlinks')
- Add resign detection for both boo.sky.go.resign and boo.sky.go.action
- Remove stale game.status field from homepage logic
- Add debug logging for game status computation
- Reduce verbose logging of full Constellation records
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit adds comprehensive support for handicap games and player color
selection when creating games.
Features:
- Players can choose their color (black, white, or random) when creating games
- Handicap option for 13x13 (max 5 stones) and 19x19 (max 9 stones) boards
- Handicap stones are automatically placed at star points in canonical order
- When handicap is selected, creator is forced to play as white
- Extra options UI: color and handicap settings hidden behind collapsible toggle
Implementation:
- Updated boo.sky.go.game lexicon to include handicap and handicapStones fields
- Added handicap column to games database table with migration
- Added creator_did column to track who owns the game record in ATProto
- Turn order reversed for handicap games (white plays first after handicap stones)
- Fixed game record fetching to use actual creator DID from AT URI
- Fixed move/pass validation to account for handicap turn order
- Fixed score submission to update correct repo (creator's, not always player_one)
- Handicap stones displayed in move history with H1, H2, etc. labels
- Updated join logic to handle games where player_one might be empty
- Fixed player resolution to use game record's actual playerOne/playerTwo values
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Winner Display:
- Add winner field to database schema
- Display winner's avatar in archive cards instead of "completed" badge
- Emphasize winner's name in player list with bold styling
- Fetch user profiles for avatars
- Show trophy emoji placeholder if no avatar available
Opponent Invite:
- Add opponent handle input field to create game form
- Resolve Bluesky handle to DID on server-side
- Create game directly with opponent (status=active) instead of waiting room
- Add validation (handle not found, can't play self)
- Update button text based on whether opponent is specified
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Keep database as index for homepage game discovery
- Keep database for game page lookups (rkey -> full game data)
- Database remains necessary for efficient discovery of games user is not involved in
- ATProtocol remains source of truth, database is kept in sync
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add findGameByRkey() to search for game by rkey
- Remove database dependency from game page
- Fetch game metadata directly from Constellation
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add fetchAllGamesFromConstellation() to query all game records
- Remove database dependency from homepage
- Filter games by time windows after fetching from Constellation
- Maintain same filtering logic (12h for active, 7d for completed)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add fetchGameResigns() to get resign records from Constellation
- Add calculateGameMetadata() to compute action counts and last action
- Add listPlayerGames() to fetch all games from a player's PDS
- Add fetchAllGames() to aggregate games from multiple players
- Add GameWithMetadata interface with computed fields
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Added beginner mode toggle to game page with Go stone checkbox style
- Integrated tenuki library for liberty calculation
- Display liberty counts on stones with dynamic sizing and coloring:
- 1 liberty: Red with "1!" and pulsing animation (atari warning)
- 2-3 liberties: Progressive orange/yellow scaling
- 4+ liberties: Normal size with appropriate contrast
- Added wins/losses stats to profile page
- Created visual game history with opponent avatars
- Implemented segmented arc borders showing W/L/A record per opponent
- Sort opponents by most games, limit to 30 for performance
- Fixed profile page to reload data when navigating between profiles
- Handle resigned games as wins/losses in stats
- Treat completed games without scores as pending (yellow)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add rotation effect to archive cards and waiting game items
- Fix inconsistent spacing in waiting-games section
- Update game-item-compact padding/gap to match game-item (1rem/1.25rem)
- All game lists now have consistent floating cloud rotation effect
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Replace translateX with rotate for off-kilter effect
- Apply small rotations (0.25deg to 1deg) to game list items
- Alternating left/right rotation creates natural cloud-like float
- 5 rotation variations for organic, non-repetitive pattern
- Makes game cards feel like they're drifting at different angles
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Remove global card drifting that affected all cards
- Apply subtle left/right shifts only to game-item elements
- Create staggered tiling effect in games lists
- Alternating pattern with 4 variations for visual variety
- Keeps main cards (header, login, etc) centered and stable
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Use Nunito for headers: friendly rounded sans-serif
- Keep Inter for body: clean, readable sans-serif
- Add drifting effect with alternating translateX on cards
- Cards shift left/right to create floating cloud aesthetic
- Buttons use rounded heading font for consistency
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This reverts commit 6c6dc24fada6efe9b241028428a2f6da524a5303.
- Use Crimson Text for body: elegant, readable serif without flourish
- Use Libre Baskerville for headings: strong traditional typography
- Add .sharp-card variant with angular corners for design contrast
- Update button styling with sharper corners and better typography
- Increase base font size to 18px for better readability
- Mix rounded cloud cards with angular elements for visual interest
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This reverts commit f31851ccdb6b58e918716c4abfda1bebc93c554a.
- Body text: Iowan Old Style (warm, readable serif)
- Headings: Hoefler Text (elegant traditional serif)
- Site title: Zapfino (calligraphic accent font)
- Add font CSS variables for consistent typography
- Update main h1 to use accent font with larger size
- Fallback to similar system fonts for compatibility
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add TutorialPopup component with multi-step wizard and SGF-based diagrams
- Add Footer with Claude logo and AI transparency modal
- Create Rules page with interactive move navigation
- Add SGF parser utility for loading game diagrams
- Make Board component reactive to gameState changes
- Add modal/footer CSS styling
- Include SGF files for tutorial examples (single capture, group capture, scoring)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1. Game list spacing: Fixed inconsistent game item heights by using
flexbox gap and making game-info flex: 1
2. Board hover: The interactive check was already correct - verified
hover only shows when it's your turn
3. Move submission: Removed page reload after moves/passes - now
updates local state directly. Only reloads if game ends (double-pass)
4. Stone-style checkboxes: Styled "My games" and "Your turn" checkboxes
to look like Go stones (white unchecked, black checked)
5. Share button: Made lighter/subtler with cloud background and border,
replaced butterfly emoji with Bluesky SVG logo, shortened to "Share"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Created shared board-svg.ts utility for generating board SVGs
- Added /api/games/[id]/board endpoint that returns SVG images
- Mini boards now use simple <img> tags pointing to the SVG endpoint
- SVGs are cached (30s for active games, 1hr for completed)
- Removed client-side MiniBoard.svelte component
- Refactored og-image to use shared buildBoardStateFromMoves
This approach is:
- Simpler (just img tags)
- More performant (server-side rendering, caching)
- Scalable (SVG format)
- Consistent with OG image styling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Created MiniBoard.svelte component using tenuki for small board previews
- Added tenuki TypeScript declarations (tenuki.d.ts)
- Integrated mini boards into current games list (both logged-in and spectating views)
- Fetches moves for active games and displays current board state
- Fixed og-image to use correct tenuki API (intersectionAt instead of intersections)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
After evaluating both libraries, decided to keep jgoboard for visual
rendering due to its superior textured stone and board aesthetics.
Tenuki is now integrated for scoring calculations, which was the
main concrete benefit mentioned in the TODO.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Created scoring utility that uses tenuki to calculate territory scores
- Added GET endpoint to /api/games/[id]/score for fetching suggested scores
- UI now shows "Calculate & Enter Scores" button that fetches auto-calculated scores
- Scores are pre-populated in the form with auto-calculated values
- Shows "Auto-calculated" badge and winner/margin info
- Users can still adjust scores before submitting (for dead stones, etc.)
- Default komi of 6.5 points for white
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- URL now updates with ?move=N when navigating to a specific move
- Visiting a game URL with ?move=N navigates directly to that move
- Move number is 1-indexed in URL for user-friendliness
- Supports sharing links to specific game positions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added "All Reactions" toggle button in reactions panel
- Shows all reactions across all moves when enabled, sorted by date
- Displays move number badge on each reaction in "all" view
- Hides the "Add Reaction" button in "all" view since it needs a selected move
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The reaction system correctly uses move AT URIs for both storing
and loading reactions - verified the implementation is working.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Always show page structure (info cards, board, etc.)
- Show skeleton placeholder for move count while loading
- Board renders immediately and fills with stones as data arrives
- Reactions panel shows loading state separately
- Add shimmer animation for skeleton text
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Loading should be true while either game OR moves are still loading,
not only when both are loading simultaneously.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Constellation backlinks only return references (did, collection, rkey),
not actual record values. Now we:
1. Get backlink refs from Constellation
2. Fetch actual records from each author's PDS
3. Group reactions by move URI
Also:
- Add uri field to MoveRecord type for proper reaction matching
- Include move URIs when fetching from PDS
- Add granular loading states (game, moves, reactions)
- Show "Loading reactions..." with pulse animation
- Load reactions async to not block page render
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add required "game" field to reaction lexicon
- Update ReactionRecord type with game field
- Refactor fetchGameReactions to query by game URI instead of
individual move URIs (single Constellation query vs N queries)
- Group reactions by move URI client-side
- Update reaction API endpoint to include game field
- Update game page to use new reaction fetching approach
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Show "Your turn" / "Waiting" badges on current games
- Add "Your turn" filter checkbox next to "My games"
- Highlight games where it's your turn with accent border
- Show which player's turn it is (black/white indicator)
- Bold the current player's name in game list
- Include action_count in game data for turn calculation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tenuki returns intersections as a flat array with {x, y, value}
properties, not a 2D array. Convert to 2D board state correctly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Social platforms don't support SVG for og:image tags.
Use @resvg/resvg-js to render SVG to PNG on the server.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Preview config is branch-specific and should only live in worktrees,
not on master.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When "All Reactions" mode is toggled, reaction emojis are overlaid
directly on the stones they reference, making it easy to see which
moves received reactions at a glance.
- Add reactionOverlay prop to Board component
- Compute overlay data mapping move reactions to stone coordinates
- Position emojis with drop shadow for visibility on both stone colors
- Show up to 3 unique emojis per stone, with +N count for more
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add custom DID resolvers for Cloudflare Workers (did:plc and did:web)
- Simplify db.ts to D1-only (removes better-sqlite3 for Workers compatibility)
- Remove dotenv dependency from hooks (not needed in Cloudflare)
- Pass platform context to OAuth endpoints for env var access
- Add deploy script and npm run deploy command
- Add backfill script to sync games from UFOS/Constellation to D1
- Configure D1 database binding in wrangler.toml
- Set PUBLIC_BASE_URL to go.sky.boo
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Server now returns pre-filtered activeGames, waitingGames, completedGames
- Removed double filtering (server filtered, then client re-filtered)
- Client now uses server's pre-filtered arrays directly
- Keeps player_two inference from moves for backward compatibility
This fixes games showing in wrong sections due to filtering mismatch.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
During migration to on-protocol, many active games lack complete
Constellation data and are misclassified as 'waiting'. Using loose
filter (status != completed) until migration is complete.
TODO: Revert to strict filter (status === active) after migration.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Replace database status with client-side derived status based on PDS data
- Game page now computes status from moves, resigns, and scores
- Homepage fetches backlinks from Constellation for moves, passes, resigns
- Fix Constellation API response handling (use 'records' not 'backlinks')
- Add resign detection for both boo.sky.go.resign and boo.sky.go.action
- Remove stale game.status field from homepage logic
- Add debug logging for game status computation
- Reduce verbose logging of full Constellation records
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit adds comprehensive support for handicap games and player color
selection when creating games.
Features:
- Players can choose their color (black, white, or random) when creating games
- Handicap option for 13x13 (max 5 stones) and 19x19 (max 9 stones) boards
- Handicap stones are automatically placed at star points in canonical order
- When handicap is selected, creator is forced to play as white
- Extra options UI: color and handicap settings hidden behind collapsible toggle
Implementation:
- Updated boo.sky.go.game lexicon to include handicap and handicapStones fields
- Added handicap column to games database table with migration
- Added creator_did column to track who owns the game record in ATProto
- Turn order reversed for handicap games (white plays first after handicap stones)
- Fixed game record fetching to use actual creator DID from AT URI
- Fixed move/pass validation to account for handicap turn order
- Fixed score submission to update correct repo (creator's, not always player_one)
- Handicap stones displayed in move history with H1, H2, etc. labels
- Updated join logic to handle games where player_one might be empty
- Fixed player resolution to use game record's actual playerOne/playerTwo values
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Winner Display:
- Add winner field to database schema
- Display winner's avatar in archive cards instead of "completed" badge
- Emphasize winner's name in player list with bold styling
- Fetch user profiles for avatars
- Show trophy emoji placeholder if no avatar available
Opponent Invite:
- Add opponent handle input field to create game form
- Resolve Bluesky handle to DID on server-side
- Create game directly with opponent (status=active) instead of waiting room
- Add validation (handle not found, can't play self)
- Update button text based on whether opponent is specified
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Keep database as index for homepage game discovery
- Keep database for game page lookups (rkey -> full game data)
- Database remains necessary for efficient discovery of games user is not involved in
- ATProtocol remains source of truth, database is kept in sync
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add fetchGameResigns() to get resign records from Constellation
- Add calculateGameMetadata() to compute action counts and last action
- Add listPlayerGames() to fetch all games from a player's PDS
- Add fetchAllGames() to aggregate games from multiple players
- Add GameWithMetadata interface with computed fields
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Added beginner mode toggle to game page with Go stone checkbox style
- Integrated tenuki library for liberty calculation
- Display liberty counts on stones with dynamic sizing and coloring:
- 1 liberty: Red with "1!" and pulsing animation (atari warning)
- 2-3 liberties: Progressive orange/yellow scaling
- 4+ liberties: Normal size with appropriate contrast
- Added wins/losses stats to profile page
- Created visual game history with opponent avatars
- Implemented segmented arc borders showing W/L/A record per opponent
- Sort opponents by most games, limit to 30 for performance
- Fixed profile page to reload data when navigating between profiles
- Handle resigned games as wins/losses in stats
- Treat completed games without scores as pending (yellow)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add rotation effect to archive cards and waiting game items
- Fix inconsistent spacing in waiting-games section
- Update game-item-compact padding/gap to match game-item (1rem/1.25rem)
- All game lists now have consistent floating cloud rotation effect
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Replace translateX with rotate for off-kilter effect
- Apply small rotations (0.25deg to 1deg) to game list items
- Alternating left/right rotation creates natural cloud-like float
- 5 rotation variations for organic, non-repetitive pattern
- Makes game cards feel like they're drifting at different angles
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Remove global card drifting that affected all cards
- Apply subtle left/right shifts only to game-item elements
- Create staggered tiling effect in games lists
- Alternating pattern with 4 variations for visual variety
- Keeps main cards (header, login, etc) centered and stable
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Use Nunito for headers: friendly rounded sans-serif
- Keep Inter for body: clean, readable sans-serif
- Add drifting effect with alternating translateX on cards
- Cards shift left/right to create floating cloud aesthetic
- Buttons use rounded heading font for consistency
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Use Crimson Text for body: elegant, readable serif without flourish
- Use Libre Baskerville for headings: strong traditional typography
- Add .sharp-card variant with angular corners for design contrast
- Update button styling with sharper corners and better typography
- Increase base font size to 18px for better readability
- Mix rounded cloud cards with angular elements for visual interest
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Body text: Iowan Old Style (warm, readable serif)
- Headings: Hoefler Text (elegant traditional serif)
- Site title: Zapfino (calligraphic accent font)
- Add font CSS variables for consistent typography
- Update main h1 to use accent font with larger size
- Fallback to similar system fonts for compatibility
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add TutorialPopup component with multi-step wizard and SGF-based diagrams
- Add Footer with Claude logo and AI transparency modal
- Create Rules page with interactive move navigation
- Add SGF parser utility for loading game diagrams
- Make Board component reactive to gameState changes
- Add modal/footer CSS styling
- Include SGF files for tutorial examples (single capture, group capture, scoring)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1. Game list spacing: Fixed inconsistent game item heights by using
flexbox gap and making game-info flex: 1
2. Board hover: The interactive check was already correct - verified
hover only shows when it's your turn
3. Move submission: Removed page reload after moves/passes - now
updates local state directly. Only reloads if game ends (double-pass)
4. Stone-style checkboxes: Styled "My games" and "Your turn" checkboxes
to look like Go stones (white unchecked, black checked)
5. Share button: Made lighter/subtler with cloud background and border,
replaced butterfly emoji with Bluesky SVG logo, shortened to "Share"
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Created shared board-svg.ts utility for generating board SVGs
- Added /api/games/[id]/board endpoint that returns SVG images
- Mini boards now use simple <img> tags pointing to the SVG endpoint
- SVGs are cached (30s for active games, 1hr for completed)
- Removed client-side MiniBoard.svelte component
- Refactored og-image to use shared buildBoardStateFromMoves
This approach is:
- Simpler (just img tags)
- More performant (server-side rendering, caching)
- Scalable (SVG format)
- Consistent with OG image styling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Created MiniBoard.svelte component using tenuki for small board previews
- Added tenuki TypeScript declarations (tenuki.d.ts)
- Integrated mini boards into current games list (both logged-in and spectating views)
- Fetches moves for active games and displays current board state
- Fixed og-image to use correct tenuki API (intersectionAt instead of intersections)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Created scoring utility that uses tenuki to calculate territory scores
- Added GET endpoint to /api/games/[id]/score for fetching suggested scores
- UI now shows "Calculate & Enter Scores" button that fetches auto-calculated scores
- Scores are pre-populated in the form with auto-calculated values
- Shows "Auto-calculated" badge and winner/margin info
- Users can still adjust scores before submitting (for dead stones, etc.)
- Default komi of 6.5 points for white
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Added "All Reactions" toggle button in reactions panel
- Shows all reactions across all moves when enabled, sorted by date
- Displays move number badge on each reaction in "all" view
- Hides the "Add Reaction" button in "all" view since it needs a selected move
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Always show page structure (info cards, board, etc.)
- Show skeleton placeholder for move count while loading
- Board renders immediately and fills with stones as data arrives
- Reactions panel shows loading state separately
- Add shimmer animation for skeleton text
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Constellation backlinks only return references (did, collection, rkey),
not actual record values. Now we:
1. Get backlink refs from Constellation
2. Fetch actual records from each author's PDS
3. Group reactions by move URI
Also:
- Add uri field to MoveRecord type for proper reaction matching
- Include move URIs when fetching from PDS
- Add granular loading states (game, moves, reactions)
- Show "Loading reactions..." with pulse animation
- Load reactions async to not block page render
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add required "game" field to reaction lexicon
- Update ReactionRecord type with game field
- Refactor fetchGameReactions to query by game URI instead of
individual move URIs (single Constellation query vs N queries)
- Group reactions by move URI client-side
- Update reaction API endpoint to include game field
- Update game page to use new reaction fetching approach
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Show "Your turn" / "Waiting" badges on current games
- Add "Your turn" filter checkbox next to "My games"
- Highlight games where it's your turn with accent border
- Show which player's turn it is (black/white indicator)
- Bold the current player's name in game list
- Include action_count in game data for turn calculation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>