extremely claude-assisted go game based on atproto! working on cleaning up and giving a more unique design, still has a bit of a slop vibe to it.

Project Summary - Go Game with AT Protocol#

Overview#

This project implements a web-based Go game application using SvelteKit, integrated with AT Protocol for decentralized game state storage. The application demonstrates how to use custom AT Protocol lexicons to store game data on the decentralized social network.

Complete File Structure#

atprotogo/
├── src/
│   ├── app.css                           # Global styles
│   ├── app.html                          # HTML template
│   ├── hooks.server.ts                   # Server hooks (firehose init)
│   │
│   ├── lib/
│   │   ├── env.ts                        # Environment configuration
│   │   ├── components/
│   │   │   └── Board.svelte              # Wgo.js board component
│   │   └── server/
│   │       ├── auth.ts                   # OAuth client & session management
│   │       ├── db.ts                     # Kysely database setup
│   │       └── firehose.ts               # AT Protocol firehose subscription
│   │
│   └── routes/
│       ├── +layout.svelte                # App layout wrapper
│       ├── +page.svelte                  # Home page (game list)
│       ├── +page.server.ts               # Home page data loading
│       │
│       ├── auth/
│       │   ├── callback/+server.ts       # OAuth callback handler
│       │   ├── login/+server.ts          # OAuth login initiation
│       │   └── logout/+server.ts         # Logout handler
│       │
│       ├── game/[id]/
│       │   ├── +page.svelte              # Game board UI
│       │   └── +page.server.ts           # Game data loading
│       │
│       └── api/
│           └── games/
│               ├── +server.ts            # Create game API
│               └── [id]/
│                   ├── join/+server.ts   # Join game API
│                   ├── move/+server.ts   # Record move API
│                   └── pass/+server.ts   # Record pass API
│
├── lexicons/
│   ├── boo.sky.go.game.json             # Game record lexicon
│   ├── boo.sky.go.move.json             # Move record lexicon
│   └── boo.sky.go.pass.json             # Pass record lexicon
│
├── static/
│   └── oauth-client-metadata.json       # OAuth client metadata
│
├── data/                                 # SQLite database directory
│   └── app.db                           # (created at runtime)
│
├── .env                                  # Environment variables
├── .env.example                          # Environment template
├── .gitignore                           # Git ignore rules
├── package.json                         # NPM dependencies
├── svelte.config.js                     # SvelteKit configuration
├── tsconfig.json                        # TypeScript configuration
├── vite.config.ts                       # Vite configuration
├── README.md                            # Project documentation
├── IMPLEMENTATION_NOTES.md              # Technical implementation guide
└── PROJECT_SUMMARY.md                   # This file

Key Components#

1. Custom AT Protocol Lexicons#

Three lexicon definitions specify the data structure for Go games:

boo.sky.go.game

  • playerOne (DID)
  • playerTwo (DID, optional)
  • boardSize (9, 13, or 19)
  • status (waiting, active, completed)
  • winner (DID, optional)
  • createdAt (datetime)

boo.sky.go.move

  • game (AT URI reference)
  • player (DID)
  • moveNumber (integer)
  • x, y (coordinates)
  • color (black or white)
  • captureCount (integer)
  • createdAt (datetime)

boo.sky.go.pass

  • game (AT URI reference)
  • player (DID)
  • moveNumber (integer)
  • color (black or white)
  • createdAt (datetime)

2. Database Schema#

SQLite tables mirror the lexicon structure:

games

  • id (AT URI, primary key)
  • rkey (TID)
  • player_one, player_two
  • board_size
  • status
  • winner
  • created_at, updated_at

moves

  • id (AT URI, primary key)
  • rkey (TID)
  • game_id (foreign key)
  • player, move_number
  • x, y, color
  • capture_count
  • created_at

passes

  • id (AT URI, primary key)
  • rkey (TID)
  • game_id (foreign key)
  • player, move_number
  • color
  • created_at

3. Game Flow#

  1. User Authentication (placeholder)

    • User enters Bluesky handle
    • OAuth flow redirects to AT Protocol
    • Session stored with DID
  2. Create Game

    • Select board size (9x9, 13x13, 19x19)
    • Generate TID for game record
    • Create game record (local DB only in current implementation)
    • Status: "waiting"
  3. Join Game

    • Browse available games
    • Click "Join" on waiting game
    • Update game record with playerTwo
    • Status: "active"
  4. Play Game

    • Players alternate placing stones
    • Wgo.js validates moves
    • Calculate captures
    • Create move records
    • Update UI in real-time
  5. Pass

    • Player clicks Pass button
    • Create pass record
    • Check for two consecutive passes
    • If yes: game status → "completed"
  6. Game End

    • Two consecutive passes
    • Update game status
    • Display winner (manual or calculated)

4. UI Components#

