A client that decides nothing. The simulation is the truth.
AI RPG Stage attaches to a running AI RPG Engine over JSON-RPC, submits what the player is trying to do, and draws what comes back. It holds no rules, advances no clock, and says so out loud when it disagrees with the sim. The play camera is a 2:1 dimetric harbour: Y-sorted buildings, Foundry HD characters, torches on normal maps, town art that passed a projection gate.
Play
node tools/play.mjs
Test
./verify.sh
One suite
godot --headless --path . --script res://tools/headless.gd -- --only=iso_world
What it is
A rendering surface for a deterministic simulation, arranged so it cannot become a second truth.
Decides nothing
Occupancy is a zone id in the engine. The stage submits intent, renders events, and on a hash mismatch reports it and re-snapshots. It never patches the sim.
2:1 dimetric harbour
One TileMapLayer, 256×128 diamonds, Y-sorted. Buildings sliced into 128 px strips so every diamond has one drawable. Contact blobs under every actor. Who stands on which cell is authored in World Forge and read off the pack, not guessed here.
Gated art
Every plate was rendered through a Blender camera at X 60° / Z 45° and must pass a ten-check ANDON before it is loaded. Wrong projection, no alpha, baked backdrop: refused.
Felt audio
The handshake asks for capabilities.audio. Zone stems, overlay stings that do not kill the stem, the spoken line once, camera trauma from the same payload. Never hashed.
Proofs with controls
Eleven headless suites, each with a fixture or control that makes it fail. A test that asserts nothing fails. A filter that matches nothing fails.
One outbound socket
No default endpoint, no discovery, no listener, no credentials, no telemetry. The trust boundary is the engine you point it at.
Usage
Play Salt Road
# Godot 4.7 on PATH, engine built as a sibling (../ai-rpg-engine)
node tools/play.mjs
# options
node tools/play.mjs --seed 71 --port 47820 --no-shock
node tools/play.mjs --headless # start the sim only, print the portRun the suite
./verify.sh
# by hand
godot --headless --path . --import
godot --headless --path . --script res://tools/headless.gd
godot --headless --path . --script res://tools/headless.gd -- --only=scene_joinGate a plate
python assets/dimetric/andon/iso_andon.py assets/dimetric/ground/dirt_a.png --kind ground
python assets/dimetric/andon/iso_andon.py assets/dimetric/structures/shed_2x2/beauty.png --kind structure --footprint 2,2
# exit 0 only when every gate passesAttach by hand
# a sidecar you started yourself
godot --path . -- --attach=127.0.0.1:47820
# the stage requests capabilities.hashes + capabilities.audio
# and reports [stale] ... when the sim disagrees