GameHarness

class GameHarness
devtools/src/harness.ts:593

Members

constructor

constructor(host: Host, scripts: readonly CutsceneScript[]) → GameHarness
hostHost
Undocumented
scriptsreadonly CutsceneScript[]
Undocumented

cutscenereadonly

The cutscene director, the way observatory is the observatory: the object itself rather than a forward per verb. ir.cutscene.status(), .lastOutcome(), .list() and .peek() are its reads; .sample() is the host's per-frame call, which moves the playhead and can end the scene, not a read. play, stopCutscene and seekCutscene stay on the harness as the three verbs a console types.

flightCameraaccessor

flightCamera() → FlightCamera

The ship arm's own camera: which view it stands in, and where.

The object, for the same reason the observatory is: a drag is forty calls a second. ir.view below is the verb worth typing.

observatoryaccessor

observatory() → Observatory

The free camera the planetarium is built on.

Exposed as the object rather than wrapped verb by verb: a pointer drag is forty calls a second and going through the harness for each would be a layer that exists only to be crossed. The convenience verbs below are the ones worth typing at a console.

onFootaccessor

onFoot() → OnFoot

Stepping out of a landed ship and back in: stepOut, board, atMarsPad, status. The object, as the observatory is, so a host's controls and a console reach the same walker.

timingaccessor

timing() → TimingVerb

The performance timeline: the level, the tracks, a marker, and the entries.

A callable object, so the verb everybody wants — ir.timing('trace') — is the short one and the rest hang off it. That is the shape ir.terrain() and ir.terrainBaseline() already argue for: the console is discoverable by tab-completion, and a verb that reads like a sentence is the one an agent writes into a --js without checking.

Built once and cached, because a fresh closure per read would make ir.timing.drain !== ir.timing.drain and break any script that held onto one.

trackOverlayShowingaccessor

trackOverlayShowing() → boolean

Whether trackOverlay is on. Read once a rendered frame by the host.

worldaccessor

world() → World

aim

aim(yaw: number, pitch: number) → ObserverStatus

Turn the head, in degrees, without moving the camera.

The free-look offset as a harness verb, so every act a planetarium button offers is reachable from a script — which is what makes a plate a command rather than a gesture. In orbit the pair is an offset from the pose, so ir.aim(0, 0) is the way back to whatever the pose is looking at.

Standing it is not an offset at all: the stance is the heading and the pitch, so these are absolute — a compass bearing and an angle above the horizon, which is what ir.visit already takes. ir.aim(0, 0) on the ground therefore faces due north and level, which is a place rather than a recentering. The way back to the composed aim on either arm is observatory.center() — the panel's Recenter button — which levels to the horizon without touching the bearing.

yawnumber
Undocumented
pitchnumber
Undocumented

ascend

ascend() → ObserverStatus

Back to orbit, at the framing the camera had before the descent.

bodies

bodies(system?: string) → readonly { 6 fields }[]

Bodies of a loaded system, as a flat listing.

systemstring
Undocumented

burnToward

burnToward(address: string, throttle: number) → HarnessStatus

Aim the ship at a body and light the main drive.

addressstring
Undocumented
throttlenumber
Undocumented

capturePicture

capturePicture(id: string, label: string, why: string) → Picture
idstring
Undocumented
labelstring
Undocumented
whystring
Undocumented

chrome

chrome(visible: boolean) → boolean

Put the interface in or out of the frame.

The harness half of Shift+H, and the reason it is a verb at all: a plate is defined as the frame taken with the chrome cleared, and pnpm presets:plates is a script. A gesture no script can make is a fixture nobody can regenerate.

visibleboolean
Undocumented

clearTerrainCache

clearTerrainCache() → Promise<void>

compose

compose(id: string) → ObserverStatus

Take a named composition of whatever the camera is on.

The observatory's placer for the same sixteen ir.shot frames with a hull. ir.shot('gibbous') teleports the ship into the picture; this moves the camera into it, changing no canonical state — and three of the sixteen were reachable only the first way until the aim became an offset.

