Skip to content

Repository files navigation

Go Fish Game - Paima Engine (Effectstream)

A Go Fish card game implementation using Paima Engine (Effectstream) with EVM for lobbies and Midnight for game logic.

⚡ Quick Start

Full Stack Development (Recommended)

Run the complete development environment with orchestrator:

# First time setup
bun install

# Build EVM contracts
bun run build:evm

# Start all services (backend + frontend + blockchain)
bun run dev

This will launch:

Batcher Mode (Midnight)

For development with Midnight blockchain integration, you can run the infrastructure and dev server separately:

# Terminal 1: Start Midnight infrastructure (node, indexer, proof server, contract deployment)
EFFECTSTREAM_STDOUT=true bun run --filter @go-fish/node midnight:setup

# Terminal 2: Start the dev server with batcher mode (after infra is ready)
USE_TYPESCRIPT_CONTRACT=false EFFECTSTREAM_STDOUT=true USE_BATCHER_MODE=true SKIP_MIDNIGHT_INFRA=true bun run dev

The SKIP_MIDNIGHT_INFRA=true flag tells the dev server to skip launching Midnight infrastructure since it's already running from the first command.

Frontend Only

For quick frontend-only development:

bun run frontend:dev

Visit http://localhost:3000

Project Structure

/packages/
├── frontend/              # Web UI (Three.js 3D game scene, HTML overlays, TypeScript, Vite)
├── client/
│   ├── node/             # Paima engine node (state machine, APIs)
│   ├── batcher/          # Transaction batching service
│   └── database/         # PGLite queries and schema (pgtyped)
└── shared/
    ├── contracts/
    │   ├── evm/          # Hardhat contracts for lobbies & stats (EVM)
    │   └── midnight/     # Midnight contracts for game logic (stub)
    ├── data-types/       # Shared types and config
    └── simulation/       # Game simulation logic

Architecture

This project follows a hybrid blockchain architecture:

  • Frontend: Three.js 3D game scene with Balatro-style post-processing, HTML overlays for lobby/menu screens
  • EVM Contracts: Handle lobbies, player stats, matchmaking (Hardhat)
  • Midnight Contracts: Handle private game state and logic
  • Paima Node: Processes blockchain transactions and maintains game state
  • Batcher: Batches user transactions to reduce on-chain costs
  • Database: PGLite (in-memory/WASM PostgreSQL) for game state storage
  • Simulation: Shared deterministic game logic (frontend + backend)

Go Fish Game Features

  • 🃏 Classic Go Fish card game mechanics
  • 🎮 Multiplayer lobbies (2-6 players)
  • 🏆 Player statistics and leaderboards (EVM)
  • 🔐 Private game state using Midnight
  • 📊 Match history and rankings

How to Play Go Fish

Go Fish is a classic card matching game:

  1. Setup: Each player is dealt 5-7 cards
  2. Turn: On your turn, ask any player for a specific rank (e.g., "Do you have any 7s?")
  3. Match: If they have it, they give you all cards of that rank. You get another turn.
  4. Go Fish: If they don't have it, they say "Go Fish!" and you draw a card
  5. Books: When you collect all 4 cards of a rank, it forms a "book" (1 point)
  6. Win: The player with the most books when the deck runs out wins!

Commands

# Frontend Development
bun run frontend:dev       # Start dev server
bun run frontend:build     # Production build

# Backend
bun run dev                # Start full stack via orchestrator
bun run mainnet            # Start in mainnet mode

# Testing
bun run test               # Node API unit tests
bun run test:e2e           # E2E game-round test

# Smart Contracts (EVM)
cd packages/shared/contracts/evm
bun run build              # Compile contracts
npx hardhat test           # Run contract tests

# Root Level
bun run build:evm          # Compile EVM contracts
bun run build:midnight     # Compile Midnight contracts
bun run frontend:dev       # Start frontend from root
bun run frontend:build     # Build frontend from root

Environment Variables

