argus run
Since next
Load a project or a scene, run it, render a PNG, and optionally keep serving and watching.
A project (its folder or its argus.project.json) runs its startup scene with the title, icon and window its manifest names, from any working directory. Any other file runs as a bare scene with the scene defaults. The launch's settings, and where each came from, are printed first as argus: application {json} on stderr.
Usage
argus run [OPTIONS] <PROJECT_OR_SCENE>
Arguments
| Argument | Description |
|---|---|
<PROJECT_OR_SCENE> |
Options
| Flag | Value | Default | Allowed values | Description |
|---|---|---|---|---|
--frames | <FRAMES> | Fixed 60 Hz ticks to simulate before the first render. 60 by default, or 0 with --paused, where the point is that nothing has run yet | ||
--out | <OUT> | frame.png | Where to write the rendered frame | |
--overlays | <OVERLAYS> | colliders, triggers, navmesh, bounds | Debug overlays drawn over the --out frame, comma-separated: colliders (every collider, a mesh's static one included: an invisible wall shows), triggers, navmesh, bounds. The query API's capture takes the same as "overlays" | |
--serve | Keep serving the query API until Ctrl-C. GET /frame.png is refreshed every 30 rendered frames, twice a second at 60 Hz; POST /capture renders an exact frame on demand and is the path to use when the frame has to be the one you asked for. | |||
--port | <PORT> | 7700 | ||
--ws-port | <WS_PORT> | 7701 | The websocket port for /stream. SPEC assigns 7701. --ws-port 0 binds an ephemeral one; there is no way to turn the socket off, because /stream is also mounted on the HTTP port and a client that knows one port always finds it | |
--watch | Reload the scene whenever the file changes, and keep running | |||
--scale | <SCALE> | 1 | Simulation speed, 0.1 to 10, for the real-time loop that --watch and --serve enter. Scaling steps more often per rendered frame; it never stretches dt, and it does not change what --frames means (N fixed ticks is always N fixed ticks) | |
--headless | Run without a GPU: simulate and build draw lists, but never submit a frame | |||
--render-on-request | Keep a renderer, but draw only when a request asks (POST /capture, GET /frame.png?fresh=1): the loop never renders a frame of its own and no start-up PNG is written. What a program that steps the simulation and only sometimes looks (an agent's play session) wants: stepping costs what --headless costs, and a capture still has a GPU to read | |||
--parent-pipe | Exit when standard input closes. The process that started this one holds the other end of the pipe, so the engine never outlives it, whichever way it died | |||
--paused | Start paused, so the simulation runs no tick until something asks it to. The loop keeps answering commands — that is what QueryBridge::pump is separate for — so a driver can attach, snapshot, and step. Without it the engine free-runs on wall-clock time between launch and the first POST /time, and how many ticks fit in that gap depends on how long the process took to start, which is what makes a clip recorded through the API irreproducible. | |||
--stub-physics | Run the stub physics backend instead of Rapier | |||
--net-join | <URL> | Play in a networked session through the relay at this address (ws://host:port), as one of its players. Needs --window; the scene must be byte-identical on every machine | ||
--net-observe | With --net-join: join as an observer, with no seat and no input (a DIS gateway, a spectator) | |||
--net-seat | <N> | With --net-join: take this seat (player number, from 1), for a player rejoining their own after a drop; without it, the lowest free seat | ||
--net-remotes | <HOW> | With --net-join: how other players are shown, predicted (live, corrected when a guess was wrong; the default) or confirmed (a few ticks behind, never corrected) | ||
--net-smoothing | <MS> | With --net-join: blend a correction away over this many milliseconds (default 100; 0 snaps) | ||
--net-snap-above | <METRES> | With --net-join: snap a correction larger than this many metres instead of blending it (default 2) | ||
--state-stream | <ADDR> | With --net-join: serve each confirmed tick's moving entities as JSON lines to WebSocket clients of this local address (e.g. 127.0.0.1:47912) | ||
--deterministic | Run as a networked session does: every peer computes it the same, whatever its core count (the Rust crowd on any thread count). A remote player sitting down does this anyway | |||
--no-audio | Do not open the audio output: a --window run mixes as usual and plays nothing. The same as setting ARGUS_NO_AUDIO=1. A run without a window never opens one anyway | |||
--audio | Let a --window --serve run be heard. A window that serves the query API is driven by a program (a playtest, an agent, a benchmark) and is silent without this; a plain --window run is heard anyway. ARGUS_AUDIO=1 asks the same from the environment (what a development export's launcher sets). --no-audio and ARGUS_NO_AUDIO still win | |||
--no-scripts | Do not run script components | |||
--nav | Build a navmesh even when the scene declares no navigation (no meta.nav, no navagent). For tools that route the player on any scene, such as an automated playtester | |||
--window | Play mode: open a window and run until Esc. Keyboard, mouse and (later) gamepad feed the same input state POST /input writes; --serve keeps the query API up beside it. Keys: Esc quit, F1 overlays, F5 reload, F9 capture, F10 pause. Needs a build with the window feature | |||
--window-size | <WINDOW_SIZE> | Initial window and internal render size in physical pixels, WxH, each side 64 to 8192. Default: the project's window, else 1280x720 | ||
--viewport | <VIEWPORT> | The offscreen surface for a run without a window, in physical pixels, WxH, each side 64 to 8192. What the UI is laid out at and what POST /capture renders at by default; POST /ui/viewport changes it while the engine runs. Default: the project's window when the manifest declares one, else 640x360. | ||
--aa | <AA> | fxaa | fxaa, off | Anti-aliasing: lightweight FXAA by default; off for comparisons |
--stats | Show FPS and CPU frame diagnostics; F3 toggles while running | |||
--no-hud | Draw the frames (a --record recording, an --out screenshot) without the game's UI and the world labels: video and stills of the world for editing. The UI still runs. Not for a window or a served run, whose captures draw the UI their own way | |||
--preview | Refresh cached /frame.png previews with GPU readback; off by default for clean profiling | |||
--no-vsync | Present without vsync | |||
--capture-dir | <CAPTURE_DIR> | . | Where F9 writes argus-capture-<frame>.png | |
--keys | <KEYS> | Hotkeys pressed for you at rendered frames: 120:F9,180:Esc (Esc, F1, F5, F9, F10). For a scripted test or capture with no one at the keyboard | ||
--title | <TITLE> | The window title for this launch. Default: the project's application.displayName, else Talos — <scene file name>. Never saved | ||
--icon | <ICON> | A PNG to use as the window icon for this launch. Default: the project's application.icon, else the built-in Talos icon. Never saved | ||
--scene | <PATH> | Run this project-relative scene instead of the project's startupScene. Only with a project; never saved | ||
--render | <PROFILE> | The renderer for this launch, standard or hd. Default: the project's render.profile; for a scene file, that of the project folder it is in, else standard. Never saved | ||
--base-dir | <BASE_DIR> | Where script.module and relative asset paths resolve, instead of the scene file's folder. What a test worker running an editor artifact's frozen copy of a scene needs | ||
--font | <FILE> | The TrueType font that draws HUD text and label components. Without it the engine looks at $ARGUS_FONT, then for fixtures/render/fonts/Inter-Regular.ttf at or above the scene's folder — which only exists inside the engine checkout. A scene that declares text and finds no font refuses to load, rather than running with every label silently dropped, so this flag is what a project kept anywhere else uses. --headless draws nothing and needs no font. | ||
--seed | <SEED> | The world seed, set before the first tick, at most 2^53-1 (the P1 contract's limit, and the largest integer a JSON number keeps exactly). Snapshots report it and POST /snapshot restores it | ||
--lod-freeze | <LEVEL> | Draw every asset that has levels of detail (a cooked scan) at this level, whatever the camera: 0 is full detail. For captures and benches that must not depend on distance | ||
--input-overrides | <FILE> | Where the player's own key bindings are kept, as JSON laid over the scene's meta.input. Read at load and rewritten by every ctx.input.rebind, so a remap survives a restart and a relaunch. The file need not exist yet; the first rebind creates it, folder and all. Without the flag the scene plays on its own map and a rebind lasts only as long as the process. The editor's Play passes <project>/.argus/input.json. | ||
--payload-exe | <EXE> | Read the game's files out of this exported executable instead of a folder: what an export's launcher passes, with --payload-id (the payload the launcher read) and --payload-mount (where its unpack would have put them). An executable whose payload cannot be read ends the run with exit code 75, and the launcher unpacks instead | ||
--payload-id | <ID> | |||
--payload-mount | <DIR> | |||
--licence-exe | <EXE> | The export's executable, for its licence check after a full unpack (docs/LICENSING.md): what an export's launcher passes when it does not pass --payload-exe | ||
--licence-activate | <FILE> | Take this activation file for the export's install before the run (an air-gapped site's file from whoever manages its licence) | ||
--licence-audit | <FILE> | Write the export's install audit file here and exit | ||
--save-dir | <DIR> | The folder ctx.save keeps each application's save under, as <DIR>/<application id>/save.json. A project run saves without being asked: the default is $ARGUS_SAVE_DIR, else the user's data folder (%LOCALAPPDATA%\Argus\saves, $XDG_DATA_HOME/argus/saves). A bare scene has no application id and keeps its save in memory unless this flag names a folder, in which case it is saved as the application scene. | ||
--session-id | <SESSION_ID> | Run as a managed session with this id (ses_ + 32 hex; docs/EDITOR.md). Needs --session-kind, implies --serve, and needs a build with the managed feature. A test session is a headless worker and refuses --window; human-play needs it | ||
--session-kind | <SESSION_KIND> | preview, human-play, test | preview, human-play or test | |
--job-id | <JOB_ID> | The job that owns a test session (job_ + 32 hex). Required for test | ||
--project-id | <PROJECT_ID> | The project (a lowercase UUID). A project location fills it from the manifest, and refuses a different one | ||
--artifact-id | <ARTIFACT_ID> | The build artifact this process runs (art_ + 64 hex) | ||
--capabilities | <CAPABILITIES> | What the session holds, comma-separated P1 names (default observe). An API caller presenting the session's nonce gets these, capped by the kind: never more than observe,capture,snapshot-read on a preview or human-play session | ||
--anonymous-capabilities | <ANONYMOUS_CAPABILITIES> | What a caller presenting no identity may use (default observe), never more than the holder | ||
--self-test | <SCENARIO> | Run a self-test scenario in-process and exit: 0 when it passes, 1 when it fails, 2 when it cannot be read. A file, <project>/selftest/<NAME>.json, or the built-in smoke. Renders offscreen (never opens a window) unless --headless; writes self-test.json to the log folder and prints one argus-self-test {json} line on stdout. docs/SELF-TEST.md | ||
--record | <DIR> | Render the scene offline to DIR as frame_00000.png, … and exit, printing one JSON line on stdout. Steps the fixed 60 Hz simulation from tick 0 and takes a frame every 1/--fps simulated seconds, however long each frame takes to draw; the size is --viewport. --frames N is then the number of frames, not a prewarm. docs/API.md, "Recording frames offline" | ||
--fps | <FPS> | 30 | Frames per simulated second for --record, 1 to 240 | |
--seconds | <SECONDS> | Simulated seconds: for a plain run, the time simulated before the first render at the fixed 60 Hz step (--seconds 3 is --frames 180; simulated time, not wall time); for --record, the clip's length (frames = round(seconds × fps)); for --record-data, ticks = round(seconds × 60) | ||
--record-format | <RECORD_FORMAT> | png | png, raw, none | png (default), raw (frame_NNNNN.rgba: RGBA8, top row first, no header), or none: every frame drawn and none read back or written, one frame queued ahead of the GPU (a timing run, with --xr-report) |
--record-until-event | <NAME> | Stop --record after the frame on which a script first emitted this event (ctx.events.emit(name)). ctx.session.quit() always stops it | ||
--supersample | <N> | 1 | Draw each --record frame at N times the viewport and filter it down (1 to 4, default 1): smoother edges and finer detail, at N x N the drawing cost | |
--aspect | <W:H> | The output frame's shape, W:H (9:16, 1:1, 2.39:1), drawn natively at that shape: no letterbox and no crop afterwards. Keeps the --viewport's longer side (the default viewport's without one) and takes the shorter from the aspect, rounded to even pixels: --viewport 1920x1080 --aspect 9:16 is 1080x1920. Beside --record or an --out shot. Each term 1 to 8192, and each side of the frame 64 to 8192 (with --supersample, of the drawn surface too) | ||
--shot-fov-fit | <FIT> | vertical, horizontal, cover | How the camera's field of view meets the frame's shape: vertical (the camera's vertical field of view as authored: today's drawing, and the default), horizontal (its horizontal field of view at the 16:9 reference is kept) or cover (the larger field of view, so the whole 16:9 view the scene was authored for stays in frame). An orthographic lens follows the same rule with its half-height. docs/API.md, "Aspect-aware shots" | |
--warmup-frames | <N> | Draw N frames before --record's frame 0, at the starting tick and not written (default 0, or 120 with --accumulate), so temporal effects, auto exposure and the GI settle first | ||
--accumulate | <N> | 1 | Make each --record frame the mean of N draws of its tick (1 to 256, default 1), in linear light: each draw has its own sub-pixel offset and noise, so edges, shadow filtering and noisy effects come out as a still's, at N times the drawing cost. Warms up 120 frames first unless --warmup-frames says otherwise. A still: --record DIR --frames 1 --accumulate 64 | |
--shots | <FILE> | Play a shot timeline from FILE as the camera, in place of the scene's meta.shots: the same JSON (shots, loop, end, doneEvent), so a camera move kept apart from the scene records the same way. Refused, with the contract's messages, when the scene rejects it | ||
--record-script | <SCENARIO> | Play a self-test scenario (docs/SELF-TEST.md: presses, action and axis holds, waits, in fixed ticks) while --record takes its frames, so a trailer has a player. A file, or <project>/selftest/<NAME>.json. The recording still ends at --seconds/--frames; a step that fails stops the scenario, not the recording, and script in the summary says where | ||
--save-replay | <FILE> | Write every tick's input (plus seed, scene identity and engine version) to FILE as the run plays, in any mode: a window, --serve, --record-script, a plain --frames run. Off, it costs nothing. Play it back with --replay. docs/API.md, "Replays" | ||
--hash-every | <N> | With --save-replay: write the per-system state hashes every N ticks into the file (60, or ARGUS_DESYNC_EVERY; 0 writes none), which a playback and argus replay verify check | ||
--replay | <FILE> | Play a --save-replay file back into the scene, offline and deterministically. Beside --record DIR --fps N --viewport WxH (or --size) it re-renders the session at any resolution; beside --record-data it writes the numbers. The length is the replay's unless --frames/--seconds say otherwise. Refuses (replay-scene-mismatch, replay-engine-mismatch) when the scene or the engine is not the recording's | ||
--replay-camera | <CAMERA> | Draw a --replay through another camera: entity:<id> (from that entity, looking along its -Z) or pose:ex,ey,ez,tx,ty,tz[,fovDegrees]. The simulation is the same either way | ||
--profile-report | <FILE> | After the run's ticks, write the world's counters to FILE and the flight recorder's last frames to FILE.argusprof: what a profiler replay re-run compares. With --frames | ||
--record-data | <FILE> | Write the simulation's numbers to FILE, .csv or .jsonl, and exit: a row every --data-every ticks from tick 0 (tick, simulated time, one column per --data-fields field), plus the events. Headless and deterministic: two identical runs write the same bytes. On its own it steps --frames N ticks or --seconds S (and needs no GPU); with --record it follows the frames. docs/API.md, "Recording data" | ||
--data-fields | <SELECTORS> | What --record-data writes: a comma list of <entity>:<field>, #<tag>:<field> or *:<field>. Fields: position[.i], rotation[.i], scale[.i], worldPosition[.i], body.velocity[.i], body.angularVelocity[.i], body.mass, controller.velocity[.i], controller.grounded, joint.position, joint.velocity, script.state.<path>, data.<name>. Default *:position | ||
--data-every | <N> | 1 | on, auto | A --record-data row every N ticks (tick 0 always). Default 1 --xr-sim[=<PROFILE>] Run the desktop XR simulator: the real XR path with no headset. Both eyes of a headset profile are drawn every frame, at its per-eye size and field of view (the real stereo cost), and the window shows one eye, both, or the game's camera (--xr-view). PROFILE is focus3 (the default; measured), pico4, quest3, index (nominal), WxH@FOV (a symmetric FOV in degrees), or a headset file (.json, docs/status/xr-sim.md). Mouse and keys move the head: F7 toggles head look, Ctrl+Shift+arrows, PageUp and PageDown move it, Ctrl+Shift+Home recenters, F6 cycles the view --xr[=<MODE>] Enter VR on a headset through the installed OpenXR runtime (docs/status/xr-sim.md, "Real headset"). Without a runtime, or with no headset attached or on, the run exits with the reason; --xr=auto runs on the desktop instead, saying why in one line. --window adds a desktop window mirroring the eyes (--xr-view; it never takes focus). --frames N is then the number of headset frames, after which the session ends cleanly; without it the run lasts until the headset's user quits. ARGUS_XR_LOADER names an OpenXR loader, ARGUS_XR_BINDINGS a controller binding file laid over the built-in one |
--xr-view | <VIEW> | left, right, both, spectator, left-16x9 | What the window (and a capture) shows under XR: left (default), right, both side by side, or spectator (the game's own camera, with its screen UI), or left-16x9 (a centred 16:9 crop of the left eye, filling a 16:9 screen with no third render) | |
--xr-scale | <S> | Scale each eye's image, the framing kept; the timing report then measures the scaled size. With --xr-sim (0.1 to 1; default 1, the headset's own size) a cheaper simulation. With --xr (0.1 to 2; default 1) it multiplies the runtime's recommended per-eye size, up to the runtime's largest: under 1 a faster frame, over 1 a sharper one. It replaces the project's render.xr.resolutionScale for this run | ||
--xr-hz | <HZ> | The simulator display's refresh rate the timing report counts missed frames against (default the profile's, 90). --xr-sim only: a headset (--xr) is refused it, as its runtime sets the rate | ||
--xr-report | <FILE> | Write the XR timing report to FILE (JSON) when the run ends: CPU and GPU frame time p50/p95/p99, frames over the budget, and the GPU time of each pass |
Example
argus run <PROJECT_OR_SCENE>