idstring
Undocumented

control

control(input: { rotation?: [number, number, number]; throttle?: number; translation?: [number, number, number] }) → void

Set the player's control input directly, as the keyboard would: the thrusters, the attitude, and the drive's throttle, each only if given.

input{ rotation?: [number, number, number]; throttle?: number; translation?: [number, number, number] }
Undocumented

descend

descend(address?: string, options: DescentOptions) → DescentReport & { text: string }

Fly a descent on paper and report what the streamer would be asked for.

The unit of terrain measurement. Pure arithmetic — no world state changes, no worker runs, no frame is drawn — so it produces the same numbers in a browser console, in pnpm sim and in a Node test. What it answers is the gap-table line "no terrain perf baseline": the level churn, the peak burst and the cache behavior of a descent from orbit to two meters.

addressstring
Undocumented
optionsDescentOptions
Undocumented

dossier

dossier(address: string) → Dossier | null

Everything known about one star or one body, as a page of astronomy.

The object panel's whole source. Split from inspect — which is an entity readout, a pose and a velocity — because a body is not an entity and the question "what is Europa" has no answer in the entity store.

addressstring
Undocumented

drop

drop(latitude: Degrees, longitude: Degrees, options: { address?: string; seconds?: number }) → ObserverStatus

Fly the camera from orbit down to a point on the ground, and stand there facing the star.

The eased entry visit is not: the camera flies the ballistic arc over seconds of wall clock and the frame after this returns is the first frame of the descent, not the last. ir.ascend() abandons one in flight. Degrees at this boundary, radians below it, like visit.

latitudeDegrees
Undocumented
longitudeDegrees
Undocumented
options{ address?: string; seconds?: number }
Undocumented

face

face(address: string) → HarnessStatus

Point the nose at a body without touching its trajectory.

addressstring
Undocumented

findWorlds

findWorlds(query: WorldQuery, options: { lightYears?: number; limit?: number; onBatch?: (found: readonly WorldMatch[], progress: number, total: number) → void }) → { cancel: () → void; done: Promise<readonly WorldMatch[]>; systems: number }

Search the volume for bodies that answer a query, in batches.

The other question a catalog can be asked. search answers "what is called this" from an index; this answers "what is out there like this", and it cannot come from an index because the bodies do not exist until they are generated. So it is a sweep, and the sweep is the cost: a system is milliseconds to build and a body is microseconds to test.

It answers in batches rather than once. The volume is cut into jobs and each is submitted separately, so rows arrive while the search is still running and a fifty-light-year question is not a blank panel for two seconds. That shape is forced as well as chosen: a job is one request and one response, with no partial-result message in the protocol, so streaming has to be several jobs rather than one job that reports as it goes.

cancel stops it — the queued jobs are dropped and the running ones are told through TaskContext.canceled, which findWorlds polls once per system. A second question therefore does not wait behind the first one's whole volume.

With no pool the batches run inline, on this thread, in order. That is the headless runner and it is slow rather than wrong, which is the same bargain every other task here makes.

queryWorldQuery
Undocumented
options{ lightYears?: number; limit?: number; onBatch?: (found: readonly WorldMatch[], progress: number, total: number) → void }
Undocumented

flightAssist

flightAssist(enabled: boolean) → void
enabledboolean
Undocumented

galaxy

galaxy() → GalaxyInspector

Field diagnostics read the current session without mutating generation.

galaxyJourney

galaxyJourney(progress: number, seconds: number) → ObserverStatus

Travel from Earth to the disk with the player's camera and presentation time.

progressnumber
Undocumented
secondsnumber
Undocumented

galaxyView

galaxyView(view: 'face-on' | 'edge-on') → ObserverStatus

Select a fixed external instrument without moving anything in the world.

view'face-on' | 'edge-on'
Undocumented

goTo

goTo(destination: string, options: { altitudeKm?: number; distanceAu?: number }) → HarnessStatus

