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.
Svelte 52%
TypeScript 42%
3%
CSS 2%
JavaScript <1%
HTML <1%
Astro <1%
Shell <1%

README.md

Go Game with AT Protocol Integration #

A SvelteKit application that implements the game of Go using jgoboard for board rendering and tenuki for scoring, with AT Protocol OAuth authentication and custom lexicons to record game state and moves on the decentralized network.

🚀 Now deployed on Cloudflare Pages! This application runs on Cloudflare's global edge network with a D1 database, and uses Cloudflare KV for sessions and OAuth state when those bindings are configured.

Features #

  • AT Protocol OAuth: Login with your Bluesky account
  • Custom Lexicons: Game state stored as AT Protocol records
    • boo.sky.go.game - Game records
    • boo.sky.go.move - Move records
    • boo.sky.go.pass - Pass records
    • boo.sky.go.resign / boo.sky.go.action - Resignation and join/action records
    • boo.sky.go.reaction / boo.sky.go.profile - Move reactions and player profiles
  • jgoboard Rendering: Canvas Go board with capture/ko handling, plus tenuki-backed scoring
  • Real-time Updates: Client-side Jetstream subscription streams new moves, passes and resignations into the game page
  • Multiple Board Sizes: Support for 5x5, 7x7, 9x9, 13x13 and 19x19 boards
  • Edge Deployment: Runs on Cloudflare's global edge network
  • D1 Database: Cloudflare's serverless SQL database for game storage
  • KV Storage: Session and state management via Cloudflare KV when the KV bindings are configured

Implementation Status #

This is a working demonstration project showing a functional Go game built on AT Protocol. The core implementation includes:

✅ Implemented:

  • SvelteKit application structure
  • AT Protocol OAuth login with Bluesky (@atcute/oauth-node-client), storing sessions in Cloudflare KV when the KV bindings are configured and in memory otherwise
  • Custom AT Protocol lexicon definitions for games, moves, passes, resignations, actions, reactions and profiles
  • Records really written to the network with com.atproto.repo.createRecord / putRecord, and read back from the player's PDS
  • jgoboard board rendering with move, pass, resign and capture handling
  • Territory scoring with tenuki, including dead-stone marking
  • Game creation and joining UI, reactions on individual moves, profiles with ELO ratings, and image generation (board, OG, reaction, nudge)
  • Client-side Jetstream subscription delivering live moves, passes and resignations to the game page
  • D1 game discovery index maintained in the background by a Durable Object Jetstream consumer (a separate Worker)

📝 Notes:

  • The boo.sky.go.* lexicons are specific to this demo rather than part of the official AT Protocol lexicon set
  • Route handlers read the D1 index first; games absent from it are looked up through the public ATProto indexes (UFOs + Constellation) before falling back to a 404

Deployment #

This application is optimized for deployment on Cloudflare Pages. See CLOUDFLARE_DEPLOYMENT.md for complete deployment instructions.

Quick steps:

  1. Create a D1 database (and optionally KV namespaces for sessions)
  2. Set environment secrets
  3. Deploy via GitHub integration or Wrangler CLI
  4. Deploy the separate firehose-worker/ Worker (npm run deploy:firehose), which keeps the D1 discovery index up to date from the Jetstream firehose

Migration Notes #

This application has been migrated from Node.js to Cloudflare Workers. See MIGRATION_SUMMARY.md for details on the changes made.

Getting Started #

Prerequisites #

  • Node.js 20+ (required for Cloudflare tooling)
  • npm or pnpm
  • Cloudflare account (for deployment)

Installation #

  1. Clone the repository

  2. Install dependencies:

    npm install
    
  3. Copy the environment file:

    cp .env.example .env
    
  4. Edit .env and set a random SESSION_SECRET:

    SESSION_SECRET=your-random-secret-here
    PUBLIC_BASE_URL=http://127.0.0.1:5173
    

    On a loopback origin the app uses the atproto localhost exception, so logging in needs no tunnel and no signing key. Open the app on 127.0.0.1 rather than localhost — the spec only allows 127.0.0.1/[::1] redirect URIs. See LOCAL_DEVELOPMENT.md.

