RenderHost

interface RenderHost
devtools/src/harness.ts:303

Members

boot

boot() → BootPhase

How far the presentation has come up: no renderer yet, a renderer drawing under the boot cover, or the cover lifted. A host with nothing to present — Node, the headless runner — is booted from the start.

cameraProcessing

cameraProcessing() → PictureProcessing

The player's settings, independent of cinematic and instrument staging.

clearTerrainCache

clearTerrainCache() → Promise<void>

declareCut

declareCut() → void

Discontinuous camera placement invalidates presentation history only.

frameStats

frameStats() → FrameStats | null

framingLens

framingLens() → Lens

The lens the framing solver uses: the flight one, never the composed one.

Separate from lensView because the observatory is the one consumer that must not see the cutscene arm. It produces a camera only when that arm is null, so framing a target against a script's lens is the observatory depending on the arm it is defined as the fallback for — and the standoff it solves is stored, so the error outlives the cutscene that caused it. Measured: focus('s:SOL/b:2') during tng-intro parks the camera 29.8 Mm out against the 20.8 Mm the flight lens asks for, 43% too far, permanently. The flight preset headlessly, where there is no camera panel.

galaxyRender

galaxyRender() → GalaxyRenderReport | null

The live volume, if a renderer is attached.

guide

guide() → GuideHostPort | null

The active mode supplies this lazy adapter; a headless host need not.

lensView

lensView() → LensView | null

The lens the picture is being taken with, and the pixels it lands on.

A getter rather than a setter for the same reason world is: the engine resolves the lens every frame under the pose's own precedence — a script's lens, then the flight one — and a host that pushed a copy in here would hold a second producer of it, which is the rule this phase exists to keep. ir.lens() reads it to print the instrument; the terrain predicate reads it to measure one. The observatory does not — it takes framingLens() below, and the block there says why. Null headlessly, where there is no camera and no display.

measureGpu

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

Submit frames frames through whatever presents one and time them across a drained queue — milliseconds per frame.

The one GPU figure this project trusts, and the reason it is a verb and not a field: the queue drain is an await in the middle of a frame, which is the stall being measured, so it cannot be sampled. Null where there is no device to drain — the WebGL backend, and every headless host — so ir.gpu() says so rather than printing a number about nothing.

framesnumber
Undocumented

measurePasses

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

measureGpu's frames with every pass timed and named. Null where there is no device, the device has no timestamp-query, or no presenting chain is mounted — measureGpu falls back to a bare render there, and this does not time a path nothing presents.

framesnumber
Undocumented

picture

picture(debugView?: string) → PictureReport | null

Inspect reconstruction or select a diagnostic view without persisting it.

debugViewstring
Undocumented

pixelRatio

pixelRatio() → number

How many display pixels one CSS pixel is, on this host.

The drag sensitivity needs both and they are not the same number. lensView().viewport is display pixels with supersampling divided out and the device ratio deliberately kept — the terrain predicate and the circle of confusion are claims about physical pixels. A pointer delta is in CSS pixels. On a 2× display the two differ by two, and a sensitivity that conflated them moved the picture at half the rate of the hand. 1 headlessly, which is also the honest answer for a display that has no ratio to report.

scene

scene() → RenderScene | null

setCameraProcessing

setCameraProcessing(processing: PictureProcessing) → void

Restore processing through the same preference owner as the camera panel.

processingPictureProcessing
Undocumented

setChrome

setChrome(visible: boolean) → void

Put the interface in or out of the frame.

A plate is defined as the frame taken with the chrome cleared, and a plate has to be reproducible from a script — so the state Shift+H reaches has to be reachable from here too. Headlessly there is no interface to clear.

visibleboolean
Undocumented

setFlightLens

setFlightLens(lens: Lens) → void

Fit a lens, for the two verbs that solve one.

preset and rise compose a picture whose lens is part of it — Earth is 1.9° across from Luna and Mars is 42.39° from Phobos, so a rise that did not fit its own lens would produce two very different frames under one name. Not a second producer of the lens: engine.lens still resolves the cutscene arm first and the flight lens second, and this writes the same flight lens a panel's slider writes. A no-op headlessly, where there is no camera to fit it to and the arithmetic is worth running anyway.

lensLens
Undocumented

setLayers

setLayers(visible: boolean) → void

Put the sky's own layers — names and traces — in or out of the frame.

Separate from setChrome because they are different claims: chrome is the interface and these are content, so Shift+H clears the first and leaves the second. A plate wants both gone, because a thumbnail of a picture is a thumbnail of what the camera does and the layers are the viewer's.

visibleboolean
Undocumented

terrain

terrain() → TerrainReport | null

What the terrain streamer is doing this frame.

The one number in the terrain rig that cannot be derived: simulateDescent says what the streamer would be asked for, and this says what it actually has — how many patches are on screen, how deep the worker queue is, and whether the cache is holding. The two disagreeing is the interesting case.

terrainCache

terrainCache() → Promise<TerrainCacheReport>

timing

timing() → TimingPort | null

The performance timeline, when the host has one.

Null rather than an empty port, because a host without one has a real answer — "this runtime does not put entries anywhere" — and ir.profile() says so instead of returning an empty report that reads like a fast session.