Go anywhere, given anything that names it. See Maneuvers.goTo.

destinationstring
Undocumented
options{ altitudeKm?: number; distanceAu?: number }
Undocumented

goToSystem

goToSystem(system: string, distanceAu: number) → HarnessStatus

Drop the player into interstellar space near a system.

systemstring
Undocumented
distanceAunumber
Undocumented

gpu

gpu(frames?: number) → Promise<{ frames: number; ms: number } | null>

The GPU's cost per presented frame, in milliseconds.

The perf dock's "measure GPU" button from a script, so a driver can take the figure without a click — render/measure.ts says why it is the only GPU number here worth quoting. Null, and a sentence, where the host has no device to drain.

framesnumber
Undocumented

guideAsk

guideAsk(text: string) → Promise<GuideStatus>

An explicit console request uses the same active guide as its dock panel.

textstring
Undocumented

guideStatus

guideStatus() → GuideStatus

Read the existing guide without importing it or opening a connection.

guideTrace

guideTrace(enabled?: boolean) → readonly GuideTraceEntry[]

Read recent messages, or explicitly toggle console tracing for this mode.

enabledboolean
Undocumented

help

help() → string

Text help, so the console is discoverable without reading this file.

hold

hold() → void

Hands off everything: thrusters neutral, attitude neutral, drive cold.

inspect

inspect(id?: string) → EntityInspection | null
idstring
Undocumented

land

land(address: string, latitude: Degrees, longitude: Degrees) → HarnessStatus

Park the player on the ground, in degrees like every other verb.

addressstring
Undocumented
latitudeDegrees
Undocumented
longitudeDegrees
Undocumented

layers

layers(visible: boolean) → boolean

Names and traces in or out of the frame.

Not part of chrome, because they are content rather than interface — the viewer turned them on and Shift+H leaves them alone. A plate is the one capture that wants them gone: the thumbnail is of what the preset does, and a trace slashing across it promises a layer the press does not set.

visibleboolean
Undocumented

lens

lens() → LensReadout | null

The camera's optics, as an instrument: focal length, aperture, the derived depth of field, the diffraction limit and the exposure.

Null headlessly, where there is no display to resolve a circle of confusion against — the honest answer rather than a plausible one taken at a nominal resolution nobody is looking at.

light

light(address?: string) → { address: string; lit: boolean; phase: number | null; sun: number | null }

How lit the view is, in degrees.

The number a scenario is chosen by. A comparison taken in the dark is a comparison of noise — a star field jittering under a black disk — and the habit this exists to break is picking an address, standing somewhere on it, and photographing whatever the terminator happened to leave. On the ground sun is the star's elevation above the local horizon, negative after sunset; from orbit phase is the angle at the body between the eye and the star, zero for a full face and 180 for a silhouette. Both are at the observatory's held instant, which is the picture's. lit is the verdict: a sun more than three degrees up, or a phase under a hundred.

A star is always lit, and the far side of the galaxy is a question for ir.galaxy(); both answer with nulls and lit: true.

addressstring
Undocumented

load

load(text: string) → Result<LoadOutcome, string>

Restore a save into this session.

Restored against this world's catalog, not the one the save names: a save is a set of references, and resolving them needs the catalog the client actually has. What the save was written against comes back as drift, which used to be computed only while building the message for a load that had already failed — so the interesting case, a load that succeeded into a sky that had moved, was silent.

textstring
Undocumented

loadSystem

loadSystem(system: string) → readonly { 6 fields }[]

Generate a system and install its frames without going there.

bodies() only sees systems that are loaded, so browsing what is in the next system along used to require flying to it first. This is the seam that makes looking cheaper than traveling.

systemstring
Undocumented

logs

logs(limit: number) → readonly LogRecord[]
limitnumber
Undocumented

look

look(destination: string, options?: { ease?: boolean; fill?: number }) → ObserverStatus

Look at something without going there.

