@threenative/core 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,23 +1,221 @@
1
1
  import * as three from 'three';
2
- import { AnimationMixer, Object3D, AnimationClip, Camera, Vector3, Group, Matrix4, Mesh, BufferGeometry, Material, InstancedMesh, ColorRepresentation, Box3, Scene, DirectionalLight, Sprite, DataTexture, CatmullRomCurve3, Texture } from 'three';
3
- export { I as IAssetLoader, a as IAssetLoaderOptions, c as createAssetLoader, r as reconcileMirroredClips } from './assets-kyoF7JlJ.js';
4
- export { A as AudioBus, I as IAudioBusOptions, b as IAudioPlayOptions } from './audio-BFiGneTL.js';
5
- export { C as CanvasLayer } from './canvas-layer-BLVijiUJ.js';
6
- import { a as IGamePluginRuntime, b as IGamePluginHooks } from './game-XGrTzapq.js';
7
- export { A as AfterPhysicsCallback, C as ContextMenuPolicy, c as ICtx, I as IGame, d as IGameObservationContribution, e as IGameObservationSampleRequest, f as IGamePlatformSource, g as IInputAction, h as IInputGamepad, i as IPointerDragHandle, j as IPointerEvent3D, k as IPointerEvents3D, l as IPointerEvents3DOptions, m as IPointerEvents3DPicker, n as IPointerState, o as IRandom, p as IRawInputPointer, q as IRawInputPointerEdge, r as IRawInputState, s as IRaycastOptions, t as IScenePickerOptions, u as IThreeNativeAudioConfig, v as IThreeNativeAudioLoop, w as IThreeNativeAudioOverride, x as IThreeNativeAudioSpectrum, y as IThreeNativeBootSplash, z as IThreeNativeConfig, B as IThreeNativeIconVariants, D as IThreeNativeTexturesConfig, E as ITweenOptions, F as IWarmUpCacheOptions, G as IWarmUpObservation, H as IWarmUpOptions, J as IWarmUpProgress, K as IWarmUpRenderer, L as IWarmUpReport, M as InputBindings, N as InputPlatformSource, P as PointerEvent3DListener, O as PointerEvent3DType, Q as PointerEvents3D, S as Scene, R as SceneFrame, T as ScenePicker, U as ScheduleHandle, V as Scheduler, W as ThreeNativeBackgroundMode, X as ThreeNativeOrientation, Y as ThreeNativeUiRenderer, Z as WarmUpCacheStatus, _ as WarmUpObservationStatus, $ as afterPhysics, a0 as createRandom, a1 as defineGame, a2 as warmUpScene } from './game-XGrTzapq.js';
2
+ import { Object3D, AnimationClip, AnimationMixer, Camera, Vector3, Group, Matrix4, Mesh, BufferGeometry, Material, InstancedMesh, ColorRepresentation, Box3, Scene, DirectionalLight, Sprite, DataTexture, CatmullRomCurve3, Texture } from 'three';
3
+ export { I as IAssetLoader, a as IAssetLoaderOptions, c as createAssetLoader, r as reconcileMirroredClips } from './assets-CYKk2WTu.js';
4
+ export { A as AudioBus, I as IAudioBusOptions, b as IAudioPlayOptions, r as resetAudioCueLedger } from './audio-7i3Xl0l3.js';
5
+ export { C as CanvasLayer } from './canvas-layer-C1SnMoJ-.js';
6
+ import { a as IGamePluginRuntime, b as IGamePluginHooks } from './game-D_6r-k4Y.js';
7
+ export { A as AfterPhysicsCallback, C as ContextMenuPolicy, G as GEOMETRY_ASSET_KEY, c as GEOMETRY_CAPTURE_DEFAULT_LIMIT, d as GEOMETRY_CAPTURE_MAX_LIMIT, e as GEOMETRY_CAPTURE_SORTS, f as GEOMETRY_CAPTURE_TIMEOUT_MS, g as GEOMETRY_CAPTURE_WALK_CAP, h as GeometryCaptureSort, i as ICtx, I as IGame, j as IGameObservationContribution, k as IGameObservationSampleRequest, l as IGamePlatformSource, m as IGeometryCaptureAsset, n as IGeometryCaptureMesh, o as IGeometryCapturePass, p as IGeometryCaptureReport, q as IGeometryCaptureRequest, r as IGeometryCaptureRow, s as IInputAction, t as IInputGamepad, u as IPointerDragHandle, v as IPointerEvent3D, w as IPointerEvents3D, x as IPointerEvents3DOptions, y as IPointerEvents3DPicker, z as IPointerState, B as IRandom, D as IRawInputPointer, E as IRawInputPointerEdge, F as IRawInputState, H as IRaycastOptions, J as IScenePickerOptions, K as IThreeNativeAudioConfig, L as IThreeNativeAudioLoop, M as IThreeNativeAudioOverride, N as IThreeNativeAudioSpectrum, O as IThreeNativeBootSplash, P as IThreeNativeConfig, Q as IThreeNativeIconVariants, R as IThreeNativeLodConfig, S as IThreeNativeLodGenerationConfig, T as IThreeNativeLodOverride, U as IThreeNativeLodRuntimeConfig, V as IThreeNativeTexturesConfig, W as ITweenOptions, X as IWarmUpCacheOptions, Y as IWarmUpObservation, Z as IWarmUpOptions, _ as IWarmUpProgress, $ as IWarmUpRenderer, a0 as IWarmUpReport, a1 as InputBindings, a2 as InputPlatformSource, a3 as PointerEvent3DListener, a4 as PointerEvent3DType, a5 as PointerEvents3D, a6 as Scene, a7 as SceneFrame, a8 as ScenePicker, a9 as ScheduleHandle, aa as Scheduler, ab as ThreeNativeBackgroundMode, ac as ThreeNativeLodMinTrianglesScope, ad as ThreeNativeLodPreset, ae as ThreeNativeOrientation, af as ThreeNativeUiRenderer, ag as WarmUpCacheStatus, ah as WarmUpObservationStatus, ai as afterPhysics, aj as createRandom, ak as defineGame, al as warmUpScene } from './game-D_6r-k4Y.js';
8
8
  import * as three_webgpu from 'three/webgpu';
9
9
  import { StorageTexture, ComputeNode, UniformNode, Node, TextureNode, NodeMaterial, StorageBufferNode, StructTypeNode, Data3DTexture, ShadowBaseNode, NodeBuilder, NodeFrame, SpriteNodeMaterial, StorageTextureNode } from 'three/webgpu';
10
- import { I as IRendererLike } from './renderer-C6hqZpoG.js';
11
- export { D as DEFAULT_PIPELINE_CENSUS_LIMIT, F as FRAME_BUDGET_MARKER, a as FRAME_BUDGET_PHASES, b as FRAME_HITCH_MARKER, c as FrameBudget, d as FrameBudgetPhase, e as IFrameBudgetOptions, f as IFrameBudgetSummary, g as IFrameBudgetWindow, h as IFramePhaseSample, i as IPipelineCensus, j as IPipelineCensusCounts, k as IPipelineCensusEvent, l as IPipelineCensusOptions, m as IPipelineProvenance, n as IPipelineShaderObservation, o as IRenderChainApplied, p as IRenderChainBudgetWindow, q as IRenderChainDroppedStage, r as IRenderChainOptions, s as IRenderChainRenderer, t as IRenderChainRequest, u as IRenderChainStage, v as IRenderChainStageContext, w as IRenderChainVelocityMeasurement, x as IRenderChainVelocityReport, y as IRenderChainVelocityRequest, z as IRenderChainVelocityResult, A as IVelocityRenderPass, P as PIPELINE_CENSUS_CAPABILITY, B as PIPELINE_CENSUS_VERSION, C as PipelineCensus, E as PipelineCensusMode, G as PipelineCensusStatus, R as RENDER_CHAIN_MARKER, H as RENDER_CHAIN_STAGE_ORDER, J as RENDER_CHAIN_TIERS, K as RenderChain, L as RenderChainSource, M as RenderChainStageId, N as RenderChainStageName, O as RenderChainTier, Q as RenderChainTierRequest, S as RenderChainVelocitySource, V as VELOCITY_OUTPUT_NAME, T as VELOCITY_PREVIOUS_BONE_MATRICES, U as VELOCITY_PREVIOUS_INSTANCE_MATRICES, W as VELOCITY_PREVIOUS_WORLD_MATRIX, X as VelocityTracker, Y as createPipelineCensus, Z as ensureVelocityOutput, _ as prewarm, $ as readRenderChainObservation, a0 as readRenderChainReport, a1 as readVelocityPreviousBoneMatrices, a2 as readVelocityPreviousMatrices, a3 as readVelocityPreviousWorldMatrix, a4 as velocityTexture, a5 as withVelocityContext } from './renderer-C6hqZpoG.js';
12
- import { I as IComputeDriven$1, a as IGPUReadbackSample } from './gpu-readback-D2iRvoe9.js';
13
- export { C as ComputeDrivenRegistry, G as GPUReadback, b as IGPUReadbackOptions } from './gpu-readback-D2iRvoe9.js';
10
+ import { I as IRendererLike, F as FramePassKind, a as IFrameBudgetWindow } from './renderer-Cy4qeBOA.js';
11
+ export { D as DEFAULT_PIPELINE_CENSUS_LIMIT, b as FRAME_BUDGET_MARKER, c as FRAME_BUDGET_PHASES, d as FRAME_HITCH_MARKER, e as FrameBudget, f as FrameBudgetPhase, g as FrameCounters, h as ICounterDevice, i as IFrameBudgetOptions, j as IFrameBudgetPassSummary, k as IFrameBudgetSummary, l as IFrameCounters, m as IFramePhaseSample, n as IPipelineCensus, o as IPipelineCensusCounts, p as IPipelineCensusEvent, q as IPipelineCensusOptions, r as IPipelineProvenance, s as IPipelineShaderObservation, t as IRenderChainApplied, u as IRenderChainBudgetWindow, v as IRenderChainDroppedStage, w as IRenderChainOptions, x as IRenderChainRenderer, y as IRenderChainRequest, z as IRenderChainStage, A as IRenderChainStageContext, B as IRenderChainVelocityMeasurement, C as IRenderChainVelocityReport, E as IRenderChainVelocityRequest, G as IRenderChainVelocityResult, H as IRenderPassSample, J as IVelocityRenderPass, P as PIPELINE_CENSUS_CAPABILITY, K as PIPELINE_CENSUS_VERSION, L as PipelineCensus, M as PipelineCensusMode, N as PipelineCensusStatus, R as RENDER_CHAIN_MARKER, O as RENDER_CHAIN_STAGE_ORDER, Q as RENDER_CHAIN_TIERS, S as RenderChain, T as RenderChainSource, U as RenderChainStageId, V as RenderChainStageName, W as RenderChainTier, X as RenderChainTierRequest, Y as RenderChainVelocitySource, Z as VELOCITY_OUTPUT_NAME, _ as VELOCITY_PREVIOUS_BONE_MATRICES, $ as VELOCITY_PREVIOUS_INSTANCE_MATRICES, a0 as VELOCITY_PREVIOUS_WORLD_MATRIX, a1 as VelocityTracker, a2 as counterDeviceOf, a3 as createPipelineCensus, a4 as ensureVelocityOutput, a5 as prewarm, a6 as readRenderChainObservation, a7 as readRenderChainReport, a8 as readVelocityPreviousBoneMatrices, a9 as readVelocityPreviousMatrices, aa as readVelocityPreviousWorldMatrix, ab as velocityTexture, ac as withVelocityContext } from './renderer-Cy4qeBOA.js';
12
+ import { I as IComputeDriven$1, a as IGPUReadbackSample } from './gpu-readback-CMklJs6r.js';
13
+ export { C as ComputeDrivenRegistry, G as GPUReadback, b as IGPUReadbackOptions } from './gpu-readback-CMklJs6r.js';
14
14
  import { Node as Node$1 } from 'three/src/nodes/Nodes.js';