Home Page (src/routes/+page.svelte)

  • Login form (OAuth)
  • Create game section with board size selector
  • List of available games (waiting/active)
  • Join button for waiting games

Game Page (src/routes/game/[id]/+page.svelte)

  • Wgo.js board component
  • Current turn indicator
  • Pass button
  • Game info (players, status, board size)
  • Move history list

Board Component (src/lib/components/Board.svelte)

  • SVGBoard from Wgo.js
  • Click handling for stone placement
  • Move validation with Game class
  • Capture calculation and stone removal
  • Interactive/readonly modes

5. API Endpoints#

POST /auth/login

  • Initiates OAuth flow with handle
  • Returns authorization URL

GET /auth/callback

  • Handles OAuth callback
  • Stores session
  • Redirects to home page

POST /auth/logout

  • Clears session cookie
  • Redirects to home page

POST /api/games

  • Creates new game record
  • Params: boardSize
  • Returns: gameId, uri

POST /api/games/[id]/join

  • Joins waiting game as playerTwo
  • Updates game status to "active"

POST /api/games/[id]/move

  • Records stone placement
  • Params: x, y, captureCount
  • Validates turn order
  • Creates move record

POST /api/games/[id]/pass

  • Records pass action
  • Checks for game end (two consecutive passes)
  • Updates game status if completed

Technical Stack#

Frontend#

  • Framework: SvelteKit 5
  • Language: TypeScript
  • Go Board: Wgo.js 3.0.0-alpha.10
  • Styling: Custom CSS with component styles

Backend#

  • Runtime: Node.js (18+ recommended)
  • Framework: SvelteKit server-side
  • Database: SQLite with better-sqlite3
  • Query Builder: Kysely 0.27.0

AT Protocol#

  • OAuth: @atproto/oauth-client-node 0.1.0
  • API: @atproto/api 0.13.0
  • Lexicon: @atproto/lexicon 0.4.0

Implementation Status#

✅ Fully Implemented#

  • Project structure and configuration
  • Custom lexicon definitions
  • Database schema and migrations
  • Wgo.js board integration
  • Game creation UI and API
  • Game joining UI and API
  • Move recording UI and API
  • Pass functionality
  • Move history display
  • Game state management
  • TID generation for records
  • AT URI structure

⚠️ Partially Implemented#

  • OAuth authentication (structure exists, needs full setup)
  • AT Protocol record creation (URIs generated, not written to network)
  • Session management (simple encoding, needs encryption)

📋 Placeholder/TODO#

  • Firehose subscription (structure exists, needs WebSocket implementation)
  • Real-time updates (page refresh currently used)
  • Automatic scoring (game ends on double pass, no winner calculation)

How to Complete the Implementation#

Step 1: OAuth Setup#

  1. Properly configure NodeOAuthClient:
const client = await NodeOAuthClient.fromClientId({
  clientId: `${PUBLIC_BASE_URL}/oauth-client-metadata.json`,
  stateStore: new StateStore(),
  sessionStore: new SessionStore(),
});
  1. Update OAuth routes to use the client
  2. Test OAuth flow with real Bluesky accounts

Step 2: AT Protocol Records#

  1. Create authenticated agents:
const oauthSession = await client.restore(session.did);
const agent = oauthSession.agent;
  1. Create records on the network:
await agent.com.atproto.repo.createRecord({
  repo: session.did,
  collection: 'boo.sky.go.game',
  rkey: tid,
  record: gameData,
});
  1. Test record creation and retrieval

Step 3: Firehose Integration#

  1. Set up WebSocket connection to AT Protocol relay
  2. Subscribe to custom lexicon collections
  3. Parse commit events and update database
  4. Emit real-time updates to connected clients

Step 4: Real-time Updates#

  1. Implement Server-Sent Events or WebSockets
  2. Subscribe clients to game updates
  3. Push moves from firehose to clients
  4. Update board without page refresh

Running the Project#

Development#

# Install dependencies
npm install

# Set up environment
cp .env.example .env
# Edit .env with your configuration

# Start development server
npm run dev

Access at http://localhost:5173

Type Checking#

npm run check

Note: Some warnings about Node version may appear (need 18+)

Building for Production#

npm run build
npm run preview

Environment Variables#

DATABASE_PATH=./data/app.db
SESSION_SECRET=your-random-secret-here

Dependencies#

Production#

  • @atproto/api: ^0.13.0
  • @atproto/oauth-client-node: ^0.1.0
  • @atproto/lexicon: ^0.4.0
  • @atproto/xrpc-server: ^0.6.0
  • kysely: ^0.27.0
  • better-sqlite3: ^11.0.0
  • wgo: ^3.0.0-alpha.10

Development#

  • @sveltejs/kit: ^2.0.0
  • @sveltejs/vite-plugin-svelte: ^4.0.0
  • svelte: ^5.0.0
  • typescript: ^5.0.0
  • vite: ^5.0.0

License#

MIT

Resources#