The planetarium's whole verb, and the difference from goTo is the point: goTo teleports the ship, changing canonical state; this moves only a camera. ir.look('s:SOL/b:5') and ir.goTo('s:SOL/b:5') end with Jupiter filling the frame, and only one of them leaves you in orbit of it.

destinationstring
Undocumented
options{ ease?: boolean; fill?: number }
Undocumented

moveStructure

moveStructure(structure: SurfacePlacement) → void

Move a structure atomically; invalid coordinates leave its existing anchor intact.

structureSurfacePlacement
Undocumented

observerSample

observerSample(dt: number) → ObserverPose | null

The observatory's pose for this frame, for the rendering host.

dt is wall-clock seconds, not simulation time — the fly-to easing is a presentation filter and has to keep running while the clock is paused.

dtnumber
Undocumented

observerStatus

observerStatus() → ObserverStatus | null

The observatory's camera, or null when it has no target.

orbit

orbit(address: string, altitudeKm?: number) → HarnessStatus

Put the player in a circular orbit around a body — or, given a system address, around its star. Maneuvers.orbit holds the placement.

addressstring
Undocumented
altitudeKmnumber
Undocumented

passes

passes(frames?: number) → Promise<PassReport | null>

Where the GPU's frame goes, pass by pass.

gpu()'s held frames with a timestamp pair on every pass three encodes, named by the target it draws into — scene is the sensor's pass, and a scene after copy row is the same pass resumed after the sea read the frame behind it. gaps are the time between passes that none accounts for: a copy, a raw WebGPU pass such as the upscaler's. The upscaler's own passes are in owned, timed by its own timer over the run's first frames, as many as it has query slots, and reported beside the rest as begin-to-end means. wallMs is the drained figure over the same frames, so busyMs can be checked against it. Null where the host has no device, no timestamps, or no presenting chain — the last is a case where gpu() still answers.

framesnumber
Undocumented

pause

pause() → void

picture

picture(debugView?: string) → PictureReport | null

Reconstruction dimensions, jitter phase, allocations and GPU timings.

debugViewstring
Undocumented

placeStructure

placeStructure(structure: SurfacePlacement) → void

Place a durable structure; angles are degrees, height is above terrain.

structureSurfacePlacement
Undocumented

play

play(id: string, options?: PlayOptions) → CutsceneStatus

Play a scripted scene. Presentation only: the camera and the hero hull follow the script while the world keeps ticking, and stopping — or the script ending — restores the player's captured state, clock settings included. The game boots exactly as it always did; this runs only when asked to, from the dock's cutscene section or here. hold keeps the last frame on stage instead of restoring on it — the cinema player's way of watching; a measurement wants the default.

idstring
Undocumented
optionsPlayOptions
Undocumented

preset

preset(id: string) → { fovDeg: number; picture: Picture; status: ObserverStatus }

Take a named picture — the same frame, every time.

A composition plus the two things a composition leaves out: an address and a lens. That is what makes it a fixture rather than a framing, and a fixture is what a before/after plate is — the geology phase is judged from these, so they exist before the geology does.

The lens is fitted, through the host's own owner of it — a picture that named a lens and did not wear it would be a fixture that produced a different frame on a machine with a different slider position. It comes back as well, because a caller composing a plate has to be able to say what the picture was taken at.

Headlessly the port is absent and the fit is a silent no-op: the arithmetic is worth running there and there is no display for a field of view to be about.

idstring
Undocumented

presets

presets() → readonly { id: string; label: string; why: string }[]

The pictures preset can take.

profile

profile(ms: number) → Promise<ProfileReport>

Arm, record, disarm, report.

The verb that matters, and the reason phase 5 exists: one --js call gives a terminal a sentence about why the last two seconds were slow, rather than a screenshot and a p95. It returns structured data and a .text block, the shape terrainBaseline already established.

The level is restored afterward rather than left at full, so a profile taken mid-session does not silently leave the retained timeline growing for the rest of it.

msnumber
Undocumented

removeStructure

removeStructure(id: string) → void
idstring
Undocumented

resume

resume() → void

rise

