Input macro (asset type)
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 the sim toolbox's key / click tools 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..metadata— agent-editable tags + free-form fields. Required.
How to create one
Two paths:
-- Record a live sequence: recordMacro captures real input for
-- `duration` seconds and returns the recorded events; saveMacro
-- persists them as the asset.
local events = tools.use("sim", "recordMacro", { duration = 5 })
tools.use("sim", "saveMacro", "<name>", events)
-- 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": "keyDown", "arg": "KeyW" }t: seconds since macro start.op: event op —keyDown,keyUp,mouseDown,mouseUp,mouseMove,scroll,lockPointer,tap,click.arg: op-specific argument — a key code ("KeyW","Space","ShiftLeft","Digit1","ArrowUp"), a mouse button index (0 = LMB, 1 = RMB, 2 = MMB), or a delta table ({ dx = 200, dy = 0 }formouseMove).
- Playback.
tools.use("sim", "macro", "<name>")schedules every event at itstoffset relative to playback start; events are sorted on play. The same tool takes an inline event list or anAssetRef<inputMacro>instead of a name. - Determinism. Macros are deterministic relative to engine state at playback start — same start state + same macro = same end state.
- Recording.
tools.use("sim", "recordMacro", { duration = n })polls live input state and returns the recorded events;tools.use("sim", "saveMacro", "<name>", events)writes them to/zero/source/<name>.inputMacro/events.jsonand returns the macro'sAssetRef.
Discovery
asset.list("inputMacro")— every registered macro.asset.inspect("<name>")— event count, duration, source, this type README.cat /zero/source/<name>.inputMacro— same summary.tools.use("sim", "listMacros")— every registered.inputMacro.
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
tools.use("sim", "macro", "a")thentools.use("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.
mouseMoveargument. It carries a{ dx, dy }delta, the same shape the recorder emits. 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.