Play-testing with simulation
game.simulate plays a fresh copy of the committed project without a window or renderer. It uses
the same scripts, Blueprints, Rapier physics and player controller as Play and the exported player,
runs for a fixed number of 1/60-second ticks with scheduled key presses, and returns a report. The
project, selection, revision and undo history are never changed.
Use it to check that a mechanic works after an edit: that a door opens, a body falls, a script runs without errors, or the player can reach a platform.
Run a simulation
Section titled “Run a simulation”- Decide how many frames to run. At 60 ticks per second, 240 frames is four seconds.
- Schedule inputs as key transitions. A key stays held until you release it.
- Run the command and read the report.
# Hold D for the first second of a four-second run.feather-cli --workspace ./my-game --project project.feather.json command game.simulate --json '{ "frames": 240, "inputs": [ {"frame": 0, "key": "D", "pressed": true}, {"frame": 60, "key": "D", "pressed": false} ]}'Headless, the command returns {report} directly. In a live editor it starts a background job and
returns a job_id; poll job.inspect until status is completed, and read the report from its
output.
Arguments
Section titled “Arguments”| Field | Description |
|---|---|
frames |
Ticks to run, 1 to 600. Default 240 |
inputs |
Up to 256 {frame, key, pressed} transitions. frame is zero-based and must be less than frames |
blasts |
Up to 64 explosions {frame, position, radius, damage}; needs destruction enabled |
weather |
Weather events {frame, action, weather, seconds, at} with actions set, strike, tornado and stop_tornado; needs weather enabled |
| Keys | Effect |
|---|---|
W, A, S, D |
Move the player |
Space |
Jump |
Shift, ShiftLeft, ShiftRight |
Change movement speed |
E, arrow keys (Up, Down, Left, Right or ArrowUp…) |
Reach script and Blueprint input such as key_down |
Q, F, C, G, R, V, Ctrl, ControlLeft |
Further gameplay actions |
Pad:South, Pad:East, … Pad:DPadRight |
Gamepad buttons |
Pad:LeftStickAxis, Pad:RightStickAxis |
Gamepad sticks; pass axis: [x, y] in −1..1, where y = 1 pushes forward |
Look |
Turns the view like mouse look; pass look: [yaw, pitch] in degrees. Yaw 0 faces −Z; pitch is −89 to 89, negative looks down. E then picks up what the centre of the view is on |
The player spawns during the first tick. Schedule jump presses after the player exists and is standing on the ground.
Report
Section titled “Report”| Field | Description |
|---|---|
success |
true if the run finished without runtime errors and Stop restored the authored state |
frames, timestep_seconds, prewarm_frames |
The ticks run, the tick length, and the warm-up ticks used to load terrain before the run |
objects |
For each object: initial and final state (position, rotation, scale, velocity, visibility, physics suspension), min_height, max_height and max_upward_velocity |
player |
The player’s initial and final state and its height range |
score |
Collectible score at the end |
logs |
The most recent runtime messages, up to 128 |
error_count, errors |
Total runtime errors, and up to 128 distinct messages |
restored |
Whether Stop restored every authored object |
limitations |
What this run could not verify |
Further sections appear when the project uses the matching system: blueprints (per-node execution
counts), destruction, boat, vehicle, traversal, weather, feel (stamina, climbing,
footsteps and the surface underfoot), fluids, smoke, interaction (doors, switches, pickups,
carrying and throwing) and ai (agent paths, blackboards, perception and events).
The interactive water surface (water.interactive in project.environment) is part of the run
too.
Live editor
Section titled “Live editor”- Pending editor edits must be committed or discarded first; see
editor.commit. - A simulation can run during Play; it uses an isolated copy of the authored project.
- Only one background simulation can run at a time in an editor session.
Limits
Section titled “Limits”| Limit | Value |
|---|---|
| Frames per run | 1 to 600, at 1/60 second each |
| Input transitions | 256 |
| Authored objects | 2,048 |
| Work budget | 1,000,000 object × frame steps |
The runner does not render pixels, load model visuals, or play animation or audio. Imported models
use their authored colliders. Dynamic bodies far from the player may stay suspended while their
terrain is not loaded; check physics_suspended in the report. Fixed ticks make runs repeatable on
one machine, but results are not guaranteed to be bit-identical across platforms.
Automate it
Section titled “Automate it”Use simulation as a regression check after every change. For example, confirm that a cube set to Dynamic falls:
feather-cli --workspace ./my-game --project project.feather.json \ command game.simulate --json '{"frames":120}' \ | python3 -c 'import json,sys; o=json.load(sys.stdin)["data"]["report"]["objects"][0]; print(o["initial"]["position"][1], o["final"]["position"][1])'The War City example shows a run with scheduled blasts; see Example projects.