Skip to content

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.

  1. Decide how many frames to run. At 60 ticks per second, 240 frames is four seconds.
  2. Schedule inputs as key transitions. A key stays held until you release it.
  3. Run the command and read the report.
Terminal window
# 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.

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.

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.

  • 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.
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.

Use simulation as a regression check after every change. For example, confirm that a cube set to Dynamic falls:

Terminal window
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.