15
15
  import 'zustand/vanilla';
16
16
 
17
+ /**
18
+ * Nested cost spans across the render phase, default-off.
19
+ *
20
+ * The frame budget names six phases and one of them — `render` — is 16.1 ms of a 20.2 ms frame
21
+ * while every engine-owned thing inside it sums to under 1.5 ms. A phase that big with nothing
22
+ * inside it is not a measurement, it is a question, and four ranked optimisation options were
23
+ * priced against four different answers to it. This is the instrument that answers it: a span tree
24
+ * whose leaves are the parts of the render phase, with the leftover computed rather than assumed.
25
+ *
26
+ * Three properties make it trustworthy enough to price work against:
27
+ *
28
+ * - **The residual is arithmetic, not a category.** Every non-leaf reports its own duration minus
29
+ * the durations of the spans it contains, so an unmeasured part shows up as a number instead of
30
+ * being quietly filed under "other". A child that outlives its parent reports a negative
31
+ * residual rather than being clamped to zero, because a negative residual means the nesting is
32
+ * wrong and a clamped one means nothing at all.
33
+ * - **It is default-off and costs one guarded return when off.** `TN_FRAME_SPANS=1` installs it;
34
+ * unset, every call site is `if (recorder === undefined) return;` with no clock read.
35
+ * - **Nothing here decides anything.** It measures the path that exists. It does not select a
36
+ * renderer, a traversal strategy or a pass order, and no number it produces is evidence for
37
+ * owning the renderer.
38
+ *
39
+ * The ids are integers on the hot path — a span call must not allocate a string to be cheap enough
40
+ * to put around a per-draw call — and the names exist only in the report.
41
+ */
42
+ /** Marker printed once per report window when spans are installed. */
43
+ declare const SPANS_MARKER = "TN_FRAME_SPANS";
44
+ /**
45
+ * The launch flag that installs the spans. Off by default: this is a diagnostic that adds work to
46
+ * the frame it measures, so a game must ask for it.
47
+ */
48
+ declare const SPANS_FLAG = "TN_FRAME_SPANS";
49
+ /**
50
+ * Every span, in the order the report prints them. Integers, because `beginSpan` runs per draw.
51
+ *
52
+ * `pass` and its nested kinds are one id per render call three makes, not one per camera: three
53
+ * renders the main camera first and the shadow and reflection cameras from inside that call, so
54
+ * the nesting is the renderer's own and a flat list of passes would have to invent a relationship
55
+ * the measurement already has.
56
+ */
57
+ declare const SPANS: {
58
+ /** Compute-driven render work dispatched by the engine before the world render. */
59
+ readonly compute: 0;
60
+ /** The engine's own `beforeRender` seam, where a game prepares the scene it is about to draw. */
61
+ readonly beforeRender: 1;
62
+ /** The scene-graph matrix walk. */
63
+ readonly sceneUpdate: 2;
64
+ /** The projection's reconcile, when one is installed. */
65
+ readonly reconcile: 3;
66
+ /** Virtual-geometry clustered mesh update. */
67
+ readonly clustered: 4;
68
+ /** Automatic discrete LOD selection. */
69
+ readonly lod: 5;
70
+ /** The projected-size cull, apply and restore together. */
71
+ readonly cull: 6;
72
+ /** The main camera's render call. */
73
+ readonly mainPass: 7;
74
+ /** A nested render call three names as a shadow map. */
75
+ readonly shadowPass: 8;
76
+ /** A nested render call three names as a reflector. */
77
+ readonly reflectionPass: 9;
78
+ /** Any other nested render call. */
79
+ readonly nestedPass: 10;
80
+ /** Render-list construction inside a render call. */
81
+ readonly projectObject: 11;
82
+ /** Render-list sort inside a render call. */
83
+ readonly sort: 12;
84
+ /** Per-draw submission inside a render call, accumulated across the draws of one pass. */
85
+ readonly draw: 13;
86
+ };
87
+ type SpanId = (typeof SPANS)[keyof typeof SPANS];
88
+ /** Names, indexed by id. The only place a span name is a string. */
89
+ declare const SPAN_NAMES: readonly string[];
90
+ declare const SPAN_COUNT: number;
91
+ /** One span's cost across a reported window. */
92
+ interface ISpanSummary {
93
+ /** Frames in the window that entered this span at least once. */
94
+ readonly frames: number;
95
+ /** Entries per frame, mean over the frames that entered it. */
96
+ readonly perFrame: number;
97
+ readonly mean: number;
98
+ readonly p50: number;
99
+ readonly p95: number;
100
+ readonly max: number;
101
+ /**
102
+ * This span's own time minus the time of the spans inside it, at p50.
103
+ *
104
+ * Negative when a child outlived its parent, which means the nesting is wrong. Never clamped: a
105
+ * clamped residual reads as a complete attribution, and this is the number that says whether the
106
+ * attribution is complete.
107
+ */
108
+ readonly residualP50: number;
109
+ }
110
+ /**
111
+ * One reported window of the span tree.
112
+ *
113
+ * `residual` is the render phase's own cost with every top-level span subtracted — the number this
114
+ * instrument exists to shrink. `coverage` is its complement as a fraction of the phase, and a
115
+ * reader that sees 0.68 is being told that a third of the phase is still unmeasured.
116
+ */
117
+ interface ISpanWindow {
118
+ readonly window: number;
119
+ readonly frames: number;
120
+ /** The render phase as the frame budget charged it, at p50. */
121
+ readonly renderMs: number;
122
+ readonly residualMs: number;
123
+ readonly coverage: number;
124
+ /** Frames whose span nesting exceeded `MAX_DEPTH`, whose residual is therefore incomplete. */
125
+ readonly overflowed: number;
126
+ readonly spans: Readonly<Record<string, ISpanSummary>>;
127
+ }
128
+ /**
129
+ * Accumulates a nested span tree, one frame at a time, and reports it windowed.
130
+ *
131
+ * The owner brackets a frame with `beginFrame` and `endFrame`; the render phase's own duration is
132
+ * handed in at the close rather than measured here, so the root residual is arithmetic against the
133
+ * number the frame budget already reports and cannot drift from it.
134
+ *
135
+ * Nesting is strict: `end(id)` must name the span `begin(id)` opened. A mismatch throws, because a
136
+ * tree whose parentage is wrong produces a residual that is confidently wrong, and that is worse
137
+ * than a loud failure in a mode a game opted into.
138
+ */
139
+ declare class SpanRecorder {
140
+ #private;
141
+ readonly capacity: number;
142
+ constructor(capacity?: number);
143
+ /** Opens a span. Returns false when the tree is already at `MAX_DEPTH` and the span is dropped. */
144
+ begin(id: SpanId, now: number): boolean;
145
+ /** Closes the span `begin` opened. Throws when it names a different span. */
146
+ end(id: SpanId, now: number): void;
147
+ /**
148
+ * Adds `ms` to a span that is entered many times per frame — a per-draw call, or a call site that
149
+ * cannot be bracketed. Counts as one entry and attributes to the enclosing span exactly as a
150
+ * bracketed one would.
151
+ */
152
+ add(id: SpanId, ms: number): void;
153
+ /** How many spans are currently open. Zero outside a frame's own work. */
154
+ get depth(): number;
155
+ /**
156
+ * Throws a half-open frame away without recording it.
157
+ *
158
+ * A frame that failed mid-render has a span stack that cannot be closed honestly, and recording
159
+ * it would put a fabricated zero in the window. The loop abandons it instead, so the window only
160
+ * ever reports frames whose spans all closed.
161
+ */
162
+ abandonFrame(): void;
163
+ /** Records the frame's totals against the render phase the frame budget charged. */
164
+ endFrame(renderPhaseMs: number): void;
165
+ /** The window just closed, or `undefined` when no frame was recorded in it. */
166
+ window(): ISpanWindow | undefined;
167
+ }
168
+ /** Installs or removes the recorder every `beginSpan`/`endSpan` routes to. */
169
+ declare function setSpanRecorder(next: SpanRecorder | undefined): void;
170
+ declare function spanRecorder(): SpanRecorder | undefined;
171
+ /** The one clock the spans and the frame budget share, so their numbers are comparable. */
172
+ declare function spanNow(): number;
173
+ /**
174
+ * Opens a span. One guarded return when spans are off — no clock read, no allocation, no branch on
175
+ * anything but the recorder's own presence.
176
+ */
177
+ declare function beginSpan(id: SpanId): void;
178
+ declare function endSpan(id: SpanId): void;
179
+ /** Adds an already-measured duration to a span entered many times per frame. */
180
+ declare function addSpan(id: SpanId, ms: number): void;
181
+ /**
182
+ * Whether `TN_FRAME_SPANS` asks for spans on this launch.
183
+ *
184
+ * Three ways in, because the three launches have three different seams and none of them is
185
+ * `import.meta.env` (Vite replaces that at build time, and a measurement flag must be settable
186
+ * without rebuilding the game): a native host forwards `TN_FRAME_SPANS` through `process.env`, a
187
+ * browser page carries `?tnFrameSpans=1` in its URL, and any harness can set
188
+ * `globalThis.__tnFrameSpans` before the game boots.
189
+ */
190
+ declare function spansRequested(): boolean;
191
+ /** The window as the marker line prints it. */
192
+ declare function formatSpansWindow(window: ISpanWindow): string;
193
+
194
+ /** A stride measured at unit world scale, so uniformly scaled clones can share it. */
195
+ interface ISharedStride {
196
+ /** Metres of ground per clip-second at rate 1, per unit of uniform world scale. */
197
+ readonly groundSpeed: number;
198
+ readonly inPlace: boolean;
199
+ }
200
+ declare class RigPreparation {
201
+ #private;
202
+ /** The cached binding count for an equivalent preparation, or `undefined` on a miss. */
203
+ boundCount(source: Object3D, clip: AnimationClip): number | undefined;
204
+ rememberBound(source: Object3D, clip: AnimationClip, bound: number): void;
205
+ /** The cached unit-scale stride for an equivalent, fully covered clip, or `undefined`. */
206
+ stride(source: Object3D, clip: AnimationClip): ISharedStride | undefined;
207
+ rememberStride(source: Object3D, clip: AnimationClip, stride: ISharedStride): void;
208
+ }
209
+
17
210
  interface IAnimationPlayerOptions {
18
211
  readonly clips: readonly AnimationClip[];
19
212
  readonly root: Object3D;
20
213
  readonly requiredClips?: readonly string[] | Readonly<Record<string, string>>;
214
+ /**
215
+ * Shared preparation for clones of one source rig. Set by `SkeletalMesh3D`; a standalone
216
+ * player leaves it undefined and keeps the per-instance binding audit and stride sample.
217
+ */
218
+ readonly preparation?: RigPreparation;
21
219
  /**
22
220
  * Match a travelling clip's playback rate to the ground the body actually covers.
23
221
  *
@@ -192,6 +390,37 @@ declare class CameraShake {
192
390
  update(dt: number): ICameraShakeOffset;
193
391
  }
194
392
 
393
+ /**
394
+ * Why a launch stopped, said where the player can read it.
395
+ *
396
+ * A launch has exactly two ways to go wrong quietly, and both were measured on a real game:
397
+ * progress stops moving (a decode that never returns, an asset that never settles) and the GPU
398
+ * device is lost (another process had taken 94% of VRAM). In both the loop keeps iterating, the
399
+ * loading layer keeps painting, and the only account of what happened is a line on stdout — which
400
+ * a player does not have, and which a bug report therefore never carries.
401
+ *
402
+ * So the failure is reported as text, once, through `onLaunchFailure` — and core stops there. Core
403
+ * cannot draw it: on the native host `document` is a Three.js compatibility stub whose
404
+ * `appendChild` is a no-op, so an overlay written here would be invisible on exactly the target
405
+ * that needs it. The page owns the presentation (and the copy-to-clipboard button players are
406
+ * asked for when they report a launch that hung); this owns the noticing and the wording.
407
+ */
408
+ /** What failed. `stalled` is "no progress for a while"; `device-lost` is the GPU going away. */
409
+ type LaunchFailureKind = "stalled" | "device-lost";
410
+ interface ILaunchFailure {
411
+ readonly kind: LaunchFailureKind;
412
+ /** One human sentence, already naming the numbers — this is what the Copy button copies. */
413
+ readonly message: string;
414
+ }
415
+ /**
416
+ * Called for every launch failure the engine notices, with the message to show the player.
417
+ *
418
+ * @situation show the player why the game stopped loading instead of leaving the loading screen up
419
+ * @situation report a stalled launch or a lost GPU device in the game's own UI
420
+ * @example const off = onLaunchFailure((failure) => shell.loading({ failure: failure.message }));
421
+ */
422
+ declare function onLaunchFailure(listener: (failure: ILaunchFailure) => void): () => void;
423
+
195
424
  type AtmosphereRgb = readonly [number, number, number];
196
425
  type AtmosphereVector = AtmosphereRgb | Readonly<{
197
426
  x: number;
@@ -593,9 +822,20 @@ interface IMergePart {
593
822
  interface IMergePartsOptions {
594
823
  /** Named in the error when the merge is refused. Say what was being built. */
595
824
  readonly label: string;
825
+ /**
826
+ * Channels to keep from each part besides `position`. Absent or empty keeps today's
827
+ * position-only merge, whose normals are recomputed from the merged result.
828
+ *
829
+ * `"normal"` keeps each part's authored normals, transformed by the part's placement matrix
830
+ * (the inverse-transpose normal matrix) and **never** recomputed. `"uv"` keeps each part's
831
+ * texture coordinates verbatim — the placement matrix moves position and normal, so UV values
832
+ * are retained unchanged. A part that does not carry a listed channel refuses the merge.
833
+ */
834
+ readonly preserve?: readonly ("uv" | "normal")[];
596
835
  }
597
836
  /**
598
- * Merge game-authored pieces into one buffer, keeping each piece's own colour.
837
+ * Merge game-authored pieces into one buffer, keeping each piece's own colour and, when asked,
838
+ * its uv and authored normals.
599
839
  *
600
840
  * Two things go wrong every time an agent bakes a building, a ship or a character out of
601
841
  * primitives, and neither is about how any of it looks. `mergeGeometries` returns `null` on
@@ -603,7 +843,9 @@ interface IMergePartsOptions {
603
843
  * a hundred indexed primitives — is invisible until the whole scene is missing; and a merged
604
844
  * buffer draws with one surface, so per-piece colour is gone unless every piece carries a flat
605
845
  * `color` attribute written before the merge. Writing that attribute is mechanical. The colours
606
- * are entirely the game's, one per part, and changing them changes nothing here.
846
+ * are entirely the game's, one per part, and changing them changes nothing here. By default the
847
+ * merged normals are recomputed from the merged buffer; `preserve` keeps the authored normals and
848
+ * texture coordinates instead so an imported model's shading survives the bake.
607
849
  */
608
850
  declare function mergeParts(parts: Iterable<IMergePart>, options: IMergePartsOptions): BufferGeometry;
609
851
 
@@ -686,8 +928,9 @@ declare class ClusteredMesh extends Mesh {
686
928
  * Takes every clustered mesh and every clustered batch under `root` through this frame's cut.
687
929
  *
688
930
  * The engine calls this itself, once a frame, before the render — virtual geometry ships on and a
689
- * game that has to remember to call something has not been given it. A scene holding neither costs
690
- * one traversal that finds nothing.
931
+ * game that has to remember to call something has not been given it. The first call censuses the
932
+ * root once and subscribes to its graph events; later calls walk only the clustered meshes and
933
+ * batch roots themselves, so a scene holding neither costs a map lookup.
691
934
  *
692
935
  * @returns triangles the clustered meshes and batches will submit.
693
936
  */
@@ -772,6 +1015,420 @@ declare class ClusteredBatch {
772
1015
  update(camera: Camera, viewportHeight: number): number;
773
1016
  }
774
1017
 
1018
+ /** The LOD0 geometry of a mesh under a discrete chain, or the mesh's own geometry otherwise. */
1019
+ declare function baseGeometryOf(mesh: Mesh): BufferGeometry;
1020
+ /**
1021
+ * Takes every discrete-LOD mesh under `root` through this frame's selection.
1022
+ *
1023
+ * The engine calls this itself, once a frame, after matrices are synced and before the render.
1024
+ * Multi-view callers that need the finest level across passes use {@link selectLodLevel} directly;
1025
+ * this entry point selects for the one camera it is handed — which is the main view, and is at
1026
+ * least as fine as a shadow pass of lower resolution needs.
1027
+ *
1028
+ * @returns triangles the managed meshes will submit this frame.
1029
+ */
1030
+ declare function updateModelLods(root: {
1031
+ traverse(callback: (object: object) => void): void;
1032
+ }, camera: Camera, viewportHeight: number): number;
1033
+
1034
+ /**
1035
+ * What the gate did on the last frame, in the shape a frame-budget window reports.
1036
+ *
1037
+ * `enabled: false` means the game declined the gate, and the counts are still measured — turning
1038
+ * the convention off must not turn its measurement off. Every exemption is named separately so an
1039
+ * override is visible rather than silent.
1040
+ */
1041
+ interface IRenderCameraCullReport {
1042
+ readonly schemaVersion: 1;
1043
+ readonly enabled: boolean;
1044
+ /**
1045
+ * False when the camera has no perspective distance term (orthographic) or no viewport to
1046
+ * project into; the gate then leaves the whole scene drawn rather than guessing.
1047
+ */
1048
+ readonly cameraResolved: boolean;
1049
+ readonly thresholdPixels: number;
1050
+ /** Renderables walked this frame. */
1051
+ readonly considered: number;
1052
+ /** Renderables hidden by this gate this frame. */
1053
+ readonly culled: number;
1054
+ readonly exemptCameraAttached: number;
1055
+ readonly exemptMarked: number;
1056
+ readonly exemptShadowCasters: number;
1057
+ readonly exemptWithoutBounds: number;
1058
+ /**
1059
+ * Objects whose position buffer is rewritten every frame, so the gate cannot trust a bound it
1060
+ * cannot afford to rescan. Kept drawn, like `frustumCulled = false`.
1061
+ */
1062
+ readonly exemptDynamicBounds: number;
1063
+ /** Objects that already set `frustumCulled = false`, and so never had trustworthy bounds. */
1064
+ readonly exemptFrustumCulled: number;
1065
+ }
1066
+ /**
1067
+ * Keep an object drawn regardless of how small the render camera resolves it.
1068
+ *
1069
+ * The named per-object override for the projected-size gate, which is on by default. Mark the
1070
+ * player's own cockpit, a nameplate, a quest marker, or anything a game never wants to pop out.
1071
+ * `alwaysRender(object, false)` removes the marker. The count of marked objects is reported beside
1072
+ * the cull, so an override is stated rather than hidden.
1073
+ *
1074
+ * @situation keep a small object drawn when the engine would skip it as too far to resolve
1075
+ * @situation stop my cockpit, marker or player model popping out at distance
1076
+ * @situation a tiny object disappeared at range and I need it always visible
1077
+ * @constraint the marker is per object and survives scene rebuilds only as long as the object does
1078
+ * @constraint disabling the gate (`renderer.minimumProjectedPixels: false`) keeps its measurement on
1079
+ * @example alwaysRender(ctx.camera.children[0]); // a camera-attached cockpit stays drawn
1080
+ */
1081
+ declare function alwaysRender(object: Object3D, enabled?: boolean): void;
1082
+
1083
+ /**
1084
+ * The per-frame world-matrix walk, with a hidden subtree left where it stands.
1085
+ *
1086
+ * `three`'s `Object3D.updateMatrixWorld` recurses into every child of every node whatever its
1087
+ * `visible` flag, multiplying a world matrix for each. That is the correct default for a library
1088
+ * that cannot know what a game is doing, and it is the wrong one for a renderer that is about to
1089
+ * skip exactly those subtrees: a full-detail body while its merged stand-in draws, a hidden LOD
1090
+ * level, a parked or hangared model each pay the walk and none of them can draw.
1091
+ *
1092
+ * Native flight in `sandbox/midway-open-pacific` profiled `updateMatrixWorld` plus
1093
+ * `multiplyMatrices` at **29 % of all JavaScript ticks**, and the same scene's hand-rolled
1094
+ * visible-only pass walked **779 nodes per frame instead of 9,903**, 3.1 ms down to 0.3 ms. That
1095
+ * pass was the game's; this is the engine's, so the next game does not write it again.
1096
+ *
1097
+ * The pass mirrors three exactly for a visible node: `matrixAutoUpdate` -> `updateMatrix()`, then
1098
+ * the `matrixWorldNeedsUpdate || force` recompute honouring `matrixWorldAutoUpdate` and a null
1099
+ * parent, then force the children. A node with `visible === false` still composes its **own**
1100
+ * matrix — that is what makes the next part cheap — and is not recursed into; when it was forced
1101
+ * (or carried a dirty flag) it is remembered, so the first frame it is visible again its whole
1102
+ * subtree is recomputed with `force = true`.
1103
+ *
1104
+ * Two things are never dropped by the pruning, because both are read while nothing above them is
1105
+ * visible:
1106
+ *
1107
+ * - a class that overrides `updateMatrixWorld` runs its own. `SkinnedMesh` refreshes
1108
+ * `bindMatrixInverse`, `Camera` its `matrixWorldInverse`; re-implementing only the base walk
1109
+ * left every deck-crew sailor that had moved since load drawing with a stale bind matrix and
1110
+ * vanishing from the frame. Their subtrees are small, so walking them whole costs nothing;
1111
+ * - a hidden node that holds a `Bone` is walked, because a visible `SkinnedMesh` draws with its
1112
+ * skeleton's matrices wherever the armature happens to sit. Whether bones sit below a node is
1113
+ * decided once and remembered — a rig is built whole and does not grow.
1114
+ *
1115
+ * A game that reads a **hidden** object's `matrixWorld` directly must not rely on this pass
1116
+ * having reached it: use `getWorldPosition`/`getWorldQuaternion`/`getWorldScale` (which update the
1117
+ * chain they need) or call `object.updateWorldMatrix(true, false)` first. The convention's named
1118
+ * override is `renderer.matrixWorld: "all"`, which visits every node exactly as three's own walk
1119
+ * does; `"visible"` is the default.
1120
+ */
1121
+ /** How much of the scene graph the engine walks for world matrices each frame. */
1122
+ type MatrixWorldMode = "visible" | "all";
1123
+ /** What the pass did on the last frame, for the frame telemetry a window reports. */
1124
+ interface IMatrixWorldReport {
1125
+ readonly schemaVersion: 1;
1126
+ readonly mode: MatrixWorldMode;
1127
+ /**
1128
+ * Nodes the engine walked this frame, summed over every application (authored scene and a
1129
+ * projection mirror when one is in use). One number both ways, so `"all"` can be read as the
1130
+ * cost of the walk the convention just removed.
1131
+ */
1132
+ readonly visited: number;
1133
+ }
1134
+ interface IMatrixWorldOptions {
1135
+ /** `"visible"` (default) skips a hidden subtree; `"all"` reproduces three's own walk. */
1136
+ readonly mode?: MatrixWorldMode;
1137
+ }
1138
+ /**
1139
+ * One game's world-matrix walk, holding the state the pruning needs between frames.
1140
+ *
1141
+ * The stale set and the bone cache live on the instance rather than in module scope: two games,
1142
+ * two playtest scenarios or two roots in one process must not share "this subtree was skipped
1143
+ * while hidden", or one game's hidden node would be force-refreshed by the other's frame.
1144
+ */
1145
+ declare class MatrixWorldPass {
1146
+ #private;
1147
+ constructor(options?: IMatrixWorldOptions);
1148
+ get mode(): MatrixWorldMode;
1149
+ /** What the current frame has walked so far, across every {@link apply} call. */
1150
+ get report(): IMatrixWorldReport;
1151
+ /** Starts a frame's count. The pass's state (stale set, bone cache) is untouched. */
1152
+ beginFrame(): void;
1153
+ /**
1154
+ * Walks `root`, mirroring three for every node the mode visits.
1155
+ *
1156
+ * Returns the nodes this call visited, so a caller can report one application's cost without
1157
+ * also reporting the frame's total.
1158
+ */
1159
+ apply(root: Object3D, force?: boolean): number;
1160
+ /** Forgets what was skipped. A whole-scene swap has no hidden ancestors left to refresh. */
1161
+ dispose(): void;
1162
+ }
1163
+
1164
+ /**
1165
+ * Where the spans attach to three's own render path.
1166
+ *
1167
+ * Kept apart from the recorder because they are two different kinds of risk. The recorder is
1168
+ * arithmetic over a stack and is proven by unit tests; this file reaches into another library's
1169
+ * private methods, and every line of it is a bet about how three 0.185 is shaped. Reading them
1170
+ * separately is how the bet stays visible.
1171
+ *
1172
+ * Every wrapper is an own property on the instance, so it is the object the frame actually uses
1173
+ * and uninstalling restores the prototype's method. Three's private methods are read defensively:
1174
+ * a renderer whose internals have moved loses that span rather than throwing, and the span simply
1175
+ * does not appear in the report — an absent measurement, never a fabricated zero.
1176
+ */
1177
+
1178
+ /** The slice of the raw three renderer the probes wrap. Structural, so a test can stand in a fake. */
1179
+ interface ISpanProbeTarget {
1180
+ render(scene: unknown, camera: unknown): unknown;
1181
+ _projectObject?(...args: unknown[]): void;
1182
+ _renderObjectDirect?(...args: unknown[]): void;
1183
+ }
1184
+ /**
1185
+ * Wraps the renderer's own render path so each part of a frame lands in its own span.
1186
+ *
1187
+ * Every wrapper is an own property on the instance, so it is the object the frame actually uses and
1188
+ * uninstalling restores the prototype's method. Three's private methods are read defensively: a
1189
+ * renderer whose internals have moved loses that span rather than throwing, and the span simply
1190
+ * does not appear in the report — an absent measurement, never a fabricated zero.
1191
+ *
1192
+ * The recursion guards matter: `_projectObject` calls itself once per child, so only the outermost
1193
+ * call opens a span, and `render` is deliberately not guarded because a nested render *is* the
1194
+ * shadow and reflection passes.
1195
+ */
1196
+ declare function installSpanProbes(target: ISpanProbeTarget, root: Object3D): () => void;
1197
+
1198
+ /**
1199
+ * The engine telling the agent that built the scene what a human would otherwise find by playing.
1200
+ *
1201
+ * A scene reached 1,815 triangles per draw with its GPU ten times under budget and nobody knew,
1202
+ * because the census and the phase split are measured every frame and nothing reads them. The
1203
+ * frame already carries the shape: how many objects the cull considered, how many draws each pass
1204
+ * submitted, how many casters are exempt, and what share of the frame the GPU actually used. This
1205
+ * turns those numbers into a verdict, once per reported window.
1206
+ *
1207
+ * **The rule is derived, never a constant an author is told to revisit.** It fires when
1208
+ *
1209
+ * - the GPU used less than a third of the frame — the device is not the constraint, and
1210
+ * - the JS render phase alone is longer than the display's own period — so the scene cannot make
1211
+ * the display's rate even if everything else in the frame were free.
1212
+ *
1213
+ * Both numbers come from the frame meter. The display's period comes from the host's own
1214
+ * presentation cap where there is one, and otherwise from the frame rate the game itself declared;
1215
+ * no third source is invented, and a launch that can name neither gets no verdict rather than a
1216
+ * guessed one.
1217
+ *
1218
+ * It is silent on an honestly GPU-bound scene with the same draw count, which is the property that
1219
+ * makes it worth reading: a warning that fires on every heavy scene is a warning nobody reads.
1220
+ */
1221
+
1222
+ /** Marker printed at most once per reported window. */
1223
+ declare const SCENE_WARNING_MARKER = "TN_SCENE_WARNING";
1224
+ /**
1225
+ * What the frame already knows about the scene's shape.
1226
+ *
1227
+ * Every field is a count the engine measures anyway — the projection's cull census and the render
1228
+ * pass budget — so the warning adds a reading, never a measurement.
1229
+ */
1230
+ interface ISceneShape {
1231
+ /** Objects the projected-size cull looked at this window. */
1232
+ readonly objectsConsidered: number;
1233
+ /** Objects it hid. */
1234
+ readonly culled: number;
1235
+ /** Objects exempt from the gate because they cast shadows. */
1236
+ readonly shadowExemptCasters: number;
1237
+ /** Draws submitted per pass kind, from the render pass budget. */
1238
+ readonly draws: Readonly<Partial<Record<FramePassKind, number>>>;
1239
+ /** Triangles per draw across every pass; the number a merge or an atlas moves. */
1240
+ readonly trianglesPerDraw: number;
1241
+ }
1242
+ /** The verdict, and the shape behind it. */
1243
+ interface ISceneWarning {
1244
+ readonly window: number;
1245
+ /** The GPU's share of the frame, as a fraction. */
1246
+ readonly gpuShare: number;
1247
+ /** The JS render phase's mean, in milliseconds. */
1248
+ readonly renderMs: number;
1249
+ /** The period the display works at, in milliseconds, and where that number came from. */
1250
+ readonly displayPeriodMs: number;
1251
+ readonly displaySource: "host-cap" | "declared-target";
1252
+ /** The largest thing the CPU describes every frame, and its share of the terms compared. */
1253
+ readonly dominantTerm: string;
1254
+ readonly dominantShare: number;
1255
+ readonly shape: ISceneShape;
1256
+ }
1257
+ /**
1258
+ * The display's own period, in milliseconds, or `undefined` when nothing can say.
1259
+ *
1260
+ * The host's presentation cap first, because on a native launch that is literally the rate frames
1261
+ * reach the display at. A browser has no refresh-rate API, so the rate the game declared is the
1262
+ * only honest second source — and it is the same number the resolution scaler already judges
1263
+ * against, not a new one.
1264
+ */
1265
+ declare function displayPeriodMs(declaredTargetFps: number | undefined): {
1266
+ ms: number;
1267
+ source: ISceneWarning["displaySource"];
1268
+ } | undefined;
1269
+ /**
1270
+ * The verdict for one reported window, or `undefined` when the frame does not earn one.
1271
+ *
1272
+ * Fails closed in both directions: a window whose GPU was never measured gets no verdict, because
1273
+ * "the GPU is idle" is a claim and an absent reading is not evidence for it; and a window with no
1274
+ * shape to report gets none either, because a warning that cannot say what to change is noise.
1275
+ */
1276
+ declare function sceneWarning(window: IFrameBudgetWindow, shape: ISceneShape | undefined, declaredTargetFps: number | undefined): ISceneWarning | undefined;
1277
+ /**
1278
+ * The scene's shape for one window, from the counts the frame already reported.
1279
+ *
1280
+ * `undefined` when the window carries no pass split: without draws there is nothing to name, and
1281
+ * a verdict built on an absent census would be a sentence about a scene nobody measured.
1282
+ */
1283
+ declare function describeSceneShape(window: IFrameBudgetWindow, cull: IRenderCameraCullReport | undefined): ISceneShape | undefined;
1284
+ /** The one-line summary a reader sees without opening a log viewer. */
1285
+ declare function describeSceneWarning(warning: ISceneWarning): string;
1286
+ /** The marker line. */
1287
+ declare function formatSceneWarning(warning: ISceneWarning): string;
1288
+
1289
+ /**
1290
+ * Authored static subtrees: stop recomposing transforms that nobody moves.
1291
+ *
1292
+ * The matrix walk is 2.22 ms of the reference game's 16.1 ms render phase, and almost none of what
1293
+ * it recomputes changed since the previous frame — island geometry, deck fittings, static props and
1294
+ * terrain are composed from the same position, quaternion and scale every frame, then multiplied
1295
+ * into the same world matrix, for as long as the game runs.
1296
+ *
1297
+ * **What this deletes, exactly, so the claim can be checked.** Three's `updateMatrixWorld` does
1298
+ * three things per object: `updateMatrix()` composes the local matrix when `matrixAutoUpdate`,
1299
+ * the world matrix is multiplied out when `matrixWorldNeedsUpdate || force`, and the walk recurses
1300
+ * into every child — the recursion is unconditional in three 0.185, so a frozen subtree still gets
1301
+ * visited. Freezing removes the two composes and keeps the visit. That is the honest bound: this
1302
+ * deletes arithmetic, not traversal, and the traversal is a separate lever with a separate PRD.
1303
+ *
1304
+ * **Staticness is authored, never guessed.** A heuristic that decides an object has "not moved in
1305
+ * 60 frames" is a correctness bug with no reproduction, so nothing here watches gameplay. What the
1306
+ * engine does do is check the promise where it is cheap to check it: the root's own local transform
1307
+ * is compared against what was frozen, once per frame, and a root the author moved thaws and
1308
+ * refreezes itself. That is O(static roots), not O(objects), and it turns the most common way to
1309
+ * get this wrong into a non-event. Writes deeper inside a frozen subtree are the author's to
1310
+ * announce with `invalidateStatic`, and `TN_RENDERLIST_VALIDATE=1` is what proves they did.
1311
+ */
1312
+
1313
+ /** Marker printed with the static census on each reported window. */
1314
+ declare const STATIC_TRANSFORM_MARKER = "TN_STATIC_TRANSFORMS";
1315
+ /**
1316
+ * Marks a subtree static: its transforms are composed once here and never again until something
1317
+ * changes them.
1318
+ *
1319
+ * Idempotent, and it answers the version the subtree is now at, so a caller can assert on the
1320
+ * contract rather than on the flag. Marking a root twice re-arms it, which is the same thing
1321
+ * `invalidateStatic` does and the reason a generator can emit the call unconditionally.
1322
+ */
1323
+ declare function markStatic(root: Object3D): number;
1324
+ /**
1325
+ * Thaws a subtree: every object composes again from the next walk.
1326
+ *
1327
+ * The flags are restored to three's defaults rather than to whatever they were before, because a
1328
+ * game that had already turned `matrixAutoUpdate` off for its own reasons and then marked the
1329
+ * subtree static is asking for the same behaviour either way.
1330
+ */
1331
+ declare function unmarkStatic(root: Object3D): void;
1332
+ /**
1333
+ * Announces that something inside a frozen subtree moved. The subtree recomposes once and refreezes
1334
+ * at its new transform.
1335
+ *
1336
+ * Takes the object that moved, or the root; either way the root that owns it is what re-arms, since
1337
+ * a world matrix deeper in the subtree is a product of everything above it.
1338
+ */
1339
+ declare function invalidateStatic(object: Object3D): number | undefined;
1340
+ /** Whether this object is a frozen root. */
1341
+ declare function isStatic(root: Object3D): boolean;
1342
+ /** One window's census of what is frozen and what had to thaw. */
1343
+ interface IStaticTransformCensus {
1344
+ /** Subtrees currently frozen. */
1345
+ readonly roots: number;
1346
+ /** Objects inside them, which is the count that stopped recomposing. */
1347
+ readonly objects: number;
1348
+ /** Roots the per-frame check found moved, and re-armed, since the previous census. */
1349
+ readonly rearmed: number;
1350
+ }
1351
+ /**
1352
+ * Re-arms any frozen root whose authored transform has changed since it was frozen.
1353
+ *
1354
+ * Called once per render phase, before the walk. It reads 26 numbers per frozen root and writes
1355
+ * nothing when nothing moved, so a scene that stays still pays a comparison per subtree and no
1356
+ * allocation at all. It cannot see a write deeper inside the subtree — that is `invalidateStatic`'s
1357
+ * job and `TN_RENDERLIST_VALIDATE=1`'s proof — and it does not pretend to.
1358
+ */
1359
+ declare function refreshStaticTransforms(): void;
1360
+ /** The census, and the re-arm counter it resets. */
1361
+ declare function staticTransformCensus(): IStaticTransformCensus;
1362
+ /** Drops every registration. A game that tore down its scene must not keep its roots alive. */
1363
+ declare function resetStaticTransforms(): void;
1364
+
1365
+ /**
1366
+ * The parity oracle for anything that stops recomputing a transform.
1367
+ *
1368
+ * A cache that is right on the scene you tested and wrong on the one you did not is worse than no
1369
+ * cache, because it ships as a visual bug nobody can reproduce. This is the instrument that makes
1370
+ * the difference falsifiable: with `TN_RENDERLIST_VALIDATE=1`, every frame recomputes every world
1371
+ * matrix from the authored transforms, the long way, and compares it elementwise against the one
1372
+ * the frame is about to draw with. The first disagreement throws, naming the object and the
1373
+ * element, because a validation mode that logs and continues is a validation mode nobody reads.
1374
+ *
1375
+ * It is a validation mode, not a proof: it proves the frames it ran on. Run it on the scenes you
1376
+ * care about, in CI, for as many frames as you can afford.
1377
+ *
1378
+ * Off by default and expensive by construction — it does the work it is checking, twice.
1379
+ */
1380
+
1381
+ /** Marker printed when the validator is installed, so a log says which mode produced it. */
1382
+ declare const RENDERLIST_VALIDATE_MARKER = "TN_RENDERLIST_VALIDATE";
1383
+ /** The launch flag. */
1384
+ declare const RENDERLIST_VALIDATE_FLAG = "TN_RENDERLIST_VALIDATE";
1385
+ /** Whether `TN_RENDERLIST_VALIDATE` asks for validation on this launch. */
1386
+ declare function renderListValidationRequested(): boolean;
1387
+ /** What one frame's check found. */
1388
+ interface IValidationReport {
1389
+ /** Objects whose world matrix was recomputed and compared. */
1390
+ readonly checked: number;
1391
+ /** Objects skipped because they own their own world matrix; reported, never counted as checked. */
1392
+ readonly gameOwned: number;
1393
+ /** Frames validated so far. */
1394
+ readonly frames: number;
1395
+ }
1396
+ /**
1397
+ * Recomputes every world matrix under `root` and throws on the first that disagrees.
1398
+ *
1399
+ * The recomputation is deliberately independent of the flags a freeze sets: it composes the local
1400
+ * matrix from `position`/`quaternion`/`scale` when the object composes its own, uses the authored
1401
+ * `matrix` when it does not, and multiplies by the parent's *recomputed* world matrix rather than
1402
+ * the cached one — so an error at the top of a subtree cannot be hidden by a matching error
1403
+ * underneath it.
1404
+ */
1405
+ declare function validateWorldMatrices(root: Object3D): {
1406
+ checked: number;
1407
+ gameOwned: number;
1408
+ };
1409
+ /**
1410
+ * The per-frame validator, installed when the flag asks for it.
1411
+ *
1412
+ * Holds a frame counter so the marker can say how much was proven, which is the difference between
1413
+ * "validation passed" and "validation passed on 1,800 frames of the reference game".
1414
+ */
1415
+ declare class RenderListValidator {
1416
+ #private;
1417
+ /**
1418
+ * Validates one frame. Throws on the first divergence.
1419
+ *
1420
+ * `roots` is the thing being drawn plus every frozen subtree. Those are not the same object
1421
+ * when the engine's projection is collapsing the scene: the draw root is then the mirror, and
1422
+ * validating only it reported three objects checked and zero divergences on a scene with two
1423
+ * hundred frozen meshes, one of which really was stale. A freeze is authored on the authored
1424
+ * scene, so the authored roots are checked whether or not they are what reaches the GPU.
1425
+ */
1426
+ frame(...roots: readonly Object3D[]): void;
1427
+ report(): IValidationReport;
1428
+ }
1429
+ /** The marker line for one reported window. */
1430
+ declare function formatValidationReport(report: IValidationReport): string;
1431
+
775
1432
  /** The atlas has one copied edge texel on either side of each packed SH sub-volume. */
776
1433
  declare const ATLAS_PADDING = 1;
777
1434
  /** The machine-readable marker emitted whenever the probe state changes. */
@@ -1531,6 +2188,100 @@ declare class FluidField2D extends Group {
1531
2188
  detach(): void;
1532
2189
  }
1533
2190
 
2191
+ /**
2192
+ * A disturbance that propagates. `WaveField` in this same package evaluates a fixed analytic
2193
+ * swell: it is the sea a game always has, and nothing a game does changes it. This is the other
2194
+ * half — a square patch of surface that is flat until something hits it, carries the rings
2195
+ * outward at a real celerity, and forgets them again.
2196
+ *
2197
+ * The solve is the 2-D wave equation on a regular grid, plus an advected foam density. It owns no
2198
+ * Three.js object, no material and no colour: it reports height, foam and horizontal flow, and the
2199
+ * game decides what those look like. Add its height to an analytic swell; do not replace one.
2200
+ *
2201
+ * There is deliberately no obstacle or hull mask. A mask is only correct for a body that does not
2202
+ * move, and a game whose hulls move is better served drawing the displacement those hulls make
2203
+ * than re-rasterising a mask every time one of them advances a metre.
2204
+ */
2205
+ interface IRippleFieldFlow {
2206
+ x: number;
2207
+ z: number;
2208
+ }
2209
+ interface IRippleFieldOptions {
2210
+ /** Cells per side. Cost is quadratic in this; 128 over a 400 m patch is ~3 m per cell. */
2211
+ readonly resolution: number;
2212
+ /** Width of the patch in metres. */
2213
+ readonly size: number;
2214
+ /** Wave celerity in metres per second. Sets both ring speed and the stable step. */
2215
+ readonly speed?: number;
2216
+ /** Bulk damping. Higher forgets a disturbance sooner. */
2217
+ readonly damping?: number;
2218
+ /** Seconds for undisturbed foam to halve. */
2219
+ readonly foamHalfLife?: number;
2220
+ /** Steady surface drift in metres per second, added to the solved flow. */
2221
+ readonly current?: IRippleFieldFlow;
2222
+ /**
2223
+ * Integration step in seconds. Defaults to 1/60 s, or the CFL limit for this cell size and
2224
+ * celerity where that is smaller.
2225
+ */
2226
+ readonly step?: number;
2227
+ /** Substeps one `advance` will run before it drops the rest of the frame's time. */
2228
+ readonly maxSteps?: number;
2229
+ }
2230
+ declare class RippleField {
2231
+ #private;
2232
+ readonly resolution: number;
2233
+ readonly size: number;
2234
+ readonly dx: number;
2235
+ readonly speed: number;
2236
+ readonly damping: number;
2237
+ readonly step: number;
2238
+ readonly maxSteps: number;
2239
+ foamHalfLife: number;
2240
+ current: IRippleFieldFlow;
2241
+ /** Surface height per cell, row-major from the patch's -x/-z corner. Read-only to the game. */
2242
+ height: Float32Array;
2243
+ /** Foam density per cell in 0..1. */
2244
+ foam: Float32Array;
2245
+ /** Horizontal flow per cell, metres per second, excluding `current`. */
2246
+ readonly flowX: Float32Array;
2247
+ readonly flowZ: Float32Array;
2248
+ /** Patch centre in world metres, always snapped to a whole cell. */
2249
+ centerX: number;
2250
+ centerZ: number;
2251
+ /** Simulated seconds elapsed. */
2252
+ time: number;
2253
+ /** Bumped whenever a cell changes, so a texture upload can skip an unchanged frame. */
2254
+ version: number;
2255
+ constructor(options: IRippleFieldOptions);
2256
+ /** True while the point is inside the patch, `margin` metres in from its rim. */
2257
+ contains(x: number, z: number, margin?: number): boolean;
2258
+ /**
2259
+ * Move the patch so it covers the action. The grid shifts by whole cells and the newly exposed
2260
+ * band arrives flat, which is what the sponge rim had already damped it to.
2261
+ */
2262
+ recenter(x: number, z: number): void;
2263
+ /**
2264
+ * Push the surface at a point: a Gaussian of the given radius, with the kernel corrected so the
2265
+ * disturbance injects no net volume. Without that correction every splash slowly raises the sea.
2266
+ * Returns false when the point is outside the patch.
2267
+ */
2268
+ impulse(x: number, z: number, radius: number, amplitude: number, foam?: number): boolean;
2269
+ /** Lay down entrained air without claiming a pressure impulse happened. */
2270
+ depositFoam(x: number, z: number, radius: number, amount: number): boolean;
2271
+ /** Run whole fixed steps to consume `dt`, and report how many ran. */
2272
+ advance(dt: number): number;
2273
+ /** Disturbance height in metres at a world point, zero outside the patch. */
2274
+ heightAt(x: number, z: number): number;
2275
+ /** Foam density in 0..1 at a world point. */
2276
+ foamAt(x: number, z: number): number;
2277
+ /** Surface flow in metres per second at a world point, including `current`. */
2278
+ flowAt(x: number, z: number, out?: IRippleFieldFlow): IRippleFieldFlow;
2279
+ /** Total disturbance energy. Zero on an undisturbed patch; useful as a test oracle. */
2280
+ energy(): number;
2281
+ /** Flatten the patch and forget every disturbance. Position, options and time survive. */
2282
+ reset(): void;
2283
+ }
2284
+
1534
2285
  type WaveDirection = readonly [number, number] | {
1535
2286
  readonly x: number;
1536
2287
  readonly z?: number;
@@ -1597,7 +2348,21 @@ declare class WaveField {
1597
2348
  constructor(options: IWaveFieldOptions);
1598
2349
  /** Update the default graph clock. Explicit sample times remain available for fixed-step code. */
1599
2350
  setTime(value: number): void;
2351
+ /**
2352
+ * Surface height and normal at a point. Allocates the result and its vector; a caller that wants
2353
+ * only the number should call `heightAt`, which is the same evaluation without either.
2354
+ */
1600
2355
  sample(x: number, z: number, time: number): IWaveFieldSample;
2356
+ /**
2357
+ * Surface height at a point, as a number.
2358
+ *
2359
+ * The scalar half of `sample`, and the same arithmetic in the same order, so the two agree
2360
+ * exactly. What it skips is everything only a normal needs: the domain warp's jacobian, the
2361
+ * cosine and slope of every wave, the normalisation, the result object and the `Vector3`. A
2362
+ * floating hull, a splash query or a whitewater height test asks this question thousands of times
2363
+ * a frame and throws the normal away every time.
2364
+ */
2365
+ heightAt(x: number, z: number, time: number): number;
1601
2366
  /** Surface height at a point, as a graph. The scalar half of what `sample` returns. */
1602
2367
  heightNode(options?: IWaveFieldGraphOptions): Node<"float">;
1603
2368
  /**
@@ -1617,17 +2382,53 @@ declare class WaveField {
1617
2382
  displacementNode(timeNode?: three_webgpu.UniformNode<"float", number>): Node<"vec3">;
1618
2383
  }
1619
2384
 
1620
- /** How the mirrored pass is sized. Both numbers are cost, not appearance. */
2385
+ /** What the mirrored pass costs: how big it is, how many of them, and how much of the world. */
1621
2386
  interface IWaterReflectionOptions {
1622
2387
  /**
1623
2388
  * The mirrored pass's render target, as a fraction of the drawing buffer.
1624
2389
  *
1625
- * A reflection is a second draw of the whole world, so this is the one number that decides
1626
- * whether a water surface is affordable. Half is the usual answer.
2390
+ * How many *pixels* the second pass costs. Half is the usual answer. This is not on its own the
2391
+ * number that decides whether a surface is affordable, and a game that reads it that way will
2392
+ * measure no improvement and conclude its water is free: a scene with many objects is bound by
2393
+ * the draw calls the mirrored pass submits, not by its pixels, and those do not shrink with the
2394
+ * target. Measured on `sandbox/midway-open-pacific` at 1920x1080 on an nvidia/turing adapter with
2395
+ * 1,965 draws in the frame, halving this again — 0.5 to 0.25 — moved GPU p95 from 17.80 ms to
2396
+ * 17.58 ms. Removing the pass entirely moved it to 7.67 ms. `layers` is the number that mattered.
1627
2397
  */
1628
2398
  readonly resolutionScale: number;
1629
2399
  /** Whether this surface may appear in other reflectors' passes. Off is one pass; on is n². */
1630
2400
  readonly bounces?: boolean;
2401
+ /**
2402
+ * Which layers the mirrored pass draws, as a three `Layers` mask. Omit to draw everything the
2403
+ * scene camera draws, which is the default and what a reflection means when nothing says
2404
+ * otherwise.
2405
+ *
2406
+ * This is how much *world* the second pass costs, and on a crowded scene it is the whole bill.
2407
+ * The mirrored pass is a second draw of everything, so a frame with sixty-eight aircraft in it
2408
+ * pays for sixty-eight aircraft twice — once where the player can see them and once in the water,
2409
+ * where they are a few pixels and half of them are behind the camera anyway. Put the big
2410
+ * silhouettes a player actually reads in the water on their own layer and name it here.
2411
+ *
2412
+ * The mask decides what appears in the mirror, so the game owns it: this only carries the number
2413
+ * through to the pass, and a game that omits it gets the whole world reflected as before.
2414
+ */
2415
+ readonly layers?: number;
2416
+ /**
2417
+ * How often the mirrored pass redraws, in presented frames.
2418
+ *
2419
+ * The reflection is a second render of the world and on a crowded sea it is the largest single
2420
+ * item in the frame. It is also low-frequency: a swell, a hull and a wake read the same whether
2421
+ * the mirror was taken this frame or two frames ago, and at speed the eye cannot hold a reflected
2422
+ * silhouette still enough to notice it lag. `2` redraws every second frame and samples the
2423
+ * previous frame's target in between, halving the pass's cost; a higher number halves it again.
2424
+ *
2425
+ * Omit it — or pass `1` — and the pass redraws every frame, which is the shipping behaviour and
2426
+ * the default. The trade is temporal: while the camera moves, the reflection is up to
2427
+ * `refreshInterval - 1` frames behind the scene it mirrors. Fast camera motion can make a
2428
+ * reflected edge shimmer, and a moving object's reflection trails it. A still camera sees none of
2429
+ * that, so name it only where the measured pass dominates the frame.
2430
+ */
2431
+ readonly refreshInterval?: number;
1631
2432
  }
1632
2433
  interface IWaterSurfaceOptions {
1633
2434
  /** World-space height of the surface, in metres. The mirror plane, and where thickness is 0. */
@@ -1681,6 +2482,19 @@ declare class WaterSurface3D {
1681
2482
  */
1682
2483
  readonly target: Object3D | undefined;
1683
2484
  constructor(options: IWaterSurfaceOptions);
2485
+ /**
2486
+ * The camera the mirrored pass draws this surface with, for one scene camera.
2487
+ *
2488
+ * The pass mints one of these per scene camera, lazily, and reflects the camera through the
2489
+ * mirror plane each frame. It is exposed because `layers` is not the only thing a game may need
2490
+ * to say about the second draw — a near/far pair is the other — and because a reflection you
2491
+ * cannot inspect is a reflection you cannot cost. Undefined when this surface has no reflection.
2492
+ */
2493
+ reflectionCameraFor(camera: Camera): Camera | undefined;
2494
+ /** What the mirrored pass draws, as the mask the game supplied. Undefined means everything. */
2495
+ readonly reflectionLayers: number | undefined;
2496
+ /** How often the mirrored pass redraws, in presented frames. `1` is every frame, the default. */
2497
+ readonly reflectionRefreshInterval: number;
1684
2498
  /** The world-space height of the surface, in metres. */
1685
2499
  get level(): number;
1686
2500
  /** Move the surface — a tide, a sluice, a flooding room. The mirror plane follows. */
@@ -1872,6 +2686,213 @@ declare class GroundSnap {
1872
2686
  audit(): number | null;
1873
2687
  }
1874
2688
 
2689
+ /**
2690
+ * Force-integrated fixed-wing flight dynamics for a game-owned aircraft.
2691
+ *
2692
+ * The model integrates lift, drag, thrust and aerodynamic moments in SI units, `+Y` up, with the
2693
+ * nose down local `-Z`. Attitude is a quaternion, so there are no Euler clamps and no commanded
2694
+ * velocity vectors: the game writes controls, the model writes forces, and the aircraft keeps its
2695
+ * own momentum. Every number that decides how the aircraft looks or performs — mass, wing area,
2696
+ * engine power, inertia, control authority, wind, damage multipliers and payload — arrives from
2697
+ * the game. This module owns only the mechanism that turns those inputs into motion.
2698
+ */
2699
+ interface IFlightVector3 {
2700
+ x: number;
2701
+ y: number;
2702
+ z: number;
2703
+ }
2704
+ interface IFlightQuaternion {
2705
+ x: number;
2706
+ y: number;
2707
+ z: number;
2708
+ w: number;
2709
+ }
2710
+ interface IFlightAxes {
2711
+ readonly r: IFlightVector3;
2712
+ readonly u: IFlightVector3;
2713
+ readonly f: IFlightVector3;
2714
+ }
2715
+ /** Per-aircraft constants. The game supplies these; the model ships no airframe of its own. */
2716
+ interface IAircraftAirframe {
2717
+ /** Empty mass, kg. */
2718
+ readonly dryMass: number;
2719
+ /** Mass of a full fuel load, kg. */
2720
+ readonly fuelMass: number;
2721
+ /** Reference wing area, m². */
2722
+ readonly wingArea: number;
2723
+ /** Wingspan, m. */
2724
+ readonly span: number;
2725
+ /** Mean aerodynamic chord, m. */
2726
+ readonly chord: number;
2727
+ /** Shaft power at full throttle, W. */
2728
+ readonly power: number;
2729
+ /** Propeller efficiency, 0–1. */
2730
+ readonly propEfficiency: number;
2731
+ /** Maximum static thrust, N. */
2732
+ readonly staticThrust: number;
2733
+ /** Pitch moment of inertia, kg·m². */
2734
+ readonly pitchInertia: number;
2735
+ /** Roll moment of inertia, kg·m². */
2736
+ readonly rollInertia: number;
2737
+ /** Yaw moment of inertia, kg·m². */
2738
+ readonly yawInertia: number;
2739
+ }
2740
+ /** Multipliers a game applies for damage, load or upgrades. 1 / 0 is the undamaged case. */
2741
+ interface IFlightModifiers {
2742
+ readonly power: number;
2743
+ readonly lift: number;
2744
+ readonly drag: number;
2745
+ readonly roll: number;
2746
+ readonly controls: number;
2747
+ }
2748
+ declare const NEUTRAL_FLIGHT_MODIFIERS: IFlightModifiers;
2749
+ /** One fixed step of pilot input. Every field is a dimensionless command in `[-1, 1]`. */
2750
+ interface IFlightControls {
2751
+ readonly turn?: number;
2752
+ readonly pitch?: number;
2753
+ readonly rudder?: number;
2754
+ readonly wheelBrake?: boolean;
2755
+ /** When true, stability assist is bypassed and the game commands the attitude directly. */
2756
+ readonly autopilot?: boolean;
2757
+ }
2758
+ /** The moving deck an aircraft launches from. */
2759
+ interface IFlightDeck {
2760
+ readonly x: number;
2761
+ readonly y?: number;
2762
+ readonly z: number;
2763
+ readonly heading: number;
2764
+ readonly speed: number;
2765
+ readonly length: number;
2766
+ readonly width: number;
2767
+ }
2768
+ interface IFlightState {
2769
+ x: number;
2770
+ y: number;
2771
+ z: number;
2772
+ vx: number;
2773
+ vy: number;
2774
+ vz: number;
2775
+ attitude?: IFlightQuaternion;
2776
+ heading: number;
2777
+ pitch: number;
2778
+ roll: number;
2779
+ rollRate: number;
2780
+ pitchRate: number;
2781
+ yawRate: number;
2782
+ speed: number;
2783
+ ias: number;
2784
+ groundSpeed: number;
2785
+ throttle: number;
2786
+ rpm: number;
2787
+ fuel: number;
2788
+ hp: number;
2789
+ engineCut: boolean;
2790
+ gear: boolean;
2791
+ brakes: boolean;
2792
+ gearPos: number;
2793
+ brakePos: number;
2794
+ flapPos: number;
2795
+ flaps: number;
2796
+ aileron: number;
2797
+ elevator: number;
2798
+ rudder: number;
2799
+ controlAileron: number;
2800
+ assist: boolean;
2801
+ trim: number;
2802
+ gforce: number;
2803
+ aoa: number;
2804
+ beta: number;
2805
+ stall: number;
2806
+ /** Mass of everything under the wings, kg. The game writes it as stores are released. */
2807
+ payloadMass: number;
2808
+ /** Extra flat-plate drag coefficient from external stores. */
2809
+ payloadDrag: number;
2810
+ flightTime: number;
2811
+ lift: number;
2812
+ drag: number;
2813
+ thrust: number;
2814
+ mass: number;
2815
+ deckSpeed?: number;
2816
+ deckLateral?: number;
2817
+ deckOffset?: number;
2818
+ chocks?: boolean;
2819
+ }
2820
+ interface IFlightEnvironment {
2821
+ readonly airframe: IAircraftAirframe;
2822
+ readonly wind?: IFlightVector3;
2823
+ readonly modifiers?: IFlightModifiers;
2824
+ readonly gravity?: number;
2825
+ /** Height of the carrier deck surface above the water, m. */
2826
+ readonly deckHeight?: number;
2827
+ }
2828
+ interface IFlightForces {
2829
+ readonly x: number;
2830
+ readonly y: number;
2831
+ readonly z: number;
2832
+ readonly normalLoad: number;
2833
+ readonly lift: number;
2834
+ readonly drag: number;
2835
+ readonly thrust: number;
2836
+ readonly alpha: number;
2837
+ readonly beta: number;
2838
+ readonly airspeed: number;
2839
+ readonly density: number;
2840
+ readonly mass: number;
2841
+ readonly qs: number;
2842
+ readonly axes: IFlightAxes;
2843
+ readonly cl: number;
2844
+ readonly cd: number;
2845
+ readonly stall: number;
2846
+ readonly critical: number;
2847
+ }
2848
+ /** ISA air density at altitude `y` metres, kg/m³. */
2849
+ declare function airDensity(y: number): number;
2850
+ /** Current mass of the aircraft from its empty mass, fuel load and game-written payload. */
2851
+ declare function aircraftMass(state: IFlightState, airframe: IAircraftAirframe): number;
2852
+ /** Lift and drag coefficients for an angle of attack and the deployed high-lift devices. */
2853
+ declare function aerodynamicCoefficients(alpha: number, flaps?: number, gear?: number, brakes?: number): {
2854
+ cl: number;
2855
+ cd: number;
2856
+ stall: number;
2857
+ critical: number;
2858
+ };
2859
+ /** Write a heading/pitch/roll pose into the body quaternion. Nose down local `-Z`. */
2860
+ declare function setAttitude(state: IFlightState, heading?: number, pitch?: number, roll?: number): IFlightQuaternion;
2861
+ /** Right, up and forward unit vectors of the body frame. */
2862
+ declare function attitudeAxes(state: IFlightState): IFlightAxes;
2863
+ /** Height of the gear contact point below the body origin at the current pitch. */
2864
+ declare function gearClearance(state: IFlightState): number;
2865
+ interface IFlightModelOptions<TState extends IFlightState = IFlightState> extends IFlightEnvironment {
2866
+ /** The game's own aircraft object, extended with whatever else the game needs on it. */
2867
+ readonly state: TState;
2868
+ }
2869
+ /**
2870
+ * One aircraft's dynamics: a thin owner of a game-authored state object plus its environment.
2871
+ *
2872
+ * The step record copies the options' own fields once, at construction — so `airframe`, `wind`,
2873
+ * `gravity` and `deckHeight` are read from the objects those fields reference, which stay live,
2874
+ * but replacing a field on the options object afterwards is not observed. Change a model's airframe
2875
+ * or deck by building it again, as a game that binds aircraft to carriers already does.
2876
+ *
2877
+ * @example
2878
+ * const model = new FlightModel({ airframe: sbd, state: aircraft, wind: seaWind });
2879
+ * model.setAttitude(0, 0.2, 0);
2880
+ * model.step(1 / 60, { turn: -1, pitch: 0.4 });
2881
+ */
2882
+ declare class FlightModel<TState extends IFlightState = IFlightState> {
2883
+ #private;
2884
+ readonly state: TState;
2885
+ readonly environment: IFlightEnvironment;
2886
+ constructor(options: IFlightModelOptions<TState>);
2887
+ setAttitude(heading?: number, pitch?: number, roll?: number): void;
2888
+ reset(): void;
2889
+ axes(): IFlightAxes;
2890
+ gearClearance(): number;
2891
+ forces(modifiers?: IFlightModifiers): IFlightForces;
2892
+ step(dt: number, controls: IFlightControls, modifiers?: IFlightModifiers): void;
2893
+ stepDeck(deck: IFlightDeck, dt: number, controls: IFlightControls, modifiers?: IFlightModifiers): "liftoff" | "overrun" | null;
2894
+ }
2895
+
1875
2896
  type ThreePoseVector = readonly [number, number, number];
1876
2897
  type ThreePoseQuaternion = readonly [number, number, number, number];
1877
2898
  interface IThreePoseBounds {
@@ -2189,6 +3210,6 @@ declare function boneLengthDeviations(root: Object3D, bind: IBoneLengthSnapshot,
2189
3210
  * unavoidable here — core is bundled for browsers and cannot read `package.json` at runtime — so
2190
3211
  * the spec now asserts this equals the manifest instead of asserting a number somebody typed.
2191
3212
  */
2192
- declare const version = "0.3.2";
3213
+ declare const version = "0.3.3";
2193
3214
 
2194
- export { ATLAS_PADDING, ATMOSPHERE_LUT_RESOLUTIONS, AnimationPlayer, Atmosphere, type AtmosphereDirection, AtmosphereLuts, type AtmosphereRgb, Billboard3D, type BillboardLockAxis, CameraShake, type CameraShakeCurve, ClusteredBatch, ClusteredMesh, FluidField2D, GPUParticles3D, GPUSceneBVH, type GPUSceneBVHTraceFunction, GroundSnap, type IAddInSlicesOptions, type IAddInSlicesProgress, type IAddInSlicesReport, type IAnimationPlayOptions, type IAnimationPlayerOptions, type IAtmosphereLutResolution, type IAtmosphereLutResolutions, type IAtmosphereOptions, type IAtmosphereParameterPatch, type IAtmosphereParameters, type IAtmosphereScenePass, type IBillboard3DOptions, type IBoneContactReport, type IBoneLengthDeviation, type IBoneLengthDeviationReport, type IBoneLengthDeviationsOptions, type IBoneLengthSnapshot, type IBonePoseError, type ICameraShakeOffset, type ICameraShakeOptions, type IClipBindingReport, type IClipCoverageReport, type IClipPoseErrorOptions, type IClipPoseErrorReport, type IClipPoseSubject, type IClipTrackBinding, type IClusterTable, type IClusteredBatchBuildOptions, type IClusteredBatchOptions, type IClusteredMeshOptions, type IClusteredPlacement, IComputeDriven$1 as IComputeDriven, type IFluidFieldOptions, type IFluidFieldSampler, type IFluidFieldVector2, IGPUReadbackSample, type IGPUSceneBVHMaterialGroup, type IGPUSceneBVHOptions, IGamePluginHooks, IGamePluginRuntime, type IGroundSnapOptions, type IInstancedBatchBuildOptions, type IInstancedBatchOptions, type IInstancedPlacement, type ILoadAllOptions, type ILoadAllProgress, type IMeasureThreePoseOptions, type IMergePart, type IMergePartsOptions, type INormaliseToMetresOptions, type IPathFollow3DOptions, type IPathFollow3DProjection, type IPathFollow3DSample, type IPlatformInfo, type IProbeVolumeBakeProgress, type IProbeVolumeCoefficient, type IProbeVolumeObservation, type IProbeVolumeOptions, type IReplayOptions, type IReplayRecording, type IReplayRecordingSample, type IResolvedAtmosphereParameters, type ISkeletalMesh3DOptions, type ISoftBody3DOptions, type ISoftBodyCollision, type ISolarPosition, type ISolarPositionInput, type ISpectralOceanCascade, type ISpectralOceanHeight, type ISpectralOceanOptions, type ISpriteAnimator3DOptions, type ISpriteFrame3D, type IStrideReport, type IThreePoseBounds, type IThreePoseMeasurement, type ITracerPool3DOptions, type ITracerSpawnOptions, type IVirtualShadowOptions, type IVirtualShadowStats, type IWaterReflectionOptions, type IWaterSurfaceOptions, type IWaveFieldDomainWarp, type IWaveFieldGraphOptions, type IWaveFieldOptions, type IWaveFieldSample, type IWaveFieldWave, InstancedBatch, LUT_RESOLUTIONS, type NormaliseAxis, PROBE_VOLUME_MARKER, PathFollow3D, type PlatformFormFactor, type PlatformOS, type PlatformRuntime, ProbeVolume, type ProbeVolumeDensity, type Recording, type ReplayPointer, SkeletalMesh3D, SoftBody3D, SpectralOcean, SpriteAnimator3D, type SpritePlaybackMode, type ThreePoseQuaternion, type ThreePoseVector, TracerPool3D, VIRTUAL_SHADOW_MARKER, VIRTUAL_SHADOW_MOVER_LAYER, VirtualShadowNode, WaterSurface3D, type WaveDirection, WaveField, addInSlices, attachToBone, boneContact, boneLengthDeviations, boneLengths, bvhIntersectFirstHit, clipBoneCoverage, clipPoseError, clipTrackBindings, createReplayDriver, directionFromSolarPosition, directionalTransmittance, getPlatform, isMobile, isNative, isTouchscreenAvailable, isWeb, loadAll, measureThreePose, mergeParts, normaliseToMetres, parseReplayRecording, posedBounds, rayStruct, readProbeVolumeObservation, readVirtualShadowMarker, replay, resolveAtmosphereLutResolutions, resolveAtmosphereParameters, skeletonBones, softCircleDataTexture, solarPosition, solarPositionAt, updateAtmosphereParameters, updateClusteredMeshes, version, zenithTransmittance };
3215
+ export { ATLAS_PADDING, ATMOSPHERE_LUT_RESOLUTIONS, AnimationPlayer, Atmosphere, type AtmosphereDirection, AtmosphereLuts, type AtmosphereRgb, Billboard3D, type BillboardLockAxis, CameraShake, type CameraShakeCurve, ClusteredBatch, ClusteredMesh, FlightModel, FluidField2D, FramePassKind, GPUParticles3D, GPUSceneBVH, type GPUSceneBVHTraceFunction, GroundSnap, type IAddInSlicesOptions, type IAddInSlicesProgress, type IAddInSlicesReport, type IAircraftAirframe, type IAnimationPlayOptions, type IAnimationPlayerOptions, type IAtmosphereLutResolution, type IAtmosphereLutResolutions, type IAtmosphereOptions, type IAtmosphereParameterPatch, type IAtmosphereParameters, type IAtmosphereScenePass, type IBillboard3DOptions, type IBoneContactReport, type IBoneLengthDeviation, type IBoneLengthDeviationReport, type IBoneLengthDeviationsOptions, type IBoneLengthSnapshot, type IBonePoseError, type ICameraShakeOffset, type ICameraShakeOptions, type IClipBindingReport, type IClipCoverageReport, type IClipPoseErrorOptions, type IClipPoseErrorReport, type IClipPoseSubject, type IClipTrackBinding, type IClusterTable, type IClusteredBatchBuildOptions, type IClusteredBatchOptions, type IClusteredMeshOptions, type IClusteredPlacement, IComputeDriven$1 as IComputeDriven, type IFlightAxes, type IFlightControls, type IFlightDeck, type IFlightEnvironment, type IFlightForces, type IFlightModelOptions, type IFlightModifiers, type IFlightQuaternion, type IFlightState, type IFlightVector3, type IFluidFieldOptions, type IFluidFieldSampler, type IFluidFieldVector2, IFrameBudgetWindow, IGPUReadbackSample, type IGPUSceneBVHMaterialGroup, type IGPUSceneBVHOptions, IGamePluginHooks, IGamePluginRuntime, type IGroundSnapOptions, type IInstancedBatchBuildOptions, type IInstancedBatchOptions, type IInstancedPlacement, type ILaunchFailure, type ILoadAllOptions, type ILoadAllProgress, type IMatrixWorldReport, type IMeasureThreePoseOptions, type IMergePart, type IMergePartsOptions, type INormaliseToMetresOptions, type IPathFollow3DOptions, type IPathFollow3DProjection, type IPathFollow3DSample, type IPlatformInfo, type IProbeVolumeBakeProgress, type IProbeVolumeCoefficient, type IProbeVolumeObservation, type IProbeVolumeOptions, type IReplayOptions, type IReplayRecording, type IReplayRecordingSample, type IResolvedAtmosphereParameters, type IRippleFieldFlow, type IRippleFieldOptions, type ISceneShape, type ISceneWarning, type ISkeletalMesh3DOptions, type ISoftBody3DOptions, type ISoftBodyCollision, type ISolarPosition, type ISolarPositionInput, type ISpanProbeTarget, type ISpanSummary, type ISpanWindow, type ISpectralOceanCascade, type ISpectralOceanHeight, type ISpectralOceanOptions, type ISpriteAnimator3DOptions, type ISpriteFrame3D, type IStaticTransformCensus, type IStrideReport, type IThreePoseBounds, type IThreePoseMeasurement, type ITracerPool3DOptions, type ITracerSpawnOptions, type IValidationReport, type IVirtualShadowOptions, type IVirtualShadowStats, type IWaterReflectionOptions, type IWaterSurfaceOptions, type IWaveFieldDomainWarp, type IWaveFieldGraphOptions, type IWaveFieldOptions, type IWaveFieldSample, type IWaveFieldWave, InstancedBatch, LUT_RESOLUTIONS, type LaunchFailureKind, type MatrixWorldMode, MatrixWorldPass, NEUTRAL_FLIGHT_MODIFIERS, type NormaliseAxis, PROBE_VOLUME_MARKER, PathFollow3D, type PlatformFormFactor, type PlatformOS, type PlatformRuntime, ProbeVolume, type ProbeVolumeDensity, RENDERLIST_VALIDATE_FLAG, RENDERLIST_VALIDATE_MARKER, type Recording, RenderListValidator, type ReplayPointer, RippleField, SCENE_WARNING_MARKER, SPANS, SPANS_FLAG, SPANS_MARKER, SPAN_COUNT, SPAN_NAMES, STATIC_TRANSFORM_MARKER, SkeletalMesh3D, SoftBody3D, type SpanId, SpanRecorder, SpectralOcean, SpriteAnimator3D, type SpritePlaybackMode, type ThreePoseQuaternion, type ThreePoseVector, TracerPool3D, VIRTUAL_SHADOW_MARKER, VIRTUAL_SHADOW_MOVER_LAYER, VirtualShadowNode, WaterSurface3D, type WaveDirection, WaveField, addInSlices, addSpan, aerodynamicCoefficients, airDensity, aircraftMass, alwaysRender, attachToBone, attitudeAxes, baseGeometryOf, beginSpan, boneContact, boneLengthDeviations, boneLengths, bvhIntersectFirstHit, clipBoneCoverage, clipPoseError, clipTrackBindings, createReplayDriver, describeSceneShape, describeSceneWarning, directionFromSolarPosition, directionalTransmittance, displayPeriodMs, endSpan, formatSceneWarning, formatSpansWindow, formatValidationReport, gearClearance, getPlatform, installSpanProbes, invalidateStatic, isMobile, isNative, isStatic, isTouchscreenAvailable, isWeb, loadAll, markStatic, measureThreePose, mergeParts, normaliseToMetres, onLaunchFailure, parseReplayRecording, posedBounds, rayStruct, readProbeVolumeObservation, readVirtualShadowMarker, refreshStaticTransforms, renderListValidationRequested, replay, resetStaticTransforms, resolveAtmosphereLutResolutions, resolveAtmosphereParameters, sceneWarning, setAttitude, setSpanRecorder, skeletonBones, softCircleDataTexture, solarPosition, solarPositionAt, spanNow, spanRecorder, spansRequested, staticTransformCensus, unmarkStatic, updateAtmosphereParameters, updateClusteredMeshes, updateModelLods, validateWorldMatrices, version, zenithTransmittance };