Development Configuration

  • USE_TYPESCRIPT_CONTRACT=true - Use local TypeScript-compiled Midnight contract (for testing without Midnight infrastructure)
  • SKIP_EVM_LAUNCH=true - Skip launching Hardhat node and EVM deployment (use when Hardhat is already running externally)
  • SKIP_MIDNIGHT_INFRA=true - Skip launching Midnight infrastructure (node, indexer, proof-server)
  • SKIP_PGLITE=true - Skip launching PGLite database (for shared infrastructure environments)
  • USE_BATCHER_MODE=true - Run frontend in batcher mode (no Lace wallet needed)
  • DEPLOY_MIDNIGHT_CONTRACT=true - Deploy Midnight contract at startup (takes ~6 minutes)
  • EFFECTSTREAM_STDOUT=true - Log all output to stdout instead of tmux

Frontend Configuration (VITE_ prefix)

These are set in a .env file in packages/frontend/ or passed inline when running the dev server. Vite exposes them to the frontend via import.meta.env.

Variable Default Description
VITE_USE_LEGACY_GAME_UI "false" Set to "true" to use the old DOM-based game screen instead of the Three.js 3D scene. Lobby, wallet, and setup screens are unaffected.
VITE_BATCHER_MODE_ENABLED "false" Set to "true" to enable batcher mode (transactions go through Paima batcher, no Lace wallet needed).
VITE_BATCHER_URL http://localhost:3334 URL of the Midnight batcher service.
VITE_INDEXER_HTTP_URL http://127.0.0.1:8089/api/v1/graphql Midnight indexer HTTP/GraphQL endpoint.
VITE_INDEXER_WS_URL ws://127.0.0.1:8089/api/v1/graphql/ws Midnight indexer WebSocket endpoint.
VITE_PAIMA_L2_CONTRACT_ADDRESS 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 Paima L2 contract address on the EVM chain.
VITE_EVM_RPC_URL http://localhost:8545 EVM JSON-RPC endpoint (Hardhat by default).
VITE_PROOF_SERVER_URL (unset) URL of an external Midnight proof server (e.g. http://localhost:6300). When set, the frontend delegates ZK proof generation to this HTTP server instead of running proofs locally in the browser via WASM. Leave unset (the default) for in-browser WASM proving, which requires no separate proof server — the recommended mode for production since the Lace wallet does not ship with a built-in proof server.

Example: Using with External Hardhat

# Start with existing Hardhat instance
SKIP_EVM_LAUNCH=true USE_TYPESCRIPT_CONTRACT=true EFFECTSTREAM_STDOUT=true bun run dev

Database Schema

PGLite database tables for the Go Fish game:

  • lobbies - Active game lobbies with player counts
  • lobby_players - Players in each lobby with ready status
  • games - Game instances with status (planned for Midnight integration)
  • effectstream.accounts - Account management (Paima Effectstream)
  • effectstream.addresses - Address-to-account mapping (Paima Effectstream)

All migrations are in packages/client/database/src/mod.ts

Queries are defined in SQL files and auto-generated using pgtyped:

Game Commands

Blockchain commands (Paima concise grammar format).

Go Fish is a fixed 2-player game with auto-start on the second join, so the EVM grammar is deliberately minimal — just three commands:

Lobby Management (EVM):

  • createdLobby|playerName|lobbyName — Create a new lobby. Host is added as the first player.
  • joinedLobby|playerName|lobbyID — Second player joins. The state machine flips the lobby to in_progress in the same transition.
  • closedLobby|lobbyID — Host cancels an open lobby while still alone. Deletes the lobby row.

Game Actions: Game-round logic (asking for cards, drawing, booking) runs on the Midnight contract as ZK circuits. See packages/shared/contracts/midnight/. None of those actions touch the EVM grammar.

See packages/shared/data-types/src/grammar.ts

Technology Stack

  • Backend: Bun, TypeScript, Paima Engine
  • Frontend: Vite, TypeScript, Three.js, postprocessing, gsap
  • Blockchain (EVM): Hardhat, Solidity (lobbies & stats)
  • Blockchain (Midnight): Midnight contracts (game logic - stub)
  • State Management: Paima State Machine (PaimaSTM)

Resources

License

MIT

About

An implementation of the classic card game 'Go Fish' in Effectstream, running on the Midnight blockchain

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages