The code for Snaketron.io, a multiplayer competitive Snake game written with Rust and Typescript.
48
stars
507
commits
Rust
primary language
Aug 30, 2026
updated
SnakeTron is a competitive online multiplayer Snake game — real-time matches, ranked seasons, and no mercy! The game engine and the auto-scaling server architecture behind snaketron.io are written in Rust and open-sourced in this repository.
common/ crate compiles to both native (server) and WASM (client).Prerequisites: Rust (stable), wasm-pack, Node.js, and Docker.
# Start LocalStack (DynamoDB), Redis (Valkey), and the server with auto-reload on code changes
./dev.sh
# In another terminal, build and start the client
cd client
wasm-pack build --target web --out-dir pkg
cd web
npm install
npm start
# Start LocalStack (DynamoDB), Redis (Valkey), and the server (full rebuild each time)
docker-compose up --build
This starts only the backend stack — build and start the client in another terminal with the same commands as in development.
The game will be available at:
Start the data services (LocalStack + Redis) and create the DynamoDB tables:
./test-deps.sh
Run the server (.cargo/config.toml supplies the LocalStack/Redis defaults; only the region must be set explicitly):
SNAKETRON_REGION=us cargo run --bin server
Build and run the client:
cd client
wasm-pack build --target web --out-dir pkg
cd web
npm install
npm start
Server integration tests need Redis and LocalStack DynamoDB running — start them with ./test-deps.sh first (it also creates the DynamoDB tables).
# Run all Rust tests
cargo test
# Run server tests with logging
RUST_LOG=info cargo test -p server -- --nocapture
# Curated serial suites (set up their own env, run single-threaded)
./run_matchmaking_tests.sh
./run_quickmatch_tests.sh
Client tests and checks:
cd client/web
npm test # Playwright end-to-end tests
npm run test:unit # Node unit tests
npm run type-check # TypeScript type check
PRs are welcome. CI requires clean formatting and a warning-free clippy pass on every PR:
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
TypeScript types for everything crossing the WebSocket are generated from the Rust source of truth with ts-rs. After changing any wire type, regenerate them and commit the diff:
./scripts/gen-types.sh
Replays of production matches now also create a versioned deterministic GameRecordingV1.
The completion outbox uploads its canonical gzip to private S3, stores verified
replay metadata plus the server-selected Play of the Game in DynamoDB, and
serves public reads through a bounded Valkey/ElastiCache cache-aside layer.
Large recordings are stored as content-addressed manifests plus chunks and are
served through bounded HTTP byte ranges. Synthetic stress/bot matches are
server-attested and deliberately excluded; SNAKETRON_TEST_MODE also disables
recording for the entire test process.
See server/README.md for storage variables, public endpoints, and the
LocalStack integration test.
The terminal viewer can play the sample captures in replays/:
cargo run --bin snaketron -- replays/
The bot CLI must present the server's configured stress key so test users do not contaminate production replay storage:
cargo run -p bot -- --stress-test-key "$SNAKETRON_STRESS_TEST_KEY" --bots 4 --games 10
ITCH_BUILD=true npm run build:prod (in client/web) produces a relative-path HTML5 bundle suitable for uploading to itch.io.
CRAZYGAMES_BUILD=true npm run build:prod (in client/web) produces a relative-path HTML5 bundle that loads the CrazyGames v3 SDK before the game bundle and omits third-party analytics. The build makes the CrazyGames ad adapter available; the server-side advertisement configuration above decides at runtime whether it is used. CrazyGames cloud-data storage stays off unless CRAZYGAMES_DATA_ENABLED=true is explicitly set at build time. See CRAZYGAMES.md for portal settings and the QA checklist.
Point a coordinated fleet of AI players at a cluster and make it sweat:
cargo run --release -p loadtest -- \
--target https://snaketron.io \
--confirm-production \
--require-scale-out \
--mode duel \
--queue-mode competitive
The load runner supports Solo, Duel, 2v2, and FFA; creates deterministic full-party multiplayer lobbies; plays real games using the shared Rust game engine and AI; ramps to 256 maintained sessions by default; and writes an HTML/JSON report with per-failure details. See loadtest/README.md for profiles, safety controls, and report semantics.
common/ - Shared game logic (compiled to both native and WASM)server/ - Game server: WebSocket sessions, matchmaking, game executors, persistenceclient/ - WebAssembly client module and the React/TypeScript web app (client/web/)bot/ - CLI that runs one or more AI bots against a live server over WebSocketmacros/ - Proc-macro crate defining a serde_wasm_bindgen attribute (not currently used by other crates)terminal/ - Terminal-based replay player for .replay capturesloadtest/ - Coordinated AI load generator and aggregate reportingreplays/ - Sample .replay game captures for the terminal viewerscripts/ - Development helpers (type generation, DynamoDB init, test dependencies)specs/ - Design documents and PRDs (matchmaking, Boost, autoscaling resilience, ...)tla_specs/ - TLA+ specifications (model-check them with tla2tools.jar at the repo root)docs/ - Screenshots, pull-request assets, and assorted design notesSee server/docker-readme.md for detailed Docker and AWS Fargate deployment instructions.
MIT — see LICENSE.
Rust
53.7%
Python
18.3%
TypeScript
13.5%
JavaScript
9.1%
Shell
2.4%
CSS
2.0%
The code for Snaketron.io, a multiplayer competitive Snake game written with Rust and Typescript.
48
stars
507
commits
Rust
primary language
Aug 30, 2026
updated
SnakeTron is a competitive online multiplayer Snake game — real-time matches, ranked seasons, and no mercy! The game engine and the auto-scaling server architecture behind snaketron.io are written in Rust and open-sourced in this repository.
common/ crate compiles to both native (server) and WASM (client).Prerequisites: Rust (stable), wasm-pack, Node.js, and Docker.
# Start LocalStack (DynamoDB), Redis (Valkey), and the server with auto-reload on code changes
./dev.sh
# In another terminal, build and start the client
cd client
wasm-pack build --target web --out-dir pkg
cd web
npm install
npm start
# Start LocalStack (DynamoDB), Redis (Valkey), and the server (full rebuild each time)
docker-compose up --build
This starts only the backend stack — build and start the client in another terminal with the same commands as in development.
The game will be available at:
Start the data services (LocalStack + Redis) and create the DynamoDB tables:
./test-deps.sh
Run the server (.cargo/config.toml supplies the LocalStack/Redis defaults; only the region must be set explicitly):
SNAKETRON_REGION=us cargo run --bin server
Build and run the client:
cd client
wasm-pack build --target web --out-dir pkg
cd web
npm install
npm start
Server integration tests need Redis and LocalStack DynamoDB running — start them with ./test-deps.sh first (it also creates the DynamoDB tables).
# Run all Rust tests
cargo test
# Run server tests with logging
RUST_LOG=info cargo test -p server -- --nocapture
# Curated serial suites (set up their own env, run single-threaded)
./run_matchmaking_tests.sh
./run_quickmatch_tests.sh
Client tests and checks:
cd client/web
npm test # Playwright end-to-end tests
npm run test:unit # Node unit tests
npm run type-check # TypeScript type check
PRs are welcome. CI requires clean formatting and a warning-free clippy pass on every PR:
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
TypeScript types for everything crossing the WebSocket are generated from the Rust source of truth with ts-rs. After changing any wire type, regenerate them and commit the diff:
./scripts/gen-types.sh
Replays of production matches now also create a versioned deterministic GameRecordingV1.
The completion outbox uploads its canonical gzip to private S3, stores verified
replay metadata plus the server-selected Play of the Game in DynamoDB, and
serves public reads through a bounded Valkey/ElastiCache cache-aside layer.
Large recordings are stored as content-addressed manifests plus chunks and are
served through bounded HTTP byte ranges. Synthetic stress/bot matches are
server-attested and deliberately excluded; SNAKETRON_TEST_MODE also disables
recording for the entire test process.
See server/README.md for storage variables, public endpoints, and the
LocalStack integration test.
The terminal viewer can play the sample captures in replays/:
cargo run --bin snaketron -- replays/
The bot CLI must present the server's configured stress key so test users do not contaminate production replay storage:
cargo run -p bot -- --stress-test-key "$SNAKETRON_STRESS_TEST_KEY" --bots 4 --games 10
ITCH_BUILD=true npm run build:prod (in client/web) produces a relative-path HTML5 bundle suitable for uploading to itch.io.
CRAZYGAMES_BUILD=true npm run build:prod (in client/web) produces a relative-path HTML5 bundle that loads the CrazyGames v3 SDK before the game bundle and omits third-party analytics. The build makes the CrazyGames ad adapter available; the server-side advertisement configuration above decides at runtime whether it is used. CrazyGames cloud-data storage stays off unless CRAZYGAMES_DATA_ENABLED=true is explicitly set at build time. See CRAZYGAMES.md for portal settings and the QA checklist.
Point a coordinated fleet of AI players at a cluster and make it sweat:
cargo run --release -p loadtest -- \
--target https://snaketron.io \
--confirm-production \
--require-scale-out \
--mode duel \
--queue-mode competitive
The load runner supports Solo, Duel, 2v2, and FFA; creates deterministic full-party multiplayer lobbies; plays real games using the shared Rust game engine and AI; ramps to 256 maintained sessions by default; and writes an HTML/JSON report with per-failure details. See loadtest/README.md for profiles, safety controls, and report semantics.
common/ - Shared game logic (compiled to both native and WASM)server/ - Game server: WebSocket sessions, matchmaking, game executors, persistenceclient/ - WebAssembly client module and the React/TypeScript web app (client/web/)bot/ - CLI that runs one or more AI bots against a live server over WebSocketmacros/ - Proc-macro crate defining a serde_wasm_bindgen attribute (not currently used by other crates)terminal/ - Terminal-based replay player for .replay capturesloadtest/ - Coordinated AI load generator and aggregate reportingreplays/ - Sample .replay game captures for the terminal viewerscripts/ - Development helpers (type generation, DynamoDB init, test dependencies)specs/ - Design documents and PRDs (matchmaking, Boost, autoscaling resilience, ...)tla_specs/ - TLA+ specifications (model-check them with tla2tools.jar at the repo root)docs/ - Screenshots, pull-request assets, and assorted design notesSee server/docker-readme.md for detailed Docker and AWS Fargate deployment instructions.
MIT — see LICENSE.
Rust
53.7%
Python
18.3%
TypeScript
13.5%
JavaScript
9.1%
Shell
2.4%
CSS
2.0%