commits
The tutorial popup was auto-opening on first visit and causing
issues on mobile that blocked all tap events, making the site
unusable. Temporarily disabled auto-open behavior.
- Tutorial still accessible via Footer "Tutorial" link
- Added better error handling for localStorage access
- Added error handling for SGF loading failures
- TODO: Re-enable auto-open with proper mobile testing
Fixes mobile usability issue.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Create spectating store for cross-component state sharing
- Show header login button when spectating on homepage
- Remove "Want to play?" banner (replaced by header login button)
- Add explicit Enter key handler to main login form input
Fixes:
- Login button now shows when spectating (games view)
- No login button on home login screen (avoids duplicate UI)
- Enter key explicitly triggers login on main form
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Hide login button on homepage (avoid duplicate login UI)
- Add actor-typeahead to login modal for handle autocompletion
- Add z-index: 1000 to actor-typeahead for proper layering
- Add onchange handler to modal input for typeahead sync
Fixes:
- No more confusing dual login UI on homepage
- Modal now has same typeahead functionality as main form
- Typeahead dropdown renders above all page content
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Move z-index from .header to .header-wrapper to avoid creating
stacking context that traps ProfileDropdown
- Add z-index: 50 to ProverbBanner to ensure it stays below header
- Header wrapper now at z-index: 100, higher than page content
This fixes:
- ProfileDropdown now renders above ProverbBanner
- ProfileDropdown renders above login form separator line
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Changed from bind:value to oninput handler to properly support
form submission. The Input component doesn't support two-way
binding, so we need to use the oninput callback pattern.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add keyboard handler to close modals with ESC key
- Add close button (X) in top-right corner of modals
- Style close button with hover rotation effect
- Both login forms already support Enter key submission
Improves UX by preventing users from getting stuck in modals.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add login modal to Header with handle input
- Replace non-functional login link with modal trigger button
- Configure preview environment with correct PUBLIC_BASE_URL
- Fix OAuth redirects to use preview URLs instead of production
This allows users to log in from any page without navigation,
and enables testing OAuth on feature branches.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Issues fixed:
- Section header elements were cramped on one line
- Game count and filter toggles were breaking awkwardly
- Text was getting truncated
Changes:
- Add flex-wrap to .section-header to allow wrapping
- Add flex-wrap to .section-title-row for responsive layout
- Add flex-wrap to .filter-toggles for better mobile support
- Add white-space: nowrap to .game-count to prevent mid-text breaks
- Add gap spacing to section-header for consistent spacing
Now the layout gracefully wraps when space is limited, preventing
awkward text breaking and maintaining readability.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Header:
- Replace custom cloud card styling with Card component (variant="large")
- Remove duplicate CSS for cloud effects
- Keep only header-specific positioning and layout styles
Footer:
- Replace custom buttons with Button components (secondary, primary)
- Replace custom modal with Modal component
- Remove duplicate button and modal CSS
This reduces code duplication and ensures consistent styling across
the application using the unified component library.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Create reusable cloud-themed components:
- Card: cloud-styled containers with variants (default, large, compact)
- Button: primary, secondary, ghost variants with hover effects
- Input: form inputs with focus states
- Badge: status badges (success, warning, danger, info)
- StatusGlow: glowing status indicators for player states
- Modal: cloud-styled modal overlays
All components follow the 0.6s ease transition pattern and integrate
with existing design tokens for consistent cloud aesthetic.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Card.svelte: Unified card with variants (default, large, compact)
- Button.svelte: Unified button with variants (primary, secondary, ghost)
- Input.svelte: Unified input styling
- Badge.svelte: Status badges with color variants
- Modal.svelte: Reusable modal wrapper
Reduces CSS duplication from ~1,480 lines to ~460 lines (69% reduction)
Co-Authored-By: Claude Sonnet 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>
- 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>
The tutorial popup was auto-opening on first visit and causing
issues on mobile that blocked all tap events, making the site
unusable. Temporarily disabled auto-open behavior.
- Tutorial still accessible via Footer "Tutorial" link
- Added better error handling for localStorage access
- Added error handling for SGF loading failures
- TODO: Re-enable auto-open with proper mobile testing
Fixes mobile usability issue.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Create spectating store for cross-component state sharing
- Show header login button when spectating on homepage
- Remove "Want to play?" banner (replaced by header login button)
- Add explicit Enter key handler to main login form input
Fixes:
- Login button now shows when spectating (games view)
- No login button on home login screen (avoids duplicate UI)
- Enter key explicitly triggers login on main form
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Hide login button on homepage (avoid duplicate login UI)
- Add actor-typeahead to login modal for handle autocompletion
- Add z-index: 1000 to actor-typeahead for proper layering
- Add onchange handler to modal input for typeahead sync
Fixes:
- No more confusing dual login UI on homepage
- Modal now has same typeahead functionality as main form
- Typeahead dropdown renders above all page content
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Move z-index from .header to .header-wrapper to avoid creating
stacking context that traps ProfileDropdown
- Add z-index: 50 to ProverbBanner to ensure it stays below header
- Header wrapper now at z-index: 100, higher than page content
This fixes:
- ProfileDropdown now renders above ProverbBanner
- ProfileDropdown renders above login form separator line
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add keyboard handler to close modals with ESC key
- Add close button (X) in top-right corner of modals
- Style close button with hover rotation effect
- Both login forms already support Enter key submission
Improves UX by preventing users from getting stuck in modals.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add login modal to Header with handle input
- Replace non-functional login link with modal trigger button
- Configure preview environment with correct PUBLIC_BASE_URL
- Fix OAuth redirects to use preview URLs instead of production
This allows users to log in from any page without navigation,
and enables testing OAuth on feature branches.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Issues fixed:
- Section header elements were cramped on one line
- Game count and filter toggles were breaking awkwardly
- Text was getting truncated
Changes:
- Add flex-wrap to .section-header to allow wrapping
- Add flex-wrap to .section-title-row for responsive layout
- Add flex-wrap to .filter-toggles for better mobile support
- Add white-space: nowrap to .game-count to prevent mid-text breaks
- Add gap spacing to section-header for consistent spacing
Now the layout gracefully wraps when space is limited, preventing
awkward text breaking and maintaining readability.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Header:
- Replace custom cloud card styling with Card component (variant="large")
- Remove duplicate CSS for cloud effects
- Keep only header-specific positioning and layout styles
Footer:
- Replace custom buttons with Button components (secondary, primary)
- Replace custom modal with Modal component
- Remove duplicate button and modal CSS
This reduces code duplication and ensures consistent styling across
the application using the unified component library.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Create reusable cloud-themed components:
- Card: cloud-styled containers with variants (default, large, compact)
- Button: primary, secondary, ghost variants with hover effects
- Input: form inputs with focus states
- Badge: status badges (success, warning, danger, info)
- StatusGlow: glowing status indicators for player states
- Modal: cloud-styled modal overlays
All components follow the 0.6s ease transition pattern and integrate
with existing design tokens for consistent cloud aesthetic.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Card.svelte: Unified card with variants (default, large, compact)
- Button.svelte: Unified button with variants (primary, secondary, ghost)
- Input.svelte: Unified input styling
- Badge.svelte: Status badges with color variants
- Modal.svelte: Reusable modal wrapper
Reduces CSS duplication from ~1,480 lines to ~460 lines (69% reduction)
Co-Authored-By: Claude Sonnet 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>