Input macro (asset type)
An input macro is a recorded or hand-authored sequence of input simulation events — keystrokes, mouse moves, button clicks, scroll wheel deltas — timestamped and played back via sim.macro. Macros are…
The engine deliberately does NOT ship per-feature input recipes (walk, sprint, drive). Authors record or hand-write the macro they need; the playback primitive is type-agnostic.
When to use one
- You want to script an input sequence for testing (e.g. "walk forward 3 seconds, jump, look around").
- You're capturing a demo / repro of a user interaction sequence.
- You want deterministic input playback across runs.
If you need per-frame programmatic input (more than a fixed sequence
allows), drive sim.key / sim.click directly from a script. If
you need real input handling, that's the input API
(man input).
Where it lives
- Source:
/zero/source/.../<name>.inputMacro/ - Identity:
<name>(the.inputMacrosuffix strips). - Folder shape:
events.json— JSON array of{ t, op, arg }event tuples. Required.README.md— instance documentation. Required.
How to create one
Two paths:
-- Record a live sequence:
local rec = sim.recordMacro()
-- ... drive the engine for as long as you want to capture ...
rec:stop("<name>") -- writes events.json into the macro's asset folder
-- Hand-author an empty macro scaffold and fill events in:
asset.create("inputMacro", "<name>")
The record path is preferred for sequences any human could perform; hand-authoring is for synthetic or precisely-timed sequences.
How it operates
- Event format.
events.jsonis a JSON array of triples:{ "t": 0.5, "op": "key.down", "arg": "W" }t: seconds since macro start.op: event op —key.down,key.up,mouse.move,mouse.button.down,mouse.button.up,mouse.wheel.arg: op-specific argument (key name, axis delta, button index).
- Playback.
sim.macro("<name>")schedules every event at itstoffset relative to playback start. Events are dispatched in order; earlier events fire before later ones even if theirtcollides. - Determinism. Macros are deterministic relative to engine state at playback start — same start state + same macro = same end state.
- Recording.
sim.recordMacro()returns a recorder; calling:stop("<name>")finalises the macro and writes it to disk.
Discovery
asset.list("inputMacro")— every registered macro.asset.inspect("<name>")— event count, duration, source, this type README.cat /zero/source/<name>.inputMacro— same summary.
Authoring conventions
- Start macros from a known state (call
layers.load("base")before playback) so determinism holds across runs. - Keep macros focused on one user-facing action sequence. Longer
macros are harder to compose and debug; chain shorter ones via
sim.macro("a"); sim.macro("b"). - Document the expected start state and end state in the macro's instance README — what scene / mode / focus the playback assumes.
Common pitfalls
- Non-deterministic start state. Playing a macro from a different starting scene produces different outcomes. Always lead with a scene load.
- Frame-rate dependence. Times are in seconds; the dispatcher schedules events relative to wall time, not frames. Effects that depend on per-frame logic may diverge across hardware.
mouse.moveargument. It's an absolute screen-coordinate delta, not a relative one. Check the recorded values match.
Related types
.tool— for agent-callable input wrappers that may invoke macros as part of larger flows..scene— macros pair with scenes for deterministic test setups.