@threenative/core 0.3.0 → 0.3.2
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/README.md +10 -0
- package/capabilities.json +1881 -131
- package/dist/assets-kyoF7JlJ.d.ts +103 -0
- package/dist/{audio-Dp2mXpD3.d.ts → audio-BFiGneTL.d.ts} +62 -0
- package/dist/canvas-layer-BLVijiUJ.d.ts +62 -0
- package/dist/{game-CYIaKhgl.d.ts → game-XGrTzapq.d.ts} +350 -164
- package/dist/gpu-readback-D2iRvoe9.d.ts +112 -0
- package/dist/hot.d.ts +5 -3
- package/dist/hot.js +5 -1
- package/dist/index.d.ts +813 -143
- package/dist/index.js +4548 -941
- package/dist/net.d.ts +65 -0
- package/dist/net.js +643 -0
- package/dist/playtest.d.ts +29 -5
- package/dist/playtest.js +181 -35
- package/dist/react.d.ts +4 -2
- package/dist/{canvas-layer-CtrZHgIh.d.ts → renderer-C6hqZpoG.d.ts} +237 -75
- package/dist/world.d.ts +203 -4
- package/dist/world.js +2536 -25
- package/gpl/LICENSE.GPL +117 -0
- package/gpl/convert.py +192 -0
- package/gpl/recipes/_common.py +169 -0
- package/gpl/recipes/bake_ao.py +111 -0
- package/gpl/recipes/decimate.py +64 -0
- package/gpl/recipes/retarget.py +131 -0
- package/gpl/recipes/unwrap.py +71 -0
- package/mcp/blender-server.mjs +632 -0
- package/mcp/blender.mjs +27 -0
- package/mcp/engine-server.mjs +271 -23
- package/mcp/engine.mjs +15 -7
- package/mcp/install.d.mts +37 -0
- package/mcp/install.mjs +94 -26
- package/mcp/servers.d.mts +34 -0
- package/mcp/servers.mjs +110 -9
- package/package.json +36 -8
- package/patches/three@0.185.1.patch +249 -14
- package/scripts/ensure-mcp.mjs +20 -13
- package/scripts/bundle-engine-mcp.mjs +0 -15
- package/scripts/generate-version.mjs +0 -13
|
@@ -1,57 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { h as IFramePhaseSample,
|
|
1
|
+
import { I as IAssetLoader, a as IAssetLoaderOptions } from './assets-kyoF7JlJ.js';
|
|
2
|
+
import { h as IFramePhaseSample, i as IPipelineCensus, I as IRendererLike, a6 as IRendererOptions, g as IFrameBudgetWindow, e as IFrameBudgetOptions } from './renderer-C6hqZpoG.js';
|
|
3
|
+
import { Vector2, Vector3, Object3D, Camera, Intersection, Scene as Scene$1 } from 'three';
|
|
4
|
+
import { V as Viewport, C as CanvasLayer, I as IViewportOptions } from './canvas-layer-BLVijiUJ.js';
|
|
3
5
|
import { StoreApi } from 'zustand/vanilla';
|
|
4
6
|
|
|
5
|
-
interface IAssetLoaderOptions {
|
|
6
|
-
readonly basePath?: string;
|
|
7
|
-
/**
|
|
8
|
-
* URL of the manifest written by the asset compile step (`public/assets.manifest.json`).
|
|
9
|
-
* Defaults to `assets.manifest.json` resolved against `basePath`. A logical path is resolved
|
|
10
|
-
* to its compiled output through it; a manifest that is absent — 404 or unfetchable — falls
|
|
11
|
-
* back to loading every path verbatim, while one that is served malformed or with an unknown
|
|
12
|
-
* version throws.
|
|
13
|
-
*/
|
|
14
|
-
readonly manifest?: string;
|
|
15
|
-
readonly model?: (url: string) => Promise<unknown>;
|
|
16
|
-
readonly texture?: (url: string) => Promise<Texture>;
|
|
17
|
-
readonly audio?: (url: string) => Promise<AudioBuffer>;
|
|
18
|
-
/**
|
|
19
|
-
* The live renderer (`IRendererLike.raw`), handed to `KTX2Loader.detectSupport()` exactly
|
|
20
|
-
* once so compiled KTX2 textures transcode to a format this machine's GPU actually supports.
|
|
21
|
-
* Required for games whose textures compile to `.ktx2`; without it such a load throws rather
|
|
22
|
-
* than silently uploading decoded RGBA.
|
|
23
|
-
*/
|
|
24
|
-
readonly renderer?: unknown;
|
|
25
|
-
}
|
|
26
|
-
/** The structural slice of three's `KTX2Loader` core depends on. */
|
|
27
|
-
interface IKTX2LoaderLike {
|
|
28
|
-
detectSupport(renderer: unknown): unknown;
|
|
29
|
-
load(url: string, onLoad: (texture: Texture) => void, onProgress?: (event: ProgressEvent<EventTarget>) => void, onError?: (error: unknown) => void): unknown;
|
|
30
|
-
setTranscoderPath(path: string): unknown;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Present only when a renderer was handed to the asset loader. `ready` settles once support
|
|
34
|
-
* detection ran; it rejects naming the renderer and platform when no compressed format is
|
|
35
|
-
* supported, and `defineGame` awaits it during boot so such a target fails at construction.
|
|
36
|
-
*/
|
|
37
|
-
interface ICompressedTextureSupport {
|
|
38
|
-
/**
|
|
39
|
-
* The one shared instance, also handed to `GLTFLoader.setKTX2Loader()` for models. Resolves
|
|
40
|
-
* `undefined` when the renderer exposed no surface to probe (see `createKtx2Loader`).
|
|
41
|
-
*/
|
|
42
|
-
readonly loader: Promise<IKTX2LoaderLike | undefined>;
|
|
43
|
-
readonly ready: Promise<void>;
|
|
44
|
-
}
|
|
45
|
-
interface IAssetLoader {
|
|
46
|
-
readonly compressedTextures?: ICompressedTextureSupport;
|
|
47
|
-
model<T = unknown>(path: string): Promise<T>;
|
|
48
|
-
texture(path: string): Promise<Texture>;
|
|
49
|
-
audio(path: string): Promise<AudioBuffer>;
|
|
50
|
-
release(kind: "audio" | "model" | "texture", path: string): boolean;
|
|
51
|
-
clear(): void;
|
|
52
|
-
}
|
|
53
|
-
declare function createAssetLoader(options?: IAssetLoaderOptions): IAssetLoader;
|
|
54
|
-
|
|
55
7
|
type ThreeNativeOrientation = "landscape" | "portrait" | "sensor";
|
|
56
8
|
/** Which renderer draws a game's `src/ui/`. @see IThreeNativeConfig.ui */
|
|
57
9
|
type ThreeNativeUiRenderer = "native" | "web";
|
|
@@ -78,8 +30,59 @@ interface IThreeNativeBootSplash {
|
|
|
78
30
|
readonly backgroundColor?: string;
|
|
79
31
|
readonly image?: string;
|
|
80
32
|
}
|
|
33
|
+
/** What a clip is for, stated as a bound on where its energy sits, in the inspector's bands. */
|
|
34
|
+
interface IThreeNativeAudioSpectrum {
|
|
35
|
+
readonly band: "air" | "high" | "low" | "mid" | "sub";
|
|
36
|
+
/** Most of the clip's energy that may sit in the band. */
|
|
37
|
+
readonly maxPercent?: number;
|
|
38
|
+
/** Least of the clip's energy that must sit in the band. */
|
|
39
|
+
readonly minPercent?: number;
|
|
40
|
+
}
|
|
41
|
+
/** Loop conditioning for a clip that repeats forever; its seam is cross-faded, then asserted. */
|
|
42
|
+
interface IThreeNativeAudioLoop {
|
|
43
|
+
/** Equal-power cross-fade in milliseconds. `0` keeps the clip's own length and still asserts. */
|
|
44
|
+
readonly crossFadeMs?: number;
|
|
45
|
+
/** How far the splice may move to find a quiet seam, in milliseconds. */
|
|
46
|
+
readonly spliceToleranceMs?: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Per-glob audio declarations. Which clips loop, which are positional, and what a clip is for are
|
|
50
|
+
* facts only the game knows, so they are declared and never inferred from a filename.
|
|
51
|
+
*/
|
|
52
|
+
interface IThreeNativeAudioOverride {
|
|
53
|
+
/** `"none"` ships these bytes as committed; measurement and a declared loop's assertion run. */
|
|
54
|
+
readonly conditioning?: "none";
|
|
55
|
+
/** First matching override wins; matched against the logical path, e.g. `"audio/bed.ogg"`. */
|
|
56
|
+
readonly glob: string;
|
|
57
|
+
readonly loop?: boolean | IThreeNativeAudioLoop;
|
|
58
|
+
readonly normalise?: "ceiling" | "peak";
|
|
59
|
+
/** Peak ceiling in dBFS, between -60 and 0. */
|
|
60
|
+
readonly peakDb?: number;
|
|
61
|
+
/** The clip plays from a place in the world, so it is downmixed to mono. */
|
|
62
|
+
readonly positional?: boolean;
|
|
63
|
+
/** Vorbis VBR quality, -1 to 10. */
|
|
64
|
+
readonly quality?: number;
|
|
65
|
+
/** The largest wrap-to-neighbourhood step ratio a declared loop may ship with, 1 to 5. */
|
|
66
|
+
readonly seamMaxRatio?: number;
|
|
67
|
+
readonly spectrum?: IThreeNativeAudioSpectrum;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Audio conditioning options for the asset compile step; `"none"` ships clips verbatim.
|
|
71
|
+
*
|
|
72
|
+
* `"ceiling"` normalisation only ever attenuates, keeping the game's relative mix; `"peak"` also
|
|
73
|
+
* lifts a quiet clip to the ceiling.
|
|
74
|
+
*/
|
|
75
|
+
interface IThreeNativeAudioConfig {
|
|
76
|
+
readonly normalise?: "ceiling" | "peak";
|
|
77
|
+
readonly overrides?: readonly IThreeNativeAudioOverride[];
|
|
78
|
+
readonly peakDb?: number;
|
|
79
|
+
readonly quality?: number;
|
|
80
|
+
readonly seamMaxRatio?: number;
|
|
81
|
+
}
|
|
81
82
|
/** Texture compression options for the asset compile step; `"none"` ships sources verbatim. */
|
|
82
83
|
interface IThreeNativeTexturesConfig {
|
|
84
|
+
/** Integer at least 4; caps the longest edge, preserving aspect and 4x4 alignment; never upscales. */
|
|
85
|
+
readonly maxSize?: number;
|
|
83
86
|
readonly overrides?: readonly {
|
|
84
87
|
readonly codec: "etc1s" | "none" | "uastc";
|
|
85
88
|
readonly glob: string;
|
|
@@ -109,6 +112,13 @@ interface IThreeNativeModelsConfig {
|
|
|
109
112
|
readonly positionBits?: number;
|
|
110
113
|
readonly uvBits?: number;
|
|
111
114
|
};
|
|
115
|
+
/**
|
|
116
|
+
* Write each distinct embedded image once under `shared/images/` and reference it from every
|
|
117
|
+
* model that carries it. A marketplace pack whose eight pines all embed the same bark map then
|
|
118
|
+
* ships and encodes it once. Default true; false embeds and re-encodes duplicate images in
|
|
119
|
+
* each model. The served GLB references files beside it.
|
|
120
|
+
*/
|
|
121
|
+
readonly sharedImages?: boolean;
|
|
112
122
|
/**
|
|
113
123
|
* Embedded-texture compression for images carried inside a `.glb`.
|
|
114
124
|
*
|
|
@@ -193,9 +203,27 @@ interface IThreeNativeConfig {
|
|
|
193
203
|
readonly title?: string;
|
|
194
204
|
readonly width?: number;
|
|
195
205
|
readonly height?: number;
|
|
206
|
+
/** Start maximized on desktop when `display.fullscreen` is false. */
|
|
207
|
+
readonly maximized?: boolean;
|
|
196
208
|
readonly resizable?: boolean;
|
|
197
209
|
};
|
|
198
210
|
readonly assets?: {
|
|
211
|
+
/**
|
|
212
|
+
* Audio conditioning options, or `"none"` to ship every clip exactly as committed. Absent
|
|
213
|
+
* means conditioning runs with defaults. `"none"` still measures and still reports.
|
|
214
|
+
*/
|
|
215
|
+
readonly audio?: "none" | IThreeNativeAudioConfig;
|
|
216
|
+
/**
|
|
217
|
+
* Byte ceilings: uncooked defaults to 64,000,000; total defaults to "none". Mobile
|
|
218
|
+
* targets without decoders are exempt from uncooked. A number sets uncooked; "none"
|
|
219
|
+
* disables both gates. Measurements still print when a gate is disabled.
|
|
220
|
+
*/
|
|
221
|
+
readonly budget?: number | "none" | {
|
|
222
|
+
readonly uncooked?: number | "none";
|
|
223
|
+
readonly total?: number | "none";
|
|
224
|
+
};
|
|
225
|
+
/** Source-relative globs omitted from builds; excluded bytes are still reported. */
|
|
226
|
+
readonly exclude?: readonly string[];
|
|
199
227
|
readonly models?: "none" | IThreeNativeModelsConfig;
|
|
200
228
|
readonly output?: string;
|
|
201
229
|
readonly source?: string;
|
|
@@ -222,6 +250,14 @@ interface IThreeNativeConfig {
|
|
|
222
250
|
readonly resolutionScale?: number | "auto";
|
|
223
251
|
/** Portable multisampling. Sampling and resolution are one pixel budget, not two. */
|
|
224
252
|
readonly antialias?: boolean;
|
|
253
|
+
/**
|
|
254
|
+
* Portable alpha antialiasing: resolve alpha-tested cutout silhouettes — foliage, fences,
|
|
255
|
+
* hair — through the multisample coverage mask rather than a binary `discard`. On by default,
|
|
256
|
+
* costing no target and no pass; it buys the cutouts the samples `antialias` already pays
|
|
257
|
+
* for. Set false for a deliberately hard-edged look. It does nothing on a single-sampled
|
|
258
|
+
* surface, and says so in `TN_ALPHA_ANTIALIASING` rather than reporting itself applied.
|
|
259
|
+
*/
|
|
260
|
+
readonly alphaAntialiasing?: boolean;
|
|
225
261
|
/**
|
|
226
262
|
* Android-only rendering overrides selected by the engine.
|
|
227
263
|
*
|
|
@@ -233,6 +269,12 @@ interface IThreeNativeConfig {
|
|
|
233
269
|
readonly android?: {
|
|
234
270
|
readonly resolutionScale?: number | "auto";
|
|
235
271
|
readonly antialias?: boolean;
|
|
272
|
+
/**
|
|
273
|
+
* `alphaAntialiasing` belongs here for the reason `antialias` does, one step on: a phone
|
|
274
|
+
* that bought sampling back must be able to spend it on cutouts, and one that gave sampling
|
|
275
|
+
* up has nothing to spend.
|
|
276
|
+
*/
|
|
277
|
+
readonly alphaAntialiasing?: boolean;
|
|
236
278
|
};
|
|
237
279
|
};
|
|
238
280
|
readonly ui?: {
|
|
@@ -300,8 +342,14 @@ interface IInputAction {
|
|
|
300
342
|
readonly scroll?: boolean;
|
|
301
343
|
/** Add the signed two-pointer distance change to `axis(name)`; moving apart is positive. */
|
|
302
344
|
readonly pinch?: boolean;
|
|
303
|
-
/**
|
|
345
|
+
/**
|
|
346
|
+
* Add raw mouse movement since the last input tick to `vector(name)`. A click on the pointer
|
|
347
|
+
* target automatically asks for pointer capture when this binding is present; call
|
|
348
|
+
* `captureMouse()` explicitly when a game needs to start capture from another named gesture.
|
|
349
|
+
*/
|
|
304
350
|
readonly pointerRelative?: boolean;
|
|
351
|
+
/** Disable the automatic click capture for a relative binding that has its own gesture. */
|
|
352
|
+
readonly captureOnClick?: boolean;
|
|
305
353
|
/** The +x direction of `vector(name)`. */
|
|
306
354
|
readonly right?: readonly string[];
|
|
307
355
|
/** The +y direction of `vector(name)`. */
|
|
@@ -370,7 +418,7 @@ declare class InputMap {
|
|
|
370
418
|
* a third pointer is ignored and a changing pair starts a new gesture without a jump.
|
|
371
419
|
*/
|
|
372
420
|
axis(name: string): number;
|
|
373
|
-
/** Request pointer capture
|
|
421
|
+
/** Request pointer capture explicitly from a named game gesture. Relative bindings request it on canvas click by default. */
|
|
374
422
|
captureMouse(): void;
|
|
375
423
|
/** Release pointer capture. A browser refusal remains an unhandled rejection. */
|
|
376
424
|
releaseMouse(): void;
|
|
@@ -382,6 +430,12 @@ declare class InputMap {
|
|
|
382
430
|
dispose(): void;
|
|
383
431
|
}
|
|
384
432
|
|
|
433
|
+
type AfterPhysicsCallback = (dt: number) => void;
|
|
434
|
+
interface IAfterPhysicsContext {
|
|
435
|
+
readonly afterPhysics: (callback: AfterPhysicsCallback) => () => void;
|
|
436
|
+
}
|
|
437
|
+
/** Register work that reads transforms after every simulation step and before the frame renders. */
|
|
438
|
+
declare function afterPhysics(context: IAfterPhysicsContext, callback: AfterPhysicsCallback): () => void;
|
|
385
439
|
interface IRenderPerformanceMetrics {
|
|
386
440
|
readonly drawCalls?: number;
|
|
387
441
|
readonly triangles?: number;
|
|
@@ -408,6 +462,7 @@ declare class Registry {
|
|
|
408
462
|
#private;
|
|
409
463
|
add<T extends object>(name: string, entity: T): T;
|
|
410
464
|
get<T extends object = object>(name: string): T | undefined;
|
|
465
|
+
forEach(callback: (name: string, entity: object) => void): void;
|
|
411
466
|
remove(name: string): void;
|
|
412
467
|
queueFree(target: string | object): void;
|
|
413
468
|
sweep(): void;
|
|
@@ -558,84 +613,6 @@ type GameStore<T extends Record<string, unknown>> = StoreApi<T> & {
|
|
|
558
613
|
stop(): void;
|
|
559
614
|
};
|
|
560
615
|
|
|
561
|
-
declare abstract class Scene<TState extends Record<string, unknown> = Record<string, unknown>, TPhysics = undefined> {
|
|
562
|
-
static readonly initialState: Record<string, unknown> | undefined;
|
|
563
|
-
load(_ctx: ICtx<TState, TPhysics>): void | Promise<void>;
|
|
564
|
-
enter(_ctx: ICtx<TState, TPhysics>): SceneEnterResult<TState, TPhysics>;
|
|
565
|
-
exit(_ctx: ICtx<TState, TPhysics>): void;
|
|
566
|
-
update(_ctx: ICtx<TState, TPhysics>, _dt: number): void;
|
|
567
|
-
render(_ctx: ICtx<TState, TPhysics>): void;
|
|
568
|
-
}
|
|
569
|
-
type SceneConstructor<TState extends Record<string, unknown> = Record<string, unknown>, TPhysics = undefined> = new () => Scene<TState, TPhysics>;
|
|
570
|
-
type SceneFrame<TState extends Record<string, unknown> = Record<string, unknown>, TPhysics = undefined> = (ctx: ICtx<TState, TPhysics>, dt: number) => void;
|
|
571
|
-
type SceneEnterResult<TState extends Record<string, unknown> = Record<string, unknown>, TPhysics = undefined> = // biome-ignore lint/suspicious/noConfusingVoidType: void preserves existing Scene.enter overrides.
|
|
572
|
-
void | SceneFrame<TState, TPhysics>;
|
|
573
|
-
interface IStartupStatus {
|
|
574
|
-
/**
|
|
575
|
-
* True once first-use compilation has settled — earlier than `phase === "ready"`, which also
|
|
576
|
-
* waits for a sustained in-budget frame window.
|
|
577
|
-
*
|
|
578
|
-
* This is the signal a game wants when something must not run during the launch. `phase` cannot
|
|
579
|
-
* express it: it is binary, and on a software rasteriser the frame window can only ever expire
|
|
580
|
-
* rather than be met, so a game gated on `phase` alone does nothing for tens of seconds there.
|
|
581
|
-
* Measured as a chase route of length `0.000000` against a required `6`, because the scenario
|
|
582
|
-
* ended before the window did.
|
|
583
|
-
*/
|
|
584
|
-
readonly compileSettled: boolean;
|
|
585
|
-
/**
|
|
586
|
-
* `collapsing` until first-use work and a sustained in-budget frame window complete, `ready`
|
|
587
|
-
* once the world is safe to show.
|
|
588
|
-
*/
|
|
589
|
-
readonly phase: "observing" | "collapsing" | "ready";
|
|
590
|
-
/** 0 while first-use work or the sustained frame window is pending, then 1. */
|
|
591
|
-
readonly progress: number;
|
|
592
|
-
/** Resolves after first-use work and the sustained frame window, so it is always awaitable. */
|
|
593
|
-
whenReady(): Promise<void>;
|
|
594
|
-
}
|
|
595
|
-
interface ICtx<TState extends Record<string, unknown> = Record<string, unknown>, TPhysics = undefined> {
|
|
596
|
-
readonly fps: number;
|
|
597
|
-
readonly renderer: IRendererLike;
|
|
598
|
-
readonly viewport: Viewport;
|
|
599
|
-
readonly scene: Scene$1;
|
|
600
|
-
readonly camera: Camera;
|
|
601
|
-
readonly canvasLayer: CanvasLayer;
|
|
602
|
-
readonly entities: Registry;
|
|
603
|
-
/**
|
|
604
|
-
* Adds a node to the scene and hands it straight back, with its own type intact.
|
|
605
|
-
*
|
|
606
|
-
* Generic rather than `Object3D` because a game writes `const sea = ctx.add(new SpectralOcean())`
|
|
607
|
-
* and then calls a method on it. Erasing the type here makes every typed node in every scene need
|
|
608
|
-
* a cast back to what it already was, and that cast is where a game stops noticing it is holding
|
|
609
|
-
* something else.
|
|
610
|
-
*/
|
|
611
|
-
readonly add: <T extends Object3D>(object: T) => T;
|
|
612
|
-
readonly input: InputMap;
|
|
613
|
-
readonly pointer: IPointerEvents3D;
|
|
614
|
-
readonly assets: IAssetLoader;
|
|
615
|
-
readonly after: (delay: number, callback: () => void) => ScheduleHandle;
|
|
616
|
-
readonly every: (callback: (dt: number) => void) => ScheduleHandle;
|
|
617
|
-
readonly state: GameStore<TState>;
|
|
618
|
-
readonly tween: <T extends object>(target: T, properties: {
|
|
619
|
-
[K in keyof T]?: number;
|
|
620
|
-
}, duration: number, options?: ITweenOptions) => Promise<void>;
|
|
621
|
-
readonly random: IRandom;
|
|
622
|
-
readonly raycast: (options?: IRaycastOptions) => Intersection | undefined;
|
|
623
|
-
readonly raycastAll: (options?: IRaycastOptions, target?: Intersection[]) => readonly Intersection[];
|
|
624
|
-
/**
|
|
625
|
-
* The framework's own startup work — what a loading screen waits on.
|
|
626
|
-
*
|
|
627
|
-
* A shader may compile the first time something using it is drawn, and the render projection may
|
|
628
|
-
* do its first build in that same frame. Both costs are real and belong before the world is shown.
|
|
629
|
-
*
|
|
630
|
-
* Keeping the world hidden until `whenReady()` resolves does more than hide the mess: the
|
|
631
|
-
* shaders that would have been compiled for geometry the projection then discards are never
|
|
632
|
-
* compiled at all, so waiting is *faster* than not waiting.
|
|
633
|
-
*/
|
|
634
|
-
readonly startup: IStartupStatus;
|
|
635
|
-
readonly goto: (name: string) => Promise<void>;
|
|
636
|
-
physics: TPhysics;
|
|
637
|
-
}
|
|
638
|
-
|
|
639
616
|
/**
|
|
640
617
|
* Compiles a scene's pipelines before the first frame, in slices, yielding between them.
|
|
641
618
|
*
|
|
@@ -661,16 +638,28 @@ interface ICtx<TState extends Record<string, unknown> = Record<string, unknown>,
|
|
|
661
638
|
*/
|
|
662
639
|
/** One renderable's worth of progress, reported as the warm-up advances. */
|
|
663
640
|
interface IWarmUpProgress {
|
|
664
|
-
/**
|
|
641
|
+
/** Renderable candidates handed to the renderer so far. */
|
|
665
642
|
readonly done: number;
|
|
666
|
-
/**
|
|
643
|
+
/** Renderable candidates the warm-up will hand to the renderer in total. */
|
|
667
644
|
readonly total: number;
|
|
668
645
|
}
|
|
646
|
+
/** The result of the optional persistent warm-up hint. */
|
|
647
|
+
type WarmUpCacheStatus = "disabled" | "unavailable" | "miss" | "hit" | "stored";
|
|
648
|
+
interface IWarmUpCacheOptions {
|
|
649
|
+
/**
|
|
650
|
+
* A game-owned revision for the scene's materials, shaders and renderer settings.
|
|
651
|
+
*
|
|
652
|
+
* The value is a hint that the native driver's own pipeline cache survived a relaunch; it is
|
|
653
|
+
* not a serialized WebGPU pipeline. Change it whenever those inputs change. A missing or
|
|
654
|
+
* unavailable localStorage implementation never prevents the warm-up from running.
|
|
655
|
+
*/
|
|
656
|
+
readonly key: string;
|
|
657
|
+
}
|
|
669
658
|
interface IWarmUpOptions {
|
|
670
659
|
/** Compute kernels to compile in the same bounded startup window as draw pipelines. */
|
|
671
660
|
readonly computeNodes?: readonly unknown[];
|
|
672
661
|
/**
|
|
673
|
-
*
|
|
662
|
+
* Renderable candidates handed to the renderer between yields. Default 24.
|
|
674
663
|
*
|
|
675
664
|
* The trade is presented frames against total warm-up time: every yield costs one frame's
|
|
676
665
|
* present, and a slice of one would spend more time presenting than compiling. 24 puts a frame
|
|
@@ -705,18 +694,47 @@ interface IWarmUpOptions {
|
|
|
705
694
|
* for and the only one measured to be affordable: on a Pixel 8 the renderer builds all 107 of
|
|
706
695
|
* this game's pipelines in **8.1 s** that way.
|
|
707
696
|
*
|
|
708
|
-
* `"object"` walks
|
|
709
|
-
*
|
|
710
|
-
*
|
|
711
|
-
* few pipelines can afford it and a progress bar is worth something there; the default may not
|
|
712
|
-
* be a mechanism that turns a 8 s launch into a 15 s one.
|
|
697
|
+
* `"object"` walks every renderable candidate and yields between slices, which is the only way
|
|
698
|
+
* to show candidate progress. The renderer owns cache reuse and actual pipeline identity, so the
|
|
699
|
+
* warm-up never drops an object based on a material or geometry guess.
|
|
713
700
|
*/
|
|
714
701
|
readonly granularity?: "scene" | "object";
|
|
702
|
+
/**
|
|
703
|
+
* Remember a completed warm-up so a later launch can trust the driver's persistent cache.
|
|
704
|
+
* This is opt-in because WebGPU does not expose a portable pipeline-serialization API.
|
|
705
|
+
*/
|
|
706
|
+
readonly cache?: IWarmUpCacheOptions;
|
|
715
707
|
}
|
|
716
708
|
/** What the warm-up did, so a caller can report it rather than assume it. */
|
|
709
|
+
type WarmUpObservationStatus = "complete" | "incomplete" | "unavailable";
|
|
710
|
+
interface IWarmUpObservation {
|
|
711
|
+
/** Pipeline creations observed between the census snapshots. */
|
|
712
|
+
readonly created: number;
|
|
713
|
+
/** Pipeline creations that failed between the census snapshots. */
|
|
714
|
+
readonly failed: number;
|
|
715
|
+
/** Pipeline creations still pending at the ending census snapshot, delta-adjusted. */
|
|
716
|
+
readonly pending: number;
|
|
717
|
+
/** New shader-program identities observed between the census snapshots. */
|
|
718
|
+
readonly uniquePrograms: number;
|
|
719
|
+
/** New backend pipeline identities observed between the census snapshots. */
|
|
720
|
+
readonly uniquePipelines: number;
|
|
721
|
+
/** Whether the renderer supplied a complete observation for this warm-up. */
|
|
722
|
+
readonly status: WarmUpObservationStatus;
|
|
723
|
+
}
|
|
717
724
|
interface IWarmUpReport {
|
|
718
|
-
/**
|
|
725
|
+
/** Compile calls that settled successfully; retained for compatibility with existing callers. */
|
|
719
726
|
readonly compiled: number;
|
|
727
|
+
/**
|
|
728
|
+
* @deprecated Candidate count retained under the old public name. Use `candidates` for its
|
|
729
|
+
* actual unit and `observed` for backend-created pipelines.
|
|
730
|
+
*/
|
|
731
|
+
readonly pipelines: number;
|
|
732
|
+
/** Renderable objects selected for warm-up, before backend cache identity is known. */
|
|
733
|
+
readonly candidates: number;
|
|
734
|
+
/** Number of compileAsync calls attempted, including rejected and timed-out calls. */
|
|
735
|
+
readonly attempted: number;
|
|
736
|
+
/** Backend creation counts observed between the warm-up's start and end snapshots. */
|
|
737
|
+
readonly observed: IWarmUpObservation;
|
|
720
738
|
/** Slices the work was cut into, and therefore the frames the loop got to present. */
|
|
721
739
|
readonly slices: number;
|
|
722
740
|
/** Wall-clock milliseconds the warm-up took, compiling and yielding together. */
|
|
@@ -750,11 +768,14 @@ interface IWarmUpReport {
|
|
|
750
768
|
readonly computeUnsupported?: boolean;
|
|
751
769
|
/** True when compute warm-up consumed the startup budget. Present only when computeNodes was set. */
|
|
752
770
|
readonly computeTimedOut?: boolean;
|
|
771
|
+
/** The optional persistent warm-up hint's outcome. */
|
|
772
|
+
readonly cache?: WarmUpCacheStatus;
|
|
753
773
|
}
|
|
754
774
|
/** The narrow slice of the renderer this needs. Structural so a test needs no renderer. */
|
|
755
775
|
interface IWarmUpRenderer {
|
|
756
776
|
compileAsync?: (scene: Object3D, camera: Camera, targetScene?: Object3D) => Promise<void>;
|
|
757
777
|
computeAsync?: (node: unknown) => Promise<void>;
|
|
778
|
+
pipelineCensus?: () => IPipelineCensus;
|
|
758
779
|
raw?: unknown;
|
|
759
780
|
}
|
|
760
781
|
/**
|
|
@@ -768,6 +789,165 @@ interface IWarmUpRenderer {
|
|
|
768
789
|
*/
|
|
769
790
|
declare function warmUpScene(renderer: IWarmUpRenderer, scene: Object3D, camera: Camera, options?: IWarmUpOptions): Promise<IWarmUpReport>;
|
|
770
791
|
|
|
792
|
+
declare abstract class Scene<TState extends Record<string, unknown> = Record<string, unknown>, TPhysics = undefined> {
|
|
793
|
+
static readonly initialState: Record<string, unknown> | undefined;
|
|
794
|
+
load(_ctx: ICtx<TState, TPhysics>): void | Promise<void>;
|
|
795
|
+
enter(_ctx: ICtx<TState, TPhysics>): SceneEnterResult<TState, TPhysics>;
|
|
796
|
+
exit(_ctx: ICtx<TState, TPhysics>): void;
|
|
797
|
+
update(_ctx: ICtx<TState, TPhysics>, _dt: number): void;
|
|
798
|
+
render(_ctx: ICtx<TState, TPhysics>): void;
|
|
799
|
+
}
|
|
800
|
+
type SceneConstructor<TState extends Record<string, unknown> = Record<string, unknown>, TPhysics = undefined> = new () => Scene<TState, TPhysics>;
|
|
801
|
+
type SceneFrame<TState extends Record<string, unknown> = Record<string, unknown>, TPhysics = undefined> = (ctx: ICtx<TState, TPhysics>, dt: number) => void;
|
|
802
|
+
type SceneEnterResult<TState extends Record<string, unknown> = Record<string, unknown>, TPhysics = undefined> = // biome-ignore lint/suspicious/noConfusingVoidType: void preserves existing Scene.enter overrides.
|
|
803
|
+
void | SceneFrame<TState, TPhysics>;
|
|
804
|
+
/**
|
|
805
|
+
* When the framework's startup milestones happened, in milliseconds on the host's monotonic
|
|
806
|
+
* clock (`performance.now()`: since navigation on the web, since process start on native).
|
|
807
|
+
*
|
|
808
|
+
* Absent members have not happened yet. Published to the playtest bridge so a scenario asserts
|
|
809
|
+
* startup time as an observation rather than reading it off a console log.
|
|
810
|
+
*/
|
|
811
|
+
interface IStartupTimeline {
|
|
812
|
+
/** The start scene's `load()` began. */
|
|
813
|
+
readonly loadStartedMs?: number;
|
|
814
|
+
/** The start scene's `enter()` returned: the world is built and the loop can move. */
|
|
815
|
+
readonly enteredMs?: number;
|
|
816
|
+
/** First-use compilation settled or its budget expired. */
|
|
817
|
+
readonly compileSettledMs?: number;
|
|
818
|
+
/**
|
|
819
|
+
* The framework's own launch work finished: compilation settled and the frame window held.
|
|
820
|
+
*
|
|
821
|
+
* Equal to `readyMs` unless the game registered a `startup.hold()`. Kept separate so that making
|
|
822
|
+
* `readyMs` honest about the player's wait does not delete the only measurement of the
|
|
823
|
+
* framework's own cost — a game with a slow asset tier would otherwise hide a framework
|
|
824
|
+
* regression inside its own loading time.
|
|
825
|
+
*/
|
|
826
|
+
readonly frameworkReadyMs?: number;
|
|
827
|
+
/**
|
|
828
|
+
* `whenReady()` resolved: the world is safe to show, including anything the game held for.
|
|
829
|
+
*
|
|
830
|
+
* This is the number to compare against what a player experiences. It used to be the
|
|
831
|
+
* framework's own readiness and nothing else, which reported 1.5 s on a valley that took 8.8 s
|
|
832
|
+
* to appear — and `assert.startup`'s `maxReadyMs` passed on it.
|
|
833
|
+
*/
|
|
834
|
+
readonly readyMs?: number;
|
|
835
|
+
}
|
|
836
|
+
interface IStartupStatus {
|
|
837
|
+
/** The most recent warm-up accounting, when a warm-up has run. */
|
|
838
|
+
readonly warmup?: {
|
|
839
|
+
readonly attempted?: number;
|
|
840
|
+
readonly candidates?: number;
|
|
841
|
+
readonly observed?: IWarmUpObservation;
|
|
842
|
+
readonly status: WarmUpObservationStatus;
|
|
843
|
+
};
|
|
844
|
+
/**
|
|
845
|
+
* True once first-use compilation has settled — earlier than `phase === "ready"`, which also
|
|
846
|
+
* waits for a sustained in-budget frame window.
|
|
847
|
+
*
|
|
848
|
+
* This is the signal a game wants when something must not run during the launch. `phase` cannot
|
|
849
|
+
* express it: it is binary, and on a software rasteriser the frame window can only ever expire
|
|
850
|
+
* rather than be met, so a game gated on `phase` alone does nothing for tens of seconds there.
|
|
851
|
+
* Measured as a chase route of length `0.000000` against a required `6`, because the scenario
|
|
852
|
+
* ended before the window did.
|
|
853
|
+
*/
|
|
854
|
+
readonly compileSettled: boolean;
|
|
855
|
+
/**
|
|
856
|
+
* `collapsing` until first-use work and a sustained in-budget frame window complete, `ready`
|
|
857
|
+
* once the world is safe to show.
|
|
858
|
+
*/
|
|
859
|
+
readonly phase: "observing" | "collapsing" | "ready";
|
|
860
|
+
/**
|
|
861
|
+
* 0 to 1, monotonic and honest: the loader's settled/requested ratio carries the first 0.7
|
|
862
|
+
* while the start scene loads, 0.8 once the world is entered, 0.9 once first-use compilation
|
|
863
|
+
* settled, 1 when `whenReady()` resolves.
|
|
864
|
+
*/
|
|
865
|
+
readonly progress: number;
|
|
866
|
+
/** When each milestone happened; members appear as they are reached. */
|
|
867
|
+
readonly timeline: IStartupTimeline;
|
|
868
|
+
/** Resolves after first-use work, the sustained frame window, and every game `hold()`. */
|
|
869
|
+
whenReady(): Promise<void>;
|
|
870
|
+
/**
|
|
871
|
+
* Resolves after first-use work and the sustained frame window, and **before** any `hold()`.
|
|
872
|
+
*
|
|
873
|
+
* This is what a game should sequence its own launch work off. `whenReady()` cannot be used for
|
|
874
|
+
* that once the game holds startup: the hold makes readiness wait for the game's work, so work
|
|
875
|
+
* *started* from `whenReady()` waits for a gate that is waiting for it. The cycle is only broken
|
|
876
|
+
* by the hold's budget expiring, which looks exactly like a very slow asset load — measured as a
|
|
877
|
+
* valley revealing its critical tier after a 45 s stall with `trees=1`.
|
|
878
|
+
*
|
|
879
|
+
* Use this when the reason to wait is the framework's launch cost — not competing with first-use
|
|
880
|
+
* compilation, not stealing frames from the stable-frame window — which is the usual reason.
|
|
881
|
+
*
|
|
882
|
+
* @situation start the game's own asset streaming after the framework's launch work, without deadlocking the readiness gate
|
|
883
|
+
*/
|
|
884
|
+
whenFrameworkReady(): Promise<void>;
|
|
885
|
+
/**
|
|
886
|
+
* Add the game's own launch work to the readiness gate, so every framework-owned observation of
|
|
887
|
+
* startup describes the moment the player actually reached the world.
|
|
888
|
+
*
|
|
889
|
+
* For a game that streams a second asset tier after the framework is done. Without it the only
|
|
890
|
+
* options are to show a half-built world or to hold a curtain past `whenReady()`, and the second
|
|
891
|
+
* leaves `progress`, `phase`, `timeline.readyMs` and the playtest bridge's `assert.startup` all
|
|
892
|
+
* describing a moment nobody experienced.
|
|
893
|
+
*
|
|
894
|
+
* Fails open twice: a hold that rejects counts as settled, and `budgetMs` bounds how long it may
|
|
895
|
+
* delay the world (45 s by default). A launch slower than it could be is a disappointment; a
|
|
896
|
+
* launch that never finishes because one asset 404'd is a bug.
|
|
897
|
+
*
|
|
898
|
+
* Throws on an empty or duplicate label, and on a hold registered after startup already
|
|
899
|
+
* resolved — each means the caller believes it is gating something it is not.
|
|
900
|
+
*
|
|
901
|
+
* @situation hold the loading screen until the game's own asset tier has landed
|
|
902
|
+
*/
|
|
903
|
+
hold(label: string, work: Promise<unknown>, budgetMs?: number): void;
|
|
904
|
+
}
|
|
905
|
+
interface ICtx<TState extends Record<string, unknown> = Record<string, unknown>, TPhysics = undefined> {
|
|
906
|
+
readonly fps: number;
|
|
907
|
+
readonly renderer: IRendererLike;
|
|
908
|
+
readonly viewport: Viewport;
|
|
909
|
+
readonly scene: Scene$1;
|
|
910
|
+
readonly camera: Camera;
|
|
911
|
+
readonly canvasLayer: CanvasLayer;
|
|
912
|
+
readonly entities: Registry;
|
|
913
|
+
/**
|
|
914
|
+
* Adds a node to the scene and hands it straight back, with its own type intact.
|
|
915
|
+
*
|
|
916
|
+
* Generic rather than `Object3D` because a game writes `const sea = ctx.add(new SpectralOcean())`
|
|
917
|
+
* and then calls a method on it. Erasing the type here makes every typed node in every scene need
|
|
918
|
+
* a cast back to what it already was, and that cast is where a game stops noticing it is holding
|
|
919
|
+
* something else.
|
|
920
|
+
*/
|
|
921
|
+
readonly add: <T extends Object3D>(object: T) => T;
|
|
922
|
+
readonly input: InputMap;
|
|
923
|
+
readonly pointer: IPointerEvents3D;
|
|
924
|
+
readonly assets: IAssetLoader;
|
|
925
|
+
readonly after: (delay: number, callback: () => void) => ScheduleHandle;
|
|
926
|
+
/** Register a callback for the engine-owned phase after physics writes solved transforms. */
|
|
927
|
+
readonly afterPhysics: (callback: AfterPhysicsCallback) => () => void;
|
|
928
|
+
readonly every: (callback: (dt: number) => void) => ScheduleHandle;
|
|
929
|
+
readonly state: GameStore<TState>;
|
|
930
|
+
readonly tween: <T extends object>(target: T, properties: {
|
|
931
|
+
[K in keyof T]?: number;
|
|
932
|
+
}, duration: number, options?: ITweenOptions) => Promise<void>;
|
|
933
|
+
readonly random: IRandom;
|
|
934
|
+
readonly raycast: (options?: IRaycastOptions) => Intersection | undefined;
|
|
935
|
+
readonly raycastAll: (options?: IRaycastOptions, target?: Intersection[]) => readonly Intersection[];
|
|
936
|
+
/**
|
|
937
|
+
* The framework's own startup work — what a loading screen waits on.
|
|
938
|
+
*
|
|
939
|
+
* A shader may compile the first time something using it is drawn, and the render projection may
|
|
940
|
+
* do its first build in that same frame. Both costs are real and belong before the world is shown.
|
|
941
|
+
*
|
|
942
|
+
* Keeping the world hidden until `whenReady()` resolves does more than hide the mess: the
|
|
943
|
+
* shaders that would have been compiled for geometry the projection then discards are never
|
|
944
|
+
* compiled at all, so waiting is *faster* than not waiting.
|
|
945
|
+
*/
|
|
946
|
+
readonly startup: IStartupStatus;
|
|
947
|
+
readonly goto: (name: string) => Promise<void>;
|
|
948
|
+
physics: TPhysics;
|
|
949
|
+
}
|
|
950
|
+
|
|
771
951
|
type PluginCleanup = () => void;
|
|
772
952
|
interface IGameObservationSampleRequest {
|
|
773
953
|
readonly entities?: readonly string[];
|
|
@@ -795,14 +975,13 @@ interface IGamePluginRuntime {
|
|
|
795
975
|
/** The frame's cost attribution so far, or undefined when the game turned the budget off. */
|
|
796
976
|
readonly frameBudgetWindow?: () => IFrameBudgetWindow | undefined;
|
|
797
977
|
/**
|
|
798
|
-
* Hold
|
|
978
|
+
* Hold start-scene entry until `gate` settles.
|
|
799
979
|
*
|
|
800
|
-
*
|
|
801
|
-
*
|
|
802
|
-
*
|
|
803
|
-
* loop at the last possible moment — everything is registered, nothing has stepped.
|
|
980
|
+
* The returned promise settles after `Scene.enter()` has run. A runner can therefore release the
|
|
981
|
+
* gate after applying pre-entry setup, then await the returned promise before describing
|
|
982
|
+
* entity-derived capabilities. The frame loop remains held throughout.
|
|
804
983
|
*/
|
|
805
|
-
readonly holdStart?: (gate: Promise<void>) => void
|
|
984
|
+
readonly holdStart?: (gate: Promise<void>) => Promise<void>;
|
|
806
985
|
readonly observations: IGameRuntimeObservations;
|
|
807
986
|
readonly tick: () => number;
|
|
808
987
|
readonly runtimeDiagnosticsSeries?: () => readonly IRenderPerformanceSample[];
|
|
@@ -818,6 +997,10 @@ interface IGamePluginRuntime {
|
|
|
818
997
|
* must be reported rather than inferred from a phase that cannot distinguish the two.
|
|
819
998
|
*/
|
|
820
999
|
readonly startupCompileSettled?: () => boolean;
|
|
1000
|
+
/** When the startup milestones happened, for the playtest bridge's startup observation. */
|
|
1001
|
+
readonly startupTimeline?: () => IStartupTimeline;
|
|
1002
|
+
/** The renderer-owned bounded pipeline capture, when the renderer has not been opted out. */
|
|
1003
|
+
readonly pipelineCensus?: () => IPipelineCensus;
|
|
821
1004
|
readonly step: number;
|
|
822
1005
|
}
|
|
823
1006
|
interface IGamePlatformSource {
|
|
@@ -860,7 +1043,7 @@ interface IGameConfig<TState extends Record<string, unknown> = Record<string, un
|
|
|
860
1043
|
readonly frameBudget?: IFrameBudgetOptions | false;
|
|
861
1044
|
readonly initialState?: TState;
|
|
862
1045
|
/**
|
|
863
|
-
*
|
|
1046
|
+
* The **pre-start** shader warm-up. Off by default, and that is not the same as no warm-up.
|
|
864
1047
|
*
|
|
865
1048
|
* Every distinct pipeline is otherwise built the first time something using it is drawn, inside
|
|
866
1049
|
* the first rendered frame of a fully built scene. On a Pixel 8 that frame lasted **12.0 s, of
|
|
@@ -868,21 +1051,24 @@ interface IGameConfig<TState extends Record<string, unknown> = Record<string, un
|
|
|
868
1051
|
* loop presents nothing for the whole span. Warming those pipelines while the loading screen is
|
|
869
1052
|
* up is the obvious fix, and it is the one this option exists for.
|
|
870
1053
|
*
|
|
871
|
-
*
|
|
872
|
-
*
|
|
873
|
-
*
|
|
874
|
-
*
|
|
875
|
-
*
|
|
876
|
-
*
|
|
877
|
-
*
|
|
878
|
-
*
|
|
879
|
-
*
|
|
880
|
-
*
|
|
881
|
-
*
|
|
882
|
-
*
|
|
883
|
-
*
|
|
884
|
-
*
|
|
885
|
-
*
|
|
1054
|
+
* **A game with this unset still warms up.** `startupCompile` runs the same `warmUpScene` from
|
|
1055
|
+
* inside the loading layer's bounded readiness gate, where the opaque layer is on screen and the
|
|
1056
|
+
* loop is turning. This option only moves that work *earlier*, to before `start()` releases the
|
|
1057
|
+
* loop, where nothing is presenting — which is a thing to choose deliberately, not a default.
|
|
1058
|
+
*
|
|
1059
|
+
* **What PRD-327 changed is the mechanism, not this default.** The native host used to answer
|
|
1060
|
+
* `createRenderPipelineAsync` with the synchronous create wrapped in a resolved promise, so
|
|
1061
|
+
* `compileAsync` compiled on the main loop and was abandoned by its own budget having finished
|
|
1062
|
+
* nothing — `TN_WARMUP:{"compiled":0,"abandoned":1,"timedOut":true,"elapsedMs":15325}` — while
|
|
1063
|
+
* the first frame compiled the identical pipelines in 8.0 s anyway. Both entries are native
|
|
1064
|
+
* handlers now, handing the descriptor to a host compile pool and holding the main thread for
|
|
1065
|
+
* 0.27 ms of a 70 ms compile (ratio 0.0038 against a pre-registered bar of 0.25, asserted by
|
|
1066
|
+
* `threenative-async-pipeline-thread-test`). The default path started working without its
|
|
1067
|
+
* default moving.
|
|
1068
|
+
*
|
|
1069
|
+
* Pass `{}` or an options object to opt in, or `false` to opt out of warm-up entirely. Either
|
|
1070
|
+
* way `TN_WARMUP` and `TN_STARTUP_WARMUP` report what happened, because turning a convention off
|
|
1071
|
+
* must not turn its measurement off.
|
|
886
1072
|
*/
|
|
887
1073
|
readonly warmUp?: IWarmUpOptions | false | true;
|
|
888
1074
|
readonly inputTarget?: EventTarget;
|
|
@@ -977,4 +1163,4 @@ interface IGame<TState extends Record<string, unknown> = Record<string, unknown>
|
|
|
977
1163
|
}
|
|
978
1164
|
declare function defineGame<TState extends Record<string, unknown>, TPhysics = undefined>(config: IGameConfig<TState, TPhysics>): IGame<TState, TPhysics>;
|
|
979
1165
|
|
|
980
|
-
export { type
|
|
1166
|
+
export { afterPhysics as $, type AfterPhysicsCallback as A, type IThreeNativeIconVariants as B, type ContextMenuPolicy as C, type IThreeNativeTexturesConfig as D, type ITweenOptions as E, type IWarmUpCacheOptions as F, type IWarmUpObservation as G, type IWarmUpOptions as H, type IGame as I, type IWarmUpProgress as J, type IWarmUpRenderer as K, type IWarmUpReport as L, type InputBindings as M, type InputPlatformSource as N, type PointerEvent3DType as O, type PointerEvent3DListener as P, PointerEvents3D as Q, type SceneFrame as R, Scene as S, ScenePicker as T, type ScheduleHandle as U, Scheduler as V, type ThreeNativeBackgroundMode as W, type ThreeNativeOrientation as X, type ThreeNativeUiRenderer as Y, type WarmUpCacheStatus as Z, type WarmUpObservationStatus as _, type IGamePluginRuntime as a, createRandom as a0, defineGame as a1, warmUpScene as a2, type IGamePluginHooks as b, type ICtx as c, type IGameObservationContribution as d, type IGameObservationSampleRequest as e, type IGamePlatformSource as f, type IInputAction as g, type IInputGamepad as h, type IPointerDragHandle as i, type IPointerEvent3D as j, type IPointerEvents3D as k, type IPointerEvents3DOptions as l, type IPointerEvents3DPicker as m, type IPointerState as n, type IRandom as o, type IRawInputPointer as p, type IRawInputPointerEdge as q, type IRawInputState as r, type IRaycastOptions as s, type IScenePickerOptions as t, type IThreeNativeAudioConfig as u, type IThreeNativeAudioLoop as v, type IThreeNativeAudioOverride as w, type IThreeNativeAudioSpectrum as x, type IThreeNativeBootSplash as y, type IThreeNativeConfig as z };
|