A · Building a Game — Overview

How Effectstream thinks

One mental model carries you through this whole workshop: blockchains are input devices; your game state lives in PostgreSQL. Three chains feed our game — an EVM chain holding the NFTs, another EVM contract (EffectstreamL2) where batched player moves land, and Midnight for the seasons. Effectstream itself is the L2: the deterministic state machine that consumes all three.

▼ details below
EVM · NFT ERC-721 card mints players pay gas EVM · EffectstreamL2 contract for game moves batcher pays gas players → BATCHER signed inputs, gasless MIDNIGHT ZK contract state seasons NTP clock main timeline SYNCPROTOCOLS one per chain PRIMITIVES watch one contract, emit typed inputs THE L2 — EFFECTSTREAM state machine your game logic — deterministic, replayable by anyone PostgreSQL = the game state REST API + MQTT :9999 / :8883 — read-only your UI game.html
three blockchains in, one deterministic L2 out — the game state anyone can recompute.
(in this workshop's dev setup, both EVM roles run on a single local Hardhat chain; in production they can be separate networks)

Six words you'll hear all session

TermWhat it isWhere it lives
networka chain (or clock) the node connects toconfig.dev.ts
sync protocolhow blocks are fetched from one network; one main timeline, many parallel chainsconfig.dev.ts
primitivea watcher on one contract that turns chain events into typed inputsconfig.dev.ts
grammarthe schema of every input your app understandsgrammar.ts
state machine (STM)your logic: one transition function per input kind, writing to Postgresstate-machine.ts
batchercollects signed user inputs off-chain and lands them on-chain in batches — users pay no gaspackages/batcher/

Why determinism is the whole point

Anyone can run this node. It reads the same chains, applies the same state transitions, and arrives at byte-identical Postgres state. That's what makes the game state trustless: the chain is the source of truth, and the node is just a deterministic replay of it.

It's also the one rule you must never break inside a state transition: no Math.random(), no Date.now(), no network calls. (In Step 2 you'll see the framework hand you a seeded random generator instead — that's how our cards get random stats without breaking determinism.)

Checkpoint
Can you answer these two? Where does game state live? (Postgres, not the chain.) What happens if two nodes disagree? (They can't — same inputs, same transitions, same state.)
← Why Effectstream?The game rules →