rise(options: { clearance?: number; height?: number }) → { fovDeg: number; status: ObserverStatus }

Stand on a moon with its parent over the horizon. Earthrise.

The one composition that names two bodies, so it is the one that cannot be a compose id. The lens it solves comes back rather than being applied: the observatory has no lens of its own by design, so fitting it is the shell's — ir.rise() from a console reports the angle and leaves the camera panel alone, which is the honest split rather than a verb that quietly moves a control somebody else owns.

options{ clearance?: number; height?: number }
Undocumented

rowsFor

rowsFor(addresses: readonly string[], options: TravelTargetOptions) → readonly TravelTarget[]

Rows for addresses the caller already holds, nearest first not implied — the order is the caller's.

The third question, after targets and search: a fuzzy index in the navigator answers with addresses, and this turns them back into the rows the survey draws, measured from the same eye. b:2 and friends resolve against the system the player is in, exactly as goTo reads them; an address that names nothing is dropped rather than thrown, so one stale entry cannot empty the list.

addressesreadonly string[]
Undocumented
optionsTravelTargetOptions
Undocumented

runSeconds

runSeconds(seconds: number) → HarnessStatus

Advance n seconds of simulation time, exactly.

secondsnumber
Undocumented

save

save() → string

scenario

scenario(name: string) → Promise<ScenarioResult>

Named, repeatable set-ups. Each returns the resulting status.

namestring
Undocumented

scenarios

scenarios() → readonly string[]

searchEntries

searchEntries() → readonly SearchEntry[]

Every string a place can be found by, paired with its address.