Running the Development Server #

npm run dev

The application will be available at http://127.0.0.1:5173

Building for Production #

npm run build
npm run preview

Note: database-backed routes require a D1 binding. Run the built app under Wrangler for the full stack locally (see CLOUDFLARE_DEPLOYMENT.md):

npm run build && npx wrangler pages dev .svelte-kit/cloudflare --d1=DB

How to Play #

  1. Login: Click login and enter your Bluesky handle (e.g., yourname.bsky.social)
  2. Create Game: Choose a board size and create a new game
  3. Wait or Join: Either wait for another player to join your game, or join an existing waiting game
  4. Play: Take turns placing stones on the board
  5. Pass: Click the Pass button if you want to pass your turn
  6. Game End: The game ends when both players pass consecutively

Project Structure #

/src
  /routes
    +page.svelte              # Home: game list, create/join
    /auth                     # OAuth login, callback, logout
    /game/[id]                # Game board (jgoboard) with live Jetstream updates
    /profile/[did]            # Player profiles and game history
    /api/games                # Create, join, move, pass, resign, reaction, score, ...
    /og-image/[id]            # Social/OG image generation
  /lib
    /server                   # auth.ts, db.ts, scoring.ts, elo.ts, board-svg.ts, firehose-records.ts
    /components               # Board.svelte (jgoboard) and shared UI components
    firehose.ts               # Client-side Jetstream subscriber
    atproto-client.ts         # PDS / public-index record helpers
/lexicons                     # boo.sky.go.* lexicon definitions
/migrations                   # D1 schema migrations
/scripts                      # OAuth key generation, index backfill
/firehose-worker              # Durable Object Jetstream consumer that maintains the D1 index
/wrangler.toml                # Cloudflare Pages + D1 bindings

Architecture #

Technology Stack #

  • Frontend: SvelteKit 5 with TypeScript
  • Go Board: jgoboard (rendering, moves, captures)
  • Go Scoring: tenuki (territory scoring)
  • Authentication: AT Protocol OAuth (@atcute/oauth-node-client)
  • Data Storage: AT Protocol records with custom lexicons
  • Database: Cloudflare D1 (serverless SQLite) with Kysely query builder
  • Session Storage: Cloudflare KV when the KV bindings are configured (in-memory store otherwise)
  • Image Generation: @cf-wasm/resvg (WebAssembly-based)
  • Deployment: Cloudflare Pages with Workers runtime
  • Real-time: Client-side Jetstream subscription, plus a Durable Object Jetstream consumer that maintains the D1 discovery index

Custom Lexicons #

The application defines seven custom AT Protocol lexicons:

  1. boo.sky.go.game: Represents a game between two players
  2. boo.sky.go.move: Represents a stone placement move
  3. boo.sky.go.pass: Represents a pass action
  4. boo.sky.go.resign: Represents a resignation
  5. boo.sky.go.action: Represents a join/action on a game
  6. boo.sky.go.reaction: Represents a comment on a move
  7. boo.sky.go.profile: Represents a player profile and rating

All game data is stored as AT Protocol records, making it decentralized and portable.

Known Limitations #

  • Scoring is a territory estimate that relies on players marking dead stones
  • The D1 discovery index is filled from the Jetstream firehose, so games created before the consumer started (or outside the indexed collections) may be missing until backfilled (npm run backfill)
  • No time controls or undo functionality
  • Local development sessions live in memory, so they do not survive a server restart
  • Reaction and board images are rendered on the edge with @cf-wasm/resvg

Future Enhancements #

Contributing #

This is a demonstration project showing AT Protocol integration with a game application. Feel free to fork and extend!

License #

MIT