Full per-flag reference for the Godot project's user arguments, passed after --:
tools/godot/.../Godot_v4.7-stable_mono_win64_console.exe --path CSVM res://scenes/Main.tscn -- --plane=player_bhawk
RunGame.ps1 (play) and RunDev.ps1 (dev, with console prompts) forward these verbatim. Godot's
own engine arguments go before the separator instead; the ones this project relies on are in the
last section, Godot engine arguments.
Flight is the default. Any content arg builds a flight unless
--viewer is present: --plane=player_fury flies the Fury and --chapter=C4 flies over C4.
--viewer asks for the static inspection view instead, and is where the damage, livery and mesh
labs live. A bare launch (no content arg) shows the launchscreen. PROJECT_CONTEXT.md carries a
compact table of the day-to-day subset; this page is the long tail.
Every flag below has exactly one bullet under ## Flags, and that bullet is the description of
record. Find the flag here, then read only its bullet, one flag is one line, so this returns the
whole thing. Never read this file whole.
Grep "^- .--collision" docs/cli.md
Names only, deliberately: a gloss here would be a second description of the same flag, and that is
exactly how PROJECT_CONTEXT.md's day-to-day table drifted from this page. One flag, one description.
Modes and content, what gets built
--viewer · --fly · --stunt · --vs · --vs-kills · --vs-time · --vs-lives · --vs-no-respawn · --vs-bots · --vs-bot · --ctf · --zvz · --coop · --freecam · --anim-lab · --menu · --skip-intro · --intro · --chapter · --stage · --node · --plane · --players · --mission · --scenario · --ia · --campaign · --profiles · --scores · --play-anim · --movie · --presentation
Multiplayer, the wire a match flies over
--net-host · --net-join · --net-shape · --net-port-base · --master-server
Placement, where the subject starts and which way it faces
--pos · --direction · --lookat · --fov · --view · --xr-chase · --spawn · --campos · --spawn-at · --spawn-dir
Capture, screenshots and the scripted-run workhorses
--screenshot · --export-gltf · --frames · --shots · --jitter · --no-focus · --no-vsync · --xr-sim
Determinism, pin a run so two runs are byte-identical
--det · --no-det · --seed · --no-pads
Livery and paint
--paint · --paint-color · --paint-decal · --paint-seed · --rof
Weapons, ordnance and damage
--loadout · --rocket · --gun-select · --target · --fire · --fire-rockets · --incoming · --ai · --ai-attack · --ai-damage · --canopy-holes · --ai-targeting · --difficulty · --no-assist · --no-crash-loss · --generators · --zeppelins · --zep · --wake-turrets · --wake-generators · --craters · --infinite-ammo · --ammo · --weapon-lab · --weapon-mount · --weapon-fire · --weapon-cycle · --weapon-click · --weapon-target · --weapon-surface · --weapon-standoff · --weapon-camera · --weapon-test · --damage · --damage-hd · --destroy · --crash
Debug labs, the scripted twin of each interactive lab key
--debug-livery · --debug-mesh · --debug-select · --debug-nodelab · --debug-damage · --debug-ocean · --debug-wake · --debug-names · --debug-fps · --hud-text · --debug-join · --debug-pointer · --debug-marquee · --debug-graphics-switch · --debug-shaders · --debug-scoreboard · --debug-scores · --debug-race-ghost · --xr-tune · --debug-race-end · --debug-wash · --debug-anim-ui · --debug-collision · --debug-dzpaths · --debug-ainets · --debug-targets · --debug-markers · --debug-spectate · --debug-pause · --debug-load · --debug-objective · --collision · --debug-colliders · --debug-classoverlay · --debug-tilegrid · --debug-clutterflag · --hide-alpha · --markers
Dumps and the test harness, report text plus a verdict, then quit
--dump-markers · --dump-weapons · --dump-loadout · --dump-flight · --dump-config · --dump-mips · --dump-ai · --dump-sticks · --dump-tilegrid · --run-tests · --damage-test · --effects-test · --hud-font-test
Logging and profiling
--log · --perf · --gc-types · --debug-finalizers · --debug-mem · --debug-anim · --debug-net · --debug-net-trace · --anim-lod · --hitch-inject
Rendering probes, is this thing drawing at all?
--tex-override · --tex-census · --no-fog · --no-flare · --screen-flare · --no-clutter · --clutter-templates · --cloud-jitter · --no-zone-cull · --sky-zone · --mips · --no-cockpit-pass · --graphics · --shadow-quality · --view-distance · --water-quality · --anti-aliasing · --msaa · --xr-render-scale · --xr-vignette · --xr-quality · --xr-foveation · --shader-warmup · --no-ssao · --no-ssr · --no-glow · --no-soft-shadows · --no-ocean · --dump-ocean-mask
Map-edge continuation, the fold past the map boundary
--map-edge-block · --map-edge-mode
Scripted input, fly a fixed stick input, no hands
--hold · --lever · --yaw · --pitch · --look
Data paths, override where the extraction is read from
--data-root · --synthetic-data · --gamez · --textures · --zrdr · --interp · --sounds · --zip-assets · --hd · --messages
Extraction, build extracted/ from an original install and exit
--extract · --extract-force · --extract-unzip · --extract-allow-missing · --unzbd
Audio
--mute · --volume · --sound-range-scale
Neither of those reaches the player's own mix, and no flag or config key does. The four volume
levels (Master, Music, Effects, Voice) are set on Preferences' AUDIO page, saved in
user://options.json and written on the three category buses beneath Master, so the two gains
multiply rather than compete: --volume=0 silences a repo run whatever the saved levels say, and a
--det run reads none of them. The mix is
docs/menu-presentations.md's Audio section.
Three flag families live in their own sections further down, with the lab they script:
the shared selection (--debug-select), the node lab (--debug-nodelab), the world damage lab
(--debug-damage).
⚠ A new flag adds its index entry and its ## Flags bullet in the same edit. Both are in this
file so they cannot drift apart. PROJECT_CONTEXT.md carries a curated day-to-day subset
whose rows are glosses, never the description of record, a behaviour change edits the bullet
here.
Written exceptions to "one flag, one bullet": --spawn-dir shares --spawn-at's bullet, since
the pair is one mechanism, so Grep the partner's name to find it; --debug-nodelab and
--debug-damage each carry a short opener bullet plus the full behaviour under their lab's own
section further down; --perf carries four further bullets for its other readouts, and
--dump-sticks and --menu one more each. The counts reconcile as 218 index entries, 218 parser
flags and 225 bullet lines.
--viewer(the static inspection view: the parked-plane orbit, or with--chapter=the static world for deterministic weather, fog and edge screenshots. It hosts three labs, always built and needing no extra flag: the damage lab on F19, the livery lab on L and the mesh lab on M. All three start hidden, so an unadorned--viewerscreenshot matches the pre-paint viewer. F19 toggles the damage lab as a whole, slider panel and HUD gauges together; the panel's own checkbox controls the gauges while it is up. P halts the simulation and.advances one frame)--debug-livery[=N](--vieweronly: open the livery panel at launch and, with N, step the pattern N times first, one scripted screenshot then exercises the stepper + repaint + widget sync, not just the layout; same role as--debug-scoreboard/--debug-join)--debug-mesh[=spec](open the mesh lab at launch with its modes preset. The subject is the parked plane in--viewerand the run's selection elsewhere, where it stands in for the M press; the panel is hidden in a--screenshotrun. Comma-separated tokens, unknown ones reported:normals[=corners],color=provenance|direction|winding,wire[=seams|seamsonly],boxes,enginewire,cull=double|single|inverted,source=flat|smooth|negated,headlight,ambient=off,sun=<energy>,dir=x/y/z(slashes; the direction the light travels),cycle=N,force,restore)--collision[=show](build the world's colliders in a mode that otherwise builds none:--freecam,--anim-laband--viewerbuild noStaticBody3Dat all, so what is solid there is unmeasurable without it (WORLD-9).=showalso opens the F20 collider-wireframe overlay, colouring each wireframe by the surface id its body resolves to. The id is per body, not per polygon: the colour is what the engine selects. It prints per-id counts and the on and off transitions separately (WORLD-10). In--viewerit builds colliders but no overlay)--debug-colliders(open the F20 collider-wireframe overlay without forcing the collision build first; the opener that always builds is--collision=show. This is how the "no collision here" notice (WORLD-9) is exercised in--freecam/--anim-lab, which build none on their own; pass--collisionalongside it to populate the overlay there. In a flight mode, or after--collision, the colliders already exist and the overlay just opens against them. Distinct from--debug-collision, which draws the flown plane's own probe, not the world's)--debug-classoverlay(open the F21 colour-by-class overlay at launch, in--freecam/--anim-lab/--fly/--stunt. It tints every world mesh by what it is rather than what it looks like: destructible red, from theDestructibleRegistry.Resolveclimb a weapon hit takes, so a door that only looks breakable reads as scenery; facade pink; clutter green; everything else scenery blue. It is rebuilt on every H press, so a death never tints a freed node, and it is not keyed onSceneBuilder.SurfaceMeta, which answers what a bullet does here. Debug-only: goldens are unaffected)--debug-tilegrid(open the map-edge tile-grid overlay at launch. Flag-only, and built wherever a map-edge continuation exists (--fly,--freecam, a--sky-zoneviewer). It tints every ground tile at 20 % by how it was folded, neutral in-map and one hue per fold parity (copied,x-mirrored,z-mirrored,xz-mirrored); one colour band is one block depth. Ground only. Pair it with--no-fog(SHOT-14). It paints only the tiles the extender accepted, so refused ground shows as unpainted terrain;--dump-tilegridnames the node and the reason)--debug-clutterflag(build the chapter world recoloured by each polygon's decodedno_clutterflag. A polygon carrying the flag is RED, one without it GREEN, and all clutter BLUE. A decoration's own polygons are unflagged, so without it a whole city block reads as clutter-eligible ground. The flag is polygon bit0x800,GameZPolygon.NoClutter(docs/formats/gamez.md). There is no runtime toggle: the recolour is written into the vertex colours at build time. One log line per build carries the census, which counts polygons per built model, not per placement)--hide-alpha=<class>[,<class>…](isolation aid for a draw-order question: build the world without the named transparency classes, so a frame where two of them paint in the wrong order names the pair by elimination. Classes:blend-surfaces,scissor-surfaces,blend-cards,scissor-cards, named apart because a surface and a card take different shaders and different depth modes at the same verdict. Build-time, no runtime toggle: the surface is never committed and the kind's MultiMesh is never made. One log line per build carries the census and what was hidden)--dump-tilegrid[=path](build the chapter world, write the map-edge tile census and quit; the written twin of--debug-tilegrid, and the only place a refused tile appears. JSON to./.scratch/tilegrid_<chapter>.jsonunless a path is given. One row per tile candidate: verdict (Accepted/TooSmall/TooLarge/SkyOrCloud), footprint in metres and in cells, its grid cell and its surface class, plus a per-cell roll-up carryingcoverX/coverZand asuspectflag for a border cell short of ground. Implies--freecam, where the extender it reports on is built)--map-edge-block=N(how many border cells deep the repeated block past the map edge is. Default is per chapter (MapEdgeExtender.DefaultBlockCells): 2 on C1/C2/C4, 1 on C5 and on C1B/C1C/C2B/C3, whose borders carry only water tiles, which fixes them at 1 and makes the depth moot there. An unknown chapter falls back to 1. Clamped to the chapter's grid, at which point the continuation repeats the whole map. ⚠ Do not size this from a video-derived period (docs/verification.mdDET-12))--map-edge-mode=mirror|repeat(defaultrepeat: translate the block, which is what the original does, matching it on C1/C2/C4/C5 with no seam gaps.mirroralternately reflects the block instead, so every seam is a shared mirror plane, and is kept for comparison. No key toggles it. ⚠ Do not read the choice off a frame-derived strip period (docs/verification.mdDET-12). Repetition that shares the map-edge vertex row is deliberately not offered: it is mesh surgery rather than a per-cell transform, and plain repeat shows no step at the shipped block depths)--plane=(a comma-separated list gives one plane per splitscreen player,--plane=player_bhawk,player_fury, and implies that player count unless--players=says otherwise)--rof=(defaultextracted/rof, the extracted UI archive holding the paint patterns;--extractproduces it)--paint=<pattern|random|none>(aircraft livery: a pattern name,random, ornone. Patterns are per aircraft, and naming one the plane lacks logs its actual set and paints decals only;randomdraws from that plane's set. Comma-separated per player like--plane=, the last covering the rest. The default everywhere isplayer_fortune, the only pattern covering all eleven airframes;--paint=noneasks for the bare shipped skins. Instant Action's enemies keep their own militia skins rather than the player militia's colours)--paint-color=R,G,B/R,G,B/R,G,B(override the scheme's three colours, slot 1 body, 2 dark trim, 3 light trim; integer 0–255, fewer than three repeats the last)--paint-decal=nose,tail,wing(override the three decal indices into the chapter archive's 00–49 set: 00–20 squadron logos, 21–49 nose art)--paint-seed=N(seed the random-livery RNG directly, overriding thepaintstream--seed/--detwould derive, pins liveries alone in an otherwise unpinned run)--damage[=part:frac,...](decide whether the damage lab opens at launch; every session with an aircraft builds one, reachable on F19. On its own it implies--viewerand drives the parked plane, whose per-part HP sliders play the torn-skin flips, panel fires and nose smoke. With an explicit--fly/--stuntit stays in flight, where the sliders write the aircraft's real per-part HP. Presets take a fraction of 0-1 or a percent above 1 (--damage=leftwing:0.25,nose:40). Ignored by--freecam/--anim-lab, which have their own world damage lab. Splitscreen: P1-only)--chapter[=C1](which chapter world to build, flown by default, or rendered statically with--viewer; takesC1/C1B/C1C/C2/C2B/C3/C4/C5, drives the default gamez to<chapter>/gamez.zipand textures to<chapter>/texture.zip; the world node name is alwaysworld1)--stage=empty(replace the chapter world with a synthetic test stage: a flat, collidable 20 km ground plane under a code-drawn 100 m grid, the default sky and sun, the plane over the grid origin, and under--vsevery seat on the stage's 600 m ring or its team's own block. No chapter gamez, mission, clutter, animation program, weather, skydome or edge extender is built unless--zep=grafts one in. Without that gamez, rockets fly without their FLYOUT body, pylons carry no mounted ordnance, and an impact draws the spark fallback. An unknown stage name is reported, not guessed)--node=<cs_name>(in--viewer, the default for this flag, or--anim-lab, build only the named gamez subtree out of--chapter='s world, with the camera auto-framed on it. Matching is on the sourcecs_namemeta, never the sanitized Godot node name. Multiple matches are normal: the first is built, and the ambiguity is a warning. A name matching nothing lists the candidates containing it and quits cleanly (exit 0). The mission's interp script and the clutter are skipped, but the animation program still loads and binds.--pos/--direction/--lookatoverride the framing)--fly(the default: free flight, a chapter world with skydome and plane, on the original's own keymap (docs/controls.md): the arrows pitch and roll,,/.rudder,=/-throttle and the digits set it outright, Backspace respawns, Esc (or gamepad Start) halts the sim and opens the pause board's Resume, Restart and Exit menu, where the chase camera free-orbits the frozen plane, and.advances one sim frame while halted. It defaults to C1; combine it with--chapter=for another. It spawns from the mission'sia.json, so see--mission/--scenario/--spawn)--stunt(--flyplus the mission's Danger Zones (ia.jsondzones) as fly-through objectives, spawning from thestunt_flyinglist, which it forces unless--scenario=is explicit. The objective marker HUD draws the marker, edge arrow and bearing with the run timer; completing every zone raises the results scoreboard, which halts the sim (R restarts). CLI only: the launchscreen's stunt row attaches an Instant Action mission instead. With--players=Nit is a 5-minute time attack ranked by best run on the board it ends on; bests record under the solo key)--vs("Dogfight" mode: splitscreen free-for-all deathmatch,--flyplus thedogfight_acespawn list unless--scenario=is explicit. It beats--stuntby fixed precedence rather than last-flag-wins, dropping stunt mode with a warning when both are given.--vs-kills=/--vs-time=set the match rules. The menu needs two pilots, join board bots included; this flag only warns when--players=1has no--vs-bots=opponent. The opening spawn is the list walk; a downed seat respawns on a rotated list point clear of the living field and its killer)--vs-kills=N(with--vs, the kill target that ends a match early once a player reaches it. Default 5;0disables the kill limit, so the match runs to--vs-time=alone. A menu Dogfight opens on the lobby's own rules instead, and spelling this flag out beats its Score box)--vs-time=N(with--vs, the match time limit in minutes. Default 5;0disables the time limit, so the match runs to--vs-kills=alone. Both limits at0is a match with no end condition, accepted, not guarded against, since the mode's win/lose flow is a later item. A menu Dogfight opens on the lobby's 10 minutes instead, and spelling this flag out beats its Time box, each flag beating only the rule it names)--vs-lives=N(with--vs, how many deaths a pilot has before it stays down and watches the rest of the match, on every machine. Default0, no limit. The Multiplayer Lobby's Limited Lives box carries the same setting, and spelling this flag out beats it)--vs-no-respawn(with--vs, a downed pilot stays on the crash camera until it presses the respawn key itself, rather than coming back on the timer. The Multiplayer Lobby's Auto Respawn box unchecked is the same rule, and spelling this flag out beats the box)--vs-bots=N(with--vsor--stunt, whose bots race the course: seat N bots after this machine's panes, or with--net-hostafter the guests: a Random stock plane, veteran, no team, and a callsign drawn from the pilot names. This machine flies them and a host's roster carries them, so a guest passes no flag; one passed there, or beside a local--ctfor--zvz, is ignored with a warning. Past 16 seats the field is cut, warned, and guests that fill it leave the last bots out.--vs-bot=entries take the first places. A menu launch seats its join board's bots)--vs-bot=<plane>[:skill=<tier>][:team=<n>][:name=<callsign>][,...](with--vsor--stunt, local or--net-host, one bot per entry, ahead of--vs-bots='s.<plane>is a stock node such asplayer_fury, orrandomor empty for Random;skill=takes--difficulty='s words or 0-2, default veteran;team=a lobby team 0-16, the command line's pilots flying on 0;name=the callsign, cut to 12 characters. A part it cannot read keeps its default with a warning, and the last flag wins)--ctf,--ctf=home(with--vsover the wire, fly the match as Capture the Flag: each lobby team'scs_flag_nflag is live, taken, carried, dropped and brought home, the host deciding and scoring. Pair with--mission=MP2, the one mission that lays the flags out.homeadds the host's option that an enemy flag scores only while the carrier's own flag is at home. A host's bots fly for the flags. The Multiplayer Lobby's Capture the Flag type sets both. Ignored without--vs, with a warning)--zvz(with--vsover the wire, fly the match as Zeppelin vs Zeppelin: the zeppelins run, the first two lobby teams in seat order each fly one hull, the host scores every gas bag and cannon downed and the first hull lost ends the match for the other side. Pair with--mission=MP3, the mission that lays outmultiplayer1zepandmultiplayer2zep. The Multiplayer Lobby's Zeppelin vs Zeppelin type sets it. Ignored without--vsor beside--ctf, with a warning)--net-host[=port],--net-host=address:port(open a listen server and fly this session as its host, the scripted twin of the menu's multiplayer door over the same socket. A bare flag takes port 47500 (or--net-port-base) on IPv4's wildcard, the stable global IPv6 address and::1, a number sets the port, andaddress:portbinds that one address, IPv6 in brackets. ⚠ A scripted run names127.0.0.1: a wildcard bind is what puts a Windows firewall dialog on somebody's screen. A host waits 30 s for its first guest, then closes its socket and flies alone)--net-join=address[:port](join the match at that address and fly this session as a guest, the port defaulting to 47500 (or--net-port-base) and an IPv6 address written in brackets. The launch holds at the load screen until the link stands or 30 seconds pass, because a guest with no host has no seats to fly. The roster it flies is the host's, so the plane this end picked is a request, not a promise)--net-shape=latency,jitter,loss,--net-shape=soak50|soak100|soak200(shape this end's--net-joinor--net-hostsocket both ways under the loopback's model, in milliseconds, milliseconds and per cent, or the soak's three cells by name. Only unreliable payloads are lost. The shaping adds to the real link's own delay, plus up to a frame each way, since a payload moves on a step. The other end needs nothing; the menu door and WebRTC are never shaped. Logged at launch and named in--debug-net-trace. A bad value is refused with a warning)--net-port-base=N(this process's game port N and LAN discovery port N+1, in place of the shipped 47500 and 47501: the door's port row starts on N, the LAN search asks and answers on N+1, and a bare--net-hostor--net-jointakes N. N lies in [1024, 65436], else a warning keeps the shipped pair.RunTests.ps1hands every engine shard its own, and a suite that opens a socket stays inside the 100 ports from N up (Testing/SuitePorts.cs). A player never needs it)--master-server=url(the master server the menu's multiplayer door lists games on and joins by code through,https://host[/path]or a bare host name, which takes https. It beats the hand-setnetMasterServerkey inoptions.json, which beatsMasterAddress.Default; an empty value turns it off, an unreadable one with a warning. Off, LAN and direct play are unchanged.--dettakes neither key nor default. Hosting for and joining internet guests also needs the WebRTC library (InstallWebRtc.ps1);server/README.mdsets up the server.--net-host/--net-joinnever use it)--coop(plain splitscreen free flight defaults to FFA, every human on their own team (AimAssist.TeamOfPilot), so aim assist, world turrets and AI gunners treat the other humans as hostile.--coopopts a plain--fly/--stuntsession into one shared human team instead, the same team Instant Action puts its wingmen on (AimAssist.PlayerTeam). Has no effect with--vs, Dogfight's FFA is explicit and outranks it, logged as a warning if both are given)--freecam(spectator mode: the live chapter world with no aircraft at all, seen from a free-flying camera. RMB looks, WASD and Q/E move, Shift and Ctrl scale the speed, the wheel sets the base. There is no collision. It starts at the mission's spawn position, which--pos=/--direction=override. P halts the simulation and.advances one frame. Left-click selects, PgUp/PgDn walk the ancestor ladder, M opens the mesh lab and F20 the collider wireframes. Wins over--fly/--stunt/--viewer/--damage)--anim-lab(the animation debugger: the chapter world as a quiet stage (no ON_STARTUP defs, no startanims) under a deterministic fixed-dt clock. The camera is the freecam, and clicking an object locks the camera onto it. Transport is an on-screen panel with P pause,.step, R restart and F the def picker; M and F20 work here too. The picker lists every def; the timeline draws authored start times against the ticks the runtime fired. The lab UI is hidden in a--screenshotrun unless--debug-anim-uiforces it. Wins over the other modes)--play-anim=<name>(implies--anim-lab: resolve the def(s) carrying that ANIMATION_NAME and play them at launch, exactly the way bootstrap pass 3 starts a startanim, anchored defs once per anchor, unanchored ones globally resolved, and auto-frame the orbit camera on the played def's anchor (fallback: its first resolved target node;--pos/--directionsuppress the auto-frame). An unknown name logs and leaves the stage quiet)--seed=N(the session's master seed: every random draw comes from a named subsystem stream derived from it assplitmix64(master ^ fnv1a(name)). Default 1 under--det,--anim-laband--effects-test, drawn from the clock otherwise, so a bare--flygets a random spawn, liveries and spread; the resolved value prints asrng: master seed N, and passing it back replays the run. An unpinned session advances its master per flight, so flying again is a new draw. Weather zones, wave composition and terrain placement do not vary.--paint-seed=Noverrides the paint stream alone)--debug-anim-ui(implies--anim-lab: force the lab's def picker + timeline visible in a scripted--screenshot, the timeline-verification path, since the whole lab UI is otherwise hidden there to keep shots byte-identical; the same house convention as--debug-livery/--debug-scoreboard)--det(the determinism bundle: a fixed-dt sim clock, master seed 1,--spawn=0, pinned liveries,--no-padsand--jitter=0. The clock steps 1/60 s per rendered frame, so the sim runs at the refresh over 60: a 120 Hz screen doubles a cheap stage. Shader time is clock-driven too, so pixel output is a function of frame count;config.jsonoverrides and every saved option are dropped (DET-8), so no display setting reaches a golden. Each pin is overridable;[core] det ... via=names what won.--screenshot=,--dump-*and the--*-testprobes imply it;--no-detopts out)--no-det(opt out of the implied bundle, the one way to ask for wall-clock behaviour whatever else is on the command line: it beats both the implication (--screenshot, the--dump-*reports,--damage-test) and an explicit--det, so--det --no-detruns on the wall clock. Use it to measure what--dethides: frame-rate-dependent behaviour, live randomness, the same-build noise floor. It announces itself as[core] no-det: --screenshot would run deterministically ...and prints nothing at all when there was no implication to cancel)--no-pads(ignore every gamepad and every SDL2 flight stick, which is then never loaded, debug/verification aid: a connected pad with stick drift steers the free camera and nudges the flight model, quietly making a scripted screenshot non-deterministic; SDL's own hints don't disable pads in Godot 4.7, so this is our own switch. Part of the--detbundle, so a scripted run already has it)--perf(every 60 frames:[perf] window sim_frame= frames= wall_ms= fps= frame_ms= script_ms= proc_ms= proc_max_ms= proc_passes= ai_ms= ai_planes= render_cpu_ms= setup_ms= gpu_ms= physics_ms= phys_tick_ms= phys_tick_max_ms= phys_hz= phys_engine_ms= defer_ms= draw_ms= idle_ms= draws= prims= nodes= mem_mb= max_ms= p95_ms= sim_ms= proc_sites_ms=. Means but for*_max_ms/counts;phys_*empty under--det. Readproc_ms,ai_ms,render_cpu_ms,gpu_ms, counts, notfps/script_ms/physics_ms(PERF-1, PERF-2). Also[perf] startup)--perf's frame split:sim_mssplits the tick by phase andproc_sites_msthe pass by consumer, each slotmean/max.phys_engine_ms(the flush and physics step after each tick),defer_ms(the end-of-frame flush, every_Drawin it),draw_ms(the rendering server's frame and present) andidle_msare per frame, so they,proc_msand ticks per frame timesphys_tick_mssum toframe_ms.setup_msis the instance update insidedraw_msthatrender_cpu_msleaves out (PERF-40)--perf's GC readout, one[perf] gc up_s= win_s= pause_ms= pause_per_s_ms= gc0= gc1= gc2= fin= fin_per_s= alloc_mb_s= heap_mb=line per ten wall seconds (GcTrace).finis how many FINALIZABLE objects died, which is what the pause tracks;up_sis process uptime, so drop the windows under about 50 s, which are the world build settling. Judge a change onfin_per_sandpause_per_s_ms, never on the per-collection pause (PERF-19, PERF-20)--perf's per-phase allocation row, one[perf] alloc sim_frame= sim_alloc_b=line beside each window, the same session-simulation phasessim_ms=names in allocated BYTES,mean/maxper TICK (SimPhaseCost). It answers the question the millisecond row cannot: a GC pause lands in whichever phase happens to be open (PERF-34), so the phase that reads expensive is rarely the one feeding the collector. Read it with[perf] gc'salloc_mb_s, which is the whole process including the_Processpass, and expect a settled tick's phases to sum to a few tens of KB--perf's spyglass line, one[perf] spyglass sim_frame= discs= disc_draws= disc_shadow_draws= disc_prims= disc_gpu_ms=line per window in which a disc rendered (SpyglassView.Census): mean live discs and their draws, primitives and GPU time per frame, read on the render thread (PERF-43).gpu_msleaves the discs out anddraws/primsfold them in (PERF-47). Under Enhanceddisc_shadow_drawsreads 0 (a shadowless sun copy), anddisc_primsstill counts the ocean grid the disc submits and collapses (SplitScreen.FlatSeaLayer), so readdisc_gpu_msfor cost--gc-types(implies--perf; adds one[perf] gc-types win_s= samples= per_s= top=Type:count,...line per GC window, the types the runtime's allocation sampler saw most. One sample per ~100 KB allocated, so the tally is a share of BYTES: a small wrapper type high on the list is made in very large numbers, which is howfin_per_sis traced to the call making the wrappers. The listener's own event objects (MoreEventInfo,EventWrittenEventArgs, boxed payload) head every list and inflatealloc_mb_s, so read past them and never judge allocation on such a run)--debug-finalizers(with--run-tests: each suite runs with the .NET finalizer thread parked and a collection forced every 20 ms, then the queue is drained before the next suite, and a[test] finalizer gate suite= held= collections= handle_errors=line follows the suite's verdict. A Godot wrapper whose object was reached natively after the wrapper died logsHandle is not initializedfrom that drain, so the error lands beside the suite that dropped the wrapper instead of wherever the finalizer thread happened to run. Slow on world-building suites;docs/verification.mdINSTR-99)--debug-mem(the process's memory split by holder,Utils/MemoryCensus.cs, terms in MB: with--run-testsa[test] mem after=<n>/<total> suite=line before the first suite and after each suite; in any other run a[perf] mem frame=line per wall second; in both a[perf] mem exitline at an ordinary quit.peak_priv_mbis the process's peak private bytes;tex_mb/buf_mbmove under--run-testsonly after a drawn frame; the harness'slive=counts shaders still cached. What each holder is and what each kind of launch holds:analysis/shard-memory/FINDINGS.md)--no-vsync(a measurement flag, not a display one: it uncaps the frame loop (vsync disabled,Engine.MaxFps0) so--perf's frame timings stop sitting pinned at the refresh rate. Safe with--det: that clock advances one sim step per rendered frame, so the simulation is identical and only the wall time changes. Precedence: this flag, then the savedvsyncoption (the VIDEO page's row, which can also name a frame cap), then thedisplay.vsyncconfig key (trueturns it on), then off, uncapped.--detreads no saved option; the[perf] vsyncline names the winner)--debug-anim(log every live animation motion's target node, world position and rotation once a second, rotation because a spinning prop (OBJECT_MOTION) turns in place and a position-only line reads identically whether or not it runs. It also prints eachIf/Elseifcondition on its first evaluation and thereafter only when its verdict flips, and every ambientSOUND_NODEemitter's host, position, distance, range and playing state. Thedistcolumn is the range to the nearest of the session's audio listeners, one per pane, and names it; that is a range, not a loudness)--debug-net(a network match's desync counters once a wall second: the session's own send and receive counts, state and fire samples dropped as sequence gaps, late arrivals, reliable events out of their causal order, and every remote aeroplane's buffer reads by feed with its extrapolation error; a guest adds its clock offset onto host time, its snaps, the round trip and its clock questions answered. Logged undercoreand shown in the top-left corner while a session holds a wire; nothing without one)--debug-net-trace(--debug-net, plus onecoredebug line per simulation step: the step count, the wall clock, the session and match clocks, a guest's clock offset, and every seat's position markedownorcopy. Two machines' logs laid over each other on the wall clock give the position error of each copy against its owner's own path, the soak's measure on a real link;analysis/net-real-link/runs a two-machine pair and reads its logs. About 10 KB a second of log per machine)--log=<spec>(console log filter: a comma list ofcat,cat:level,*,*:level, or a barelevel, over the nine categoriesanim world flight weapons sound perf test ui coreand the four levelserror warn info debug. A bare category means debug, a bare level sets every category; the default isinfo, and warnings and errors are never suppressible. It moves the console threshold only: everyLogline at every level also goes to.scratch/logs/<mode>-<stamp>.log(logs\in an exported build), line-flushed.--debug-animimplies--log=anim:debug,sound:debug)--anim-lod=N(our answer to the data'sANIMATION_LODcondition, a quality setting, not a fact about the world. Default 2 = the reader'sHIGH, the only tier anything in this install asks for, so every LOD-gated branch runs (the refinery/dock/lighthouse light sequences, the muzzle bursts, the wing-light blinks). Lower it purely to A/B what the original hid on slow hardware)--hitch-inject=[alloc:]<ms>[@frame](inject a synthetic stall of known magnitude, soHitchMonitorhas something deterministic to verify against. It fires once, on the stated frame inHitchMonitor.FrameCount's own space, never the sim frame, since the injector has to work with no session built at all; a bare<ms>fires at frame 300. The default form busy-waits; thealloc:prefix burns the same wall time allocating and discarding 4 KB buffers, the only way to move the GC columns on demand. The frame must clear the grace window in wall time, not frame count (PERF-12))--debug-dzpaths(build the danger-zone route/gate geometry the world skips; debug inspection only, never in the original. The material-matched gate pair is green then red at 50% transparency; the route is an open white line strip)--debug-ainets[=name,...](open the AI patrol-net overlay at launch: the chapter'sneindexwaypoint graphs (docs/formats/ai-nets.md), with edges drawn as the explicit edge list and never as an assumed loop, since the graph branches. While it is up it also draws one live leash per AI aircraft, from the plane to its follower'sCurrentTarget, so a follower that has stopped advancing shows as a leash that stops changing. Bare draws every net, a comma-separated value only those names. F13 toggles it in any chapter world)--debug-scoreboard(with--stunt, force-complete the run on the first frame with synthetic splits so the results scoreboard renders immediately, for a deterministic--screenshot. A splitscreen race's window closes at once, so its staggered forced finishes run as the final run and the last raises the board. With--vsit fires one scripted, attributed kill on the first sim step, P1 downing P2 through the realCrash/Downedpath rather than a synthetic score, so the shot has a real K/D and kill line; with--vs-kills=1that kill also completes the match)--debug-scores(every local seat reads Display Scores as held for the whole run, the scripted twin of holdingTab, so a--screenshotof a split screen or network stunt race or Dogfight shows the held scores in each pane with nobody at the controls, in the original's HUD text. A mode that keeps no scores shows nothing)--debug-race-ghost(each local seat's own aircraft draws as a race ghost to its own cameras: built with the ghost's shaders and stamped with the layer every camera draws, so one seat in--view=chaseshows the full ghost's dither at the chase distance with nobody else flying. A capture aid for the ghost's look, flat or under--xr-sim, where a race arms the ghost only between its pilots; it makes no race and changes nothing else)--xr-tune(the VR cockpit tuning lab, a headset or--xr-simflight only: the right grip held, the right controller nudges the flown plane's interior scale and seated eye offset live, saves them intoCSVM/data/vr_cockpits.jsonon disk and steps to the next plane by an airframe swap; F22 to F24 are the keyboard's twin. A readout on the HUD panel, anxr tune:log line per change. A flat launch ignores it with a warning. Controls:docs/controls.md;Flight/Hud/XrCockpitTuner.cs)--debug-race-end=host|guest(with--stunt --players=N --debug-scoreboard: the split screen race's board posed as a network race's,hostoffering Restart and Lobby,guestreading "Waiting for the host" over Photo Mode and Leave, with player 2 marked left once its first run counts, so a--screenshotshows a left pilot's row in either presentation. A capture aid: a network race takes its roles from the wire and ignores it)--debug-pause[=frame](open the pause board at that sim frame, the scripted twin of the Start press, so a--screenshotcaptures the pause screen with nobody at the controls; bare is frame 1. Player 0 owns the pause, as a solo press would.--frames=counts rendered frames and the board halts only the sim, so pass a--frames=comfortably past the pause frame for the shot to land. A campaign session draws its objectives readout there, so this is how that readout is captured, and a frame late enough for the mission to have run is what lets the shot show a completion the sim has reached)--debug-load[=dir](stand the real load screen over a CLI launch, deferred build and all, the way a menu launch does, and write one PNG per presented pump frame intodir; bare shows the screen and photographs nothing. A CLI launch otherwise builds with no screen over it, so this is the only way to watch the bar fill with nobody at the menu, and the shots are read back off the GPU from inside the build, which nothing yields during. The load screen's own log line lists every step the build reported against its wall clock, with a-on the ones no frame was drawn for)--debug-objective=N(campaign only: wake objective N and drive every node itsINACTIVEnconditions name inactive, at session build. It is the scripted twin of flying whatever completes that objective: the graph then completes it off its own conditions on the first step, so the readout's mark comes from the real completion path rather than being faked into the display. The build summary saysforced OBJECTIVEN, or(not armed here)when the mission arms no such number. Pair it with--debug-pause=for a shot of a marked objectives line)--debug-wash=N(address two scripted victim-routed screen washes to viewer N, 1-based, throughScreenFlash.PlayBlend: red at weight 1 for 5 s on the first sim frame, then white at weight 0.5 for 5 s two seconds in, so the second lands on the first and the blend is on screen as well as the routing. In--coop --players=2,--debug-wash=2washes pane 2 and leaves pane 1 untouched; an N no pane answers to paints nothing. It fires on sim time in every clock mode, so a--det --screenshotat a chosen frame catches the attack, the sustain or the release.)--debug-markers(mark every live aircraft at once on the targeting HUD, alongside your own selected target's marker: red for a hostile team, blue for your own, each carrying the full identity string (TargetHud.DebugTag): type, slant range, health and armour as separate whole percentages, and the AI mode. Health, armour and mode are omitted rather than defaulted when the source carries no figure. It reads the projectile pool's live-aircraft roster, so a spawn appears and a downed plane drops. Your own aircraft is never marked. F16 toggles it in flight, on every pane at once.)--debug-spectate(build the session exactly as it would be flown, then take every human out of it: each player's aircraft is pinned where it spawned and goes inert (undrawn, uncollidable and not a candidate in any AI scan, so nothing pursues you), and the pane's camera becomes theSpectatorCamera, parked at the spawn and following the first AI aircraft until a move input releases it. It runs after the rigs are built, so spawn placement still reads the player's real position. ⚠ The mission still runs its own end conditions, so one whose enemies have nobody to shoot never resolves)--debug-targets(switch the targeting overlay on at launch: one line from every turret and AI gunner to the target it has actually acquired, read off that gunner's own live state and never re-derived. Red is firing this tick, amber tracking with a gate that will pass on its own, grey held by a gate that will not. The HUD counts the four states, then per shooter its gate, what it is aiming at and the range, aircraft before emplacements and a count of any left out. Depth test is off, since the interesting line runs into a hull. The sight lines draw in every pane, the roll-call once)--debug-names[=meshes|all](switch the node-name labels on at launch, available in both--viewerand flight and reachable this way alone, since the labels carry no key;meshes(default) labels only nodes that draw something,allincludes the empty group/pivot nodes. Splitscreen: the nearest/de-clutter selection reads P1's camera alone, the labels it picks are P1's view of the world, but the label nodes themselves are world-space and render in every pane)--debug-fps[=compact|full](switch the frame-cost readout on at launch, in every mode including the launchscreen: frames per second, the current frame's wall cost and the worst recent frame, a peak that spikes and decays over a few seconds so a hitch you felt is still readable a moment later.compact, the default, is that trio;fullparses and cycles but renders the same panel. It is fed the same rawStopwatchcostHitchMonitorticks on, never Godot'sdelta. Off by default, and drawn once for the window rather than per splitscreen pane, so the goldens are unaffected)--debug-select[=x,y[,up]](--freecam/--anim-labonly, the scripted twin of clicking an object and pressing PgUp. On the first frame it casts the same pick ray a click would, at screen positionx,y(default the middle of the viewport), then walksuprungs toward the world root. In any other mode it warns and is ignored. The report goes to theuilog category and is the whole ladder, oneselect rung=...line per rung with the current one starred. Pin the camera with--pos/--directionfirst: a screen-position pick is meaningless without the pose it was taken at)--debug-nodelab[=spec](--freecam/--anim-labonly, open the node lab (N) at launch and dump its readouts to theuilog category. Tokens:deps,dest,open,node=<cs_name>; full behaviour under "The node lab" below)--debug-damage[=script](--freecam/--anim-labonly, open the world damage lab (F19) at launch and run an ordered damage script against the selected destructible, logging each step to theuilog category. Steps:node=<cs_name>,pool=<n>,hp=<value>,kill,reset,tick=<seconds>,open. Forces the collision build on so the kill's collider census is real; full behaviour under "The world damage lab" below)--debug-ocean[=spec](--freecamonly, the scripted twin of the ocean lab (Shift+F1): apply<field>:<value>overrides over the chapter's saved sea for this launch, so a--screenshotshows a setting nobody saved;openshows the panel. Field names, ranges and the fold limit areEffects/SeaState.cs'sFields; values clamp, unknown tokens are reported. The lab's Save writes the chapter's entry inCSVM/data/ocean_seas.jsonfrom the source tree. Example:--debug-ocean=height:1.4,length:1.5,open)--debug-wake=<speed>[,<turn>](Enhanced at water quality waves: the wave ocean sails the first wake ship on the water along its own -Z at<speed>m/s, turning<turn>degrees a second, from where it stands, on the sim clock, so a--screenshotshows the procedural wake at a chosen speed and turn. Only the hull node moves: lights and smoke an animation carries stay on its path. Logged as[world] --debug-wake:; a malformed value warns and is dropped)--markers(implies--viewer: open the marker overlay at launch, the firepoint, pylon and target gizmos on the parked aircraft. Firepoints draw orange, firepoints sharing a mount magenta, pylons cyan and the aimtargetgreen. Every gizmo dot shows; the labels de-clutter nearest-first. Toggle it in any--viewer --planesession with K, or combine it with--screenshot. Only the parked plane carries a marker rig, so a--viewer --chapterworld has none, and--viewerforces--players=1, so the overlay is not reachable in splitscreen)--dump-markers[=plane](implies--det; print each player airframe's marker rig to stdout and./.scratch/markers_dump.txt, then quit. It needs no world or camera, so--headlessmakes it windowless. Each block lists everyfirepoint*/pylon*/targetwith its plane-frame position (nose −Z, right +X, up +Y), a firepoint's mirror pair and any co-located mounts. Thedocs/formats/markers.mdtables regenerate from it, and themarkers-rigsuite asserts the same report. The optional value filters to one airframe by model node or display name; an unmatched value lists the names)--dump-weapons[=id|name](implies--det; print all 48BALLISTICSdefs ofweapons.json(WeaponDefs) to stdout and./.scratch/weapons_dump.txt, then quit. Each block gives the id,NAME, theDESCdisplay name resolved throughmessages.json, the ballistics, damage and allotment numbers, the class flags and theFIRE/FLYOUT/IMPACTbindings. A clean run reports no unhandled keys, the tripwire for data growing a key the reader has not learned;--run-tests=weapons-defsasserts it and the 48 count. Optional value filters by id orNAMEsubstring)--dump-loadout[=plane](implies--det; for each plane instock_loadouts.json, build its model and bind the stock loadout (Loadout), reporting the resolved gun groups, the inert turret slots and the hardpoints (count × per-pylonCLUSTER_SIZE= total), to stdout and./.scratch/loadout_dump.txt, then quit. A clean run binds all 11 with every marker resolved; a marker that does not resolve prints a loud!!line naming plane, slot and marker rather than being skipped.--run-tests=loadout-bindasserts the same verdict. Optional value filters by def or model substring)--loadout=<def>(bind the named loadout def instead of the plane's own, a testing override. In flight the flown plane carries that def's guns and hardpoints, whose markers must resolve on the flown model. It takes a menu-chosen fit away entirely rather than merging with it, so the flag names the fit outright. With--dump-loadoutit binds every dumped plane's model to that def, which is how the missing-marker error is exercised:--dump-loadout=Kestrel --loadout=pbloodhawkbinds a loadout wantingfirepoint8to an airframe with seven firepoints and prints the loud error)--dump-flight[=plane|=all](implies--det; step a throwawayFlightModel, needing no world or scene, through sixteen manoeuvres and print each one's number beside the value it is judged against, to stdout and./.scratch/flight_dump.txt, then quit. ⚠ Thetargetcolumn is never footage. Five rows carry a decoded target and the other eleven show(not asserted); a filmed figure disagreeing with a traced mechanism is named in the row as discarded and gates nothing (docs/org/flightModel.md, "Parity ledger").--dump-flight=allflies all eleven stock airframes in one run)--dump-config(implies--det; exercise the Config-wired modules once (TuningWarmup,src/Launch/TuningWarmup.cs), then write a fully-populated template of every tunable key with its in-code default, nested by module block, to./.scratch/config.dump.json, and quit. Copy that toCSVM/config.json(git-ignored) and edit only the values you want to override; every other key falls through to itsconst. A key in the file matching no tunable is warned about loudly, as is a queried key missing from a loaded file. Deleting the file restores pure-default behaviour)--dump-mips[=name](implies--det; for every base texture in the chapter's archive shipping an authored_1/_2sibling, build the chain throughTextureArchive.BuildMippedand print each level's size, mean luminance and share of pixels above luminance 128, beside the authored artwork's own numbers and whether the installed level is that artwork. The header names the chapter's authored mip LOD bias and the texel density each level is first read at under it. Writes to stdout and./.scratch/mips_dump.txt, then quits. Run it once per--mips=policy)--dump-ai[=chapter](implies--det; report five AI data families read off the extraction (Probes.Ai, no world and no scene): patrol nets,aivvehicle rosters,ai.zrdturrets, zeppelins and generators (docs/formats/ai-nets.mdand its neighbours). With no value it walks every chapter and mission directory under the data root; a chapter value restricts the nets,aiv, zeppelin and generator half, whileai.zrd's turrets are one shared file always reported in full. Writes to./.scratch/ai_dump.txt, then quits, exiting nonzero on a parse failure or an unknown chapter)--dump-sticks(does not imply--det, whose--no-padswould empty the Godot roster the gap-filler subtracts; load SDL2 (SDL2.dll, orlibSDL2-2.0.so.0on Linux), log Godot's pad models, the stick roster (name, model, GUID, axis/button/hat counts) and each stick's resting axes, held buttons and hats, then quit. Axes print corrected by the model's polarity quirks, named on the line (quirks=[axis 5 flipped]). Exits nonzero only when no SDL2 library loads. Under--no-padsit printsreads blockedinstead of the readings. Run it throughRunProbe.ps1)--dump-sticks=<seconds>(the--dump-sticksreport, then a watch of 1 to 120 seconds that logssticks watch:lines: an axis each time it travels 0.25 from its last logged value, a button on press and release, a hat on every change. Move one control at a time to learn its number, for example twist the grip to find the yaw axis. Numbers are 0-based, as profile files write them; screens show one higher. SDL2 reads the sticks with the window hidden, soRunProbe.ps1works for it too)--fire(hold the gun trigger down for the flown plane(s), the scripted-run equivalent of holding Space, as--holdis for flight input. Combine with--hold/--screenshotfor deterministic firing captures; every player fires. In interactive flight the trigger is Space or gamepad B)--fire-rockets(hold the rocket trigger down for the flown plane(s), auto-repeats a launch at the rocket'sFIRE_RATEcooldown (1 s), unlike a human pull which is one rocket per press. In interactive flight the rocket trigger is F or gamepad A; one rocket per pull, drawn from the next armed pylon round-robin)--gun-select=N(initial gun group, 0-based;0= the first group, the default. Only one gun group fires at a time, a headless testing hook so a scripted run fires one group in isolation. Interactively the gun selector cycles with F3/F4 or gamepad D-pad Right (tapped forward, held back), the hardpoint/ordnance selector with F5/F6 or gamepad D-pad Left)--target=<what>(the initial target selection:nearest,crosshair,next,none, or a name to pin. The flag reaches only a state the pilot could reach:nearestis the head of the cycle, not the nearest thing in space;crosshairis the 15-degree nose-cone scan and reaches allies;nonestays cleared. A name matches pool entries case-insensitively, a plane's node name (ai1_player_fury) or a zeppelin sub-part's; no match warns with what is selectable. Applied once per pane, on the first frame its pool is filled, then spent. Keys T/Y/U/I/O)--incoming[=metres[,wep_id]](the incoming-fire test rig: a phantom shooter 120 m on every player's six walks a burst up the tailpipe, four rounds a second, under a shooter identity no player holds, so both cues are reachable in single player. It fires the target's own gun, or the named weapon. The first rounds are absorbed by the shippedwarning_shot_*shield and soundbullet_warning_sg; two seconds of them saturate it, and rounds then damage and ringbullet_hit_sg. The metres offset the burst sideways, alternating sides (default 0, on the airframe); a wide offset hits nothing)--ai=<plane>[:<net>][:accent=<id>][:def=<vehicle def>][:team=<id>][:n=<count>][:pos=x/y/z][,...](spawn AI-piloted aircraft.n=makes an entry a squadron;team=is the only way two share a side, since a plane naming none is banded alone and fights every other. Netless it sits 250 m ahead of P1, fanned 60 m; under--stage=emptyeach side anchors to a 1000 m ring about the origin,pos=overriding.<net>is a chapterneindexnet, orgrid, the stage's own ring; either patrols on its volumes.accent=a rosteraccentID,def=a militia variant. Arm with--ai-attack)--ai-attack[=<1-9>](arm every AI plane this session spawns, from--ai=and--generators, with forward-gun gunnery. Bare, each plane flies its vehicle def's nine-slot pilot vector, falling back to 5 for an unset slot;=Npins every plane and slot to N. The rating interpolates the dead-eye and quick-draw cones from the shippedai_skill_parameters. The gunner auto-targets the nearest hostile aircraft and fires throughFireControlonly in pursue, and only when the intercept is inside the weapon's RANGE and both cones. An AI never gets the human aim assist)--ai-damage=<fraction>(spend every--ai=plane's hull down to this health fraction as it spawns, so a run sees an enemy already staging itsinjure_animsladder.--damage=is the player's counterpart and writes per-part HP, which an AI airframe resolves none of; this spends the whole-vehicle pair the ladder reads, armour first and health second. Clamped to [0.01, 1] and never zero, since a preset that killed would leave a wreck, and logged asai damage preset:. Only--ai=planes take it. A frame hash cannot see it (SHOT-29): read thedamage stage:lines)--canopy-holes[=<1-5>](open this many canopy glass holes on every human pane as it spawns, so a scripted shot catches struck glass without waiting on an AI burst and the cue's 0.3 draw. Bare opens one. It spends the sameCanopyHoleCueledger a landed round spends, so a later round picks up where the preset left off, and plays the samebullet1..bullet5defs: thebulNxquads light on the glass in every view, and outside the cockpit the def also calls its exterior overlay.--fly/--stuntonly. Logged ascanopy holes preset)--ai-targeting=<aircraft-first|decoded>(what an ally's AI fights: the defaultaircraft-firstranks live enemy aircraft ahead of every turret and structure candidate, in the aeroplane picker and the turret gunner alike, so wingmen and an airship's guns agree; a structure is fought only when no aeroplane is in reach.decodedrestores the original's one running minimum over all four pools, where a def'starget_biasandstruct_bias(negative against a minimised rank, so both attract) rank a structure about 100 m ahead of an equidistant aeroplane. An unknown word keeps the default)--difficulty=<normal|hard|hardest>(the difficulty setting: enemy armour and health maxima scale at spawn by 0.75, 1.0 or 1.25, nothing else (docs/org/vehicleDamage.md); wingmen are spared and an Instant Action wave'senemy_skilloverrides it per spawn. Also takesnovice/veteran/aceand0/1/2; an unparseable name counts as absent. The Options screens save adifficultyword intooptions.json, read at every launch: this flag beats the saved word, which beats the defaultnormal;--detreads no saved option)--no-assist(disable the rubber-band assist: every AI mode machine this session spawns getsAssistEnabledfalse, solay offis never entered and an engaged AI stays in pursue. The assist is on by default, the original's shipped behaviour: an AI whose human target is chasing it from more than 350 m back eases intolay off, holds its course, walks its throttle towardsixth_sense_factortimes the pursuer's speed and holds fire, until the pursuer closes inside 250 m or stops chasing. Meaningful only alongside--ai-attack, since without a gunner no AI acquires a target)--generators[=<plane>](run the mission's egen enemy generators: loadegen.zrd.jsonfor the flown mission, drop a generator whose host node or nets do not resolve, then step each survivor's cycle: waves ofwave_size, individualsind_periodapart, wavesind_period + wave_periodapart, capped atmax_activelive spawns. The optional value picks the airframe for a generator that authors none (defaultplayer_bhawk). The authoredcapacityis never read; a generator launches only what aWAKEUP_GENERATOR, a wave or a cutscene credits, which--wake-generatorsgrants at build)--zeppelins(place and fly the mission's zeppelins: loadzeppelins.zrd.jsonfor the flown mission, place each record's node at its authored position, yaw and pitch, and move it along itsneindexnet under the record's own limits (max_speed/max_accel, the rate ramps, the pitch band), forward-only, never banking, with no flight model. A record whose node or net does not resolve is placed-but-held or skipped with azep:line. Per-part damage and the broadside cannons are wired. It also releases the zeppelin generators a--generatorslaunch gate holds, and stop points are live)--zep=<chapter>/<mission>:<record>[:team=<id>][:pos=x/y/z][:net=grid](graft one zeppelin record onto--stage=empty, so an AI-versus-airship test needs no campaign flight. The hull comes through the--node=subtree path, so the zones keep their geometry and a liveAnimRuntime, and damage, targeting and the sub-part feed wire as in a mission. Takes the chapter and mission with it. Seated at the grid origin at the record's altitude unlesspos=says so, station-keeping on a one-node net, or flying the stage's ring onnet=grid.team=reaches the parts throughAuthoredTeam)--wake-turrets(wake every dormant world AA emplacement at session build. The emplacements need no flag: any chapter flight places theai.zrdfamily and honours the shippedACTIVATEDvalues, leaving the hostile AA belt dormant until a mission script firesWAKEUP_TURRETS. This flag stands in for the script and wakes them all, oneturret ...: wokenline each. An emplacement with no TEAM is hostile to every pilot, the decoded loader default; each fires its authored weapon at the nearest hostile inside itsDETECTION_RANGE. Theturrets:census counts awake, dormant and woken)--wake-generators(credit every script-gated generator of a campaign mission at session build. A--campaign=mission starts each generator itsobjectives.zrdnames in aWAKEUP_GENERATORon an empty capacity budget, so nothing launches until play reaches the objective that grants the credit. This flag grants that host's whole scripted credit at build, oneegen: ... woken by --wake-generators: +N creditline each, so a headless run sees the launches without flying the mission up to them. Inert outside a campaign mission. The cycle still paces the launches from the session start)--craters(arm the rocket carve for this run, so every rocket warhead's ground burst digs a bowl and flattens the decorations inside it. The original carves nothing in play (org/craters.md): the carve is remake-only chrome, off wherever nothing asks for it. ⚠ No menu row offers it: this flag and the options file's ownrocketCraterskey are its two doors, and only the flag survives--det, which reads no saved option, so a probe photographs a bowl while every golden sees untouched ground. The burst still plays itsIMPACTrow)--infinite-ammo(guns and hardpoints fire without depleting, frictionless weapon testing; the HUD ammo line shows∞)--ammo=N(the low-ammo start knob: cap every firable gun group's load and every pylon's ordnance load toNat rig build. It mirrorsweapons.gunAmmoCap/weapons.ordnanceCapfromconfig.jsonbut survives--det, which drops that file (DET-8), so those knobs are otherwise unreachable in a scripted run. It capsCapacityas well as the live counter, so the gauge reads full atNand a respawn refills toN. Mutually exclusive with--infinite-ammo: whichever appears last on the command line wins, and the loser is logged as a warning)--rocket=<wep_id>(swap every hardpoint's ordnance on the flown planes to the named weapon (--rocket=wep_08), resetting each pylon to that weapon'sCLUSTER_SIZE. All eleven stock loadouts carry HE (wep_06), so a different mounted model comes either from here or from the menu's Ammo Selection screen. It beats a menu-chosen fit and applies after the bind, so a scripted run gets the type it names whatever was picked on the way in. An unknown id warns and leaves the stock ordnance. Distinct from--loadout=<def>, which swaps whole plane defs)--hud-text(draw the flight text block, the remake's ownSPD/ALT/THR/DMGreadout in each pilot pane's upper left, with its stall, impact, stunt-status and paused lines. The original has no such display, so it is off by default. ⚠ No menu row offers it: this flag and the options file's ownflightTextBlockkey are its two doors, and only the flag survives--det, so a probe can read the block while no golden carries it)--hud-font-test[=STRING](overlay a sample string drawn with the game's own HUD bitmap font (HudFont, fromextracted/rimage/5pointhud*.png) on each player's pane, in both the normal and highlight variants with aMeasure()-width rule under each. Pair it with--players=4and--screenshot, run windowed, never--headless(SHOT-9), to confirm that a 1P view and a 4-way pane render identical glyphs scaled only by the pane factor. The default string is a mock ammo readout; an optional value overrides it. With the flag off the font is not loaded and the flight HUD is unchanged)--weapon-lab[=wep_id](implies--fly: a chapter-world flight session whose aircraft is held in place, hosting the weapon lab panel on it (B hides and shows it). It fires through the session's ownProjectilePoolat the chapter world's real surfaces. The panel writes into the boundLoadoutand the aircraft's own trigger fires it: GUNS arm the gun groups, HARDPOINTS the pylons, and picking a hardpoint weapon re-arms every pylon and rebuilds the mounted models. The optional value mounts that weapon at launch. Ammo is infinite until the panel's toggle says otherwise. P1-only)--weapon-mount=<token>(with the weapon lab, the mount selected at launch, the gun group or pylon the trigger fires from:g<slot>for a gun group by its W-slot (g1/g2/g3/g4), orpylon<n>for a pylon (pylon1…pylon8). The default is the bank's first. The token is resolved in the bank the selected weapon implies, ag*token needs a gun weapon, apylon*token a hardpoint weapon. There is noalltoken: the aircraft's real trigger fires one gun group at a time, as the original does)--weapon-fire(hold the aircraft's trigger from launch in a--weapon-labsession, the same trigger a pilot pulls, chosen by the selected weapon's class: a hardpoint weapon launches from the pylons, anything else fires the gun groups. For a clean firing screenshot run windowed, never--headless, a--screenshotunder--headlesshas no rendered frame to save, SHOT-9)--weapon-click[=x,y[,aim]](with the weapon lab, replay one left click at that viewport pixel on the first physics frame. No value clicks the viewport centre; a trailingaimis the scripted shift-click, which aims without re-parking. The lab casts its own physics ray from the camera, notSelectionService's AABB pick, which skips map-scale meshes and can never select the sea or a terrain tile. It logs what it struck and re-parks the held aircraft on that ray at the panel's stand-off; a click that hits nothing leaves the aircraft where it was)--weapon-target=x,y,z(with the weapon lab, park facing that world point on the first physics frame, on the line from the aircraft's spawn, the mouse-free placement for a point you already have from a log or an earlier capture. The point is taken as given, so a coordinate in mid-air is a legitimate aim; a short probe ray through it names the body under it when there is one, and the readout says(world point)when there is not. Wins over--weapon-surface=and--weapon-click=, which win over each other in that order)--weapon-surface=<registry name>(with the weapon lab, park facing the nearest collider carrying that surface id. Any of the registry's fourteen names is namable:defaultwaterseafloorquicksandlavafireplayerenemyairstripopensesamedeathbuildingsdzonedirt, wheredirtis id 13, real dirt-tagged ground, not the untagged grounddefault. The search measures to the nearest vertex of the collision geometry, not to the body origin. A chapter with no such collider, or a name outside the registry, warns and leaves the aircraft at spawn)--weapon-standoff=<m>(with the weapon lab, the parking distance every placement uses, click,--weapon-target=,--weapon-surface=, and the panel slider's starting value. Clamped to 15–1100 m; omitted or 0 keeps the 90 m default)--weapon-camera=free|orbit|<frames>(with the weapon lab, which camera has the view. By default the lab orbits the held plane on wall time, swung with WASD and zoomed with Shift/Ctrl.freehands the sameCamera3Dto aSpectatorCamera, so the eye can fly out and watch an impact close up; V toggles it interactively. While the free camera holds it the controller writes nothing to the camera at all, and handing it back re-seeds the orbit from where the eye is, so neither direction jumps. A frame count toggles the two every N physics frames. With--players>1the lab binds to P1)--weapon-cycle[=frames](with the weapon lab, step the current bank's weapon list one entry every N physics frames, default 30, the scripted twin of holding the panel's>button down, so the arm-and-rebuild path can be walked with nobody at the controls. Each step logs oneweaponsdebug line naming the new weapon, itsFLYOUTmodel, the per-pylon load, how many models mounted and how many ordnance bodies are parented to the rig; that last is the leak tripwire and must equal the mounted count however long the cycle runs. Pair it with--frames=and--log=weapons:debug)--weapon-test(implies--det: a parked-plane probe in the viewer that needs no world, no colliders and no frame. It mounts and fires every one of the 48weapons.jsonentries once from every mount of its own class, a gun from each of the airframe's gun groups and a hardpoint weapon from each pylon, reports any that throw to stdout and./.scratch/weapon_test.txt, then quits; windowless under--headless. A clean run reports 48/48 fired OK, 0 errors, 0 skipped, and a skip means a real gap. It needs a parked plane, so omit--chapter; pair with--plane=for another airframe)--damage-test[=name](implies--det; the headless destructible sweep. It builds the--chapterworld via the freecam path, then for one live destructible per distinctDAMAGE_SEQUENCE-carrying def sweeps its HP from full to zero and logs which stage effect fires at which health, plus aresolve✓check that a deep descendant node, what a projectile's raycast strikes, maps back to that destructible; to stdout and./.scratch/damage_test.txt, then quits, windowless under--headless. Optional value filters destructibles byNAMEsubstring, e.g.--damage-test=ap_h2otwr)--damage-hd=<n>(with--damage-test, switch to discrete-hit mode: applynHEALTH_DAMAGEper hit throughAnimRuntime.DamageAtand count hits to destruction, rather than sweeping HP. It logs the stage-crossing hits and, at death, aswap[...]subtree check, acol[off N, on M]collider census (WORLD-10), adebris[N launched]count. Discrete mode covers every destructible, not onlyDAMAGE_SEQUENCEones. It forcesCollisionon, since a freecam world builds none (WORLD-9), and dumps the collidable-mesh inventory to./.scratch/world_colliders.txt)--effects-test(implies--det; build the--chapterworld via the freecam path, then play every impact and destruction effect at the camera point, reporting whether each resolves and whether it builds a puffer (verification.mdWORLD-12: a started def whose factory or textures are absent renders nothing), to stdout and./.scratch/effects_test.txt, then quit.--detpins the seed the runtime's dice derive from, and every effect is stopped before the next because they sharetrailpuffer2. Point-light and container effects build no puffer by construction)--run-tests[=filter](implies--det; the in-engine test harness: run the suites, print a PASS/FAIL/SKIP table and./.scratch/test-report.json, exit 1 if any suite failed (LOG-12); an absent input SKIPs and exits 0 (DIAG-15), except undertier:ci. Terms are comma-separated, unioned:suite:<name>exact,tier:quick/tier:ci, else a substring; a term matching nothing exits nonzero.shard:<i>/<n>divides the choice byanalysis/engine-suite-weights.json;render:<kind>[+<kind>]keeps itswindowed,headlessorsyntheticsuites (SuiteRender); LOG-8)--destroy=<name>(kill a named world destructible at build, unattended.<name>is a case-insensitive substring of a destructible's def, animation or anchorcs_name; every distinct match dies, capped at 64, and a dormant pool (a deactivated zeppelin's parts) refuses the hit and is logged as refused, not counted. It reuses the weapon-hit path, so debris, effects and audio match a rocket kill. It needs a--chapterworld, forces no mode, and is a no-op in--viewer. In--freecamit auto-frames the object unless--pos/--directionplaced the camera.--damage-testlists the names)--crash[=frame](force the flying players' crash rig at a fixed sim frame, default 5:FlightController.DebugForceCrash()fires on every rig when the clock reaches it, which is the only headless route to a crash. A no-op past the first fire, and inert without--fly/--stunt. The wreck scatters off theRng.Crashstream, so pin--seedand the player count. It needs a--chapterworld, the crash def coming from the mission'sAnimProgram, so it is inert under--stage=emptyunless--zep=grafts a program in. Spawned AI planes crash too, indexing theai_crash_*family)--menu[=<screen>](forces the menu with other args, else bare only. A value opens that screen, an unknown one the top level. A:suffix is its argument:campaign-briefingseconds,join-boardpads,keysa category,loadboard-campaigna mission,pauseboarda mission and a marked count,pauseboard-iaa chapter and type, else aCampaignAidScript: counteddulrabmoves and confirms (4da), a number steps. Original refusesx: exit 1, no shot. Campaign aids use scratch stores barcampaign-fly; seedocs/org/menu-inventory.md)--menu=extract-picker[:<folder>],--menu=extract-run[:<install>](screenshot aids for the extraction screen, which a launch reaches instead of the menu when the data root holds no extraction or a stale stamp; with a good tree they do nothing.extract-pickeropens the install folder picker, on<folder>when given.extract-runputs<install>in the field and presses Extract, so a pair with--data-root=at a scratch folder and--screenshot=catches the progress view or, with a bad--unzbd=, the failure view. A scripted run never remembers the install)--skip-intro(no boot sequence on this launch. A bare launch playsmsopen1,zipperandchap0over the whole window before the launchscreen, infmv.zrd's own order, and any key or a left click ends the one playing and starts the next. Any argument at all already suppresses the sequence, so no test, golden or perf run sees it; this flag is for the one launch that carries no other argument, a desktop shortcut whose owner has watched the movies. It selects no content, forces no mode and still shows the launchscreen, so a launch carrying it alone is the bare launch minus the movies)--intro(a dev flag,--skip-intro's opposite: play the boot sequence although this launch carries other arguments. It exists becauseRunGame.ps1andRunDev.ps1prepend--volume=1.0unless you pass a volume or--mute, which suppresses it, so without this flag the sequence is unreachable through the repo's launch scripts and judgeable only from an exported build.--skip-introbeats it, since a suppressor another flag can overrule is not one. It selects no content and forces no mode, so pair it with--menuon a launch that would otherwise build content, or it plays nothing)--movie=<name>(play that one cinema over the whole window, then quit; any key or a left click ends it early. The name resolves case-blind underextracted/rof/ASSETS/GRAPHICS/MPG/and takes.mpgwhen none is spelled, so--movie=zipperand--movie=CrimFlag.MPGboth work; a name nothing matches names the folder and quits 0. No world, menu or session is built; the sound rides the Voice bus;--screenshot=captures it. It does not imply--det: the picture is clocked by what the audio device played. ⚠ A repo run's gain is 0, so pass--volume=1.0or it plays silent and says so)--presentation=<name>(the menu presentation for this run, recorded asSessionSpec.PresentationOverride: a registered presentation's id, ahead of the Original default.originalis the one that ships, so a name no presentation registered resolves to Original and the reason is logged. No Options screen offers a presentation and a savedmenuPresentationis ignored. An Options apply keeps the presentation. A saved option that leaves the menu unusable is recovered by deletinguser://options.json: the store reads a missing file as empty, so every option falls back to its default)--mission=IA1(which mission's spawns--flyuses; IA1 readsia.jsonspawn_points, M0x story missions readobjectives.jsonPLAYER_INIT, pair with the matching--chapter=so the world fits the spawn. A Dogfight launched from a menu ignores it and flies its type'sMP1,MP2orMP3)--scenario=zeppelin_run(which instant-action scenario's spawn list,zeppelin_run/dogfight_ace/dogfight_squadron/stunt_flying/…)--ia=<path>(fly an Instant Action mission from a hand-authored JSON file: a plain object using a chapter's shippedia.zrd.jsonfield names plus the inventedlives; omitted keys take the original's reset defaults. Pair it with--chapter=. The launchscreen wizard's in-memoryIaDefis checked beforeIaPath.mission_typedrives the spawn list, the ace, wingmen, waves, the objective zeppelin, the danger zones and the end condition.livesis per pilot: 1 faithful, N for N-1 respawns, 0 unlimited. A malformed or missing file logs and leaves the session non-Instant-Action)--campaign=<profile>:<seq>(the scripted-testing entry for a campaign session:<profile>is a profile folder underuser://Profiles/or--profiles=,<seq>thecm_sequence.zrdflat mission index, 0-23. Both are recorded as plain values (SessionSpec.CampaignProfile/CampaignMissionSeq); loading the profile and building the mission's world is the campaign director's job. A missing or unparseable:<seq>keeps the profile name and warns rather than dropping the flag. There is no dedicated mode: like--stunt/--vs, a bare--campaign=rides the default Fly resolution)--profiles=<dir>(the campaign profile store for this process, in place ofuser://Profiles/:--campaign=loads, seats and saves through it, and so do the cabin and last-played pilot of a--menurun. A relative path resolves against the working directory. A probe points it at a store under.scratch/, seeded withCampaignProfileStore.Saveor a copied profile folder, so no run reads or writes a player's profiles. A copied folder is read and saved under its own name)--scores=<path>(the stunt best-time file for this process, in place ofuser://stunt_scores.json, read and recorded by the solo scoreboard and the Instant Action wrap-up. A relative path resolves against the working directory. Without it, a--detrun, a run a scripted flag drives and ends (--screenshot=and the rest ofSessionSpec.ScriptedBy) and a--debug-scoreboardrun record into an empty in-memory store that is never saved, so such a board always reads NEW BEST. A probe that needs a stored best seeds a file under.scratch/and names it here)--no-crash-loss(keep flying after losing the aircraft in a campaign mission, the opt-out from the game rule. By default the loss ends the mission where the wreck comes to rest (docs/formats/objectives.md, "Win and loss"); this flag leaves the objective graph running instead. In co-op an earlier death costs that human their aircraft alone, and the last one lost ends the mission; the flag opts out of all of it. Campaign sessions only: Instant Action's lives ledger and Dogfight's respawn are untouched. Losing the aircraft is the plane's ownDownedreport (INSTR-22))--spawn=N(force spawn index N in that list; default is a random pick per launch like the original, drawn from thespawnstream, and the chosen spawn is logged.--detdefaults it to 0, a pinned choice rather than a pinned dice roll: a seeded pick still moves when the mission's spawn list grows, index 0 does not. An explicit--spawn=Nstill wins under--det)--spawn-at=x,y,z/--spawn-dir=x,y,z(deprecated, the pre-A5 flight-only spelling of--pos/--direction; each logsWARN [core] deprecated flag=… use=…once per run and otherwise behaves exactly as it did. They still carry their old per-mode meaning, which--posdeliberately does not copy: in--anim-lab--spawn-atmoves the parked stage prop as well as the camera, and in--freecamit moves the camera through the spawn path, where--posbeats it)--sky-zone=zone1|zone2|zone3(horizon zone, defaultzone2. It also selects that zone's distance fog and enables fog, whiteout and the map-edge extension in a static view. The names are per chapter: C1 to C4 shipzone1+zone2, C5 shipszone1+zone3, and a zone the chapter does not define falls back to the first itsweather.jsonlists. The default is also corrected by the horizon's geometry: where the named zone builds no dome, the one that has renders. Passing the flag explicitly opts out of that correction, pins the fog and forces thezone_idgate to that zone)--data-root=(whereextracted/lives; default the repo root. Also settable as theCSVM_DATA_ROOTenvironment variable, which the flag overrides. It exists so a git worktree can run the game:/extracted/,/CrimsonSkiesGame/and/tools/are git-ignored, so a worktree checkout has none of them. Point it at the primary tree and a worktree session renders byte-identically to that tree. It affects asset lookup only:planes.zip,zrdr.zip,soundsh.zip,interp.json,messages.json,rof/, and the per-chaptergamez/textureand missionzrdrpaths)--synthetic-data(read an invented test tree instead of the data root: writes anextracted/ofCSVM.Tests/fixtures/records and generated files into.scratch/synthetic-data/<pid>/, stamped synthetic, and reads it in place of the root named. Logged asWARN [core] SYNTHETIC DATA;test-report.json'ssyntheticDatareads true. An unwritable tree quits 1. With no--plane=it flies the armed stand-inprobe_plane. Needs a repo checkout, so an export refuses it; dropped beside--extract.Tooling/SyntheticData.cs)--gamez=--textures=--zrdr=(default extracted/zrdr.zip)--interp=(default extracted/interp.json, the boot scripts naming each chapter's clutter templates; every world build stamps them viaClutterBuilder, logged asclutter: N sprites, solid only in--fly)--sounds=(default extracted/soundsh.zip)--zip-assets(read the.ziparchives even where--extract-unzipleft an unpacked sibling folder, the asset shape an exported build ships. Process-wide: it flipsSessionPaths.ForceZippedbefore the first path resolves, so the chapter gamez, texture and zrdr paths, the sounds archive and the menu pages' own lookups all take it. A path that only ever had the folder still resolves to the folder: the flag narrows the choice rather than adding a requirement. Use it before shipping a build, since the two shapes do not fail alike (INSTR-46))--hd=<folder>(the HD texture pack folder, under the data root unless rooted, defaultHD, also config.json'stextures.hd; empty reads none. Drop a pack's release zips there unchanged,Extraction/HdTextures.cshas the matching rules. A--detrun, and so every--screenshot=and--run-testsrun, reads no pack unless this flag names one)--messages=(default extracted/messages.json, the string table resolving targets.jsonMSG_*keys for objective marker text)--extract=<install>(extract an original install into<data-root>/extracted/and exit, before any world or menu loads: the ZBD archives through unzbd, then the.rofUI resources, both stamped. Prints a summary and exits 0, or 1 on any failure, including a folder that is not an install or lacks any of the 184 archivesZbdManifestexpects. The install may be the disc, itsGAMEfolder or an.iso(laid out byunzbd cs disc). A ZBD failure stops the run before the.rofhalf. No window opens, even without--headless. Does not remember the install for menus.ExtractionRun)--extract-force(with--extract, re-extract archives the stamp calls up to date; without it an unchanged archive is skipped. Ignored with a warning when--extractis absent)--extract-unzip(with--extract, also expand every extracted.zipinto a sibling folder, the dev tree's shape. The rootrimage.zipis expanded either way, since the HUD font, the reticle and the board art read its PNGs loose. Ignored with a warning when--extractis absent)--extract-allow-missing(with--extract, extract an install missing some expected archives, each named as a warning instead of failing the run. The in-game Extract screen always fails. Ignored with a warning when--extractis absent)--unzbd=<path>(with--extract, the unzbd executable to run. Default: next to the executable in an exported build, elsetools/mech3ax/target/release/under the repo root, which a worktree lacks, so a worktree run passes this flag. A missing tool fails the run before anything is written. The in-game extraction screen runs the same tool, so the flag applies there too and is not warned about without--extract)--mips=authored|generated(which mip levels a texture gets, defaultauthored. A chapter ships hand-drawn half- and quarter-resolution siblings (cblock1_1,cblock1_2) that no gamez material references, the original's own mip chain (docs/formats/gamez.md).authoredinstalls those siblings as levels 1 and 2 wherever one exists, box-filtering the rest; a texture with no sibling is untouched.generatedrunsImage.GenerateMipmaps()all the way down. A sibling whose size disagrees with the level it claims is refused with a warning, never installed. Measure it with--dump-mips)--graphics=original|enhanced(the opt-in lit-world mode, defaultoriginal. Precedence: this flag, then the savedgraphicsModeoption (user://options.json), then thegraphics.modeconfig key, thenoriginal. Under--detonly the flag survives, so it is the one way to ask for the enhanced path in a scripted or golden capture. It resolves at launch (GraphicsMode.Resolve), announced on the[world] graphics mode:line; an Options apply or G in flight switches it live after that. An unrecognised word at any layer warns and falls back tooriginal)--anti-aliasing=off|fxaa|smaa|taa|fsr2(the 3D viewports' anti-aliasing method. Precedence: this flag, then a headset's VR quality profile (--xr-quality), the savedantiAliasingoption, thegraphics.antiAliasingconfig key, then the mode's default (offOriginal,taaEnhanced). Survives--det, so it is the scripted door on the method. An unknown word is dropped with a note.Utils/AntiAliasingSetting.cs)--msaa=off|2x|4x|8x(the root viewport's 3D MSAA in place of the project's 4x, flat or stereo; beats the VR profile's word. A measurement door: the SubViewports keep the project's level. An unknown word is dropped with a note.Utils/VrQuality.cs)--shadow-quality=off|low|medium|high|ultra(the Enhanced sun's shadow level. Precedence: this flag, a headset's VR quality profile (low), the savedshadowQualityoption, thegraphics.shadowQualityconfig key, thenultra; an integrated GPU (the Steam Deck) falls back tohigh, or tooffat 3 or 4 panes (shadow_quality_source=default_integrated_gpu_panes).--detkeeps only the flag, overultra. Logged on[world] graphics mode:and each[world] word settingsline (apply, switch, panes); an apply re-resolves it live. The faithful path ignores it; an unknown word warns)--view-distance=normal|far|veryfar|unlimited(how far Enhanced draws the clutter before its fade: 1x, 2x or 4x the Enhanced fade, or no fade, the fog unchanged. Defaultfar. Precedence: this flag, then the savedviewDistanceoption, then thegraphics.viewDistanceconfig key, thenfar. Under--detonly the flag survives. An unknown word is dropped with a note. Original ignores it and keeps the decoded fade)--water-quality=flat|waves(whether Enhanced draws the wave ocean or the flat sea sheet. Precedence: this flag, the savedwaterQualityoption, thegraphics.waterQualityconfig key, then the machine's fallback:waves, orflaton Linux or an integrated GPU, the Steam Deck (logged aswater_quality_source=default_linux_or_integrated_gpu).--detkeeps only the flag, overwaves. Logged on[world] graphics mode:and[world] word settings applied:; an apply builds or drops the ocean live.--no-oceanstill wins. Original ignores it; an unknown word is dropped)--shader-warmup=auto|load|off(whether a load compiles the other graphics mode's shaders, so a live switch only moves materials onto shaders Godot already compiled.auto, the default, warms once this process has switched.loadalways warms, and in an Original process that has drawn no Enhanced frame it also draws one hidden TAA frame, so Godot builds its advanced variants at load (6 to 10 s of first frame on C1 to CM24) rather than on the first switch.offnever warms; a shader not made yet costs its compile on the switch that needs it. An unknown word is dropped with a note)--no-ssao(enhanced bisect door: leave the ambient-occlusion pass out of the--graphics=enhancedbuild. The five doors here accumulate on one command line and reach enhanced alone, the faithful path building none of these passes; together they bisect a full-screen artefact to the pass that draws it, one pose per closed door. ⚠ Read the result on a plain--screenshot=, never a--shotsburst, whose frames carry--jitter's camera dither)--no-ssr(enhanced bisect door: leave screen-space reflection out, so the water draws with its own specular alone)--no-glow(enhanced bisect door: leave the glow pass out. The AgX tonemap stays and has no door of its own, every enhanced frame's exposure depending on it)--no-soft-shadows(enhanced bisect door: zero the sun's angular distance and shadow blur together, so the shadow is still cast but with a hard edge. That isolates the penumbra filter, which resolves through a sample disc rotated per screen pixel, from the shading the shadow itself carries)--no-ocean(enhanced bisect door: leave the wave ocean (Effects/Ocean) out, so the flat sea-level sheet draws as it does in a chapter without one. The ocean builds only on a chapter with a sea at y = 0 (every chapter but C4) in--fly/--freecamat thewaveswater quality, so elsewhere the door changes nothing. Announced asocean: skipped (--no-ocean). It is also the flat-sea arm of an ocean A/B: same pose, with and without the flag)--dump-ocean-mask=<path>(inspection aid: write the wave ocean's baked shore mask as a PNG when the ocean builds, R the sea coverage and G the distance to the nearest shore, surf or solid texel (saturating at 160 m), and the base sheet's tint beside it as<name>.tint.png. Unlike the other--dump-*flags it does not end the run, so pair it with--screenshot=. Writes nothing where no ocean builds; theocean: builtline beside it carries the bake's size,ms=and its per-phase split)--no-fog(inspection aid: neutralise the distance-fog range and the cloud-band whiteout so geometry stays visible to the horizon. It also opens the band's per-object zone gate. It leavesWorldLightandFOG_COLORunchanged, so a shading question stays answerable with fog off. It is implemented by pushing every view's fog range (csky_fog_rangeand the per-view table) toWeather.NoFog's no-op value, not thecsky_fog_oninstance uniform (seeClutter.ShaderCode); every fogged shader reads it: world, clutter, city blocks, dome. Announced in theweather [...]log line)--no-flare(inspection aid: suppress the sun's lens flare in the two chapters that author one (C2, C3). The flare's full-screen wash reaches α ≈ 0.66, survives terrain occlusion and whitens the HUD as well as the world, so in C2 and C3 any capture with the sun near screen centre is contaminated for unrelated comparisons. The flare is announced in thelens flare [...]log line either way. It is otherwise gated purely on chapter data, a gamezsunnode in the horizon subtree plusLensFlareTextureslots insupport\<ch>\init.gw, so the other six chapters need no flag)--screen-flare(comparison switch: in a flat Enhanced session, draw the lens flare with the screen rig (Session/World/LensFlareRig, canvas sprites after the tonemap) instead of Enhanced's default world rig (Session/World/WorldFlareRig, depth-tested core, rings under their Enhanced gain), the A/B door for flare work. Original draws the screen rig anyway; stereo (--xr-simor a headset) always draws the world rig. Chosen at the session build. The log names the world rig aslens flare [<ch>]: world rig)--no-cockpit-pass(opt out of the cockpit pass, the shipped path that draws thecockpit1interior in aSubViewportworld of its own with the panel and the camera at the origin, composited under the HUD (Flight/Hud/CockpitOverlay); the flag leaves the interior in the main world, where each dial face rounds differently on a rotated attitude, a panel jitter. A stereo session (--xr-mode onor--xr-sim) builds no pass and drawsFlight/Hud/XrCockpit's interior, which does not jitter, with or without the flag. Costs a second 3D pass per player. Not covered: an airframe swap)--no-clutter(inspection aid: skip the chapter's ground-clutter build entirely, so no tree or bush sprite cards, no C2/C5 3D city-block decorations and no clutter colliders. It is how the ground under the clutter becomes visible at all. It removes the population and does not re-place it, so nothing about the placement rule is exercised and a density question cannot be settled with it. Theclutter: skipped (--no-clutter)line replaces the per-chapter census. ⚠ It does not touch the ambient cloud field (Effects/FogVolumeClutter, thefvolsprites))--clutter-templates=<name>[,<name>…](inspection aid: replace the chapter's registered clutter template set with the named templates, so one district can be flown on its own. Names are the stringsinterp.json'sAddClutterTemplateslines carry, matched case-insensitively against the gamez's template roots. ⚠ It replaces the template set only: the per-polygonno_cluttergate still applies. A name this chapter does not carry is not an error, so the build line names what was asked for, what resolved and what is absent.--no-clutterwins if both are given)--cloud-jitter=<m>(remake-only departure, default30: moves every lattice-scatteredfvolcloud card (cloudsprite1/cloudsprite2) by a uniform random X/Z offset of up to<m>metres per axis, drawn off its owncloudjitterstream after the decoded draws, so every value lays one seeded field. The shipped field is the decoded lattice plus that offset, because the lattice alone reads as rows along the deck (docs/org/cloudCards.md). Thecloudparentgroups, map-edge ring and speed cue are untouched;=0renders the decoded field, and an unparseable or negative value warns)--no-zone-cull(isolation switch: switch off the original'szone_idvisibility gate, so every zone draws at every state, the band's per-object gate included. The gate hides a lot on purpose, in C1 the ground world onzone_id 1and the deck tiles, facades and sprites onzone_id 2, so "did the gate eat it?" takes one flag rather than a rebuild. It is not a fidelity switch: the default is what the original does (FUN_0056c430). Thezone gate: N / N / N mesh instance(s) on zone 1 / 2 / 3line prints either way. ⚠--sky-zone=zoneNdrives the gate too)--tex-override=<name>[=<color>](texture drop-in: the named texture resolves to a flat loud colour wherever it is used.<name>is the PNG's base name or the truncated name the material stores.<color>is anything Godot parses; the default magenta is also the unresolvable-texture fallback, so pass an explicit colour where a lookup failure is possible. Repeat the flag for several textures. The hook isTextureArchive.Find, so every consumer inherits it, and on an aircraft it beats the paint substitution. A name the archive lacks, or that no material resolved, warns)--tex-census[=<name>[,<name>…]](texture drop-in: every texture resolves to its own flat colour, so a frame becomes a map of which texture painted which pixel. The colour is a hash of the name (TextureDropIn.ColorForName), the same in every chapter and run, andcollisionsnames textures that hash alike. The map is.scratch/tex_census.json; a--screenshot=run also counts the saved frame into.scratch/tex_census_<shot>.jsonby chromaticity. Counts are lower bounds: use--no-fogand reject tiny ones (SHOT-14). The optional value adds names the archive lacks)--no-focus(mark the run scripted: it does not take the foreground, andLauncher._Ready()hides its window withShowWindow(SW_HIDE).--screenshot=,--run-testsand the--dump-*probes are already scripted; this is the manual lever for a run nothing else marks. Hiding is not minimizing, so rendering and golden hashes are unaffected (SHOT-16), but the window ignores keyboard input. A window still flashes before_Readyruns, whichRunTests.ps1avoids by launching on a separate desktop (HiddenDesktop.ps1).--headlesssaves a blank PNG)--mute(skip flight audio: a load-time switch, soFlightAudioandWorldSoundsare never constructed at all. Nothing plays, and nothing is counted or logged either,OneShotSoundsPlayedstays 0, the probe report'ssoundscolumn reads zero, and thesound one-shot:/crash sound:lines never print. That blindness is a measurement trap: several errors on record surfaced only in a sounded run, and every zero-baseline taken under--mutehad missed them. Reach for--volume=0instead unless the point is to skip loading the archive)--volume=N(master gain,0–1, default0in a repo run,1in an export, so a scripted run never sounds unless it asks and a recipient's double-click needs no flag;RunGame.ps1/RunDev.ps1pass--volume=1.0. Unlike--mutethe audio subsystem still loads and plays, so at--volume=0every counter and log line reads as at full volume: silent but not blind. Also theaudio.volumeconfig key, which the flag beats;--detdrops the config source, never the flag. An out-of-range value is clamped and an unreadable one ignored, each with aWARN. With--muteit warns)--sound-range-scale=<f>(remake-only departure, default2.5: multiplies bothRANGEradii of every positional voice that runsSoundFalloff(world emitters and one-shots, AI gun loops and dry cues, mount gun voices) and their 1.1x cull, so the decoded curve keeps its shape atftimes the reach. The default is the reach the world emitters read the original's at;=1is the data's own radii, and nothing decoded stands behind the factor (docs/formats/sounds.md). Thesoundlog prints it (range=x2.5). A value that is not a positive number is ignored with aWARN)--debug-collision(draw the plane's collision probe)--players=N(splitscreen, M2.5 item 5: fly N planes 1–4 in one shared world, each with its own pane/camera/sky/HUD/device, 2P stacked top/bottom, or side by side on a window 2:1 or wider, 3–4P a 2×2 grid; P1 = keyboard + the first pad, P2–P4 the next pads in roster order; needs--fly/--stunt, falls back to 1 with a note otherwise. Each player spawns at the next index in the mission's spawn list. With--stuntthis is a race, per-player zones/marker/clock and a shared ranked board (item 7). Launched from the menu instead, the item-6 join flow sets the count and binds the pads)--debug-join=N(menu only: seat N device-less players through the shared player setup so the aircraft screens can be screenshot without N controllers; they can never act (and the last one starts selected, so both states show), making the shot deterministic. Original lists them in the local lobby's player list and walks them through the per-seat aircraft screen)--debug-pointer=x,y[,down][,right](the menu only: stand seat 0's pointer at that authored 800x600 point for the run, a button held per word after the pair,downthe primary andrightthe secondary the credits screen's hidden line answers, so those states are shot with nobody at the controls. Authored not window pixels, so the shot lands on the same widget whatever the window; the press arrives as an edge once and never releases, leaving the held frame standing rather than firing. Quote it in PowerShell (SHELL-18); fewer than two numbers stands no pointer)--debug-graphics-switch=N[,N...](flip the graphics mode on the running session at each named sim frame, the scripted twin of the Toggle Graphics Mode action and the Options apply, under the sameSwitchCover(the sim held at frame N while it stands) and never saved. Each flip logsgraphics mode: ... (switched live by --debug-graphics-switch at sim frame N); with--debug-load=<dir>the cover's frame is saved aspump00_0.00.png. A network session refuses it)--debug-shaders(what the renderer compiles and when it stalls for it,Tooling/ShaderDiagnostics.cs: a[perf] shader-diag censusof the distinct shaders the tree draws by family at sim frame 240 and after every live switch, the wall time and pipeline compilations of the twelve frames after a switch, every frame over 33 ms with its pipeline counts, and a summary every 600 frames. Pair it withRunProbe.ps1 -EngineArgs --verboseto read Godot's own shader-cache hits and misses)--debug-marquee=<seconds>(hold every menu caption too wide for its cell at that phase of its scroll,Boards/BoardMarquee.cs, so a shot shows a long caption part way through; without it--detand--run-testshold the start. Pair it with--menu=keys:<category>:sticks, whosestickssuffix poses a long stick caption, several sticks in one cell and several keys in Control B on the category's first three rows, in memory and never saved)--hold=p,r,y,thr[@dur][;…](scripted flight input for automated runs:;-separated segments with@secondsdurations sequence the inputs, so1,0,0,0@1.1;0,0,0,0pulls for 1.1 s then releases, and a single segment is a constant hold.|separates per-player sequences under--players, the last covering any remaining players. A bot seat takes no segment: its AI pilot flies it. Such runs are unattended, so a crash auto-respawns after a pause and a completed stunt race auto-rematches on the same timer)--lever=<eighths>[@seconds][;…](press the throttle digit row on a schedule, the scripted twin of tapping0-8, for a capture that has to slam the lever with nobody at the keyboard. Each;-separated step is one press of that eighth at that sim-second, so0@0;8@10idles from the spawn and slams to full at ten seconds; the commanded lever jumps and stays, the live one slews to it at its own 0.5/s, and that gap is what the exhaust smoke charges from. It drives the keyboard arm, so a--hold=run ignores it, as do AI aircraft. Steps sort by time; an eighth outside 0-8 clamps)--yaw=--pitch=--pos=x,y,z(place the subject of whatever mode is running at a world position: the plane's spawn in--fly/--stunt, where it beats--spawn=N, the camera eye in--freecam/--anim-lab, the orbit eye in--viewer. Quote it in PowerShell ("--pos=-6500,300,-1500") or the comma splits the argument into an array and the run dies (SHELL-18). In flightFlightModel.Resetapplies start speed and trim, and a respawn returns to the placed pose. Under--campaign=a placement made during a mission intro cutscene waits for the cutscene'sWorldHeldhandoff)--direction=x,y,z(the world-space vector--pos's subject faces along, any length, normalized; quote it as--posis quoted (SHELL-18). In--fly/--stuntit aims the nose, and splitscreen fans the players 60 m abreast of it as--spawn-atdoes; in--freecam/--anim-labit is the view direction, and only the direction survives becauseSpectatorCameradiscards the distance; in--viewerit is the aim, and the orbit pivot is synthesized on that ray (see--lookat). In flight,--directionwith no--posis a no-op and says so, since the override engages only on a position)--fov=<degrees>(the vertical field of view of the--freecam/--anim-labcamera, 1 to 179, instead of the decoded external base every world camera outside the cockpit interior draws at. F11 appends it when a cockpit view drew the frame, so the printed line frames what was on screen. Any other mode warns and ignores it; flight's views set their own angles)--lookat=x,y,z(the point form of--direction. It stays a point, which matters in--viewer: the orbit camera pivots on it and takes its radius from eye to pivot, so a bare direction would spin the wheel and the drag about the eye. Elsewhere it converts to a direction losslessly, against--posin flight. A--viewer --directiontherefore synthesizes a pivot, the point on the aim ray nearest the subject's centre (min radius 1 m), announced on a[core] orbit pivot from --directionline; with no--posthe centre stays the pivot and the eye swings instead)--view=<1-9|back|flyby|chase|cockpit|nose>(pin a flight camera,--fly/--stuntonly, else it warns and leaves chase. A digit holds a numpad snap, swung to, not cut to, aiming the head in first person:2dead ahead,4/6the flanks,8the belly,1/3/7/9the corners below (5and out of range fall back).backis the look-behind,flybythe F7 camera, re-entered on respawn,chase/cockpit/nosean F8 view mode. Precedence:flyby,back(in first person a head snap astern, not a cut outside), a live numpad key, a pinned digit, then the saved Default View)--xr-chase=rigid|level(which frame a headset's chase view rides, defaultrigid: a fixed offset behind and above the aircraft in its own axes, so the world banks and climbs about the player as it does from the cockpit.leveldrops the roll from those axes, so the horizon never tilts and the gun pipper stays above the aircraft, and rolls the view half a turn through vertical flight (a loop's top) under a comfort fade. The A/B door for the headset; a flat launch never reads it, and an unknown word is ignored with a note.docs/org/cameraViews.md, "Views under a headset")--xr-render-scale=50|60|70|80|90|100|125(the headset's eye size as a percentage of the runtime's recommendation, OpenXR's render target multiplier, applied live: Godot recreates the swapchain on the next frame. It cuts the GPU's work and the runtime's compositing alike, and multiplies with the flat render scale inside it. Beats the saved Options row (vrRenderScale), which no--detrun reads; an unknown word is ignored with a note. Logsxr: render scale <s> eye_px=WxH.Utils/VrRenderScaleSetting.cs)--xr-vignette=off|mild|strong(the headset's tunnel vignette, defaultoff: the edge of view darkens while the aircraft turns the view, from 20 to 90 deg/s, the clear cone closing to 40 (mild) or 28 (strong) degrees. Beats the saved Options row (vrVignette), which no--detrun reads; an unknown word is ignored with a note. A flat launch never reads either flag.UI/Boards/XrVignette.cs)--xr-quality=vr|flat(which render settings a headset session flies at, defaultvr: the VR quality profile, anti-aliasing off, the project's 4x MSAA, shadow qualitylowand foveation off, in place of the saved flat options, so a stereo frame at the runtime's eye size holds 90 Hz.flatkeeps the flat options.--anti-aliasing,--msaa,--shadow-qualityand--xr-foveationbeat either. Logs[world] vr quality: profile=...; a flat launch never reads it.Utils/VrQuality.cs)--xr-foveation=on|off(whether a headset shades the edges of each eye coarser, Godot's XR variable-rate shading on the root viewport; defaultoffunder either profile. Full rate round each eye's centre; on the stand-in it saves about 0.9 ms at 3072x3264 per eye and pulls the edge's textures toward coarser mips. Needs Vulkan and a GPU with fragment shading rate; a flat launch never reads it)--look=x,y(hold a right-stick look deflection for the whole run, the scripted twin of pushing the look stick and the only way a headless run aims it. Both components are clamped to[−1, 1],+xright and+yup; a malformed pair warns and leaves the stick centred. It drives both halves of the look-around from one value: outside first person it swings the camera around the plane, and in--view=cockpit/=noseit aims the head, over one shared envelope (±150° round, ±60° up and down, seecontrols.md). A live stick beats it while deflected)--campos=x,y,z(deprecated, the pre-A5 camera-only spelling of--pos; logsWARN [core] deprecated flag=--campos use=--posonce per run, then behaves identically. It never placed the plane and still does not, so it is not simply a rename of--posin--fly. Where both reach the same camera (--freecam,--anim-lab),--poswins)--screenshot=<path>(render a few frames, save a PNG, quit. Implies--no-focusand--det, so a bare--screenshotis reproducible with no other flags;--no-detopts out. The hidden window still renders, a minimized one does not (SHOT-16). Every capture prints[core] shot pixmd5=<md5> size=<WxH> gpu=<adapter / api>, the md5 of the raw pixel buffer rather than of the PNG (SHOT-6), which is what the golden tripwire compares; copying it intoanalysis/goldens/manifest.jsonturns the shot into a golden, seeanalysis/goldens/README.md)--export-gltf=<path>(export the viewer plane's mesh to glTF, then quit: the parked model in its livery with its damage baked in (hidden panel twins, off flares and point sprites pruned). Skins convert toStandardMaterial3Dover reversed winding: baked shading survives, exterior is glTF's front face; live emitters are not part of the model. The extension picks the format:.glbself-contained,.gltfJSON plus buffer and PNGs, else.glb. Reads a throwawayDuplicate(), so the live plane is untouched; implies--det; works headless. Interactive twin F10, intoExports/)--frames=N(warm-up frames rendered before the shot, default 15. Under--det, which--screenshotimplies, this is exactly frame N: the fixed clock advances one 1/60 s step per rendered frame, so N is a frame coordinate and not a wall-clock delay. The saved-shot line carries the frame reached and the counter that named it,frame=120 clock=sim sim_frame=120 sim_time=2; a capture with no session reportsclock=renderand counts rendered frames (docs/tooling.md). Two runs at the same N are md5-identical and different Ns differ, so a shot's frame number is part of what it shows)--shots=N(after the--frameswarm-up, capture N consecutive frames, one per_Process, then quit; default 1 = the single-shot behavior at the verbatim path; N>1 writes zero-padded indexed filesfoo.png→foo_00.png/foo_01.png/… viaIndexedShotPath, for z-fighting debugging since the flicker is only visible across frames)--jitter=<deg>(per-frame camera dither during a--shotsburst, micro-orbits the eye around the framed point (_orbit.OrbitCenter) so a dead-still camera doesn't render bit-identical frames; default 0.15° when--shots>1else 0, and 0 under--detwhatever--shotsis, since the dither exists to break the bit-identity--detwants;0disables; static mode only, in--flythe FlightController owns the camera and the plane's motion already surfaces the fight; file_00is the un-jittered baseline)--xr-sim[=spec](fly through the stand-in headset: stereo through Godot's XR path with no runtime and the head pinned, so a--detshot repeats. Comma tokens:yaw=/pitch=/roll=degrees (+ right, + up, + toward the right shoulder),head=x/y/zmetres from the seated eye,ipd=mm (63),eye=WxHper eye (640x720),fov=horizontal degrees per eye (90),shot=both|left|rightfor what--screenshotsaves (both, side by side). Needs thecsvm_xr_simfeature tag the launch scripts set; else flat. In stereo a canvas layer shows only on the theater screen or the HUD panel)
Left-click picks the object under the cursor; PgUp/PgDn walk its ancestor ladder, Home jumps to the outermost rung and End back to the struck leaf. A breadcrumb names every rung leaf-first with its world-frame box, and a yellow wireframe outlines the current rung's subtree.
Neither mode builds collision (WORLD-9), so the pick casts the camera ray itself, nearest hit wins: objects
by their own AABB (a click just off a thin one can take it), meshes 350 m or wider (terrain tiles, the cloud
deck) by triangle, occluding whatever is behind them. Hide a deck tile to click the ground under the clouds.
A miss logs select miss ... tested=N map_scale=M. Rung names are cs_name, never Godot names (WORLD-8).
Ctrl+click also flips the struck leaf in the cyan-outlined export set (node lab, below).
M attaches the mesh lab to the selected rung's subtree and nothing else; M again, or selecting
something else, puts that subtree back as built. F20 draws the collider wireframes (see --collision);
in --viewer C is the mesh lab's cull cycler. Scripted twin: --debug-mesh=<spec>.
N toggles a panel down the left edge holding the world's cs_name tree, a search box and a dependency
readout for the shared selection; a click scrolls the tree to it, a row selects, a double-click frames. Buttons:
Frame, Hide/Show (flip Visible), Export glTF (the subtree to git-ignored Exports/), Deps,
Destructibles; for the export set ± set (current rung), Export set (one GLB at world positions), Clear set.
The tree fills one branch at a time on expand and stops at 500 rows per branch. The dependency readout lists the anim definitions anchored on or naming the node, its destructible pools with live HP, its mesh and material counts, and its colliders; a source not built in this mode says so rather than reading empty (LOG-1, WORLD-9).
--debug-nodelab[=spec](--freecam/--anim-labonly, the scripted twin: open the panel at launch and dump its readouts to theuilog category on the second frame. Tokens:deps,dest(destructibles view),open(panel only), andnode=<cs_name>(select it first, exact match else first substring). No spec dumps both readouts and changes no selection.)
F19 toggles a panel down the right edge that damages the destructible the shared selection is on. It
lists that object's live HP pools with a slider, Kill and Reset. The unit of control is a pool,
not an object: a node can carry several (def, anchor) pools and a weapon hit resolves to exactly one,
the only reachable one. The slider is absolute HP, spent through AnimRuntime.DamageAt.
A kill reports the swap and the collider census before any clock advance and the debris after it
(WORLD-11), and counts colliders off=N on=M, never a net (WORLD-10). The first damage action builds the
effects runtime --destroy uses; a name outside its fixed closure fires in the log and draws nothing.
--debug-damage[=script](--freecam/--anim-labonly, the scripted twin: open the panel at launch and run an ordered script on the second frame, logging to theuicategory. Steps, left to right:node=<cs_name>,pool=<n>(an unreachable pool is refused out loud),hp=<value>,kill,reset,tick=<seconds>andopen. It forces the collision build on, so the kill's census is real.)
Godot reads these itself and consumes them, so they go between the scene path and the --, never
after it. RunGame.ps1 -EngineArgs '<arg>','<value>' and RunProbe.ps1 -EngineArgs put them there.
--xr-mode onstarts OpenXR through the system's active runtime (XR_RUNTIME_JSONnames another), and with it the multiview shader variantsproject.godotkeeps off.Launch/XrSession.csthen sends the main viewport to the headset and logsxr: OpenXR live runtime=..., or a warning and a flat flight if the runtime did not start. Itsxr framesDebug line in the log file reports the headset's frame pacing once a wall second, with the seat'spos=in chapter metres, its ground speedmps=andmain_max_ms=, the worst main-loop step of that second.offanddefault(the project setting) leave it flat. An exported build takes it the same way,CSVM.exe --xr-mode on [-- <user args>], which is the command line the release zip'sCSVM-VR.cmdruns (packaging/MANIFEST.md).--render-thread safe|separateoverridesproject.godot's separate render thread for one launch;saferenders on the main thread.
VR mode and --xr-mode. The Options row (the VIDEO page's VR Mode dropdown, the last row of its
scrolled window) saves vrMode in options.json. Applied from the menu with a change, it
restarts the executable with --xr-mode on placed first, every other argument (engine and user)
carried verbatim and --skip-intro added; turning it off restarts it without the flag. A launch with
VR mode saved on and no --xr-mode restarts itself once at boot, and --xr-mode off keeps a launch
flat by name. The child carries the flag, so it never restarts again: a runtime that does not start
leaves the flat game with a notice on the menu, and so does a new process that fails to start. A run
that is --det, --run-tests, scripted, --headless, --xr-sim, a dev mode, a lab,
--net-host/--net-join or not on Windows never restarts for VR mode and never reads the saved
choice (Launch/XrRelaunch.cs). Under a headset or --xr-sim
the game flies one seat: --players above one is refused with a warning and the join boards close
the other seats. A headset flight opens in Cockpit unless --view= names a view, whatever the saved
Default View, and its head look, look-behind and chase swing are off (docs/org/cameraViews.md,
"Views under a headset"). Every cut a headset sees lands on a black frame and fades in over 0.3 s, a view key darkening over 0.15 s first (UI/Boards/ComfortQuads.cs). The VIDEO page under a live headset carries the VR render scale and comfort vignette rows in Display Mode's and V-Sync's places, applied at once. A headset launch deletes the shader cache files it wrote as it ends, so the next flat
launch reads none of them (Launch/XrShaderCache.cs).
--xr-sim is a user argument, but what it needs is engine state: Godot compiles the multiview
shader variants only at start, and project.godot turns them on (and the shared shader cache off)
under the csvm_xr_sim feature tag. The editor binary reads custom tags from the
GODOT_EDITOR_CUSTOM_FEATURES environment variable, which the three launch scripts set for that
one process alone. A direct launch needs it set by hand; a shell that keeps it set gives every later
launch from it the stand-in's variants and no shader cache.