What a fuzzy matcher indexes. The matcher itself lives in the client — it is a third-party dependency, which packages/* may not carry — so the boundary is this list: names out, addresses back in through rowsFor. searchIndexVersion says when the list has changed.

searchIndexVersion

searchIndexVersion() → string

seekCutscene

seekCutscene(frame: number) → CutsceneStatus

Jump the playhead to a reference frame. Pause first for a frame-exact still — that pairing is the verification pipeline's capture loop.

framenumber
Undocumented

selfTest

selfTest() → Promise<{ passed: number; report: string; results: readonly CapabilityResult[]; total: number }>

Run the twelve milestone capability checks against the live build.

settled

settled() → { galaxy: { pending: boolean; survey: boolean; tiles: string } | null; ok: boolean; terrain: { patches: number; pending: number } | null }

Whether the picture has stopped changing on its own.

What a capture waits for, instead of a number of milliseconds guessed at once. The sky's physical cubes publish tile by tile and the terrain streamer fills in from a worker pool, and a still taken while either is in flight differs from the next by thousands of pixels with the camera never moving. ok is every readout quiet; the rest says which one was not. Headlessly there is nothing to converge and the answer is yes.

shot

shot(name: string, address?: string) → HarnessStatus

Frame a named composition of a body — a camera bookmark. See Maneuvers.shot.

namestring
Undocumented
addressstring
Undocumented

shots

shots() → readonly { description: string; name: string }[]

The compositions shot can frame.

sites

sites(address?: string) → readonly { 8 fields }[]

The named places on a body — what visit and descend take.

Derived from the body's own field rather than authored, so a site survives regeneration by construction: "the highest ground on this world" is still the interesting place after the generator changes, and a latitude written down last month is not. See surveySites.

Empty on a giant, the same answer Observatory.sites gives. surveySites derives from body.surface, which every body carries — Jupiter included — so without the filter here the Ground section draws six clickable cards for ground that visit refuses, and each of them throws out of an onClick.

addressstring
Undocumented

snapshot

snapshot(alpha: number) → WorldSnapshot
alphanumber
Undocumented

status

status() → HarnessStatus

Everything the debug overlay shows, as data.

step

step(ticks: number) → HarnessStatus

Advance exactly n ticks, ignoring wall clock.

ticksnumber
Undocumented

stopCutscene

stopCutscene() → void

Stop the running cutscene and restore the player. Safe when idle.

structures

structures() → { 7 fields }[]

Surface anchors, in degrees and meters at the harness boundary.

summary

summary() → string

Compact one-line summary, for a quick look from a console.

systemsNearby

systemsNearby(lightYears: number) → readonly { id: string; lightYears: number; name: string }[]

Star systems within lightYears of the player, nearest first.

lightYearsnumber
Undocumented

takePicture

takePicture(picture: Picture) → { fovDeg: number; picture: Picture; status: ObserverStatus }
picturePicture
Undocumented

target

target(address: string | null) → ObserverStatus

Keep a companion in the composition while orbiting the current body.

addressstring | null
Undocumented

targets

targets(options: TravelTargetOptions) → readonly TravelTarget[]

Everywhere the player can be sent right now, nearest system first, each system followed by its bodies if it is loaded.

The one call that answers "where can I go?", which nothing answered before: every other verb here takes an address and none of them would tell you one. The debug overlay renders this list and the console prints it.

optionsTravelTargetOptions
Undocumented

terrain

terrain() → TerrainReport | null

terrainBaseline

terrainBaseline(options: BaselineOptions) → TerrainBaseline & { text: string }

The Phase 0 baseline: the zoo, a descent over each member, and the measured cost of generating the patches those descents ask for.

The CPU half only. Frame cost, draw calls and the worker queue's real depth need a browser, and the summary says so rather than inventing them.

optionsBaselineOptions
Undocumented

terrainCache

terrainCache() → Promise<TerrainCacheReport>

What the live streamer has this frame, or null in a host that draws nothing.

The counterpart to descend: that one says what should be asked for, this says what is actually held. Headlessly it is always null, and that is the honest answer rather than a zero.

throttle

throttle(fraction: number) → number

The main drive, 0..1. Returns the setting the world kept.

fractionnumber
Undocumented

timeWarp

timeWarp(scale: number) → void
scalenumber
Undocumented

trackOverlay

trackOverlay(on: boolean) → boolean

Draw the reference edit's tracked subject over the scene as it plays.

A debug surface for the seek-and-compare loop: the reference's box for the frame on screen, the render's own hull projected and boxed beside it, and the hull's nose and velocity as two short vectors — so "the descent is late" is a picture rather than two columns of a CSV.

A flag rather than a drawing, because this layer has no DOM and no React: apps/game/src/hud/TrackOverlay.tsx reads it once a frame while a scene is playing and draws nothing at all when it is false, which is the same arrangement every other presentation switch here uses.

Deliberately not persisted and not in the URL. A capture run navigates a fresh page and never turns this on, so it cannot end up in a render of the sequence — which is the one thing a surface drawn over the picture must never do. A remembered flag would put it in the next capture instead.

onboolean
Undocumented

view

Stand the flight camera in a view — chase, which flight is played in, or orbit, which the hull is looked at in — or cycle to the next with no argument. Nothing canonical moves: the ship is where it was, and only the eye beside it changes.

viewFlightView
Undocumented

visit

visit(address?: string, options: { 6 fields }) → ObserverStatus

Stand on a body and look at it. No ship, no physics, no canonical write.

The planetarium's other camera arm — see Observatory.stand. ir.land teleports the ship onto a pad and is a canonical change; this moves a camera to a place a ship may never go, at a height a slider can scrub from half a radius down to two meters.

The height is set outright rather than eased, which is what makes a plate loop work: for (const h of heights) { ir.visit(a, {site, height: h}); await ir.shot(...) } captures a descent one frame per rung, with nothing settling in between.

addressstring
Undocumented
options{ 6 fields }
Undocumented

visitStructure

visitStructure(id: string, height: number) → ObserverStatus

Stand above a structure in the planetarium, looking toward its northern approach.

idstring
Undocumented
heightnumber
Undocumented

zoo

zoo() → readonly ZooEntry[]

One body per surface archetype, found rather than written down.

The fixture every visual phase is judged through. It loads systems while it searches — the same caveat capability check 3 carries — and stops as soon as all four archetypes are filled.