@threenative/core 0.3.0 → 0.3.1

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.
Files changed (39) hide show
  1. package/README.md +10 -0
  2. package/capabilities.json +1881 -131
  3. package/dist/assets-kyoF7JlJ.d.ts +103 -0
  4. package/dist/{audio-Dp2mXpD3.d.ts → audio-BFiGneTL.d.ts} +62 -0
  5. package/dist/canvas-layer-BLVijiUJ.d.ts +62 -0
  6. package/dist/{game-CYIaKhgl.d.ts → game-XGrTzapq.d.ts} +350 -164
  7. package/dist/gpu-readback-D2iRvoe9.d.ts +112 -0
  8. package/dist/hot.d.ts +5 -3
  9. package/dist/hot.js +5 -1
  10. package/dist/index.d.ts +813 -143
  11. package/dist/index.js +4548 -941
  12. package/dist/net.d.ts +65 -0
  13. package/dist/net.js +643 -0
  14. package/dist/playtest.d.ts +29 -5
  15. package/dist/playtest.js +181 -35
  16. package/dist/react.d.ts +4 -2
  17. package/dist/{canvas-layer-CtrZHgIh.d.ts → renderer-C6hqZpoG.d.ts} +237 -75
  18. package/dist/world.d.ts +203 -4
  19. package/dist/world.js +2536 -25
  20. package/gpl/LICENSE.GPL +117 -0
  21. package/gpl/convert.py +192 -0
  22. package/gpl/recipes/_common.py +169 -0
  23. package/gpl/recipes/bake_ao.py +111 -0
  24. package/gpl/recipes/decimate.py +64 -0
  25. package/gpl/recipes/retarget.py +131 -0
  26. package/gpl/recipes/unwrap.py +71 -0
  27. package/mcp/blender-server.mjs +632 -0
  28. package/mcp/blender.mjs +27 -0
  29. package/mcp/engine-server.mjs +271 -23
  30. package/mcp/engine.mjs +15 -7
  31. package/mcp/install.d.mts +37 -0
  32. package/mcp/install.mjs +94 -26
  33. package/mcp/servers.d.mts +34 -0
  34. package/mcp/servers.mjs +110 -9
  35. package/package.json +36 -8
  36. package/patches/three@0.185.1.patch +249 -14
  37. package/scripts/ensure-mcp.mjs +20 -13
  38. package/scripts/bundle-engine-mcp.mjs +0 -15
  39. package/scripts/generate-version.mjs +0 -13
package/capabilities.json CHANGED
@@ -1,9 +1,335 @@
1
1
  {
2
2
  "entries": [
3
3
  {
4
+ "aliases": [],
5
+ "constraints": [
6
+ "a clip declared a loop has its seam measured on the decoded output bytes and fails the build when it exceeds the threshold; the assertion cannot be declared away",
7
+ "which clips loop, which are positional, and what a clip is for are declared per glob and never inferred from a filename",
8
+ "sources must be RIFF/WAVE or Ogg Vorbis, which is exactly what every native target decodes; an MP3 fails the bake"
9
+ ],
10
+ "example": "const pass = audioPass({ overrides: [{ glob: \"audio/*-bed.ogg\", loop: true }] });",
11
+ "importPath": "@threenative/assets",
12
+ "kind": "function",
13
+ "overrides": [],
14
+ "package": "@threenative/assets",
15
+ "signature": "export function audioPass(options: IAudioPassOptions = { … }",
16
+ "situations": [
17
+ "make an ambience bed loop without an audible click",
18
+ "halve what a positional sound effect costs a device's memory",
19
+ "stop an audio asset shipping silent on desktop, Android and iOS"
20
+ ],
21
+ "summary": "Conditions a game's audio and proves the conditioning did not destroy it.",
22
+ "supersedes": [],
23
+ "symbol": "audioPass"
24
+ },
25
+ {
26
+ "aliases": [],
27
+ "constraints": [
28
+ "source and output directories must be disjoint; a pass failure stops the build with the asset path"
29
+ ],
30
+ "example": "const result = await compileAssets({ source: \"assets\", output: \"public\" });",
31
+ "importPath": "@threenative/assets",
32
+ "kind": "function",
33
+ "overrides": [],
34
+ "package": "@threenative/assets",
35
+ "signature": "export async function compileAssets( options: IAssetCompileOptions = { … }",
36
+ "situations": [
37
+ "compile game assets before a web or native build",
38
+ "optimize textures for the GPU",
39
+ "produce a manifest for runtime asset loading"
40
+ ],
41
+ "summary": "Compiles a project's source assets into content-addressed runtime files and a manifest.",
42
+ "supersedes": [],
43
+ "symbol": "compileAssets"
44
+ },
45
+ {
46
+ "aliases": [],
47
+ "constraints": ["an empty row list produces no report lines"],
48
+ "example": "const lines = formatAudioSizes(audioRows);",
49
+ "importPath": "@threenative/assets",
50
+ "kind": "function",
51
+ "overrides": [],
52
+ "package": "@threenative/assets",
53
+ "signature": "export function formatAudioSizes(rows: readonly IAudioRow[]): readonly string[] { … }",
54
+ "situations": [
55
+ "see what audio conditioning did to a clip's wire and decoded size",
56
+ "read the loop seam and cross-fade a build measured"
57
+ ],
58
+ "summary": "Formats audio conditioning measurements for a build report.",
59
+ "supersedes": [],
60
+ "symbol": "formatAudioSizes"
61
+ },
62
+ {
63
+ "aliases": [],
64
+ "constraints": [
65
+ "the returned lines describe findings; target enforcement happens in runHealthReport"
66
+ ],
67
+ "example": "const lines = formatHealthReport(report);",
68
+ "importPath": "@threenative/assets",
69
+ "kind": "function",
70
+ "overrides": [],
71
+ "package": "@threenative/assets",
72
+ "signature": "export function formatHealthReport(report: IAssetHealthReport): readonly string[] { … }",
73
+ "situations": [
74
+ "print asset size, license, and target findings after compilation",
75
+ "show why an asset health check is warning or failing"
76
+ ],
77
+ "summary": "Formats asset health findings and their summary for human-readable output.",
78
+ "supersedes": [],
79
+ "symbol": "formatHealthReport"
80
+ },
81
+ {
82
+ "aliases": [],
83
+ "constraints": ["rows must use bytes before and after from the same compiled input"],
84
+ "example": "const lines = formatModelSizes(modelRows);",
85
+ "importPath": "@threenative/assets",
86
+ "kind": "function",
87
+ "overrides": [],
88
+ "package": "@threenative/assets",
89
+ "signature": "export function formatModelSizes(rows: readonly IModelSizeRow[]): readonly string[] { … }",
90
+ "situations": [
91
+ "inspect how model optimization changed file and GPU sizes",
92
+ "print model compression results after an asset build"
93
+ ],
94
+ "summary": "Formats model byte, geometry, and embedded-texture measurements for a build report.",
95
+ "supersedes": [],
96
+ "symbol": "formatModelSizes"
97
+ },
98
+ {
99
+ "aliases": [],
100
+ "constraints": ["one row per pass in registry order, per-asset rows sorted by logical path"],
101
+ "example": "const lines = formatPassCosts(result.passCosts);",
102
+ "importPath": "@threenative/assets",
103
+ "kind": "function",
104
+ "overrides": [],
105
+ "package": "@threenative/assets",
106
+ "signature": "export function formatPassCosts(rows: readonly IPassCostRow[]): readonly string[] { … }",
107
+ "situations": [
108
+ "see which asset pass owns the wall clock after a bake",
109
+ "compare pass costs between two builds before optimizing the pipeline"
110
+ ],
111
+ "summary": "Formats per-pass wall-clock costs for a build report.",
112
+ "supersedes": [],
113
+ "symbol": "formatPassCosts"
114
+ },
115
+ {
116
+ "aliases": [],
117
+ "constraints": ["an empty row list produces no report lines"],
118
+ "example": "const lines = formatTextureSizes(textureRows);",
119
+ "importPath": "@threenative/assets",
120
+ "kind": "function",
121
+ "overrides": [],
122
+ "package": "@threenative/assets",
123
+ "signature": "export function formatTextureSizes(rows: readonly ITextureSizeRow[]): readonly string[] { … }",
124
+ "situations": [
125
+ "inspect texture compression savings",
126
+ "print which codec a compiled texture uses"
127
+ ],
128
+ "summary": "Formats standalone texture byte measurements for a build report.",
129
+ "supersedes": [],
130
+ "symbol": "formatTextureSizes"
131
+ },
132
+ {
133
+ "aliases": [],
134
+ "constraints": [
135
+ "the input must be a static self-contained GLB with at least one punctual light"
136
+ ],
137
+ "example": "const pass = lightmapPass({ atlasSize: 1024, padding: 2 });",
138
+ "importPath": "@threenative/assets",
139
+ "kind": "function",
140
+ "overrides": [],
141
+ "package": "@threenative/assets",
142
+ "signature": "export function lightmapPass(options: ILightmapPassOptions): IAssetPass { … }",
143
+ "situations": [
144
+ "add baked static lighting to a model",
145
+ "generate TEXCOORD_1 data for a lightmapped scene"
146
+ ],
147
+ "summary": "Generates lightmap UVs and bakes a static GLB's lightmap atlas.",
148
+ "supersedes": [],
149
+ "symbol": "lightmapPass"
150
+ },
151
+ {
152
+ "aliases": [],
153
+ "constraints": [
154
+ "the pass self-verifies reachable geometry, animation, bounds, and embedded texture bindings before returning output"
155
+ ],
156
+ "example": "const pass = modelPass({ simplify: { ratio: 0.5 } });",
157
+ "importPath": "@threenative/assets",
158
+ "kind": "function",
159
+ "overrides": [],
160
+ "package": "@threenative/assets",
161
+ "signature": "export function modelPass(options: IModelPassOptions = { … }",
162
+ "situations": [
163
+ "reduce a model's download and GPU footprint",
164
+ "optimize a GLB before shipping it with a game"
165
+ ],
166
+ "summary": "Optimizes self-contained GLB models through the configured geometry and embedded-texture passes.",
167
+ "supersedes": [],
168
+ "symbol": "modelPass"
169
+ },
170
+ {
171
+ "aliases": [],
172
+ "constraints": [
173
+ "returns undefined for `\"none\"`, which drops the audio pass; an absent block returns the defaults",
174
+ "throws TN_ASSETS_CONFIG_INVALID or TN_ASSETS_CONFIG_UNKNOWN_KEY rather than dropping a key it does not know"
175
+ ],
176
+ "example": "const options = parseAudioConfig({ overrides: [{ glob: \"audio/*.ogg\", conditioning: \"none\" }] });",
177
+ "importPath": "@threenative/assets",
178
+ "kind": "function",
179
+ "overrides": [],
180
+ "package": "@threenative/assets",
181
+ "signature": "export function parseAudioConfig(raw: unknown): IAudioPassOptions | undefined { … }",
182
+ "situations": [
183
+ "validate a threenative.config.ts audio block before compiling assets",
184
+ "ship audio exactly as committed without conditioning it"
185
+ ],
186
+ "summary": "Validates a game's declared `assets.audio` block, the one place its keys and ranges are checked.",
187
+ "supersedes": [],
188
+ "symbol": "parseAudioConfig"
189
+ },
190
+ {
191
+ "aliases": [],
192
+ "constraints": [
193
+ "non-PNG or truncated bytes return undefined instead of being treated as a valid image"
194
+ ],
195
+ "example": "const png = parsePng(bytes); if (png !== undefined) console.log(png.width, png.height);",
196
+ "importPath": "@threenative/assets",
197
+ "kind": "function",
198
+ "overrides": [],
199
+ "package": "@threenative/assets",
200
+ "signature": "export function parsePng(value: Buffer): IPngInfo | undefined { … }",
201
+ "situations": [
202
+ "inspect a PNG before choosing a texture codec",
203
+ "read source texture dimensions in an asset health check"
204
+ ],
205
+ "summary": "Reads dimensions and alpha metadata from a PNG signature and IHDR header.",
206
+ "supersedes": [],
207
+ "symbol": "parsePng"
208
+ },
209
+ {
210
+ "aliases": [],
211
+ "constraints": [
212
+ "the supplied working directory must resolve both basis_transcoder.js and basis_transcoder.wasm from its Three.js installation"
213
+ ],
214
+ "example": "const transcoder = resolveBasisTranscoder(process.cwd());",
215
+ "importPath": "@threenative/assets",
216
+ "kind": "function",
217
+ "overrides": [],
218
+ "package": "@threenative/assets",
219
+ "signature": "export function resolveBasisTranscoder(cwd: string): IBasisTranscoder { … }",
220
+ "situations": [
221
+ "prepare compressed textures for runtime loading",
222
+ "copy the Basis transcoder into a compiled asset output"
223
+ ],
224
+ "summary": "Finds Three.js's Basis Universal transcoder files for the runtime KTX2 loader.",
225
+ "supersedes": [],
226
+ "symbol": "resolveBasisTranscoder"
227
+ },
228
+ {
229
+ "aliases": [],
230
+ "constraints": [
231
+ "a finding is fail-grade only when the corresponding project target was declared"
232
+ ],
233
+ "example": "const report = await runHealthReport(inputs, { maxTextureDimension: 2048 });",
234
+ "importPath": "@threenative/assets",
235
+ "kind": "function",
236
+ "overrides": [],
237
+ "package": "@threenative/assets",
238
+ "signature": "export async function runHealthReport( inputs: readonly IAssetHealthInput[], targets: IAssetTargets = { … }",
239
+ "situations": [
240
+ "check asset dimensions, triangles, materials, and licenses",
241
+ "enforce asset budgets during a build"
242
+ ],
243
+ "summary": "Measures compiled assets and grades them against declared project targets.",
244
+ "supersedes": [],
245
+ "symbol": "runHealthReport"
246
+ },
247
+ {
248
+ "aliases": [],
249
+ "constraints": [
250
+ "compressed source width and height must each be divisible by 4; automatic cooking retains an unaligned source unchanged and reports block-size, while an explicit compression codec override fails",
251
+ "every compressed source width and height must be divisible by 4 because BC7, BC1, ETC2, and ASTC 4x4 use 4x4 blocks; WebGPU rejects an unaligned texture at draw time",
252
+ "automatic cooking retains an unaligned source unchanged and reports block-size; an explicit compression codec override fails, while codec \"none\" remains available"
253
+ ],
254
+ "example": "const pass = texturePass({ quality: 150 });",
255
+ "importPath": "@threenative/assets",
256
+ "kind": "function",
257
+ "overrides": [],
258
+ "package": "@threenative/assets",
259
+ "signature": "export function texturePass(options: ITexturePassOptions = { … }",
260
+ "situations": [
261
+ "optimize textures for the GPU",
262
+ "compress PNG or JPEG files before runtime loading"
263
+ ],
264
+ "summary": "Encodes standalone textures as mipmapped KTX2/Basis assets for GPU storage.",
265
+ "supersedes": [],
266
+ "symbol": "texturePass"
267
+ },
268
+ {
269
+ "aliases": [],
270
+ "constraints": [
271
+ "call close on the returned handle; initial and burst failures are reported without stopping the dev server"
272
+ ],
273
+ "example": "const watcher = watchAssets({ cwd: process.cwd() });",
274
+ "importPath": "@threenative/assets",
275
+ "kind": "function",
276
+ "overrides": [],
277
+ "package": "@threenative/assets",
278
+ "signature": "export function watchAssets(options: IAssetWatchOptions = { … }",
279
+ "situations": [
280
+ "recompile a changed texture without restarting the dev server",
281
+ "see asset pipeline failures as files are saved"
282
+ ],
283
+ "summary": "Watches an asset source directory and recompiles settled changes during development.",
284
+ "supersedes": [],
285
+ "symbol": "watchAssets"
286
+ },
287
+ {
288
+ "aliases": [],
289
+ "constraints": [
290
+ "the objects, and where each one goes, stay the game's; this decides only when each joins the graph",
291
+ "input order is the attach order and cannot be changed",
292
+ "a false `while` stops the run and is reported as `stopped`, never thrown"
293
+ ],
294
+ "example": "const report = await addInSlices(objects, (object) => ctx.add(object), {\n onProgress: ({ added, total }) => setProgress(added / total),\n while: () => generation.live,\n});",
295
+ "importPath": "@threenative/core",
296
+ "kind": "function",
297
+ "overrides": [
298
+ "sliceSize defaults to 256; `marker: false` silences the TN_ADD_SLICES line, not the report"
299
+ ],
300
+ "package": "@threenative/core",
301
+ "signature": "export async function addInSlices<T>( objects: Iterable<T>, add: (object: T, index: number) => void, options: IAddInSlicesOptions = { … }",
302
+ "situations": [
303
+ "add hundreds of built objects to the scene without one multi-second frame",
304
+ "stream a detail tier in behind a loading curtain without the page looking hung"
305
+ ],
306
+ "summary": "Attach hundreds of built objects to the scene in slices, presenting a frame between each.",
307
+ "supersedes": [],
308
+ "symbol": "addInSlices"
309
+ },
310
+ {
311
+ "aliases": [],
312
+ "constraints": ["register from a scene context; callbacks are cleared when that scene exits"],
313
+ "example": "afterPhysics(ctx, (dt) => camera.position.copy(player.mesh.position));",
314
+ "importPath": "@threenative/core",
315
+ "kind": "function",
316
+ "overrides": [],
317
+ "package": "@threenative/core",
318
+ "signature": "export function afterPhysics( context: IAfterPhysicsContext, callback: AfterPhysicsCallback, ): () => void { … }",
319
+ "situations": [
320
+ "read a body after physics has moved it",
321
+ "place a camera or aim from the solved character transform"
322
+ ],
323
+ "summary": "Register work that reads a body or camera after physics has moved it and before this frame draws. The engine owns the phase ordering; a callback cannot be misplaced by plugin-array order.",
324
+ "supersedes": [],
325
+ "symbol": "afterPhysics"
326
+ },
327
+ {
328
+ "aliases": [],
4
329
  "constraints": [
5
330
  "name the body a game moves as strideRoot when the animated rig is a child of it",
6
- "a one-shot clip always plays at its authored rate; the matched rate re-times loops only"
331
+ "a one-shot clip always plays at its authored rate; the matched rate re-times loops only",
332
+ "the matched rate is held inside 0.15x-3x; a speed outside what the clip's own stride supports is clamped, and `stride.rate` says so"
7
333
  ],
8
334
  "example": "const player = new AnimationPlayer({ clips, root: rig, strideRoot: body });",
9
335
  "importPath": "@threenative/core",
@@ -17,13 +343,16 @@
17
343
  "play an animation on a character",
18
344
  "switch a character between idle and attack clips",
19
345
  "stop a walking character's feet from sliding or spinning",
20
- "match a walk or run cycle to how fast a character is moving"
346
+ "match a walk or run cycle to how fast a character is moving",
347
+ "match an in-place walk cycle with no root motion to the body's speed",
348
+ "find out what speed an animation clip was authored for"
21
349
  ],
22
- "summary": "Play a skinned or sprite animation from game code. A travelling clip's playback rate is matched to the ground the body actually covers, so feet do not skate or spin — on by default, `strideSync: false` to keep the authored rate, and `player.stride` reports the measurement either way. Name the body a game moves as `strideRoot` when the rig is a child of it.",
350
+ "summary": "Play a skinned or sprite animation from game code. A locomotion clip's playback rate is matched to the ground the body actually covers, so feet do not skate or spin — on by default, `strideSync: false` to keep the authored rate, and `player.stride` reports the measurement either way. Name the body a game moves as `strideRoot` when the rig is a child of it. Clips authored **in place** — every ActorX and Unreal export, every Mixamo \"in place\" clip, every stock animal pack — are matched too: their stride is read off the ground a planted foot sweeps, and `stride.inPlace` says so.",
23
351
  "supersedes": [],
24
352
  "symbol": "AnimationPlayer"
25
353
  },
26
354
  {
355
+ "aliases": ["bright sky saturated green platforms"],
27
356
  "constraints": [
28
357
  "supply rayleigh, mie, ozone, planetRadius, and atmosphereRadius; there is no Earth fallback",
29
358
  "the game creates the sky object, surface, and sun from the returned nodes"
@@ -43,6 +372,7 @@
43
372
  "symbol": "Atmosphere"
44
373
  },
45
374
  {
375
+ "aliases": [],
46
376
  "constraints": ["supply all physical parameters; this class creates no scene appearance"],
47
377
  "example": "const luts = new AtmosphereLuts({ rayleigh, mie, ozone, planetRadius, atmosphereRadius });",
48
378
  "importPath": "@threenative/core",
@@ -56,6 +386,7 @@
56
386
  "symbol": "AtmosphereLuts"
57
387
  },
58
388
  {
389
+ "aliases": [],
59
390
  "constraints": [
60
391
  "when a request is to hold or attach a weapon to a hand, import and call `attachToBone` from `@threenative/core`; do not manually parent, position, or rotate the rifle",
61
392
  "if a stock visual has no skeleton, add a portable Three.js Bone named `RightHand` under the character, then call `attachToBone`; do not replace the helper with manual parenting"
@@ -79,6 +410,7 @@
79
410
  "symbol": "attachToBone"
80
411
  },
81
412
  {
413
+ "aliases": [],
82
414
  "constraints": [
83
415
  "create buses before playing clips and dispose them with the game",
84
416
  "refDistance and rolloffFactor tune positional falloff and apply to playAt only"
@@ -100,6 +432,7 @@
100
432
  "symbol": "AudioBus"
101
433
  },
102
434
  {
435
+ "aliases": [],
103
436
  "constraints": [
104
437
  "call update from the owning scene; no global scene scan is installed",
105
438
  "orthographic cameras use their forward direction, and lockAxis restricts world rotation"
@@ -119,6 +452,67 @@
119
452
  "symbol": "Billboard3D"
120
453
  },
121
454
  {
455
+ "aliases": [],
456
+ "constraints": [
457
+ "this walks the target's vertices; call it on a check or a debug sample, not every frame"
458
+ ],
459
+ "example": "import { boneContact } from \"@threenative/core\";\nconst contact = boneContact(worker, \"hand_r\", keyboard);",
460
+ "importPath": "@threenative/core",
461
+ "kind": "function",
462
+ "overrides": [],
463
+ "package": "@threenative/core",
464
+ "signature": "export function boneContact( root: Object3D, boneName: string, target: Object3D, ): IBoneContactReport { … }",
465
+ "situations": [
466
+ "check that a seated character's hands reach the keyboard",
467
+ "check that a character's hips meet the chair it is sitting on",
468
+ "turn \"the character is not touching the prop\" into a number a scenario can assert"
469
+ ],
470
+ "summary": "Measure whether a named bone reaches the object it is supposed to be touching, in metres.",
471
+ "supersedes": [],
472
+ "symbol": "boneContact"
473
+ },
474
+ {
475
+ "aliases": [],
476
+ "constraints": [
477
+ "a rigid skeleton preserves every parent→child distance under any pose; a named bone is a defect with an address",
478
+ "this is a diagnostic — it reports numbers and names; it moves nothing and decides no appearance"
479
+ ],
480
+ "example": "import { boneLengths, boneLengthDeviations } from \"@threenative/core\";\nconst report = boneLengthDeviations(character, boneLengths(character));\nif (!report.rigid && report.worst !== null) console.log(report.worst.bone, report.worst.ratio);",
481
+ "importPath": "@threenative/core",
482
+ "kind": "function",
483
+ "overrides": [],
484
+ "package": "@threenative/core",
485
+ "signature": "export function boneLengthDeviations( root: Object3D, bind: IBoneLengthSnapshot, options: IBoneLengthDeviationsOptions = { … }",
486
+ "situations": [
487
+ "find out why a skinned character renders deformed",
488
+ "check that an animated pose keeps the skeleton rigid",
489
+ "name the bone that breaks a posed skeleton without taking a screenshot"
490
+ ],
491
+ "summary": "Compare a rig's bone distances now against a captured snapshot and name every bone that moved.",
492
+ "supersedes": [],
493
+ "symbol": "boneLengthDeviations"
494
+ },
495
+ {
496
+ "aliases": [],
497
+ "constraints": [
498
+ "the baseline and the later comparison must come from the same rig under the same ancestor transform, so a uniform scale cancels"
499
+ ],
500
+ "example": "import { boneLengths } from \"@threenative/core\";\nconst baseline = boneLengths(character);",
501
+ "importPath": "@threenative/core",
502
+ "kind": "function",
503
+ "overrides": [],
504
+ "package": "@threenative/core",
505
+ "signature": "export function boneLengths(root: Object3D): IBoneLengthSnapshot { … }",
506
+ "situations": [
507
+ "capture a rig's bind-pose bone lengths before any clip plays",
508
+ "measure a skeleton for the bone-length invariance check"
509
+ ],
510
+ "summary": "Measure a rig's parent→child bone distances, in world space, as it stands right now.",
511
+ "supersedes": [],
512
+ "symbol": "boneLengths"
513
+ },
514
+ {
515
+ "aliases": [],
122
516
  "constraints": [
123
517
  "amplitude, rotationAmplitude, frequency, decay, and curve are required game choices",
124
518
  "update returns an offset and never writes to a camera"
@@ -138,8 +532,9 @@
138
532
  "symbol": "CameraShake"
139
533
  },
140
534
  {
535
+ "aliases": [],
141
536
  "constraints": [],
142
- "example": "const hud = new CanvasLayer({ camera });",
537
+ "example": "const hud = new CanvasLayer(ctx.viewport);",
143
538
  "importPath": "@threenative/core",
144
539
  "kind": "class",
145
540
  "overrides": [],
@@ -154,6 +549,66 @@
154
549
  "symbol": "CanvasLayer"
155
550
  },
156
551
  {
552
+ "aliases": [],
553
+ "constraints": ["a track that binds nothing counts as driving nothing"],
554
+ "example": "import { clipBoneCoverage } from \"@threenative/core\";\nconst coverage = clipBoneCoverage(character, clip);",
555
+ "importPath": "@threenative/core",
556
+ "kind": "function",
557
+ "overrides": [],
558
+ "package": "@threenative/core",
559
+ "signature": "export function clipBoneCoverage(root: Object3D, clip: AnimationClip): IClipCoverageReport { … }",
560
+ "situations": [
561
+ "find out why a character keeps the previous animation's hand shape",
562
+ "check how much of a rig a clip covers before shipping it"
563
+ ],
564
+ "summary": "Report which bones of a character a clip does not drive.",
565
+ "supersedes": [],
566
+ "symbol": "clipBoneCoverage"
567
+ },
568
+ {
569
+ "aliases": [],
570
+ "constraints": [
571
+ "each bone is compared as a whole quaternion relative to its own rig's bind pose, so the two rigs never have to share a bind convention; a bone-direction check reports zero on the roll this catches",
572
+ "both rigs must face the same way in world space, and both are driven and then restored to the transforms they arrived with"
573
+ ],
574
+ "example": "import { clipPoseError } from \"@threenative/core\";\nconst report = clipPoseError({ root: rig, clip: retargeted }, { root: source, clip: original });",
575
+ "importPath": "@threenative/core",
576
+ "kind": "function",
577
+ "overrides": [
578
+ "bones maps one rig's bone names onto the other's when they differ; samples sets how many poses are compared"
579
+ ],
580
+ "package": "@threenative/core",
581
+ "signature": "export function clipPoseError( subject: IClipPoseSubject, reference: IClipPoseSubject, options: IClipPoseErrorOptions = { … }",
582
+ "situations": [
583
+ "find out why a retargeted animation looks wrong on a character",
584
+ "tell a fixed retarget from one that merely moved",
585
+ "catch a retarget that rolled every limb about its own axis"
586
+ ],
587
+ "summary": "Score a retargeted clip against the source it came from, per bone, in degrees.",
588
+ "supersedes": [],
589
+ "symbol": "clipPoseError"
590
+ },
591
+ {
592
+ "aliases": [],
593
+ "constraints": [
594
+ "the reason is Three.js's own, captured off its console hook so a scenario's console assertions stay clean"
595
+ ],
596
+ "example": "import { clipTrackBindings } from \"@threenative/core\";\nconst bindings = clipTrackBindings(character, clip);",
597
+ "importPath": "@threenative/core",
598
+ "kind": "function",
599
+ "overrides": [],
600
+ "package": "@threenative/core",
601
+ "signature": "export function clipTrackBindings(root: Object3D, clip: AnimationClip): IClipBindingReport { … }",
602
+ "situations": [
603
+ "find out why a character plays its bind pose instead of the animation",
604
+ "check that a loaded clip actually drives the model it was written for"
605
+ ],
606
+ "summary": "Report which of a clip's tracks bind to nothing on a character.",
607
+ "supersedes": [],
608
+ "symbol": "clipTrackBindings"
609
+ },
610
+ {
611
+ "aliases": [],
157
612
  "constraints": [
158
613
  "the body's geometry must carry a cluster table from `assets.models.virtual`",
159
614
  "every copy is placed before build(); place() after build() throws"
@@ -176,6 +631,7 @@
176
631
  "symbol": "ClusteredBatch"
177
632
  },
178
633
  {
634
+ "aliases": [],
179
635
  "constraints": [
180
636
  "the bake happens in the asset pipeline, never at run time — there is no runtime flag",
181
637
  "the payload costs about 3-4x a baked primitive's bytes; `assets.models.virtual: \"none\"` opts out and `minSourceTriangles` moves the 65,536 line",
@@ -201,10 +657,11 @@
201
657
  "symbol": "ClusteredMesh"
202
658
  },
203
659
  {
660
+ "aliases": [],
204
661
  "constraints": [
205
662
  "add the object through ctx.add so it attaches, dispatches, and releases with its scene"
206
663
  ],
207
- "example": "class Cloth extends Mesh implements IComputeDriven { ... }",
664
+ "example": "const registry = new ComputeDrivenRegistry(); registry.add(cloth, ctx.renderer.raw);",
208
665
  "importPath": "@threenative/core",
209
666
  "kind": "class",
210
667
  "overrides": [],
@@ -220,6 +677,7 @@
220
677
  "symbol": "ComputeDrivenRegistry"
221
678
  },
222
679
  {
680
+ "aliases": ["different props in each area", "first playable screen external assets"],
223
681
  "constraints": [
224
682
  "reuse the loader handed to scenes as `ctx.assets` instead of building parallel caches"
225
683
  ],
@@ -238,6 +696,26 @@
238
696
  "symbol": "createAssetLoader"
239
697
  },
240
698
  {
699
+ "aliases": [],
700
+ "constraints": [
701
+ "the capture is bounded and incomplete when the backend cannot expose an observation"
702
+ ],
703
+ "example": "const capture = game.runtime.pipelineCensus?.();\n// The game normally reaches this through `runtime.pipelineCensus`; direct construction exists\n// for renderer adapters and contract tests, not for gameplay.",
704
+ "importPath": "@threenative/core",
705
+ "kind": "function",
706
+ "overrides": [],
707
+ "package": "@threenative/core",
708
+ "signature": "export function createPipelineCensus(options: IPipelineCensusOptions): PipelineCensus { … }",
709
+ "situations": [
710
+ "inspect shader and pipeline creation work during a real launch",
711
+ "correlate pipeline creation with material, object, pass, and shader identities"
712
+ ],
713
+ "summary": "Read the renderer's bounded, versioned pipeline capture in a diagnostic or playtest tool.",
714
+ "supersedes": [],
715
+ "symbol": "createPipelineCensus"
716
+ },
717
+ {
718
+ "aliases": [],
241
719
  "constraints": ["use the returned source instead of Math.random for replayable behavior"],
242
720
  "example": "const random = createRandom(42);",
243
721
  "importPath": "@threenative/core",
@@ -254,10 +732,11 @@
254
732
  "symbol": "createRandom"
255
733
  },
256
734
  {
735
+ "aliases": ["fixed seed fixed-step simulation"],
257
736
  "constraints": [
258
737
  "use a seeded random source and fixed-step simulation for meaningful replays"
259
738
  ],
260
- "example": "const driver = createReplayDriver({ recording });",
739
+ "example": "const driver = createReplayDriver(recording, ctx.renderer.domElement);",
261
740
  "importPath": "@threenative/core",
262
741
  "kind": "function",
263
742
  "overrides": [],
@@ -272,12 +751,18 @@
272
751
  "symbol": "createReplayDriver"
273
752
  },
274
753
  {
754
+ "aliases": [
755
+ "firing line nearest target crosshair",
756
+ "third-person camera",
757
+ "restart the run without a page reload",
758
+ "field of view while aiming"
759
+ ],
275
760
  "constraints": [
276
761
  "keep DOM and React mounting in src/main.ts",
277
762
  "bind scroll or pinch and read the intent with ctx.input.axis(name); do not add a window wheel listener",
278
763
  "scroll: true uses the DOM wheel sign on browser and native: negative deltaY toward the user is positive intent"
279
764
  ],
280
- "example": "const game = defineGame({ input: { zoom: { scroll: true, pinch: true } }, scenes: { Play } });",
765
+ "example": "const game = defineGame({ input: { zoom: { scroll: true, pinch: true } }, scenes: { Play }, start: \"Play\" });",
281
766
  "importPath": "@threenative/core",
282
767
  "kind": "function",
283
768
  "overrides": [],
@@ -286,13 +771,15 @@
286
771
  "situations": [
287
772
  "start a ThreeNative game from src/game.ts",
288
773
  "register physics and gameplay plugins",
289
- "let the player zoom the camera with a wheel, pinch, or gamepad axis"
774
+ "let the player zoom the camera with a wheel, pinch, or gamepad axis",
775
+ "frame a camera behind the player"
290
776
  ],
291
777
  "summary": "Define the portable game entry shared by web and native.",
292
778
  "supersedes": [],
293
779
  "symbol": "defineGame"
294
780
  },
295
781
  {
782
+ "aliases": [],
296
783
  "constraints": ["pass a non-zero direction; coefficients and radii come from the game"],
297
784
  "example": "const transmittance = directionalTransmittance(parameters, sunDirection);",
298
785
  "importPath": "@threenative/core",
@@ -306,6 +793,7 @@
306
793
  "symbol": "directionalTransmittance"
307
794
  },
308
795
  {
796
+ "aliases": [],
309
797
  "constraints": ["elevation and azimuth must be finite degrees"],
310
798
  "example": "const direction = directionFromSolarPosition(sun.elevation, sun.azimuth);",
311
799
  "importPath": "@threenative/core",
@@ -319,6 +807,7 @@
319
807
  "symbol": "directionFromSolarPosition"
320
808
  },
321
809
  {
810
+ "aliases": [],
322
811
  "constraints": [
323
812
  "call `VelocityTracker.update()` before the render and `commit()` after it",
324
813
  "a pass is only given a velocity target when a temporal stage consumes it",
@@ -340,6 +829,7 @@
340
829
  "symbol": "ensureVelocityOutput"
341
830
  },
342
831
  {
832
+ "aliases": [],
343
833
  "constraints": [
344
834
  "add the field through `ctx.add` so renderer attachment, fixed-step dispatch, and release are automatic",
345
835
  "`dye` and `velocity` are numeric samplers; appearance stays in the game's `src/render/` code",
@@ -365,6 +855,7 @@
365
855
  "symbol": "FluidField2D"
366
856
  },
367
857
  {
858
+ "aliases": [],
368
859
  "constraints": [
369
860
  "on by default and printed as TN_FRAME_BUDGET; defineGame({ frameBudget: false }) silences the marker, not the measurement"
370
861
  ],
@@ -383,6 +874,7 @@
383
874
  "symbol": "FrameBudget"
384
875
  },
385
876
  {
877
+ "aliases": [],
386
878
  "constraints": [
387
879
  "only use the returned platform facts; native globals are host-owned",
388
880
  "ray tracing is unavailable on native until buffer-to-texture copy-out interop exists; `mystralRT.traceRays` refuses instead of resolving success without a readable result"
@@ -403,6 +895,7 @@
403
895
  "symbol": "getPlatform"
404
896
  },
405
897
  {
898
+ "aliases": [],
406
899
  "constraints": ["geometry, color, and timing remain supplied by the game"],
407
900
  "example": "const particles = new GPUParticles3D(particleOptions);",
408
901
  "importPath": "@threenative/core",
@@ -413,6 +906,7 @@
413
906
  "situations": [
414
907
  "emit sparks, smoke, or other transient effects",
415
908
  "update many small visual particles",
909
+ "trail dust, exhaust, or spray behind a moving object",
416
910
  "emit cannon smoke and muzzle flash particles",
417
911
  "fire a cannonball projectile with cannon smoke particles"
418
912
  ],
@@ -421,6 +915,7 @@
421
915
  "symbol": "GPUParticles3D"
422
916
  },
423
917
  {
918
+ "aliases": [],
424
919
  "constraints": [
425
920
  "the copy is asynchronous, so every sample carries staleFrames and is never this frame",
426
921
  "WebGPU only; the seam throws on a WebGL2 renderer rather than returning nothing",
@@ -443,6 +938,7 @@
443
938
  "symbol": "GPUReadback"
444
939
  },
445
940
  {
941
+ "aliases": [],
446
942
  "constraints": [
447
943
  "call rebuild() after a scene transform or geometry change; the snapshot is static by default",
448
944
  "rebuild() is an explicit CPU SAH build proportional to selected triangles; process() is a no-op, and the game pays upstream traversal per shader ray"
@@ -462,6 +958,7 @@
462
958
  "symbol": "GPUSceneBVH"
463
959
  },
464
960
  {
961
+ "aliases": [],
465
962
  "constraints": [
466
963
  "import from `@threenative/core`; this moves the rendered model, not its physics collider"
467
964
  ],
@@ -482,6 +979,7 @@
482
979
  "symbol": "GroundSnap"
483
980
  },
484
981
  {
982
+ "aliases": ["landmarks points of interest", "obstacles collectibles increasing pace"],
485
983
  "constraints": [
486
984
  "geometry and material are required and come from the game; the batch chooses neither",
487
985
  "span stretches along +Y, so its geometry must be unit-height and centred on the origin",
@@ -497,6 +995,7 @@
497
995
  "signature": "export class InstancedBatch { … }",
498
996
  "situations": [
499
997
  "draw hundreds of repeated props without hundreds of draw calls",
998
+ "draw thousands of identical instanced blocks or obstacles in one mesh",
500
999
  "place repeated props when the count is not known until the layout has been walked",
501
1000
  "build a chain, railing, cable, or tie rod out of point-to-point segments"
502
1001
  ],
@@ -505,6 +1004,7 @@
505
1004
  "symbol": "InstancedBatch"
506
1005
  },
507
1006
  {
1007
+ "aliases": [],
508
1008
  "constraints": [
509
1009
  "only use the returned platform facts; native globals are host-owned",
510
1010
  "ray tracing is unavailable on native until buffer-to-texture copy-out interop exists; `mystralRT.traceRays` refuses instead of resolving success without a readable result"
@@ -525,6 +1025,7 @@
525
1025
  "symbol": "isMobile"
526
1026
  },
527
1027
  {
1028
+ "aliases": [],
528
1029
  "constraints": [
529
1030
  "only use the returned platform facts; native globals are host-owned",
530
1031
  "ray tracing is unavailable on native until buffer-to-texture copy-out interop exists; `mystralRT.traceRays` refuses instead of resolving success without a readable result"
@@ -545,6 +1046,7 @@
545
1046
  "symbol": "isNative"
546
1047
  },
547
1048
  {
1049
+ "aliases": [],
548
1050
  "constraints": [
549
1051
  "only use the returned platform facts; native globals are host-owned",
550
1052
  "ray tracing is unavailable on native until buffer-to-texture copy-out interop exists; `mystralRT.traceRays` refuses instead of resolving success without a readable result"
@@ -565,6 +1067,7 @@
565
1067
  "symbol": "isTouchscreenAvailable"
566
1068
  },
567
1069
  {
1070
+ "aliases": [],
568
1071
  "constraints": [
569
1072
  "only use the returned platform facts; native globals are host-owned",
570
1073
  "ray tracing is unavailable on native until buffer-to-texture copy-out interop exists; `mystralRT.traceRays` refuses instead of resolving success without a readable result"
@@ -585,6 +1088,29 @@
585
1088
  "symbol": "isWeb"
586
1089
  },
587
1090
  {
1091
+ "aliases": [],
1092
+ "constraints": [
1093
+ "results are written to each item's own index and never appended, so a positional lookup finds the same asset on every load",
1094
+ "the first rejection rejects the call and no lane starts a load it had not begun"
1095
+ ],
1096
+ "example": "const species = await loadAll(names, (name) => ctx.assets.model(`flora/${name}.glb`));",
1097
+ "importPath": "@threenative/core",
1098
+ "kind": "function",
1099
+ "overrides": [
1100
+ "concurrency defaults to 6; `marker: false` silences the TN_LOAD_ALL line, not onProgress"
1101
+ ],
1102
+ "package": "@threenative/core",
1103
+ "signature": "export async function loadAll<TIn, TOut>( items: readonly TIn[], load: (item: TIn, index: number) => Promise<TOut>, options: ILoadAllOptions = { … }",
1104
+ "situations": [
1105
+ "load many models or textures in parallel instead of one at a time",
1106
+ "keep a loading screen moving while a list of assets downloads"
1107
+ ],
1108
+ "summary": "Load a list with bounded concurrency, returning results in the input's order.",
1109
+ "supersedes": [],
1110
+ "symbol": "loadAll"
1111
+ },
1112
+ {
1113
+ "aliases": [],
588
1114
  "constraints": ["precise per-vertex measurement is opt-in and not for frame loops"],
589
1115
  "example": "const measurement = measureThreePose(model);",
590
1116
  "importPath": "@threenative/core",
@@ -598,6 +1124,31 @@
598
1124
  "symbol": "measureThreePose"
599
1125
  },
600
1126
  {
1127
+ "aliases": [],
1128
+ "constraints": [
1129
+ "every part is de-indexed and stripped to position, so UVs and authored normals do not survive; normals are recomputed from the merged buffer",
1130
+ "either every part names a color or none does, and a mix throws",
1131
+ "an empty part list throws, and a merge three.js refuses throws naming the label"
1132
+ ],
1133
+ "example": "const wall = new Mesh(mergeParts(pieces, { label: \"gatehouse\" }), stone);\n// pieces are meshes, or { geometry, matrix, color } when the colour is per piece:\nconst banner = mergeParts([{ color: 0x8b2f1a, geometry: cloth, matrix: placement }], { label: \"banner\" });",
1134
+ "importPath": "@threenative/core",
1135
+ "kind": "function",
1136
+ "overrides": [
1137
+ "color is per part and optional; without it no colour attribute is written and the surface alone decides"
1138
+ ],
1139
+ "package": "@threenative/core",
1140
+ "signature": "export function mergeParts( parts: Iterable<IMergePart>, options: IMergePartsOptions, ): BufferGeometry { … }",
1141
+ "situations": [
1142
+ "bake a building, ship or character authored out of primitives into one draw call",
1143
+ "merge many small geometries and keep each piece's own colour",
1144
+ "stop mergeGeometries from silently returning null on an extruded shape"
1145
+ ],
1146
+ "summary": "Merge pieces a game authored out of primitives into one buffer, keeping each piece's own colour. `InstancedBatch` collapses many copies of one shape; this collapses many *different* shapes that never move relative to each other — a building, a ship, a character built from boxes. Two things go wrong every time and neither is about how any of it looks. `mergeGeometries` hands back `null` on mismatched inputs instead of throwing, and the usual mismatch is invisible: one `ExtrudeGeometry` is non-indexed while every other primitive is indexed, so the merge fails at the first piece and the scene never loads. And a merged buffer draws with one surface, so per-piece colour is gone unless every piece carries a flat `color` attribute written before the merge. Both are mechanical. Geometry, placement, colour and the surface it draws with all stay the game's.",
1147
+ "supersedes": [],
1148
+ "symbol": "mergeParts"
1149
+ },
1150
+ {
1151
+ "aliases": [],
601
1152
  "constraints": [
602
1153
  "skinned height uses a crown bone; game-specific asset expectations stay in render code"
603
1154
  ],
@@ -616,6 +1167,7 @@
616
1167
  "symbol": "normaliseToMetres"
617
1168
  },
618
1169
  {
1170
+ "aliases": [],
619
1171
  "constraints": ["recordings are version 1; the parser fails closed with TN_REPLAY_* codes"],
620
1172
  "example": "const recording = parseReplayRecording(rawRecording);",
621
1173
  "importPath": "@threenative/core",
@@ -629,8 +1181,9 @@
629
1181
  "symbol": "parseReplayRecording"
630
1182
  },
631
1183
  {
1184
+ "aliases": [],
632
1185
  "constraints": [],
633
- "example": "const follower = new PathFollow3D(curve, { loop: true });",
1186
+ "example": "const follower = new PathFollow3D({ points: patrolPoints, loop: true, speed: 3 });",
634
1187
  "importPath": "@threenative/core",
635
1188
  "kind": "class",
636
1189
  "overrides": [],
@@ -645,26 +1198,48 @@
645
1198
  "symbol": "PathFollow3D"
646
1199
  },
647
1200
  {
1201
+ "aliases": [],
648
1202
  "constraints": [
649
- "listeners are side-table registrations; Three.js prototypes are never patched",
650
- "one raycast serves each active pointer and no raycast runs when nothing is registered"
1203
+ "the capture is bounded and incomplete when the backend cannot expose an observation"
651
1204
  ],
652
- "example": "ctx.pointer.on(tile, \"tapped\", (event) => place(event.point));",
1205
+ "example": "const capture = game.runtime.pipelineCensus?.();\n// The game normally reaches this through `runtime.pipelineCensus`; direct construction exists\n// for renderer adapters and contract tests, not for gameplay.",
653
1206
  "importPath": "@threenative/core",
654
1207
  "kind": "class",
655
1208
  "overrides": [],
656
1209
  "package": "@threenative/core",
657
- "signature": "export class PointerEvents3D implements IPointerEvents3D { … }",
1210
+ "signature": "export class PipelineCensus { … }",
658
1211
  "situations": [
659
- "let the player click on a thing in the world",
660
- "show a 3D object while a pointer hovers over it",
661
- "handle touch and mouse taps on a loaded model without naming its child meshes"
1212
+ "inspect shader and pipeline creation work during a real launch",
1213
+ "correlate pipeline creation with material, object, pass, and shader identities"
662
1214
  ],
663
- "summary": "Dispatch portable pointer events from the game surface to registered Three.js objects.",
1215
+ "summary": "Read the renderer's bounded, versioned pipeline capture in a diagnostic or playtest tool.",
1216
+ "supersedes": [],
1217
+ "symbol": "PipelineCensus"
1218
+ },
1219
+ {
1220
+ "aliases": [],
1221
+ "constraints": [
1222
+ "listeners are side-table registrations; Three.js prototypes are never patched",
1223
+ "one raycast serves each active pointer and no raycast runs when nothing is registered"
1224
+ ],
1225
+ "example": "ctx.pointer.on(tile, \"tapped\", (event) => place(event.point));",
1226
+ "importPath": "@threenative/core",
1227
+ "kind": "class",
1228
+ "overrides": [],
1229
+ "package": "@threenative/core",
1230
+ "signature": "export class PointerEvents3D implements IPointerEvents3D { … }",
1231
+ "situations": [
1232
+ "let the player click on a thing in the world",
1233
+ "show a 3D object while a pointer hovers over it",
1234
+ "handle touch and mouse taps on a loaded model without naming its child meshes",
1235
+ "drag a crate or prop with the mouse or a finger"
1236
+ ],
1237
+ "summary": "Dispatch portable pointer events from the game surface to registered Three.js objects.",
664
1238
  "supersedes": [],
665
1239
  "symbol": "PointerEvents3D"
666
1240
  },
667
1241
  {
1242
+ "aliases": [],
668
1243
  "constraints": ["precise per-vertex measurement is opt-in and not for frame loops"],
669
1244
  "example": "const measurement = measureThreePose(model);",
670
1245
  "importPath": "@threenative/core",
@@ -678,6 +1253,7 @@
678
1253
  "symbol": "posedBounds"
679
1254
  },
680
1255
  {
1256
+ "aliases": [],
681
1257
  "constraints": [
682
1258
  "keep the surface visible with zero opacity; do not hide it with `visible = false`"
683
1259
  ],
@@ -696,6 +1272,7 @@
696
1272
  "symbol": "prewarm"
697
1273
  },
698
1274
  {
1275
+ "aliases": ["readable world lighting"],
699
1276
  "constraints": [
700
1277
  "request a bake after static geometry and lights are authored; this is static-lighting-first, not fully dynamic relighting",
701
1278
  "add the volume with ctx.add() so its incremental work is measured in the render phase",
@@ -716,27 +1293,27 @@
716
1293
  "symbol": "ProbeVolume"
717
1294
  },
718
1295
  {
1296
+ "aliases": [],
719
1297
  "constraints": [
720
- "request a bake after static geometry and lights are authored; this is static-lighting-first, not fully dynamic relighting",
721
- "add the volume with ctx.add() so its incremental work is measured in the render phase",
722
- "call sample() or sampleNode() from a game-owned material before screen-space GI; the volume owns no light, material, or colour"
1298
+ "the returned observation is a measurement; it does not own lighting or materials"
723
1299
  ],
724
- "example": "const probes = new ProbeVolume({ bounds, density: 0.5 }); ctx.add(probes); void probes.requestBake(scene);",
1300
+ "example": "const observation = readProbeVolumeObservation(probes);",
725
1301
  "importPath": "@threenative/core",
726
1302
  "kind": "function",
727
- "overrides": ["density, bounds, bakeBudgetMs, and bounces are game-owned choices"],
1303
+ "overrides": [],
728
1304
  "package": "@threenative/core",
729
1305
  "signature": "export function readProbeVolumeObservation(value: unknown): IProbeVolumeObservation | undefined { … }",
730
- "situations": [
731
- "light bouncing from a room I cannot see",
732
- "light a wall with an off-screen emitter"
733
- ],
734
- "summary": "Bake static diffuse irradiance that reaches surfaces from outside the camera view.",
1306
+ "situations": ["inspect the latest probe bake observation"],
1307
+ "summary": "Read the most recent observation from a probe volume.",
735
1308
  "supersedes": [],
736
1309
  "symbol": "readProbeVolumeObservation"
737
1310
  },
738
1311
  {
739
- "constraints": ["stage factories own colour, strength, and all other appearance choices"],
1312
+ "aliases": [],
1313
+ "constraints": [
1314
+ "stage factories own colour, strength, and all other appearance choices",
1315
+ "authored stages declare exactly one before or after anchor"
1316
+ ],
740
1317
  "example": "const chain = new RenderChain(renderer, { input: colour, stages, request: { stages: [\"bloom\"], tier: \"auto\" } });",
741
1318
  "importPath": "@threenative/core",
742
1319
  "kind": "function",
@@ -745,15 +1322,18 @@
745
1322
  "signature": "export function readRenderChainObservation( renderer: unknown, ): IRenderChainMarker[\"applied\"] | undefined { … }",
746
1323
  "situations": [
747
1324
  "compose screen-space effects in a canonical order",
1325
+ "insert a game-authored post stage into the measured render chain",
748
1326
  "report which render tier and velocity route actually ran"
749
1327
  ],
750
- "summary": "Compose game-provided render nodes in a measured, fail-closed chain.",
1328
+ "summary": "Compose game-provided render nodes in a measured, fail-closed chain. Authored stages use an opaque id and anchor before or after a built-in or another supplied stage; the engine does not need to know the effect's visual vocabulary.",
751
1329
  "supersedes": [],
752
1330
  "symbol": "readRenderChainObservation"
753
1331
  },
754
1332
  {
1333
+ "aliases": [],
755
1334
  "constraints": [
756
1335
  "stage factories own colour, strength, and all other appearance choices",
1336
+ "authored stages declare exactly one before or after anchor",
757
1337
  "an absent value means no chain was installed and must fail a chain assertion"
758
1338
  ],
759
1339
  "example": "const chain = new RenderChain(renderer, { input: colour, stages, request: { stages: [\"bloom\"], tier: \"auto\" } });",
@@ -764,15 +1344,17 @@
764
1344
  "signature": "export function readRenderChainReport(renderer: unknown): IRenderChainMarker | undefined { … }",
765
1345
  "situations": [
766
1346
  "compose screen-space effects in a canonical order",
1347
+ "insert a game-authored post stage into the measured render chain",
767
1348
  "report which render tier and velocity route actually ran",
768
1349
  "expose the render tier and dropped-stage reasons to a playtest",
769
1350
  "inspect whether a temporal pass received velocity"
770
1351
  ],
771
- "summary": "Compose game-provided render nodes in a measured, fail-closed chain.",
1352
+ "summary": "Compose game-provided render nodes in a measured, fail-closed chain. Authored stages use an opaque id and anchor before or after a built-in or another supplied stage; the engine does not need to know the effect's visual vocabulary.",
772
1353
  "supersedes": [],
773
1354
  "symbol": "readRenderChainReport"
774
1355
  },
775
1356
  {
1357
+ "aliases": [],
776
1358
  "constraints": [
777
1359
  "call `VelocityTracker.update()` before the render and `commit()` after it",
778
1360
  "a pass is only given a velocity target when a temporal stage consumes it"
@@ -793,6 +1375,7 @@
793
1375
  "symbol": "readVelocityPreviousBoneMatrices"
794
1376
  },
795
1377
  {
1378
+ "aliases": [],
796
1379
  "constraints": [
797
1380
  "call `VelocityTracker.update()` before the render and `commit()` after it",
798
1381
  "a pass is only given a velocity target when a temporal stage consumes it"
@@ -813,6 +1396,7 @@
813
1396
  "symbol": "readVelocityPreviousMatrices"
814
1397
  },
815
1398
  {
1399
+ "aliases": [],
816
1400
  "constraints": [
817
1401
  "call `VelocityTracker.update()` before the render and `commit()` after it",
818
1402
  "a pass is only given a velocity target when a temporal stage consumes it"
@@ -833,7 +1417,48 @@
833
1417
  "symbol": "readVelocityPreviousWorldMatrix"
834
1418
  },
835
1419
  {
836
- "constraints": ["stage factories own colour, strength, and all other appearance choices"],
1420
+ "aliases": [],
1421
+ "constraints": [
1422
+ "non-marker lines and markers with incomplete or non-numeric stats return `undefined`"
1423
+ ],
1424
+ "example": "const stats = readVirtualShadowMarker(line);\nif (stats !== undefined) console.log(stats.reuseRatio);",
1425
+ "importPath": "@threenative/core",
1426
+ "kind": "function",
1427
+ "overrides": [],
1428
+ "package": "@threenative/core",
1429
+ "signature": "export function readVirtualShadowMarker(line: string): IVirtualShadowStats | undefined { … }",
1430
+ "situations": ["inspect virtual shadow cache and mover counters from a renderer log"],
1431
+ "summary": "Parse a `TN_VIRTUAL_SHADOW` console line back into its complete stats, or `undefined`.",
1432
+ "supersedes": [],
1433
+ "symbol": "readVirtualShadowMarker"
1434
+ },
1435
+ {
1436
+ "aliases": [],
1437
+ "constraints": [
1438
+ "the model loader already applies this automatically; only a game loading GLBs around it needs the call",
1439
+ "detection votes per tracked bone and converts only on an overwhelming signature; a file that does not carry it is left byte-identical"
1440
+ ],
1441
+ "example": "import { reconcileMirroredClips } from \"@threenative/core\";\nif (reconcileMirroredClips(gltf.scene, gltf.animations)) console.info(\"clips were z-mirrored; repaired\");",
1442
+ "importPath": "@threenative/core",
1443
+ "kind": "function",
1444
+ "overrides": [],
1445
+ "package": "@threenative/core",
1446
+ "signature": "export function reconcileMirroredClips(root: Object3D, clips: readonly AnimationClip[]): boolean { … }",
1447
+ "situations": [
1448
+ "find out why a skinned character renders deformed",
1449
+ "repair an imported character that walks backwards with its spine folded",
1450
+ "load a rigged GLB through a custom loader and keep the framework's repair"
1451
+ ],
1452
+ "summary": "Repair an exported rig whose animation clips are z-mirrored against its own bind pose.",
1453
+ "supersedes": [],
1454
+ "symbol": "reconcileMirroredClips"
1455
+ },
1456
+ {
1457
+ "aliases": [],
1458
+ "constraints": [
1459
+ "stage factories own colour, strength, and all other appearance choices",
1460
+ "authored stages declare exactly one before or after anchor"
1461
+ ],
837
1462
  "example": "const chain = new RenderChain(renderer, { input: colour, stages, request: { stages: [\"bloom\"], tier: \"auto\" } });",
838
1463
  "importPath": "@threenative/core",
839
1464
  "kind": "class",
@@ -842,17 +1467,19 @@
842
1467
  "signature": "export class RenderChain { … }",
843
1468
  "situations": [
844
1469
  "compose screen-space effects in a canonical order",
1470
+ "insert a game-authored post stage into the measured render chain",
845
1471
  "report which render tier and velocity route actually ran"
846
1472
  ],
847
- "summary": "Compose game-provided render nodes in a measured, fail-closed chain.",
1473
+ "summary": "Compose game-provided render nodes in a measured, fail-closed chain. Authored stages use an opaque id and anchor before or after a built-in or another supplied stage; the engine does not need to know the effect's visual vocabulary.",
848
1474
  "supersedes": [],
849
1475
  "symbol": "RenderChain"
850
1476
  },
851
1477
  {
1478
+ "aliases": ["fixed seed fixed-step simulation"],
852
1479
  "constraints": [
853
1480
  "use a seeded random source and fixed-step simulation for meaningful replays"
854
1481
  ],
855
- "example": "const driver = createReplayDriver({ recording });",
1482
+ "example": "const driver = createReplayDriver(recording, ctx.renderer.domElement);",
856
1483
  "importPath": "@threenative/core",
857
1484
  "kind": "function",
858
1485
  "overrides": [],
@@ -867,6 +1494,7 @@
867
1494
  "symbol": "replay"
868
1495
  },
869
1496
  {
1497
+ "aliases": [],
870
1498
  "constraints": [
871
1499
  "every width and height must be a positive integer; the dimensions are not a named fidelity tier"
872
1500
  ],
@@ -882,6 +1510,7 @@
882
1510
  "symbol": "resolveAtmosphereLutResolutions"
883
1511
  },
884
1512
  {
1513
+ "aliases": [],
885
1514
  "constraints": [
886
1515
  "provide all three coefficient vectors and both radii; omitted fields are errors"
887
1516
  ],
@@ -897,6 +1526,7 @@
897
1526
  "symbol": "resolveAtmosphereParameters"
898
1527
  },
899
1528
  {
1529
+ "aliases": [],
900
1530
  "constraints": ["scene code must stay portable across web and native"],
901
1531
  "example": "class Play extends Scene { update(ctx, dt) {} }",
902
1532
  "importPath": "@threenative/core",
@@ -913,8 +1543,9 @@
913
1543
  "symbol": "Scene"
914
1544
  },
915
1545
  {
1546
+ "aliases": [],
916
1547
  "constraints": [],
917
- "example": "const picker = new ScenePicker({ camera, scene });",
1548
+ "example": "const picker = new ScenePicker({ camera: ctx.camera, scene: ctx.scene, pointer: () => ctx.input.raw.pointer, viewport: ctx.viewport });",
918
1549
  "importPath": "@threenative/core",
919
1550
  "kind": "class",
920
1551
  "overrides": [],
@@ -929,6 +1560,7 @@
929
1560
  "symbol": "ScenePicker"
930
1561
  },
931
1562
  {
1563
+ "aliases": ["tower defense game", "spawn waves"],
932
1564
  "constraints": [
933
1565
  "dispose returned handles when the owning scene exits",
934
1566
  "ease receives progress in the range 0 to 1 and its return value is the interpolation factor"
@@ -949,6 +1581,33 @@
949
1581
  "symbol": "Scheduler"
950
1582
  },
951
1583
  {
1584
+ "aliases": [],
1585
+ "constraints": [
1586
+ "use strideRoot to name the body moved by game code when the rig is parented under it",
1587
+ "requiredClips fails closed at load time if any requested clip is missing or binds 0 tracks"
1588
+ ],
1589
+ "example": "import { SkeletalMesh3D } from \"@threenative/core\";\nconst character = new SkeletalMesh3D({\n source: gltf.scene, clips: gltf.animations, requiredClips: [\"idle\", \"walk\"],\n size: { metres: 1.8, axis: \"height\" }, strideRoot: body,\n});\nbody.add(character.root); character.play(\"idle\");\nfunction update(dt: number): void { character.update(dt); }",
1590
+ "importPath": "@threenative/core",
1591
+ "kind": "class",
1592
+ "overrides": [
1593
+ "strideSync controls whether locomotion playback rate matches ground covered",
1594
+ "size normalises the instance to real-world metres with skin-aware measurement"
1595
+ ],
1596
+ "package": "@threenative/core",
1597
+ "signature": "export class SkeletalMesh3D extends AnimationPlayer { … }",
1598
+ "situations": [
1599
+ "put an animated character in the scene",
1600
+ "my imported character renders deformed",
1601
+ "instance an imported rigged character",
1602
+ "validate animation clips on a character rig at load time",
1603
+ "prepare a skinned character with safe skeleton cloning and stride sync"
1604
+ ],
1605
+ "summary": "Shared preparation for an imported rigged character. Instances the rig with a skeleton-safe clone, normalises size with skin-aware measurement, validates requested clips against the file and rig at load time, and sets up AnimationPlayer with honest stride-root accounting.",
1606
+ "supersedes": [],
1607
+ "symbol": "SkeletalMesh3D"
1608
+ },
1609
+ {
1610
+ "aliases": [],
952
1611
  "constraints": [],
953
1612
  "example": "import { skeletonBones } from \"@threenative/core\";\nconst bones = skeletonBones(character);",
954
1613
  "importPath": "@threenative/core",
@@ -965,6 +1624,7 @@
965
1624
  "symbol": "skeletonBones"
966
1625
  },
967
1626
  {
1627
+ "aliases": [],
968
1628
  "constraints": [
969
1629
  "the mesh must use one Three.js node material and contain complete triangles",
970
1630
  "pinned, stiffness, damping, gravity, and wind are required game-owned inputs",
@@ -990,6 +1650,7 @@
990
1650
  "symbol": "SoftBody3D"
991
1651
  },
992
1652
  {
1653
+ "aliases": [],
993
1654
  "constraints": [
994
1655
  "canvas-painted images sample black under WebGPURenderer; write sprites as pixel data there"
995
1656
  ],
@@ -1008,6 +1669,7 @@
1008
1669
  "symbol": "softCircleDataTexture"
1009
1670
  },
1010
1671
  {
1672
+ "aliases": [],
1011
1673
  "constraints": [
1012
1674
  "dates are interpreted as UTC unless utcOffset is supplied; no fixed sun direction is assumed",
1013
1675
  "pass a mutable { azimuth, elevation } target to reuse the result object in a steady frame loop"
@@ -1018,12 +1680,16 @@
1018
1680
  "overrides": [],
1019
1681
  "package": "@threenative/core",
1020
1682
  "signature": "export function solarPosition(input: ISolarPositionInput, target?: ISolarPosition): ISolarPosition;",
1021
- "situations": ["move a sun across a real day at a game's latitude and longitude"],
1683
+ "situations": [
1684
+ "move a sun across a real day at a game's latitude and longitude",
1685
+ "run a day and night cycle over the game's sky"
1686
+ ],
1022
1687
  "summary": "Calculate solar elevation and azimuth from time, latitude, and longitude.",
1023
1688
  "supersedes": [],
1024
1689
  "symbol": "solarPosition"
1025
1690
  },
1026
1691
  {
1692
+ "aliases": [],
1027
1693
  "constraints": [
1028
1694
  "dates are interpreted as UTC; use solarPosition for an explicit local offset"
1029
1695
  ],
@@ -1039,6 +1705,7 @@
1039
1705
  "symbol": "solarPositionAt"
1040
1706
  },
1041
1707
  {
1708
+ "aliases": [],
1042
1709
  "constraints": [
1043
1710
  "it draws nothing; the game supplies the mesh, the material and every colour",
1044
1711
  "CPU height is a throttled copy carrying staleFrames, never this frame and never exact",
@@ -1062,6 +1729,7 @@
1062
1729
  "symbol": "SpectralOcean"
1063
1730
  },
1064
1731
  {
1732
+ "aliases": [],
1065
1733
  "constraints": [
1066
1734
  "the game supplies the atlas texture, surface, filtering, layout, and every frame duration",
1067
1735
  "update is driven by the scene fixed step; no wall clock or default frame rate is used"
@@ -1081,6 +1749,7 @@
1081
1749
  "symbol": "SpriteAnimator3D"
1082
1750
  },
1083
1751
  {
1752
+ "aliases": [],
1084
1753
  "constraints": [
1085
1754
  "the surface comes from the game; pooling, travel, and fading belong to the engine",
1086
1755
  "update once per frame and dispose with the owning scene"
@@ -1100,6 +1769,7 @@
1100
1769
  "symbol": "TracerPool3D"
1101
1770
  },
1102
1771
  {
1772
+ "aliases": [],
1103
1773
  "constraints": ["patches cannot introduce omitted, negative, or non-finite physical values"],
1104
1774
  "example": "atmosphere.setAtmosphere({ rayleigh: [0.008, 0.016, 0.04] });",
1105
1775
  "importPath": "@threenative/core",
@@ -1113,6 +1783,7 @@
1113
1783
  "symbol": "updateAtmosphereParameters"
1114
1784
  },
1115
1785
  {
1786
+ "aliases": [],
1116
1787
  "constraints": [],
1117
1788
  "example": "updateClusteredMeshes(stagedRoot, myCamera, ctx.renderer.domElement.height);",
1118
1789
  "importPath": "@threenative/core",
@@ -1126,6 +1797,7 @@
1126
1797
  "symbol": "updateClusteredMeshes"
1127
1798
  },
1128
1799
  {
1800
+ "aliases": [],
1129
1801
  "constraints": [
1130
1802
  "call `VelocityTracker.update()` before the render and `commit()` after it",
1131
1803
  "a pass is only given a velocity target when a temporal stage consumes it"
@@ -1146,6 +1818,7 @@
1146
1818
  "symbol": "velocityTexture"
1147
1819
  },
1148
1820
  {
1821
+ "aliases": [],
1149
1822
  "constraints": [
1150
1823
  "call `VelocityTracker.update()` before the render and `commit()` after it",
1151
1824
  "a pass is only given a velocity target when a temporal stage consumes it",
@@ -1167,6 +1840,33 @@
1167
1840
  "symbol": "VelocityTracker"
1168
1841
  },
1169
1842
  {
1843
+ "aliases": [],
1844
+ "constraints": [
1845
+ "the light must be a DirectionalLight with `castShadow` and a target in the scene",
1846
+ "clipExtents are half-widths in world units, finest first, strictly increasing",
1847
+ "call `trackCaster(object)` for movers; it enables layer `VIRTUAL_SHADOW_MOVER_LAYER` on the object and its descendants, tracking or untracking refreshes cached levels once, and subsequent mover movement refreshes only when a window moves"
1848
+ ],
1849
+ "example": "const sun = new DirectionalLight(0xffffff, 3);\nsun.castShadow = true;\nsun.shadow.shadowNode = new VirtualShadowNode(sun, { clipExtents: [12, 40, 120] });",
1850
+ "importPath": "@threenative/core",
1851
+ "kind": "class",
1852
+ "overrides": [
1853
+ "bias, biasNode, normalBias, intensity, radius, blurSamples, mapType and filterNode stay on `light.shadow`; mapSize and the other options here have defaults, and `marker: false` silences the TN_VIRTUAL_SHADOW line, not the measurement",
1854
+ "bias, biasNode, normalBias, intensity, radius, blurSamples, mapType and filterNode stay on `light.shadow`; mapSize and the other options here have defaults"
1855
+ ],
1856
+ "package": "@threenative/core",
1857
+ "signature": "export class VirtualShadowNode extends ShadowBaseNode { … }",
1858
+ "situations": [
1859
+ "crisp shadows close to the player across a large outdoor level",
1860
+ "shadow map too coarse over a big terrain",
1861
+ "one directional light shadow for a whole open world",
1862
+ "shadows shimmer when the camera moves"
1863
+ ],
1864
+ "summary": "One directional shadow for a whole open world: camera-centred clip levels, each snapped to its own texel grid and re-rendered only when its window moves. Tracked casters draw into a per-level mover map every frame, so animated casters do not invalidate the cached levels after the one refresh caused by tracking or untracking them. Plugs into three's own `light.shadow.shadowNode` slot, so every material receives it.",
1865
+ "supersedes": [],
1866
+ "symbol": "VirtualShadowNode"
1867
+ },
1868
+ {
1869
+ "aliases": [],
1170
1870
  "constraints": [],
1171
1871
  "example": "await warmUpScene(renderer, scene, camera, { onProgress: (p) => setLoading(p) });",
1172
1872
  "importPath": "@threenative/core",
@@ -1183,6 +1883,32 @@
1183
1883
  "symbol": "warmUpScene"
1184
1884
  },
1185
1885
  {
1886
+ "aliases": [],
1887
+ "constraints": [
1888
+ "it draws nothing; the game supplies the mesh, the material and every colour",
1889
+ "the material must be transparent so the frame beneath it is already drawn",
1890
+ "thickness is metres, saturating at maxThickness; sky behind the surface reads deep",
1891
+ "one reflection is a second draw of the world, so resolutionScale is the whole cost",
1892
+ "the mirror plane is level, from level alone; do not parent target to a scaled mesh"
1893
+ ],
1894
+ "example": "const surface = new WaterSurface3D({ level: 0, maxThickness: 3, reflection: { resolutionScale: 0.5 } });\nmaterial.colorNode = mix(surface.refractionAt(offset), surface.reflectionAt(offset), fresnel);",
1895
+ "importPath": "@threenative/core",
1896
+ "kind": "class",
1897
+ "overrides": [],
1898
+ "package": "@threenative/core",
1899
+ "signature": "export class WaterSurface3D { … }",
1900
+ "situations": [
1901
+ "reflect the sky and the shoreline in a lake, pond or river",
1902
+ "see the bed through the water and have the shallows fade at the shore",
1903
+ "know how deep the water is under a pixel without a second render pass",
1904
+ "stop a water surface repeating in visible bands or stripes"
1905
+ ],
1906
+ "summary": "Give a horizontal water surface the world mirrored in it, the world beneath it, and the metres of water between them.",
1907
+ "supersedes": [],
1908
+ "symbol": "WaterSurface3D"
1909
+ },
1910
+ {
1911
+ "aliases": [],
1186
1912
  "constraints": [
1187
1913
  "supply every wave amplitude, wavelength, direction, speed and warp value",
1188
1914
  "call setTime for the default graph clock when the game advances its own time"
@@ -1203,6 +1929,7 @@
1203
1929
  "symbol": "WaveField"
1204
1930
  },
1205
1931
  {
1932
+ "aliases": [],
1206
1933
  "constraints": [
1207
1934
  "call `VelocityTracker.update()` before the render and `commit()` after it",
1208
1935
  "a pass is only given a velocity target when a temporal stage consumes it"
@@ -1223,6 +1950,7 @@
1223
1950
  "symbol": "withVelocityContext"
1224
1951
  },
1225
1952
  {
1953
+ "aliases": [],
1226
1954
  "constraints": [
1227
1955
  "use the returned value as a validation oracle; the rendered path samples the LUT"
1228
1956
  ],
@@ -1238,6 +1966,7 @@
1238
1966
  "symbol": "zenithTransmittance"
1239
1967
  },
1240
1968
  {
1969
+ "aliases": [],
1241
1970
  "constraints": ["use only in the web development entry"],
1242
1971
  "example": "acceptHotUpdate(game, import.meta.hot);",
1243
1972
  "importPath": "@threenative/core/hot",
@@ -1254,6 +1983,7 @@
1254
1983
  "symbol": "acceptHotUpdate"
1255
1984
  },
1256
1985
  {
1986
+ "aliases": [],
1257
1987
  "constraints": ["state must contain finite numbers and plain objects only"],
1258
1988
  "example": "assertPortableState(game.state.getState());",
1259
1989
  "importPath": "@threenative/core/hot",
@@ -1270,6 +2000,31 @@
1270
2000
  "symbol": "assertPortableState"
1271
2001
  },
1272
2002
  {
2003
+ "aliases": [],
2004
+ "constraints": [
2005
+ "the URL must use HTTPS and the credential is supplied by the game's identity flow; this API never issues credentials",
2006
+ "channels, message sizes, and queues are validated before WebTransport opens, and reliable overflow returns false",
2007
+ "native qualification depends on the installed host WebTransport bridge; iOS remains unverified"
2008
+ ],
2009
+ "example": "const connection = await connect(\"https://game.example/game\", { applicationProtocol: \"my-game/1\", credential, channels: [{ id: 1, delivery: \"unreliable\" }] });",
2010
+ "importPath": "@threenative/core/net",
2011
+ "kind": "function",
2012
+ "overrides": [
2013
+ "connectTimeoutMs, maxReliableMessageBytes, maxQueuedReliableBytes, and maxQueuedDatagrams are named per-connection limits"
2014
+ ],
2015
+ "package": "@threenative/core",
2016
+ "signature": "export function connect(url: string, options: INetworkOptions): Promise<INetworkConnection> { … }",
2017
+ "situations": [
2018
+ "connect two game clients over the portable WebTransport seam",
2019
+ "send ordered actions and bounded unreliable state messages between game clients",
2020
+ "exchange multiplayer messages without putting replication or gameplay in the engine"
2021
+ ],
2022
+ "summary": "Open a bounded, authenticated WebTransport message channel shared by browser and native games.",
2023
+ "supersedes": [],
2024
+ "symbol": "connect"
2025
+ },
2026
+ {
2027
+ "aliases": [],
1273
2028
  "constraints": ["install once in the game's plugin list"],
1274
2029
  "example": "const game = defineGame({ plugins: [playtest()] });",
1275
2030
  "importPath": "@threenative/core/playtest",
@@ -1286,6 +2041,7 @@
1286
2041
  "symbol": "playtest"
1287
2042
  },
1288
2043
  {
2044
+ "aliases": [],
1289
2045
  "constraints": [
1290
2046
  "styling is the `style` prop; Tailwind class names are CSS and cannot cross",
1291
2047
  "import `react`, never `react-dom`, from the portable native entry",
@@ -1308,6 +2064,7 @@
1308
2064
  "symbol": "createReactOverlay"
1309
2065
  },
1310
2066
  {
2067
+ "aliases": [],
1311
2068
  "constraints": [],
1312
2069
  "example": "const scoreWidth = measureText(\"SCORE 10\", 24)",
1313
2070
  "importPath": "@threenative/core/react",
@@ -1321,6 +2078,7 @@
1321
2078
  "symbol": "measureText"
1322
2079
  },
1323
2080
  {
2081
+ "aliases": [],
1324
2082
  "constraints": [],
1325
2083
  "example": "supportedGlyphs().includes(\"A\")",
1326
2084
  "importPath": "@threenative/core/react",
@@ -1334,6 +2092,7 @@
1334
2092
  "symbol": "supportedGlyphs"
1335
2093
  },
1336
2094
  {
2095
+ "aliases": [],
1337
2096
  "constraints": [],
1338
2097
  "example": "supportedStyleKeys().includes(\"centerX\")",
1339
2098
  "importPath": "@threenative/core/react",
@@ -1347,6 +2106,7 @@
1347
2106
  "symbol": "supportedStyleKeys"
1348
2107
  },
1349
2108
  {
2109
+ "aliases": ["objective panel journal"],
1350
2110
  "constraints": [],
1351
2111
  "example": "<Text style={{ color: \"#ffffff\", fontSize: 24 }}>SCORE 10</Text>",
1352
2112
  "importPath": "@threenative/core/react",
@@ -1360,8 +2120,9 @@
1360
2120
  "symbol": "Text"
1361
2121
  },
1362
2122
  {
2123
+ "aliases": [],
1363
2124
  "constraints": [],
1364
- "example": "<View style={{ centerX: 0, top: 24 }}><Text>READY</Text></View>",
2125
+ "example": "<View style={{ centerX: true, top: 24 }}><Text>READY</Text></View>",
1365
2126
  "importPath": "@threenative/core/react",
1366
2127
  "kind": "function",
1367
2128
  "overrides": [],
@@ -1373,6 +2134,7 @@
1373
2134
  "symbol": "View"
1374
2135
  },
1375
2136
  {
2137
+ "aliases": [],
1376
2138
  "constraints": ["the transport is discovered, never configured; no game names the web view"],
1377
2139
  "example": "const bridge = connectUiBridge({ end: \"ui\" });",
1378
2140
  "importPath": "@threenative/core/ui-layer",
@@ -1391,6 +2153,7 @@
1391
2153
  "symbol": "connectUiBridge"
1392
2154
  },
1393
2155
  {
2156
+ "aliases": [],
1394
2157
  "constraints": ["prefer game.ui.onIntent, which connects the bridge for you"],
1395
2158
  "example": "onUiIntent(bridge, (intent) => { if (intent === \"restart\") game.goto(\"Play\"); });",
1396
2159
  "importPath": "@threenative/core/ui-layer",
@@ -1408,6 +2171,7 @@
1408
2171
  "symbol": "onUiIntent"
1409
2172
  },
1410
2173
  {
2174
+ "aliases": [],
1411
2175
  "constraints": [
1412
2176
  "mark controls with data-tn-interactive; pointer-events is not the mechanism"
1413
2177
  ],
@@ -1428,6 +2192,7 @@
1428
2192
  "symbol": "publishHitRegions"
1429
2193
  },
1430
2194
  {
2195
+ "aliases": ["journal objective panel", "readable HUD"],
1431
2196
  "constraints": [
1432
2197
  "publishes at the store's throttled cadence, and not at all with no UI listening"
1433
2198
  ],
@@ -1448,6 +2213,7 @@
1448
2213
  "symbol": "publishUiState"
1449
2214
  },
1450
2215
  {
2216
+ "aliases": [],
1451
2217
  "constraints": ["one-way; the game decides what each name means and may ignore one"],
1452
2218
  "example": "sendUiIntent(bridge, \"restart\");",
1453
2219
  "importPath": "@threenative/core/ui-layer",
@@ -1466,6 +2232,7 @@
1466
2232
  "symbol": "sendUiIntent"
1467
2233
  },
1468
2234
  {
2235
+ "aliases": [],
1469
2236
  "constraints": ["returns undefined until the game publishes its first state"],
1470
2237
  "example": "const mirror = subscribeUiState(bridge);",
1471
2238
  "importPath": "@threenative/core/ui-layer",
@@ -1483,6 +2250,28 @@
1483
2250
  "symbol": "subscribeUiState"
1484
2251
  },
1485
2252
  {
2253
+ "aliases": [],
2254
+ "constraints": [
2255
+ "unsupported is returned when compute limits are unknown or below the requirement; callers must not silently continue"
2256
+ ],
2257
+ "example": "const capabilities = getWorldCapabilities({ limits: adapter.limits, cpuFallbackIterations: 8 });",
2258
+ "importPath": "@threenative/core/world",
2259
+ "kind": "function",
2260
+ "overrides": [
2261
+ "minimumWorkgroupsPerDimension, minimumStorageBufferBindingSize, and cpuFallbackIterations"
2262
+ ],
2263
+ "package": "@threenative/core",
2264
+ "signature": "export function getWorldCapabilities(options: IWorldCapabilitiesOptions = { … }",
2265
+ "situations": [
2266
+ "decide whether generated terrain can use GPU compute",
2267
+ "report why terrain generation is using a reduced CPU fallback"
2268
+ ],
2269
+ "summary": "Resolve the active world-generation path from host capability facts. The function accepts the adapter facts instead of reaching through a renderer-specific global, so browser and native hosts can report the same object. Missing limits are not treated as infinite: a host must either provide a valid GPU limit report or explicitly choose CPU fallback. GPU generation remains unavailable until a GPU readback can own the canonical field; a host adapter report therefore never upgrades a CPU fallback into a GPU generation claim.",
2270
+ "supersedes": [],
2271
+ "symbol": "getWorldCapabilities"
2272
+ },
2273
+ {
2274
+ "aliases": [],
1486
2275
  "constraints": [
1487
2276
  "sampleHeight owns the terrain shape and stays in game source; the framework stores and interpolates its output",
1488
2277
  "rows and columns are vertex counts; geometry is row-major z-then-x and collider export transposes once into Rapier's column-major matrix order"
@@ -1494,10 +2283,12 @@
1494
2283
  "rows, columns, width, depth, origin, and sampleHeight are explicit on every field"
1495
2284
  ],
1496
2285
  "package": "@threenative/core",
1497
- "signature": "export class Heightfield { … }",
2286
+ "signature": "export class Heightfield extends Group implements IComputeDriven { … }",
1498
2287
  "situations": [
1499
2288
  "build terrain geometry and collision from one game-authored height function",
2289
+ "generate a terrain a player can walk across",
1500
2290
  "query the same ground height or normal that a player sees and collides with",
2291
+ "ask how high the ground is here",
1501
2292
  "build islands and coastlines from terrain"
1502
2293
  ],
1503
2294
  "summary": "One height buffer shared by world queries, rendered geometry, and a physics heightfield. The game supplies every value, so changing the terrain's shape never requires a package edit. `fromSampler` evaluates that game function exactly once at each vertex and retains only the resulting numbers. Queries interpolate those same numbers instead of evaluating the function again.",
@@ -1505,8 +2296,32 @@
1505
2296
  "symbol": "Heightfield"
1506
2297
  },
1507
2298
  {
2299
+ "aliases": ["stream terrain across chunks"],
2300
+ "constraints": [
2301
+ "sampleHeight and surface are required game choices; no landform or surface preset is installed",
2302
+ "residentTileBudget and residentByteBudget are hard caps; a tile that cannot fit throws"
2303
+ ],
2304
+ "example": "const tiles = new TerrainTiles({ sampleHeight, surface: gameSurface(), tileSize: 256, tileResolution: 129, residentTileBudget: 25, residentByteBudget: 32_000_000 });",
2305
+ "importPath": "@threenative/core/world",
2306
+ "kind": "class",
2307
+ "overrides": [
2308
+ "tileSize, tileResolution, lodFactors, lodDistances, skirtDepth, streamRadius, and budgets"
2309
+ ],
2310
+ "package": "@threenative/core",
2311
+ "signature": "export class TerrainTiles extends Object3D implements IComputeDriven { … }",
2312
+ "situations": [
2313
+ "stream terrain without cracks",
2314
+ "keep generated terrain resident around a moving player",
2315
+ "put a generated terrain tile into a game-owned physics world"
2316
+ ],
2317
+ "summary": "Stream a bounded square of game-authored heightfields and keep their render and physics units together. The class composes ordinary THREE.LOD objects and leaves frustum/projection culling to the renderer's existing scene path.",
2318
+ "supersedes": [],
2319
+ "symbol": "TerrainTiles"
2320
+ },
2321
+ {
2322
+ "aliases": ["pick up item"],
1508
2323
  "constraints": ["add the area to the physics context before stepping the world"],
1509
- "example": "const area = new Area3D({ context, shape });",
2324
+ "example": "const goal = new Area3D({ physics: ctx.physics, shape: CollisionShape3D.sphere(1.2), position: { x: 0, y: 0.5, z: -8 } });",
1510
2325
  "importPath": "@threenative/physics",
1511
2326
  "kind": "class",
1512
2327
  "overrides": [],
@@ -1521,6 +2336,27 @@
1521
2336
  "symbol": "Area3D"
1522
2337
  },
1523
2338
  {
2339
+ "aliases": [],
2340
+ "constraints": [
2341
+ "supply the game-owned predicate for decorative meshes; the helper throws when it selects nothing",
2342
+ "generated bodies use trimesh geometry and world-space instance transforms"
2343
+ ],
2344
+ "example": "const colliders = buildStaticColliders(ctx, level, { predicate: (object) => object.name.startsWith(\"wall\") });",
2345
+ "importPath": "@threenative/physics",
2346
+ "kind": "function",
2347
+ "overrides": [],
2348
+ "package": "@threenative/physics",
2349
+ "signature": "export function buildStaticColliders( context: IStaticColliderContext, root: Object3D, filter?: StaticColliderFilter, ): readonly RigidBody3D[] { … }",
2350
+ "situations": [
2351
+ "make the level I built stop the player",
2352
+ "turn a cathedral or map scene into static collision"
2353
+ ],
2354
+ "summary": "Build fixed trimesh bodies from the meshes a game authored in a scene root.",
2355
+ "supersedes": [],
2356
+ "symbol": "buildStaticColliders"
2357
+ },
2358
+ {
2359
+ "aliases": [],
1524
2360
  "constraints": ["supply hull points, density, drag, and the height source"],
1525
2361
  "example": "new Buoyancy3D({ body, surface: field, hullPoints, density: 1_000, drag: 4 });",
1526
2362
  "importPath": "@threenative/physics",
@@ -1534,8 +2370,15 @@
1534
2370
  "symbol": "Buoyancy3D"
1535
2371
  },
1536
2372
  {
2373
+ "aliases": [
2374
+ "raised platform gap hazard restart",
2375
+ "enemy targets cooldown reload win condition",
2376
+ "platformer double jump",
2377
+ "first person",
2378
+ "run jump coins goal"
2379
+ ],
1537
2380
  "constraints": ["use moveAndSlide inside the physics update"],
1538
- "example": "const body = new CharacterBody3D({ context, object });",
2381
+ "example": "const body = new CharacterBody3D({ object: hero, physics: ctx.physics, shape: CollisionShape3D.capsule(0.5, 0.35) });",
1539
2382
  "importPath": "@threenative/physics",
1540
2383
  "kind": "class",
1541
2384
  "overrides": [],
@@ -1550,8 +2393,9 @@
1550
2393
  "symbol": "CharacterBody3D"
1551
2394
  },
1552
2395
  {
2396
+ "aliases": ["passes through body", "arena walls pickups"],
1553
2397
  "constraints": ["create shapes through the owning physics context"],
1554
- "example": "const shape = new CollisionShape3D({ context, shape: \"capsule\" });",
2398
+ "example": "const shape = CollisionShape3D.capsule(0.5, 0.35);",
1555
2399
  "importPath": "@threenative/physics",
1556
2400
  "kind": "class",
1557
2401
  "overrides": [],
@@ -1566,6 +2410,7 @@
1566
2410
  "symbol": "CollisionShape3D"
1567
2411
  },
1568
2412
  {
2413
+ "aliases": [],
1569
2414
  "constraints": [],
1570
2415
  "example": "const groups = interactionGroups(1, 3);",
1571
2416
  "importPath": "@threenative/physics",
@@ -1582,19 +2427,25 @@
1582
2427
  "symbol": "interactionGroups"
1583
2428
  },
1584
2429
  {
2430
+ "aliases": [],
1585
2431
  "constraints": ["both bodies must belong to the same physics context"],
1586
- "example": "const joint = new Joint3D({ context, kind: \"hinge\" });",
2432
+ "example": "const hinge = Joint3D.hinge({ physics: ctx.physics, bodyA: beam, bodyB: bob, anchorA: { x: 0, y: 0, z: 0 }, anchorB: { x: 0, y: 2.4, z: 0 }, axis: { x: 1, y: 0, z: 0 } });",
1587
2433
  "importPath": "@threenative/physics",
1588
2434
  "kind": "class",
1589
2435
  "overrides": [],
1590
2436
  "package": "@threenative/physics",
1591
2437
  "signature": "export class Joint3D { … }",
1592
- "situations": ["constrain a rigid body to another body", "build a hinge or pin mechanism"],
2438
+ "situations": [
2439
+ "constrain a rigid body to another body",
2440
+ "build a hinge or pin mechanism",
2441
+ "swing a pendulum, wrecking ball, or hinged door on a joint"
2442
+ ],
1593
2443
  "summary": "Connect two physics bodies with a Godot-style joint.",
1594
2444
  "supersedes": [],
1595
2445
  "symbol": "Joint3D"
1596
2446
  },
1597
2447
  {
2448
+ "aliases": ["hitscan camera"],
1598
2449
  "constraints": ["query results are bounded by the configured result limit"],
1599
2450
  "example": "const space = new PhysicsDirectSpaceState3D(context);",
1600
2451
  "importPath": "@threenative/physics",
@@ -1611,6 +2462,7 @@
1611
2462
  "symbol": "PhysicsDirectSpaceState3D"
1612
2463
  },
1613
2464
  {
2465
+ "aliases": [],
1614
2466
  "constraints": ["place rapier() before recast() in the plugin list"],
1615
2467
  "example": "const game = defineGame({ plugins: [rapier()] });",
1616
2468
  "importPath": "@threenative/physics",
@@ -1627,24 +2479,29 @@
1627
2479
  "symbol": "rapier"
1628
2480
  },
1629
2481
  {
2482
+ "aliases": [],
1630
2483
  "constraints": ["register rapier() in the game plugin list before using bodies"],
1631
- "example": "const crate = new RigidBody3D({ context, object, mode: \"dynamic\" });",
2484
+ "example": "const crate = new RigidBody3D({ object, physics: ctx.physics, shape: CollisionShape3D.box(1, 1, 1), mass: 8 });",
1632
2485
  "importPath": "@threenative/physics",
1633
2486
  "kind": "class",
1634
- "overrides": [],
2487
+ "overrides": [
2488
+ "continuousCollision: false opts one body out while body.continuousCollision still reports the effective setting"
2489
+ ],
1635
2490
  "package": "@threenative/physics",
1636
2491
  "signature": "export class RigidBody3D { … }",
1637
2492
  "situations": [
1638
2493
  "give a crate or prop physical motion",
1639
2494
  "create a body that collides with a character",
1640
2495
  "fire physical cannonballs that collide with ships or scenery",
1641
- "fire a cannonball projectile with cannon smoke particles"
2496
+ "fire a cannonball projectile with cannon smoke particles",
2497
+ "a bullet passes through a wall"
1642
2498
  ],
1643
2499
  "summary": "Simulate a dynamic or static rigid body.",
1644
2500
  "supersedes": [],
1645
2501
  "symbol": "RigidBody3D"
1646
2502
  },
1647
2503
  {
2504
+ "aliases": [],
1648
2505
  "constraints": [
1649
2506
  "every body must use CollisionShape3D.box and retain its Three.js object transform",
1650
2507
  "rotated boxes become conservative cloth-local axis-aligned bounds"
@@ -1664,6 +2521,7 @@
1664
2521
  "symbol": "softBodyCollision"
1665
2522
  },
1666
2523
  {
2524
+ "aliases": ["close engagement range"],
1667
2525
  "constraints": [
1668
2526
  "import NavigationAgent3D from exactly `@threenative/physics/navigation`; `@threenative/physics` is not a valid import for this symbol; use this capability instead of hand-written A*; requires recast() after rapier(), plus a baked NavigationRegion3D"
1669
2527
  ],
@@ -1687,6 +2545,7 @@
1687
2545
  "symbol": "NavigationAgent3D"
1688
2546
  },
1689
2547
  {
2548
+ "aliases": [],
1690
2549
  "constraints": ["create it after recast() and dispose it with the scene"],
1691
2550
  "example": "const obstacle = new NavigationObstacle3D({ navigation, object });",
1692
2551
  "importPath": "@threenative/physics/navigation",
@@ -1703,6 +2562,7 @@
1703
2562
  "symbol": "NavigationObstacle3D"
1704
2563
  },
1705
2564
  {
2565
+ "aliases": [],
1706
2566
  "constraints": ["bake before creating agents or obstacles"],
1707
2567
  "example": "const region = new NavigationRegion3D({ navigation, meshes: [floor] });",
1708
2568
  "importPath": "@threenative/physics/navigation",
@@ -1719,6 +2579,7 @@
1719
2579
  "symbol": "NavigationRegion3D"
1720
2580
  },
1721
2581
  {
2582
+ "aliases": [],
1722
2583
  "constraints": ["requires rapier() earlier in the plugins array"],
1723
2584
  "example": "const game = defineGame({ plugins: [rapier(), recast()] });",
1724
2585
  "importPath": "@threenative/physics/navigation",
@@ -1732,6 +2593,7 @@
1732
2593
  "symbol": "recast"
1733
2594
  },
1734
2595
  {
2596
+ "aliases": [],
1735
2597
  "constraints": [
1736
2598
  "bridge values must be JSON-shaped",
1737
2599
  "throws instead of silently dropping the offending field"
@@ -1752,6 +2614,7 @@
1752
2614
  "symbol": "assertJsonSafe"
1753
2615
  },
1754
2616
  {
2617
+ "aliases": [],
1755
2618
  "constraints": [
1756
2619
  "a reading the device does not expose reports unavailable, never zero",
1757
2620
  "a run that started hot or whose thermal status rose is flagged as confounded"
@@ -1771,6 +2634,7 @@
1771
2634
  "symbol": "DeviceMetricsError"
1772
2635
  },
1773
2636
  {
2637
+ "aliases": [],
1774
2638
  "constraints": [
1775
2639
  "a reading the device does not expose reports unavailable, never zero",
1776
2640
  "a run that started hot or whose thermal status rose is flagged as confounded"
@@ -1790,6 +2654,7 @@
1790
2654
  "symbol": "DeviceMetricsRecorder"
1791
2655
  },
1792
2656
  {
2657
+ "aliases": [],
1793
2658
  "constraints": ["malformed or empty assertions fail closed"],
1794
2659
  "example": "const result = evaluateRichPlaytestAssertions(input);",
1795
2660
  "importPath": "@threenative/playtest",
@@ -1806,6 +2671,7 @@
1806
2671
  "symbol": "evaluateRichPlaytestAssertions"
1807
2672
  },
1808
2673
  {
2674
+ "aliases": [],
1809
2675
  "constraints": ["unknown scenario keys fail closed"],
1810
2676
  "example": "const scenario = await loadPlaytestScenario(project, file);",
1811
2677
  "importPath": "@threenative/playtest",
@@ -1822,6 +2688,7 @@
1822
2688
  "symbol": "invalidScenario"
1823
2689
  },
1824
2690
  {
2691
+ "aliases": [],
1825
2692
  "constraints": ["bridge values must be JSON-shaped"],
1826
2693
  "example": "assertJsonSafe({ score: 10 });",
1827
2694
  "importPath": "@threenative/playtest",
@@ -1839,6 +2706,7 @@
1839
2706
  "symbol": "jsonByteLength"
1840
2707
  },
1841
2708
  {
2709
+ "aliases": [],
1842
2710
  "constraints": ["unknown scenario keys fail closed"],
1843
2711
  "example": "const scenario = await loadPlaytestScenario(project, file);",
1844
2712
  "importPath": "@threenative/playtest",
@@ -1855,6 +2723,7 @@
1855
2723
  "symbol": "loadPlaytestScenario"
1856
2724
  },
1857
2725
  {
2726
+ "aliases": [],
1858
2727
  "constraints": [],
1859
2728
  "example": "const missing = missingPlaytestCapabilities(required, available);",
1860
2729
  "importPath": "@threenative/playtest",
@@ -1871,6 +2740,7 @@
1871
2740
  "symbol": "missingPlaytestCapabilities"
1872
2741
  },
1873
2742
  {
2743
+ "aliases": [],
1874
2744
  "constraints": [
1875
2745
  "a reading the device does not expose reports unavailable, never zero",
1876
2746
  "a run that started hot or whose thermal status rose is flagged as confounded"
@@ -1890,6 +2760,7 @@
1890
2760
  "symbol": "parseDeviceBattery"
1891
2761
  },
1892
2762
  {
2763
+ "aliases": [],
1893
2764
  "constraints": [
1894
2765
  "a reading the device does not expose reports unavailable, never zero",
1895
2766
  "a run that started hot or whose thermal status rose is flagged as confounded"
@@ -1909,6 +2780,7 @@
1909
2780
  "symbol": "parseDeviceCurrent"
1910
2781
  },
1911
2782
  {
2783
+ "aliases": [],
1912
2784
  "constraints": [
1913
2785
  "a reading the device does not expose reports unavailable, never zero",
1914
2786
  "a run that started hot or whose thermal status rose is flagged as confounded"
@@ -1928,6 +2800,7 @@
1928
2800
  "symbol": "parseDevicePowerRails"
1929
2801
  },
1930
2802
  {
2803
+ "aliases": [],
1931
2804
  "constraints": [
1932
2805
  "a reading the device does not expose reports unavailable, never zero",
1933
2806
  "a run that started hot or whose thermal status rose is flagged as confounded"
@@ -1947,8 +2820,9 @@
1947
2820
  "symbol": "parseDeviceThermal"
1948
2821
  },
1949
2822
  {
2823
+ "aliases": [],
1950
2824
  "constraints": [],
1951
- "example": "playtestDiagnostic(\"physics\", \"body missing\");",
2825
+ "example": "playtestDiagnostic(\"TN_PLAYTEST_CAPABILITY_MISSING\", \"body missing\", \"register rapier() before adding bodies\");",
1952
2826
  "importPath": "@threenative/playtest",
1953
2827
  "kind": "function",
1954
2828
  "overrides": [],
@@ -1963,6 +2837,7 @@
1963
2837
  "symbol": "playtestDiagnostic"
1964
2838
  },
1965
2839
  {
2840
+ "aliases": [],
1966
2841
  "constraints": ["unknown scenario keys fail closed"],
1967
2842
  "example": "const scenario = await loadPlaytestScenario(project, file);",
1968
2843
  "importPath": "@threenative/playtest",
@@ -1979,6 +2854,7 @@
1979
2854
  "symbol": "PlaytestScenarioError"
1980
2855
  },
1981
2856
  {
2857
+ "aliases": [],
1982
2858
  "constraints": ["unknown scenario keys fail closed"],
1983
2859
  "example": "const scenario = await loadPlaytestScenario(project, file);",
1984
2860
  "importPath": "@threenative/playtest",
@@ -1995,6 +2871,7 @@
1995
2871
  "symbol": "playtestStepHoldTicks"
1996
2872
  },
1997
2873
  {
2874
+ "aliases": [],
1998
2875
  "constraints": ["unknown scenario keys fail closed"],
1999
2876
  "example": "const scenario = await loadPlaytestScenario(project, file);",
2000
2877
  "importPath": "@threenative/playtest",
@@ -2011,6 +2888,7 @@
2011
2888
  "symbol": "playtestStepWaitTicks"
2012
2889
  },
2013
2890
  {
2891
+ "aliases": [],
2014
2892
  "constraints": ["unknown scenario keys fail closed"],
2015
2893
  "example": "const scenario = await loadPlaytestScenario(project, file);",
2016
2894
  "importPath": "@threenative/playtest",
@@ -2027,13 +2905,14 @@
2027
2905
  "symbol": "rejectUnknownKeys"
2028
2906
  },
2029
2907
  {
2908
+ "aliases": [],
2030
2909
  "constraints": ["malformed or empty assertions fail closed"],
2031
2910
  "example": "const result = evaluateRichPlaytestAssertions(input);",
2032
2911
  "importPath": "@threenative/playtest",
2033
2912
  "kind": "function",
2034
2913
  "overrides": [],
2035
2914
  "package": "@threenative/playtest",
2036
- "signature": "export function requiredPlaytestCapabilities(scenario: IPlaytestScenario): PlaytestCapability[] { … }",
2915
+ "signature": "export function requiredPlaytestCapabilities( scenario: IPlaytestScenario, target?: string, ): PlaytestCapability[] { … }",
2037
2916
  "situations": [
2038
2917
  "assert movement, visibility, or diagnostics in a playtest",
2039
2918
  "turn a scenario observation into a pass or failure"
@@ -2043,19 +2922,21 @@
2043
2922
  "symbol": "requiredPlaytestCapabilities"
2044
2923
  },
2045
2924
  {
2925
+ "aliases": [],
2046
2926
  "constraints": ["absent policy fields default to rejecting errors"],
2047
2927
  "example": "const policy = resolveDiagnosticsPolicy(scenario.assert?.diagnostics);",
2048
2928
  "importPath": "@threenative/playtest",
2049
2929
  "kind": "function",
2050
2930
  "overrides": [],
2051
2931
  "package": "@threenative/playtest",
2052
- "signature": "export function resolveDiagnosticsPolicy( policy: IPlaytestDiagnosticsAssertion | undefined, ): IPlaytestDiagnosticsPolicy { … }",
2932
+ "signature": "export function resolveDiagnosticsPolicy( policy: IPlaytestDiagnosticsAssertion | undefined, target?: string, ): IPlaytestDiagnosticsPolicy { … }",
2053
2933
  "situations": ["judge captured console, network, or runtime diagnostics for a playtest"],
2054
2934
  "summary": "Resolve the effective diagnostics policy for a run, with fail-closed defaults applied.",
2055
2935
  "supersedes": [],
2056
2936
  "symbol": "resolveDiagnosticsPolicy"
2057
2937
  },
2058
2938
  {
2939
+ "aliases": [],
2059
2940
  "constraints": [
2060
2941
  "a reading the device does not expose reports unavailable, never zero",
2061
2942
  "a run that started hot or whose thermal status rose is flagged as confounded"
@@ -2075,6 +2956,7 @@
2075
2956
  "symbol": "summarizeDeviceMetrics"
2076
2957
  },
2077
2958
  {
2959
+ "aliases": [],
2078
2960
  "constraints": [],
2079
2961
  "example": "const missing = missingPlaytestCapabilities(required, available);",
2080
2962
  "importPath": "@threenative/playtest",
@@ -2091,6 +2973,7 @@
2091
2973
  "symbol": "unknownPlaytestCapabilities"
2092
2974
  },
2093
2975
  {
2976
+ "aliases": [],
2094
2977
  "constraints": ["the assertion throws instead of returning a false pass"],
2095
2978
  "example": "assertCaptureNotBlank(png, \"first frame\");",
2096
2979
  "importPath": "@threenative/playtest/capture",
@@ -2107,6 +2990,7 @@
2107
2990
  "symbol": "assertCaptureNotBlank"
2108
2991
  },
2109
2992
  {
2993
+ "aliases": [],
2110
2994
  "constraints": [],
2111
2995
  "example": "throw new CaptureGuardError(\"menu\", \"no bright pixels\");",
2112
2996
  "importPath": "@threenative/playtest/capture",
@@ -2123,6 +3007,7 @@
2123
3007
  "symbol": "CaptureGuardError"
2124
3008
  },
2125
3009
  {
3010
+ "aliases": [],
2126
3011
  "constraints": [],
2127
3012
  "example": "const stats = inspectFrame(png);",
2128
3013
  "importPath": "@threenative/playtest/capture",
@@ -2139,6 +3024,7 @@
2139
3024
  "symbol": "inspectFrame"
2140
3025
  },
2141
3026
  {
3027
+ "aliases": [],
2142
3028
  "constraints": ["throws instead of silently dropping the offending field"],
2143
3029
  "example": "assertJsonSafe(snapshot, \"$.components\");",
2144
3030
  "importPath": "@threenative/playtest/protocol",
@@ -2154,6 +3040,7 @@
2154
3040
  "symbol": "assertJsonSafe"
2155
3041
  },
2156
3042
  {
3043
+ "aliases": [],
2157
3044
  "constraints": [],
2158
3045
  "example": "const bytes = jsonByteLength(observation);",
2159
3046
  "importPath": "@threenative/playtest/protocol",
@@ -2169,6 +3056,7 @@
2169
3056
  "symbol": "jsonByteLength"
2170
3057
  },
2171
3058
  {
3059
+ "aliases": [],
2172
3060
  "constraints": ["Android evidence must name its target and transport"],
2173
3061
  "example": "const adb = discoverAdb(process.env);",
2174
3062
  "importPath": "@threenative/playtest/runner",
@@ -2185,6 +3073,7 @@
2185
3073
  "symbol": "AdbAndroidDriver"
2186
3074
  },
2187
3075
  {
3076
+ "aliases": [],
2188
3077
  "constraints": ["missing observations and malformed assertions fail closed"],
2189
3078
  "example": "const report = await runStandalonePlaytest(options);",
2190
3079
  "importPath": "@threenative/playtest/runner",
@@ -2201,8 +3090,9 @@
2201
3090
  "symbol": "advanceFixedStep"
2202
3091
  },
2203
3092
  {
3093
+ "aliases": [],
2204
3094
  "constraints": ["the bridge must answer the handshake or the run fails"],
2205
- "example": "const bridge = await connectPlaytestBridge(page);",
3095
+ "example": "const bridge = await connectPlaytestBridge(page, scenario);",
2206
3096
  "importPath": "@threenative/playtest/runner",
2207
3097
  "kind": "function",
2208
3098
  "overrides": [],
@@ -2217,6 +3107,7 @@
2217
3107
  "symbol": "advanceTimeoutMs"
2218
3108
  },
2219
3109
  {
3110
+ "aliases": [],
2220
3111
  "constraints": ["paths stay inside the managed artifact directory"],
2221
3112
  "example": "const paths = deviceMailboxPaths(projectRoot);",
2222
3113
  "importPath": "@threenative/playtest/runner",
@@ -2233,6 +3124,7 @@
2233
3124
  "symbol": "androidMailboxPaths"
2234
3125
  },
2235
3126
  {
3127
+ "aliases": [],
2236
3128
  "constraints": ["Android evidence must name its target and transport"],
2237
3129
  "example": "const adb = discoverAdb(process.env);",
2238
3130
  "importPath": "@threenative/playtest/runner",
@@ -2249,6 +3141,7 @@
2249
3141
  "symbol": "androidTouchBatches"
2250
3142
  },
2251
3143
  {
3144
+ "aliases": [],
2252
3145
  "constraints": ["missing observations and malformed assertions fail closed"],
2253
3146
  "example": "const report = await runStandalonePlaytest(options);",
2254
3147
  "importPath": "@threenative/playtest/runner",
@@ -2265,6 +3158,7 @@
2265
3158
  "symbol": "batchArtifactDirectory"
2266
3159
  },
2267
3160
  {
3161
+ "aliases": [],
2268
3162
  "constraints": ["missing observations and malformed assertions fail closed"],
2269
3163
  "example": "const report = await runStandalonePlaytest(options);",
2270
3164
  "importPath": "@threenative/playtest/runner",
@@ -2281,8 +3175,9 @@
2281
3175
  "symbol": "boundedTeardownStep"
2282
3176
  },
2283
3177
  {
3178
+ "aliases": [],
2284
3179
  "constraints": ["the bridge must answer the handshake or the run fails"],
2285
- "example": "const bridge = await connectPlaytestBridge(page);",
3180
+ "example": "const bridge = await connectPlaytestBridge(page, scenario);",
2286
3181
  "importPath": "@threenative/playtest/runner",
2287
3182
  "kind": "function",
2288
3183
  "overrides": [],
@@ -2297,6 +3192,7 @@
2297
3192
  "symbol": "bridgeWaitTimeoutMs"
2298
3193
  },
2299
3194
  {
3195
+ "aliases": [],
2300
3196
  "constraints": ["missing observations and malformed assertions fail closed"],
2301
3197
  "example": "const report = await runStandalonePlaytest(options);",
2302
3198
  "importPath": "@threenative/playtest/runner",
@@ -2313,6 +3209,7 @@
2313
3209
  "symbol": "buildReport"
2314
3210
  },
2315
3211
  {
3212
+ "aliases": [],
2316
3213
  "constraints": ["missing observations and malformed assertions fail closed"],
2317
3214
  "example": "const report = await runStandalonePlaytest(options);",
2318
3215
  "importPath": "@threenative/playtest/runner",
@@ -2329,8 +3226,9 @@
2329
3226
  "symbol": "captureVisualSurface"
2330
3227
  },
2331
3228
  {
3229
+ "aliases": [],
2332
3230
  "constraints": ["the bridge must answer the handshake or the run fails"],
2333
- "example": "const bridge = await connectPlaytestBridge(page);",
3231
+ "example": "const bridge = await connectPlaytestBridge(page, scenario);",
2334
3232
  "importPath": "@threenative/playtest/runner",
2335
3233
  "kind": "function",
2336
3234
  "overrides": [],
@@ -2345,13 +3243,14 @@
2345
3243
  "symbol": "connectPlaytestBridge"
2346
3244
  },
2347
3245
  {
3246
+ "aliases": [],
2348
3247
  "constraints": ["the bridge must answer the handshake or the run fails"],
2349
- "example": "const bridge = await connectPlaytestBridge(page);",
3248
+ "example": "const bridge = await connectPlaytestBridge(page, scenario);",
2350
3249
  "importPath": "@threenative/playtest/runner",
2351
3250
  "kind": "function",
2352
3251
  "overrides": [],
2353
3252
  "package": "@threenative/playtest",
2354
- "signature": "export async function connectPlaytestBridgeTransport( transport: IBridgeTransport, scenario: IPlaytestScenario, timeoutMs: number = bridgeWaitTimeoutMs(), ): Promise<IPlaytestBridgeClient | undefined> { … }",
3253
+ "signature": "export async function connectPlaytestBridgeTransport( transport: IBridgeTransport, scenario: IPlaytestScenario, timeoutMs: number = bridgeWaitTimeoutMs(), target?: string, ): Promise<IPlaytestBridgeClient | undefined> { … }",
2355
3254
  "situations": [
2356
3255
  "run a browser scenario against a game",
2357
3256
  "inspect bridge diagnostics from a runner"
@@ -2361,6 +3260,7 @@
2361
3260
  "symbol": "connectPlaytestBridgeTransport"
2362
3261
  },
2363
3262
  {
3263
+ "aliases": [],
2364
3264
  "constraints": ["the mailbox lifecycle must be disposed after the run"],
2365
3265
  "example": "const driver = new DesktopPlaytestDriver(options);",
2366
3266
  "importPath": "@threenative/playtest/runner",
@@ -2377,6 +3277,7 @@
2377
3277
  "symbol": "DesktopPlaytestDriver"
2378
3278
  },
2379
3279
  {
3280
+ "aliases": [],
2380
3281
  "constraints": ["paths stay inside the managed artifact directory"],
2381
3282
  "example": "const paths = deviceMailboxPaths(projectRoot);",
2382
3283
  "importPath": "@threenative/playtest/runner",
@@ -2393,6 +3294,7 @@
2393
3294
  "symbol": "DeviceBridgeTransport"
2394
3295
  },
2395
3296
  {
3297
+ "aliases": [],
2396
3298
  "constraints": ["paths stay inside the managed artifact directory"],
2397
3299
  "example": "const paths = deviceMailboxPaths(projectRoot);",
2398
3300
  "importPath": "@threenative/playtest/runner",
@@ -2409,6 +3311,7 @@
2409
3311
  "symbol": "deviceMailboxPaths"
2410
3312
  },
2411
3313
  {
3314
+ "aliases": [],
2412
3315
  "constraints": ["paths stay inside the managed artifact directory"],
2413
3316
  "example": "const paths = deviceMailboxPaths(projectRoot);",
2414
3317
  "importPath": "@threenative/playtest/runner",
@@ -2425,6 +3328,7 @@
2425
3328
  "symbol": "DeviceMailboxTransport"
2426
3329
  },
2427
3330
  {
3331
+ "aliases": [],
2428
3332
  "constraints": ["paths stay inside the managed artifact directory"],
2429
3333
  "example": "const paths = deviceMailboxPaths(projectRoot);",
2430
3334
  "importPath": "@threenative/playtest/runner",
@@ -2441,6 +3345,7 @@
2441
3345
  "symbol": "deviceTimeoutDiagnostic"
2442
3346
  },
2443
3347
  {
3348
+ "aliases": [],
2444
3349
  "constraints": ["Android evidence must name its target and transport"],
2445
3350
  "example": "const adb = discoverAdb(process.env);",
2446
3351
  "importPath": "@threenative/playtest/runner",
@@ -2457,6 +3362,7 @@
2457
3362
  "symbol": "discoverAdb"
2458
3363
  },
2459
3364
  {
3365
+ "aliases": [],
2460
3366
  "constraints": ["missing observations and malformed assertions fail closed"],
2461
3367
  "example": "const report = await runStandalonePlaytest(options);",
2462
3368
  "importPath": "@threenative/playtest/runner",
@@ -2473,6 +3379,24 @@
2473
3379
  "symbol": "failedDiagnosticsAssertion"
2474
3380
  },
2475
3381
  {
3382
+ "aliases": [],
3383
+ "constraints": ["incomplete or malformed captures never become a successful empty report"],
3384
+ "example": "summarizePipelineCapture(parsePipelineCapture(captureText));",
3385
+ "importPath": "@threenative/playtest/runner",
3386
+ "kind": "function",
3387
+ "overrides": [],
3388
+ "package": "@threenative/playtest",
3389
+ "signature": "export function formatPipelineSummary(summary: IPipelineSummary): string { … }",
3390
+ "situations": [
3391
+ "diagnose a slow shader-heavy launch from one browser or native capture",
3392
+ "reconcile pipeline creation counts and compile timing"
3393
+ ],
3394
+ "summary": "Parse and explain bounded shader-compilation captures.",
3395
+ "supersedes": [],
3396
+ "symbol": "formatPipelineSummary"
3397
+ },
3398
+ {
3399
+ "aliases": [],
2476
3400
  "constraints": ["invalid flags throw a named usage error"],
2477
3401
  "example": "const config = parseStandalonePlaytestArgs(argv);",
2478
3402
  "importPath": "@threenative/playtest/runner",
@@ -2489,6 +3413,7 @@
2489
3413
  "symbol": "formatUsage"
2490
3414
  },
2491
3415
  {
3416
+ "aliases": [],
2492
3417
  "constraints": ["missing observations and malformed assertions fail closed"],
2493
3418
  "example": "const report = await runStandalonePlaytest(options);",
2494
3419
  "importPath": "@threenative/playtest/runner",
@@ -2505,6 +3430,7 @@
2505
3430
  "symbol": "handlePlaytestSignal"
2506
3431
  },
2507
3432
  {
3433
+ "aliases": [],
2508
3434
  "constraints": ["generated scenarios must contain real assertions"],
2509
3435
  "example": "await initStandalonePlaytest(projectPath);",
2510
3436
  "importPath": "@threenative/playtest/runner",
@@ -2518,6 +3444,7 @@
2518
3444
  "symbol": "initStandalonePlaytest"
2519
3445
  },
2520
3446
  {
3447
+ "aliases": [],
2521
3448
  "constraints": ["missing observations and malformed assertions fail closed"],
2522
3449
  "example": "const report = await runStandalonePlaytest(options);",
2523
3450
  "importPath": "@threenative/playtest/runner",
@@ -2534,6 +3461,7 @@
2534
3461
  "symbol": "isRuntimeReadout"
2535
3462
  },
2536
3463
  {
3464
+ "aliases": [],
2537
3465
  "constraints": ["Android evidence must name its target and transport"],
2538
3466
  "example": "const adb = discoverAdb(process.env);",
2539
3467
  "importPath": "@threenative/playtest/runner",
@@ -2550,6 +3478,7 @@
2550
3478
  "symbol": "keyboardIsShown"
2551
3479
  },
2552
3480
  {
3481
+ "aliases": [],
2553
3482
  "constraints": ["the mailbox lifecycle must be disposed after the run"],
2554
3483
  "example": "const driver = new DesktopPlaytestDriver(options);",
2555
3484
  "importPath": "@threenative/playtest/runner",
@@ -2566,6 +3495,7 @@
2566
3495
  "symbol": "LocalDeviceMailbox"
2567
3496
  },
2568
3497
  {
3498
+ "aliases": [],
2569
3499
  "constraints": ["missing observations and malformed assertions fail closed"],
2570
3500
  "example": "const report = await runStandalonePlaytest(options);",
2571
3501
  "importPath": "@threenative/playtest/runner",
@@ -2582,6 +3512,7 @@
2582
3512
  "symbol": "ManagedServerError"
2583
3513
  },
2584
3514
  {
3515
+ "aliases": [],
2585
3516
  "constraints": ["missing observations and malformed assertions fail closed"],
2586
3517
  "example": "const report = await runStandalonePlaytest(options);",
2587
3518
  "importPath": "@threenative/playtest/runner",
@@ -2598,6 +3529,7 @@
2598
3529
  "symbol": "openPageAndConnectBridge"
2599
3530
  },
2600
3531
  {
3532
+ "aliases": [],
2601
3533
  "constraints": ["missing observations and malformed assertions fail closed"],
2602
3534
  "example": "const report = await runStandalonePlaytest(options);",
2603
3535
  "importPath": "@threenative/playtest/runner",
@@ -2614,6 +3546,7 @@
2614
3546
  "symbol": "pageLifecycleDiagnostic"
2615
3547
  },
2616
3548
  {
3549
+ "aliases": [],
2617
3550
  "constraints": ["Android evidence must name its target and transport"],
2618
3551
  "example": "const adb = discoverAdb(process.env);",
2619
3552
  "importPath": "@threenative/playtest/runner",
@@ -2630,6 +3563,24 @@
2630
3563
  "symbol": "parseAndroidConsole"
2631
3564
  },
2632
3565
  {
3566
+ "aliases": [],
3567
+ "constraints": ["Android evidence must name its target and transport"],
3568
+ "example": "const adb = discoverAdb(process.env);",
3569
+ "importPath": "@threenative/playtest/runner",
3570
+ "kind": "function",
3571
+ "overrides": [],
3572
+ "package": "@threenative/playtest",
3573
+ "signature": "export function parseAndroidTouchViewport(output: string): IAndroidTouchViewport { … }",
3574
+ "situations": [
3575
+ "run a scenario on an Android emulator or device",
3576
+ "parse Android console diagnostics"
3577
+ ],
3578
+ "summary": "Drive and inspect Android playtest transport.",
3579
+ "supersedes": [],
3580
+ "symbol": "parseAndroidTouchViewport"
3581
+ },
3582
+ {
3583
+ "aliases": [],
2633
3584
  "constraints": ["simulator evidence does not claim physical-device proof"],
2634
3585
  "example": "const driver = new XcrunIosDriver(options);",
2635
3586
  "importPath": "@threenative/playtest/runner",
@@ -2646,6 +3597,41 @@
2646
3597
  "symbol": "parseLaunchedPid"
2647
3598
  },
2648
3599
  {
3600
+ "aliases": [],
3601
+ "constraints": ["incomplete or malformed captures never become a successful empty report"],
3602
+ "example": "summarizePipelineCapture(parsePipelineCapture(captureText));",
3603
+ "importPath": "@threenative/playtest/runner",
3604
+ "kind": "function",
3605
+ "overrides": [],
3606
+ "package": "@threenative/playtest",
3607
+ "signature": "export function parsePipelineCapture(input: string | unknown): IPipelineCapture { … }",
3608
+ "situations": [
3609
+ "diagnose a slow shader-heavy launch from one browser or native capture",
3610
+ "reconcile pipeline creation counts and compile timing"
3611
+ ],
3612
+ "summary": "Parse and explain bounded shader-compilation captures.",
3613
+ "supersedes": [],
3614
+ "symbol": "parsePipelineCapture"
3615
+ },
3616
+ {
3617
+ "aliases": [],
3618
+ "constraints": ["incomplete or malformed captures never become a successful empty report"],
3619
+ "example": "summarizePipelineCapture(parsePipelineCapture(captureText));",
3620
+ "importPath": "@threenative/playtest/runner",
3621
+ "kind": "function",
3622
+ "overrides": [],
3623
+ "package": "@threenative/playtest",
3624
+ "signature": "export function parsePipelineEventMarkers(text: string): IPipelineCaptureEvent[] { … }",
3625
+ "situations": [
3626
+ "diagnose a slow shader-heavy launch from one browser or native capture",
3627
+ "reconcile pipeline creation counts and compile timing"
3628
+ ],
3629
+ "summary": "Parse and explain bounded shader-compilation captures.",
3630
+ "supersedes": [],
3631
+ "symbol": "parsePipelineEventMarkers"
3632
+ },
3633
+ {
3634
+ "aliases": [],
2649
3635
  "constraints": ["invalid flags throw a named usage error"],
2650
3636
  "example": "const config = parseStandalonePlaytestArgs(argv);",
2651
3637
  "importPath": "@threenative/playtest/runner",
@@ -2662,8 +3648,9 @@
2662
3648
  "symbol": "parseStandalonePlaytestArgs"
2663
3649
  },
2664
3650
  {
3651
+ "aliases": [],
2665
3652
  "constraints": ["the bridge must answer the handshake or the run fails"],
2666
- "example": "const bridge = await connectPlaytestBridge(page);",
3653
+ "example": "const bridge = await connectPlaytestBridge(page, scenario);",
2667
3654
  "importPath": "@threenative/playtest/runner",
2668
3655
  "kind": "class",
2669
3656
  "overrides": [],
@@ -2678,6 +3665,7 @@
2678
3665
  "symbol": "PlaytestBridgeError"
2679
3666
  },
2680
3667
  {
3668
+ "aliases": [],
2681
3669
  "constraints": ["invalid flags throw a named usage error"],
2682
3670
  "example": "const config = parseStandalonePlaytestArgs(argv);",
2683
3671
  "importPath": "@threenative/playtest/runner",
@@ -2694,6 +3682,7 @@
2694
3682
  "symbol": "PlaytestCliUsageError"
2695
3683
  },
2696
3684
  {
3685
+ "aliases": [],
2697
3686
  "constraints": ["missing observations and malformed assertions fail closed"],
2698
3687
  "example": "const report = await runStandalonePlaytest(options);",
2699
3688
  "importPath": "@threenative/playtest/runner",
@@ -2710,8 +3699,9 @@
2710
3699
  "symbol": "playtestStepDrivesMovement"
2711
3700
  },
2712
3701
  {
3702
+ "aliases": [],
2713
3703
  "constraints": ["the bridge must answer the handshake or the run fails"],
2714
- "example": "const bridge = await connectPlaytestBridge(page);",
3704
+ "example": "const bridge = await connectPlaytestBridge(page, scenario);",
2715
3705
  "importPath": "@threenative/playtest/runner",
2716
3706
  "kind": "class",
2717
3707
  "overrides": [],
@@ -2726,6 +3716,7 @@
2726
3716
  "symbol": "PlaywrightTransport"
2727
3717
  },
2728
3718
  {
3719
+ "aliases": [],
2729
3720
  "constraints": ["missing observations and malformed assertions fail closed"],
2730
3721
  "example": "const report = await runStandalonePlaytest(options);",
2731
3722
  "importPath": "@threenative/playtest/runner",
@@ -2742,6 +3733,7 @@
2742
3733
  "symbol": "preflightDisplay"
2743
3734
  },
2744
3735
  {
3736
+ "aliases": [],
2745
3737
  "constraints": ["inspect the adapter name before claiming GPU proof"],
2746
3738
  "example": "const args = resolveBrowserArguments(undefined);",
2747
3739
  "importPath": "@threenative/playtest/runner",
@@ -2758,6 +3750,7 @@
2758
3750
  "symbol": "reconcileBrowserPointers"
2759
3751
  },
2760
3752
  {
3753
+ "aliases": [],
2761
3754
  "constraints": ["an empty assertion set is a failure"],
2762
3755
  "example": "const scenario = recordToScenario(recording);",
2763
3756
  "importPath": "@threenative/playtest/runner",
@@ -2774,6 +3767,7 @@
2774
3767
  "symbol": "recordToScenario"
2775
3768
  },
2776
3769
  {
3770
+ "aliases": [],
2777
3771
  "constraints": ["an empty assertion set is a failure"],
2778
3772
  "example": "const scenario = recordToScenario(recording);",
2779
3773
  "importPath": "@threenative/playtest/runner",
@@ -2790,6 +3784,7 @@
2790
3784
  "symbol": "requireAssertions"
2791
3785
  },
2792
3786
  {
3787
+ "aliases": [],
2793
3788
  "constraints": ["inspect the adapter name before claiming GPU proof"],
2794
3789
  "example": "const args = resolveBrowserArguments(undefined);",
2795
3790
  "importPath": "@threenative/playtest/runner",
@@ -2806,6 +3801,7 @@
2806
3801
  "symbol": "resolveBrowserArguments"
2807
3802
  },
2808
3803
  {
3804
+ "aliases": [],
2809
3805
  "constraints": ["missing observations and malformed assertions fail closed"],
2810
3806
  "example": "const report = await runStandalonePlaytest(options);",
2811
3807
  "importPath": "@threenative/playtest/runner",
@@ -2822,6 +3818,7 @@
2822
3818
  "symbol": "resolveManagedServerCommand"
2823
3819
  },
2824
3820
  {
3821
+ "aliases": [],
2825
3822
  "constraints": ["missing observations and malformed assertions fail closed"],
2826
3823
  "example": "const report = await runStandalonePlaytest(options);",
2827
3824
  "importPath": "@threenative/playtest/runner",
@@ -2838,6 +3835,7 @@
2838
3835
  "symbol": "resolveManagedServerConfig"
2839
3836
  },
2840
3837
  {
3838
+ "aliases": [],
2841
3839
  "constraints": ["Android evidence must name its target and transport"],
2842
3840
  "example": "const adb = discoverAdb(process.env);",
2843
3841
  "importPath": "@threenative/playtest/runner",
@@ -2854,6 +3852,7 @@
2854
3852
  "symbol": "rotatedTouchPosition"
2855
3853
  },
2856
3854
  {
3855
+ "aliases": [],
2857
3856
  "constraints": ["the app bundle and device transport must be prepared"],
2858
3857
  "example": "await runAndroidPlaytest(options);",
2859
3858
  "importPath": "@threenative/playtest/runner",
@@ -2870,6 +3869,7 @@
2870
3869
  "symbol": "runAndroidPlaytest"
2871
3870
  },
2872
3871
  {
3872
+ "aliases": [],
2873
3873
  "constraints": ["the desktop host must be built before launching"],
2874
3874
  "example": "await runDesktopPlaytest(options);",
2875
3875
  "importPath": "@threenative/playtest/runner",
@@ -2886,6 +3886,7 @@
2886
3886
  "symbol": "runDesktopPlaytest"
2887
3887
  },
2888
3888
  {
3889
+ "aliases": [],
2889
3890
  "constraints": ["the app bundle and device transport must be prepared"],
2890
3891
  "example": "await runAndroidPlaytest(options);",
2891
3892
  "importPath": "@threenative/playtest/runner",
@@ -2902,6 +3903,7 @@
2902
3903
  "symbol": "runDevicePlaytest"
2903
3904
  },
2904
3905
  {
3906
+ "aliases": [],
2905
3907
  "constraints": ["identify simulator versus physical transport in evidence"],
2906
3908
  "example": "await runIosPlaytest(options);",
2907
3909
  "importPath": "@threenative/playtest/runner",
@@ -2915,6 +3917,7 @@
2915
3917
  "symbol": "runIosPlaytest"
2916
3918
  },
2917
3919
  {
3920
+ "aliases": [],
2918
3921
  "constraints": ["missing observations and malformed assertions fail closed"],
2919
3922
  "example": "const report = await runStandalonePlaytest(options);",
2920
3923
  "importPath": "@threenative/playtest/runner",
@@ -2931,6 +3934,7 @@
2931
3934
  "symbol": "runStandalonePlaytest"
2932
3935
  },
2933
3936
  {
3937
+ "aliases": [],
2934
3938
  "constraints": ["missing observations and malformed assertions fail closed"],
2935
3939
  "example": "const report = await runStandalonePlaytest(options);",
2936
3940
  "importPath": "@threenative/playtest/runner",
@@ -2947,6 +3951,7 @@
2947
3951
  "symbol": "runStandalonePlaytests"
2948
3952
  },
2949
3953
  {
3954
+ "aliases": [],
2950
3955
  "constraints": ["inspect the adapter name before claiming GPU proof"],
2951
3956
  "example": "const args = resolveBrowserArguments(undefined);",
2952
3957
  "importPath": "@threenative/playtest/runner",
@@ -2963,6 +3968,7 @@
2963
3968
  "symbol": "softwareAdapterName"
2964
3969
  },
2965
3970
  {
3971
+ "aliases": [],
2966
3972
  "constraints": ["missing observations and malformed assertions fail closed"],
2967
3973
  "example": "const report = await runStandalonePlaytest(options);",
2968
3974
  "importPath": "@threenative/playtest/runner",
@@ -2979,6 +3985,24 @@
2979
3985
  "symbol": "substituteManagedPort"
2980
3986
  },
2981
3987
  {
3988
+ "aliases": [],
3989
+ "constraints": ["incomplete or malformed captures never become a successful empty report"],
3990
+ "example": "summarizePipelineCapture(parsePipelineCapture(captureText));",
3991
+ "importPath": "@threenative/playtest/runner",
3992
+ "kind": "function",
3993
+ "overrides": [],
3994
+ "package": "@threenative/playtest",
3995
+ "signature": "export function summarizePipelineCapture(capture: IPipelineCapture): IPipelineSummary { … }",
3996
+ "situations": [
3997
+ "diagnose a slow shader-heavy launch from one browser or native capture",
3998
+ "reconcile pipeline creation counts and compile timing"
3999
+ ],
4000
+ "summary": "Parse and explain bounded shader-compilation captures.",
4001
+ "supersedes": [],
4002
+ "symbol": "summarizePipelineCapture"
4003
+ },
4004
+ {
4005
+ "aliases": [],
2982
4006
  "constraints": ["Android evidence must name its target and transport"],
2983
4007
  "example": "const adb = discoverAdb(process.env);",
2984
4008
  "importPath": "@threenative/playtest/runner",
@@ -2995,6 +4019,24 @@
2995
4019
  "symbol": "tapCommand"
2996
4020
  },
2997
4021
  {
4022
+ "aliases": [],
4023
+ "constraints": ["Android evidence must name its target and transport"],
4024
+ "example": "const adb = discoverAdb(process.env);",
4025
+ "importPath": "@threenative/playtest/runner",
4026
+ "kind": "function",
4027
+ "overrides": [],
4028
+ "package": "@threenative/playtest",
4029
+ "signature": "export function touchPositionForViewport( x: number, y: number, viewport: IAndroidTouchViewport, rotationOverride?: number, ): [number, number] { … }",
4030
+ "situations": [
4031
+ "run a scenario on an Android emulator or device",
4032
+ "parse Android console diagnostics"
4033
+ ],
4034
+ "summary": "Drive and inspect Android playtest transport.",
4035
+ "supersedes": [],
4036
+ "symbol": "touchPositionForViewport"
4037
+ },
4038
+ {
4039
+ "aliases": [],
2998
4040
  "constraints": ["Android evidence must name its target and transport"],
2999
4041
  "example": "const adb = discoverAdb(process.env);",
3000
4042
  "importPath": "@threenative/playtest/runner",
@@ -3011,6 +4053,7 @@
3011
4053
  "symbol": "touchRotationFromWindowDump"
3012
4054
  },
3013
4055
  {
4056
+ "aliases": [],
3014
4057
  "constraints": ["paths stay inside the managed artifact directory"],
3015
4058
  "example": "const paths = deviceMailboxPaths(projectRoot);",
3016
4059
  "importPath": "@threenative/playtest/runner",
@@ -3027,6 +4070,7 @@
3027
4070
  "symbol": "validateDeviceEndpoint"
3028
4071
  },
3029
4072
  {
4073
+ "aliases": [],
3030
4074
  "constraints": ["Android evidence must name its target and transport"],
3031
4075
  "example": "const adb = discoverAdb(process.env);",
3032
4076
  "importPath": "@threenative/playtest/runner",
@@ -3043,6 +4087,26 @@
3043
4087
  "symbol": "viewportPresentationCommands"
3044
4088
  },
3045
4089
  {
4090
+ "aliases": [],
4091
+ "constraints": ["Android evidence must name its target and transport"],
4092
+ "example": "const adb = discoverAdb(process.env);",
4093
+ "importPath": "@threenative/playtest/runner",
4094
+ "kind": "function",
4095
+ "overrides": [],
4096
+ "package": "@threenative/playtest",
4097
+ "signature": "export function viewportPresentationObserved( override: string | undefined, expected: string | undefined, physical: { … }",
4098
+ "situations": [
4099
+ "run a scenario on an Android emulator or device",
4100
+ "parse Android console diagnostics",
4101
+ "verify that an Android device presented the requested viewport",
4102
+ "accept the physical panel size when `wm size` omits its override line"
4103
+ ],
4104
+ "summary": "Drive and inspect Android playtest transport.",
4105
+ "supersedes": [],
4106
+ "symbol": "viewportPresentationObserved"
4107
+ },
4108
+ {
4109
+ "aliases": [],
3046
4110
  "constraints": ["Android evidence must name its target and transport"],
3047
4111
  "example": "const adb = discoverAdb(process.env);",
3048
4112
  "importPath": "@threenative/playtest/runner",
@@ -3059,6 +4123,7 @@
3059
4123
  "symbol": "viewportRestoreCommands"
3060
4124
  },
3061
4125
  {
4126
+ "aliases": [],
3062
4127
  "constraints": ["missing observations and malformed assertions fail closed"],
3063
4128
  "example": "const report = await runStandalonePlaytest(options);",
3064
4129
  "importPath": "@threenative/playtest/runner",
@@ -3075,6 +4140,7 @@
3075
4140
  "symbol": "writeCaptureProvenance"
3076
4141
  },
3077
4142
  {
4143
+ "aliases": [],
3078
4144
  "constraints": ["missing observations and malformed assertions fail closed"],
3079
4145
  "example": "const report = await runStandalonePlaytest(options);",
3080
4146
  "importPath": "@threenative/playtest/runner",
@@ -3091,6 +4157,7 @@
3091
4157
  "symbol": "writeObservationArtifacts"
3092
4158
  },
3093
4159
  {
4160
+ "aliases": [],
3094
4161
  "constraints": ["simulator evidence does not claim physical-device proof"],
3095
4162
  "example": "const driver = new XcrunIosDriver(options);",
3096
4163
  "importPath": "@threenative/playtest/runner",
@@ -3107,6 +4174,7 @@
3107
4174
  "symbol": "XcrunIosDriver"
3108
4175
  },
3109
4176
  {
4177
+ "aliases": [],
3110
4178
  "constraints": ["use measured input rather than visual guesses"],
3111
4179
  "example": "const advice = adviseThreeRenderWorkload(input);",
3112
4180
  "importPath": "@threenative/playtest/three",
@@ -3123,8 +4191,9 @@
3123
4191
  "symbol": "adviseThreeRenderWorkload"
3124
4192
  },
3125
4193
  {
4194
+ "aliases": [],
3126
4195
  "constraints": ["use the device transport selected by the runner"],
3127
- "example": "const connection = await connectDevicePlaytestBridge();",
4196
+ "example": "const connection = connectDevicePlaytestBridge(bridge, endpoint);",
3128
4197
  "importPath": "@threenative/playtest/three",
3129
4198
  "kind": "function",
3130
4199
  "overrides": [],
@@ -3139,6 +4208,7 @@
3139
4208
  "symbol": "connectDevicePlaytestBridge"
3140
4209
  },
3141
4210
  {
4211
+ "aliases": [],
3142
4212
  "constraints": ["install once before the runner connects"],
3143
4213
  "example": "const bridge = installThreePlaytestBridge(options);",
3144
4214
  "importPath": "@threenative/playtest/three",
@@ -3155,8 +4225,30 @@
3155
4225
  "symbol": "installThreePlaytestBridge"
3156
4226
  },
3157
4227
  {
4228
+ "aliases": [],
4229
+ "constraints": [
4230
+ "reports counts and names only; it decides nothing about how the game looks",
4231
+ "reports counts and names only; nothing here decides how the game looks",
4232
+ "a walk that hits {@link SCENE_WALK_OBJECT_CAP} reports `truncated: true`"
4233
+ ],
4234
+ "example": "const room = observeSceneResources(scene, camera);",
4235
+ "importPath": "@threenative/playtest/three",
4236
+ "kind": "function",
4237
+ "overrides": [],
4238
+ "package": "@threenative/playtest",
4239
+ "signature": "export function observeSceneResources(scene: Scene, camera: Camera): IPlaytestSceneObservation { … }",
4240
+ "situations": [
4241
+ "ask why a frame is black or washed out without opening a screenshot",
4242
+ "ask what lights, materials and framing a running game actually has"
4243
+ ],
4244
+ "summary": "Observe the room a game is played in — lights, materials, fog, background and camera framing.",
4245
+ "supersedes": [],
4246
+ "symbol": "observeSceneResources"
4247
+ },
4248
+ {
4249
+ "aliases": [],
3158
4250
  "constraints": ["use the device transport selected by the runner"],
3159
- "example": "const connection = await connectDevicePlaytestBridge();",
4251
+ "example": "const connection = connectDevicePlaytestBridge(bridge, endpoint);",
3160
4252
  "importPath": "@threenative/playtest/three",
3161
4253
  "kind": "function",
3162
4254
  "overrides": [],
@@ -3171,8 +4263,9 @@
3171
4263
  "symbol": "readPlaytestEndpoint"
3172
4264
  },
3173
4265
  {
4266
+ "aliases": [],
3174
4267
  "constraints": ["keep recorder limits within the documented caps"],
3175
- "example": "const physics = new ThreePlaytestPhysicsRecorder();",
4268
+ "example": "const physics = new ThreePlaytestPhysicsRecorder(worldPhysics);",
3176
4269
  "importPath": "@threenative/playtest/three",
3177
4270
  "kind": "class",
3178
4271
  "overrides": [],
@@ -3187,53 +4280,581 @@
3187
4280
  "symbol": "ThreePlaytestPhysicsRecorder"
3188
4281
  },
3189
4282
  {
4283
+ "aliases": [],
3190
4284
  "constraints": [
3191
- "Use the running WebGPU renderer and keep appearance choices in template render source."
4285
+ "materials are never chosen here; the geometry carries groups, the game carries materials"
3192
4286
  ],
3193
- "example": "gradualBackground(...)",
3194
- "importPath": "@threenative/template/starter/src/render/effects/gradualBackground",
4287
+ "example": "const geometry = createThreeGeometry(parseUAssetStaticMesh(buffer));",
4288
+ "importPath": "@threenative/raw-unreal",
3195
4289
  "kind": "function",
3196
4290
  "overrides": [],
3197
- "package": "template:starter",
3198
- "signature": "function gradualBackground",
3199
- "situations": ["grade a background by distance"],
4291
+ "package": "@threenative/raw-unreal",
4292
+ "requires": ["npm i @threenative/raw-unreal"],
4293
+ "signature": "export function createThreeGeometry(decoded: IDecodedUAssetStaticMesh): BufferGeometry { … }",
4294
+ "situations": [
4295
+ "build custom scene objects from Unreal mesh data instead of a whole mesh",
4296
+ "hand a decoded Unreal mesh to a framework pipeline that owns materials itself"
4297
+ ],
4298
+ "summary": "Converts a decoded `.uasset` static mesh into a `THREE.BufferGeometry`, with one draw group per material section.",
3200
4299
  "supersedes": [],
3201
- "summary": "ThreeNative equivalent for realism-effects gradualBackground.",
3202
- "symbol": "gradualBackground"
4300
+ "symbol": "createThreeGeometry"
3203
4301
  },
3204
4302
  {
4303
+ "aliases": [],
3205
4304
  "constraints": [
3206
- "Use the running WebGPU renderer and keep appearance choices in template render source."
4305
+ "the fallback is three.js's own plain MeshStandardMaterial; every real material comes from the game"
3207
4306
  ],
3208
- "example": "lensDistortion(...)",
3209
- "importPath": "@threenative/template/starter/src/render/effects/lensDistortion",
4307
+ "example": "const mesh = createThreeObject(decoded, { materialFactory: (d) => d.sections.map(() => barkMaterial) });",
4308
+ "importPath": "@threenative/raw-unreal",
3210
4309
  "kind": "function",
3211
4310
  "overrides": [],
3212
- "package": "template:starter",
3213
- "signature": "function lensDistortion",
3214
- "situations": ["warp the image with radial lens distortion"],
4311
+ "package": "@threenative/raw-unreal",
4312
+ "requires": ["npm i @threenative/raw-unreal"],
4313
+ "signature": "export function createThreeObject( decoded: IDecodedUAssetStaticMesh, options: IThreeAdapterOptions = { … }",
4314
+ "situations": [
4315
+ "put a raw .uasset mesh on screen without converting it to glTF first",
4316
+ "key materials to a package's own sections by name or section index"
4317
+ ],
4318
+ "summary": "Converts a decoded `.uasset` static mesh into a renderable `THREE.Mesh` with provenance in `userData.unreal` and material selection left to the game's `materialFactory`.",
3215
4319
  "supersedes": [],
3216
- "summary": "ThreeNative equivalent for realism-effects lensDistortion.",
3217
- "symbol": "lensDistortion"
4320
+ "symbol": "createThreeObject"
3218
4321
  },
3219
4322
  {
4323
+ "aliases": [],
3220
4324
  "constraints": [
3221
- "Use the running WebGPU renderer and keep appearance choices in template render source."
4325
+ "zlib payloads require an injected `zlib` codec; the package never bundles one, and a missing codec throws MISSING_CODEC instead of guessing",
4326
+ "a payload written to a sibling file throws MISSING_BULK_DATA_FILE naming that file, rather than inventing geometry"
3222
4327
  ],
3223
- "example": "sparkle(...)",
3224
- "importPath": "@threenative/template/starter/src/render/effects/sparkle",
4328
+ "example": "const payload = resolveBulkDataPayload(bytes, header, { zlib });",
4329
+ "importPath": "@threenative/raw-unreal",
3225
4330
  "kind": "function",
3226
4331
  "overrides": [],
3227
- "package": "template:starter",
4332
+ "package": "@threenative/raw-unreal",
4333
+ "requires": ["npm i @threenative/raw-unreal"],
4334
+ "signature": "export function decompressBulkData( container: Uint8Array, codecs: { … }",
4335
+ "situations": [
4336
+ "read a UE4 editor static mesh whose source model lives in bulk data rather than inline",
4337
+ "decompress the zlib-chunked bulk payload a UE4.2x package stores its MeshDescription in"
4338
+ ],
4339
+ "summary": "Reads the `FByteBulkData` headers an editor package serializes into its export data, and resolves each payload — inline, at the end of the package, or in a sibling `.ubulk`/`.uptnl` file whose bytes the caller supplies — decompressing `FArchive::SerializeCompressed` blocks.",
4340
+ "supersedes": [],
4341
+ "symbol": "decompressBulkData"
4342
+ },
4343
+ {
4344
+ "aliases": [],
4345
+ "constraints": [
4346
+ "Oodle and LZ4 payloads require an injected codec; the package never bundles one, and a missing codec throws MISSING_CODEC instead of guessing"
4347
+ ],
4348
+ "example": "const payload = decompressCompressedBuffer(parseCompressedBuffer(bytes, offset), { oodle });",
4349
+ "importPath": "@threenative/raw-unreal",
4350
+ "kind": "function",
4351
+ "overrides": [],
4352
+ "package": "@threenative/raw-unreal",
4353
+ "requires": ["npm i @threenative/raw-unreal"],
4354
+ "signature": "export function decompressCompressedBuffer( buffer: ICompressedBuffer, codecs: IUAssetCodecs, ): Uint8Array { … }",
4355
+ "situations": ["decompress the package-trailer payload that carries a UE5 MeshDescription"],
4356
+ "summary": "Parses one UE5 `FCompressedBuffer` and decompresses it block-by-block with the codecs the caller injected — uncompressed payloads are handled natively.",
4357
+ "supersedes": [],
4358
+ "symbol": "decompressCompressedBuffer"
4359
+ },
4360
+ {
4361
+ "aliases": [],
4362
+ "constraints": [
4363
+ "zlib payloads require an injected `zlib` codec; the package never bundles one, and a missing codec throws MISSING_CODEC instead of guessing",
4364
+ "a payload written to a sibling file throws MISSING_BULK_DATA_FILE naming that file, rather than inventing geometry"
4365
+ ],
4366
+ "example": "const payload = resolveBulkDataPayload(bytes, header, { zlib });",
4367
+ "importPath": "@threenative/raw-unreal",
4368
+ "kind": "function",
4369
+ "overrides": [],
4370
+ "package": "@threenative/raw-unreal",
4371
+ "requires": ["npm i @threenative/raw-unreal"],
4372
+ "signature": "export function findBulkDataHeaders( bytes: Uint8Array, layout: IPackageLayout, files: IUAssetBulkDataFiles = { … }",
4373
+ "situations": [
4374
+ "read a UE4 editor static mesh whose source model lives in bulk data rather than inline",
4375
+ "decompress the zlib-chunked bulk payload a UE4.2x package stores its MeshDescription in"
4376
+ ],
4377
+ "summary": "Reads the `FByteBulkData` headers an editor package serializes into its export data, and resolves each payload — inline, at the end of the package, or in a sibling `.ubulk`/`.uptnl` file whose bytes the caller supplies — decompressing `FArchive::SerializeCompressed` blocks.",
4378
+ "supersedes": [],
4379
+ "symbol": "findBulkDataHeaders"
4380
+ },
4381
+ {
4382
+ "aliases": [],
4383
+ "constraints": [
4384
+ "Oodle and LZ4 payloads require an injected codec; the package never bundles one, and a missing codec throws MISSING_CODEC instead of guessing"
4385
+ ],
4386
+ "example": "const payload = decompressCompressedBuffer(parseCompressedBuffer(bytes, offset), { oodle });",
4387
+ "importPath": "@threenative/raw-unreal",
4388
+ "kind": "function",
4389
+ "overrides": [],
4390
+ "package": "@threenative/raw-unreal",
4391
+ "requires": ["npm i @threenative/raw-unreal"],
4392
+ "signature": "export function findCompressedBufferOffsets(bytes: Uint8Array): number[] { … }",
4393
+ "situations": ["decompress the package-trailer payload that carries a UE5 MeshDescription"],
4394
+ "summary": "Parses one UE5 `FCompressedBuffer` and decompresses it block-by-block with the codecs the caller injected — uncompressed payloads are handled natively.",
4395
+ "supersedes": [],
4396
+ "symbol": "findCompressedBufferOffsets"
4397
+ },
4398
+ {
4399
+ "aliases": [],
4400
+ "constraints": [
4401
+ "every count is validated against its neighbors before any geometry is built"
4402
+ ],
4403
+ "example": "const description = parseMeshDescription(payload, offset);",
4404
+ "importPath": "@threenative/raw-unreal",
4405
+ "kind": "function",
4406
+ "overrides": [],
4407
+ "package": "@threenative/raw-unreal",
4408
+ "requires": ["npm i @threenative/raw-unreal"],
4409
+ "signature": "export function findMeshDescriptionOffsets(bytes: Uint8Array): number[] { … }",
4410
+ "situations": [
4411
+ "inspect the vertex, triangle, and polygon-group structure of a UE5 MeshDescription"
4412
+ ],
4413
+ "summary": "Parses a serialized `FMeshDescription` — element containers, allocation bit arrays, and attribute sets — into validated typed arrays, exactly consuming its byte range.",
4414
+ "supersedes": [],
4415
+ "symbol": "findMeshDescriptionOffsets"
4416
+ },
4417
+ {
4418
+ "aliases": [],
4419
+ "constraints": [
4420
+ "only inline uncompressed blobs are found; compressed or external bulk data throws rather than guessing"
4421
+ ],
4422
+ "example": "const blob = parseRawMesh(bytes, offset);",
4423
+ "importPath": "@threenative/raw-unreal",
4424
+ "kind": "function",
4425
+ "overrides": [],
4426
+ "package": "@threenative/raw-unreal",
4427
+ "requires": ["npm i @threenative/raw-unreal"],
4428
+ "signature": "export function findRawMeshBlobs(bytes: Uint8Array): IRawMeshBlob[] { … }",
4429
+ "situations": [
4430
+ "read the source geometry of a Fab pack saved by UE 4.18 straight from its .uasset"
4431
+ ],
4432
+ "summary": "Parses one `FRawMesh` blob — the UE4.18-era source-model layout — validating that the fixed eighteen-array walk consumes the blob exactly and every count agrees with the wedge totals.",
4433
+ "supersedes": [],
4434
+ "symbol": "findRawMeshBlobs"
4435
+ },
4436
+ {
4437
+ "aliases": [],
4438
+ "constraints": [
4439
+ "every count is validated against its neighbors before any geometry is built"
4440
+ ],
4441
+ "example": "const description = parseMeshDescription(payload, offset);",
4442
+ "importPath": "@threenative/raw-unreal",
4443
+ "kind": "function",
4444
+ "overrides": [],
4445
+ "package": "@threenative/raw-unreal",
4446
+ "requires": ["npm i @threenative/raw-unreal"],
4447
+ "signature": "export function looksLikeMeshDescription(bytes: Uint8Array, offset = 0): boolean { … }",
4448
+ "situations": [
4449
+ "inspect the vertex, triangle, and polygon-group structure of a UE5 MeshDescription"
4450
+ ],
4451
+ "summary": "Parses a serialized `FMeshDescription` — element containers, allocation bit arrays, and attribute sets — into validated typed arrays, exactly consuming its byte range.",
4452
+ "supersedes": [],
4453
+ "symbol": "looksLikeMeshDescription"
4454
+ },
4455
+ {
4456
+ "aliases": [],
4457
+ "constraints": [
4458
+ "the walk must consume the payload exactly; a short walk throws rather than returning the geometry it managed to read"
4459
+ ],
4460
+ "example": "const description = parseMeshDescriptionUe4(payload);",
4461
+ "importPath": "@threenative/raw-unreal",
4462
+ "kind": "function",
4463
+ "overrides": [],
4464
+ "package": "@threenative/raw-unreal",
4465
+ "requires": ["npm i @threenative/raw-unreal"],
4466
+ "signature": "export function looksLikeMeshDescriptionUe4(bytes: Uint8Array, offset = 0): boolean { … }",
4467
+ "situations": ["decode the MeshDescription a UE 4.23-4.27 editor package keeps in bulk data"],
4468
+ "summary": "Parses the UE4.2x serialization of `FMeshDescription` — fixed-order element containers, and a triangle container that trails the attribute sets rather than sitting with its siblings.",
4469
+ "supersedes": [],
4470
+ "symbol": "looksLikeMeshDescriptionUe4"
4471
+ },
4472
+ {
4473
+ "aliases": [],
4474
+ "constraints": [
4475
+ "zlib payloads require an injected `zlib` codec; the package never bundles one, and a missing codec throws MISSING_CODEC instead of guessing",
4476
+ "a payload written to a sibling file throws MISSING_BULK_DATA_FILE naming that file, rather than inventing geometry"
4477
+ ],
4478
+ "example": "const payload = resolveBulkDataPayload(bytes, header, { zlib });",
4479
+ "importPath": "@threenative/raw-unreal",
4480
+ "kind": "function",
4481
+ "overrides": [],
4482
+ "package": "@threenative/raw-unreal",
4483
+ "requires": ["npm i @threenative/raw-unreal"],
4484
+ "signature": "export function parseBulkDataHeader( bytes: Uint8Array, offset: number, layout: IPackageLayout, ): IBulkDataHeader { … }",
4485
+ "situations": [
4486
+ "read a UE4 editor static mesh whose source model lives in bulk data rather than inline",
4487
+ "decompress the zlib-chunked bulk payload a UE4.2x package stores its MeshDescription in"
4488
+ ],
4489
+ "summary": "Reads the `FByteBulkData` headers an editor package serializes into its export data, and resolves each payload — inline, at the end of the package, or in a sibling `.ubulk`/`.uptnl` file whose bytes the caller supplies — decompressing `FArchive::SerializeCompressed` blocks.",
4490
+ "supersedes": [],
4491
+ "symbol": "parseBulkDataHeader"
4492
+ },
4493
+ {
4494
+ "aliases": [],
4495
+ "constraints": [
4496
+ "Oodle and LZ4 payloads require an injected codec; the package never bundles one, and a missing codec throws MISSING_CODEC instead of guessing"
4497
+ ],
4498
+ "example": "const payload = decompressCompressedBuffer(parseCompressedBuffer(bytes, offset), { oodle });",
4499
+ "importPath": "@threenative/raw-unreal",
4500
+ "kind": "function",
4501
+ "overrides": [],
4502
+ "package": "@threenative/raw-unreal",
4503
+ "requires": ["npm i @threenative/raw-unreal"],
4504
+ "signature": "export function parseCompressedBuffer(bytes: Uint8Array, offset = 0): ICompressedBuffer { … }",
4505
+ "situations": ["decompress the package-trailer payload that carries a UE5 MeshDescription"],
4506
+ "summary": "Parses one UE5 `FCompressedBuffer` and decompresses it block-by-block with the codecs the caller injected — uncompressed payloads are handled natively.",
4507
+ "supersedes": [],
4508
+ "symbol": "parseCompressedBuffer"
4509
+ },
4510
+ {
4511
+ "aliases": [],
4512
+ "constraints": [
4513
+ "every count is validated against its neighbors before any geometry is built"
4514
+ ],
4515
+ "example": "const description = parseMeshDescription(payload, offset);",
4516
+ "importPath": "@threenative/raw-unreal",
4517
+ "kind": "function",
4518
+ "overrides": [],
4519
+ "package": "@threenative/raw-unreal",
4520
+ "requires": ["npm i @threenative/raw-unreal"],
4521
+ "signature": "export function parseMeshDescription(input: Uint8Array, offset = 0): IMeshDescription { … }",
4522
+ "situations": [
4523
+ "inspect the vertex, triangle, and polygon-group structure of a UE5 MeshDescription"
4524
+ ],
4525
+ "summary": "Parses a serialized `FMeshDescription` — element containers, allocation bit arrays, and attribute sets — into validated typed arrays, exactly consuming its byte range.",
4526
+ "supersedes": [],
4527
+ "symbol": "parseMeshDescription"
4528
+ },
4529
+ {
4530
+ "aliases": [],
4531
+ "constraints": [
4532
+ "the walk must consume the payload exactly; a short walk throws rather than returning the geometry it managed to read"
4533
+ ],
4534
+ "example": "const description = parseMeshDescriptionUe4(payload);",
4535
+ "importPath": "@threenative/raw-unreal",
4536
+ "kind": "function",
4537
+ "overrides": [],
4538
+ "package": "@threenative/raw-unreal",
4539
+ "requires": ["npm i @threenative/raw-unreal"],
4540
+ "signature": "export function parseMeshDescriptionUe4(input: Uint8Array, offset = 0): IUe4MeshDescription { … }",
4541
+ "situations": ["decode the MeshDescription a UE 4.23-4.27 editor package keeps in bulk data"],
4542
+ "summary": "Parses the UE4.2x serialization of `FMeshDescription` — fixed-order element containers, and a triangle container that trails the attribute sets rather than sitting with its siblings.",
4543
+ "supersedes": [],
4544
+ "symbol": "parseMeshDescriptionUe4"
4545
+ },
4546
+ {
4547
+ "aliases": [],
4548
+ "constraints": [
4549
+ "only inline uncompressed blobs are found; compressed or external bulk data throws rather than guessing"
4550
+ ],
4551
+ "example": "const blob = parseRawMesh(bytes, offset);",
4552
+ "importPath": "@threenative/raw-unreal",
4553
+ "kind": "function",
4554
+ "overrides": [],
4555
+ "package": "@threenative/raw-unreal",
4556
+ "requires": ["npm i @threenative/raw-unreal"],
4557
+ "signature": "export function parseRawMesh(bytes: Uint8Array, offset = 0): IRawMeshBlob { … }",
4558
+ "situations": [
4559
+ "read the source geometry of a Fab pack saved by UE 4.18 straight from its .uasset"
4560
+ ],
4561
+ "summary": "Parses one `FRawMesh` blob — the UE4.18-era source-model layout — validating that the fixed eighteen-array walk consumes the blob exactly and every count agrees with the wedge totals.",
4562
+ "supersedes": [],
4563
+ "symbol": "parseRawMesh"
4564
+ },
4565
+ {
4566
+ "aliases": [],
4567
+ "constraints": [
4568
+ "only legacy-tag uncooked editor packages are read; IoStore (.utoc/.ucas), PAK archives, cooked render buffers, Nanite, and skeletal data throw UAssetError",
4569
+ "the format layer never invents fallback geometry; every malformed or unsupported layout surfaces as UAssetError with its byte offset or counts"
4570
+ ],
4571
+ "example": "const decoded = parseUAssetStaticMesh(await file.arrayBuffer(), { oodle });",
4572
+ "importPath": "@threenative/raw-unreal",
4573
+ "kind": "function",
4574
+ "overrides": [],
4575
+ "package": "@threenative/raw-unreal",
4576
+ "requires": ["npm i @threenative/raw-unreal"],
4577
+ "signature": "export function parseUAssetStaticMesh( input: ArrayBuffer | ArrayBufferView, options: IUAssetParseOptions = { … }",
4578
+ "situations": [
4579
+ "load a raw Unreal editor .uasset mesh in the browser without conversion",
4580
+ "decode a Fab pack's UE4.18 static meshes straight from their .uasset files"
4581
+ ],
4582
+ "summary": "Parses a raw Unreal editor `.uasset` static mesh into validated, plain typed arrays — UE5 `FMeshDescription` payloads (including the Oodle-compressed package-trailer form) and the UE4.18-era `FRawMesh` source-model layout, with no interchange conversion at any step.",
4583
+ "supersedes": [],
4584
+ "symbol": "parseUAssetStaticMesh"
4585
+ },
4586
+ {
4587
+ "aliases": [],
4588
+ "constraints": [
4589
+ "returns undefined rather than guessing when the summary does not end on its own name table, or when the package uses a LegacyFileVersion this walk does not model"
4590
+ ],
4591
+ "example": "const layout = readPackageLayout(bytes); if (layout) readBulk(layout.bulkDataStartOffset);",
4592
+ "importPath": "@threenative/raw-unreal",
4593
+ "kind": "function",
4594
+ "overrides": [],
4595
+ "package": "@threenative/raw-unreal",
4596
+ "requires": ["npm i @threenative/raw-unreal"],
4597
+ "signature": "export function readPackageLayout(bytes: Uint8Array): IPackageLayout | undefined { … }",
4598
+ "situations": ["find where a .uasset's export data and bulk-data region begin"],
4599
+ "summary": "Walks the whole `FPackageFileSummary` for the offsets bulk data is addressed against — `TotalHeaderSize` and `BulkDataStartOffset` — and returns `undefined` when the walk cannot be trusted.",
4600
+ "supersedes": [],
4601
+ "symbol": "readPackageLayout"
4602
+ },
4603
+ {
4604
+ "aliases": [],
4605
+ "constraints": [
4606
+ "only the summary prefix is read; locating payload data is the payload readers' self-validating signature scans"
4607
+ ],
4608
+ "example": "const summary = readPackageSummary(bytes);",
4609
+ "importPath": "@threenative/raw-unreal",
4610
+ "kind": "function",
4611
+ "overrides": [],
4612
+ "package": "@threenative/raw-unreal",
4613
+ "requires": ["npm i @threenative/raw-unreal"],
4614
+ "signature": "export function readPackageSummary(bytes: Uint8Array): IPackageSummary { … }",
4615
+ "situations": [
4616
+ "report which engine generation a .uasset was written by before decoding it",
4617
+ "reject a non-Unreal file with the stable INVALID_PACKAGE_TAG error"
4618
+ ],
4619
+ "summary": "Reads the fixed prefix of `FPackageFileSummary` — the legacy tag, engine versions, and the custom-version list — without walking the name map, export map, or dependency graph.",
4620
+ "supersedes": [],
4621
+ "symbol": "readPackageSummary"
4622
+ },
4623
+ {
4624
+ "aliases": [],
4625
+ "constraints": [
4626
+ "zlib payloads require an injected `zlib` codec; the package never bundles one, and a missing codec throws MISSING_CODEC instead of guessing",
4627
+ "a payload written to a sibling file throws MISSING_BULK_DATA_FILE naming that file, rather than inventing geometry"
4628
+ ],
4629
+ "example": "const payload = resolveBulkDataPayload(bytes, header, { zlib });",
4630
+ "importPath": "@threenative/raw-unreal",
4631
+ "kind": "function",
4632
+ "overrides": [],
4633
+ "package": "@threenative/raw-unreal",
4634
+ "requires": ["npm i @threenative/raw-unreal"],
4635
+ "signature": "export function resolveBulkDataPayload( bytes: Uint8Array, header: IBulkDataHeader, options: { … }",
4636
+ "situations": [
4637
+ "read a UE4 editor static mesh whose source model lives in bulk data rather than inline",
4638
+ "decompress the zlib-chunked bulk payload a UE4.2x package stores its MeshDescription in"
4639
+ ],
4640
+ "summary": "Reads the `FByteBulkData` headers an editor package serializes into its export data, and resolves each payload — inline, at the end of the package, or in a sibling `.ubulk`/`.uptnl` file whose bytes the caller supplies — decompressing `FArchive::SerializeCompressed` blocks.",
4641
+ "supersedes": [],
4642
+ "symbol": "resolveBulkDataPayload"
4643
+ },
4644
+ {
4645
+ "aliases": [],
4646
+ "constraints": [
4647
+ "every parse, decompression, and geometry failure surfaces as this error; the loader never invents fallback geometry"
4648
+ ],
4649
+ "example": "catch (error) { if (error instanceof UAssetError) log(error.code, error.details); }",
4650
+ "importPath": "@threenative/raw-unreal",
4651
+ "kind": "class",
4652
+ "overrides": [],
4653
+ "package": "@threenative/raw-unreal",
4654
+ "requires": ["npm i @threenative/raw-unreal"],
4655
+ "signature": "export class UAssetError extends Error { … }",
4656
+ "situations": [
4657
+ "tell why a raw .uasset failed to load, by code, before any geometry is shown",
4658
+ "branch on an unsupported Unreal layout instead of shipping broken geometry"
4659
+ ],
4660
+ "summary": "The error thrown for every malformed, truncated, or unsupported `.uasset` input, carrying a stable `code` and structured details instead of invented fallback geometry.",
4661
+ "supersedes": [],
4662
+ "symbol": "UAssetError"
4663
+ },
4664
+ {
4665
+ "aliases": [],
4666
+ "constraints": [
4667
+ "UE5 Oodle payloads require an `oodle` codec in the parse options; see README licensing"
4668
+ ],
4669
+ "example": "const mesh = new UAssetLoader(manager, { parse: { oodle } }).parse(data);",
4670
+ "importPath": "@threenative/raw-unreal",
4671
+ "kind": "class",
4672
+ "overrides": [],
4673
+ "package": "@threenative/raw-unreal",
4674
+ "requires": ["npm i @threenative/raw-unreal"],
4675
+ "signature": "export class UAssetLoader extends Loader { … }",
4676
+ "situations": [
4677
+ "load a .uasset asset in the browser with the standard three.js loader protocol",
4678
+ "hand raw Fab-pack meshes to the framework's asset loading without a conversion step"
4679
+ ],
4680
+ "summary": "Loads a raw Unreal `.uasset` static mesh as a three.js loader — `load(url)` for the browser, `parse(data)` for bytes you already hold — with parse and adapter options passed through.",
4681
+ "supersedes": [],
4682
+ "symbol": "UAssetLoader"
4683
+ },
4684
+ {
4685
+ "constraints": [
4686
+ "Use the running WebGPU renderer and keep appearance choices in template render source."
4687
+ ],
4688
+ "example": "gradualBackground(...)",
4689
+ "importPath": "@threenative/template/starter/src/render/effects/gradualBackground",
4690
+ "kind": "function",
4691
+ "overrides": [],
4692
+ "package": "template:starter",
4693
+ "signature": "function gradualBackground",
4694
+ "situations": ["grade a background by distance"],
4695
+ "supersedes": [],
4696
+ "summary": "ThreeNative equivalent for realism-effects gradualBackground.",
4697
+ "symbol": "gradualBackground",
4698
+ "aliases": []
4699
+ },
4700
+ {
4701
+ "constraints": [
4702
+ "Use the running WebGPU renderer and keep appearance choices in template render source."
4703
+ ],
4704
+ "example": "lensDistortion(...)",
4705
+ "importPath": "@threenative/template/starter/src/render/effects/lensDistortion",
4706
+ "kind": "function",
4707
+ "overrides": [],
4708
+ "package": "template:starter",
4709
+ "signature": "function lensDistortion",
4710
+ "situations": ["warp the image with radial lens distortion"],
4711
+ "supersedes": [],
4712
+ "summary": "ThreeNative equivalent for realism-effects lensDistortion.",
4713
+ "symbol": "lensDistortion",
4714
+ "aliases": []
4715
+ },
4716
+ {
4717
+ "constraints": [
4718
+ "Use the running WebGPU renderer and keep appearance choices in template render source."
4719
+ ],
4720
+ "example": "sparkle(...)",
4721
+ "importPath": "@threenative/template/starter/src/render/effects/sparkle",
4722
+ "kind": "function",
4723
+ "overrides": [],
4724
+ "package": "template:starter",
3228
4725
  "signature": "function sparkle",
3229
4726
  "situations": ["add glints to bright highlights"],
3230
4727
  "supersedes": [],
3231
4728
  "summary": "ThreeNative equivalent for realism-effects sparkle.",
3232
- "symbol": "sparkle"
4729
+ "symbol": "sparkle",
4730
+ "aliases": []
4731
+ },
4732
+ {
4733
+ "aliases": [],
4734
+ "constraints": [
4735
+ "rejects indices, channels, or material sections that disagree with the vertex count before any geometry is constructed"
4736
+ ],
4737
+ "example": "const geometry = createThreeGeometry(model.lods[0]);",
4738
+ "importPath": "@threenative/ueformat",
4739
+ "kind": "function",
4740
+ "overrides": [],
4741
+ "package": "@threenative/ueformat",
4742
+ "requires": ["npm i @threenative/ueformat"],
4743
+ "signature": "export function createThreeGeometry( lod: IUEModelLOD, adapterOptions: IThreeAdapterOptions = { … }",
4744
+ "situations": [
4745
+ "convert one Unreal mesh LOD into a three.js BufferGeometry by hand",
4746
+ "build custom scene objects from Unreal mesh data instead of a whole model"
4747
+ ],
4748
+ "summary": "Converts one parsed Unreal mesh LOD into a `THREE.BufferGeometry` — coordinates, scale, winding, normals, tangents, UVs, vertex colours, morphs, skin weights, and material groups.",
4749
+ "supersedes": [],
4750
+ "symbol": "createThreeGeometry"
4751
+ },
4752
+ {
4753
+ "aliases": [],
4754
+ "constraints": [
4755
+ "every material comes from the game through `materialFactory`; the fallback is three.js's own GLTFLoader default, a plain MeshStandardMaterial",
4756
+ "parsed bones are exposed on `userData` but never bound into a THREE.SkinnedMesh — skeletal rendering is the game's job"
4757
+ ],
4758
+ "example": "const hero = createThreeObject(parseUEModel(buffer), { lodDistances: [0, 25, 50] });",
4759
+ "importPath": "@threenative/ueformat",
4760
+ "kind": "function",
4761
+ "overrides": [],
4762
+ "package": "@threenative/ueformat",
4763
+ "requires": ["npm i @threenative/ueformat"],
4764
+ "signature": "export function createThreeObject( model: IUEModelData, adapterOptions: IThreeAdapterOptions = { … }",
4765
+ "situations": [
4766
+ "put a mesh exported from an Unreal package on screen",
4767
+ "load an Unreal static or skeletal mesh with LODs, sockets, and collision geometry"
4768
+ ],
4769
+ "summary": "Builds a renderable Three.js object — a `Group` for single-LOD models, a `THREE.LOD` for multi-LOD ones — from parsed `.uemodel` data, with collision geometry on `userData`.",
4770
+ "supersedes": [],
4771
+ "symbol": "createThreeObject"
4772
+ },
4773
+ {
4774
+ "aliases": [],
4775
+ "constraints": [
4776
+ "only UEFormat v10 UEMODEL files are accepted; anything else throws UEFormatError with the byte offset",
4777
+ "ZSTD-compressed bodies require an injected `zstdDecoder`; the package never bundles a ZSTD implementation"
4778
+ ],
4779
+ "example": "const model = parseUEModel(await file.arrayBuffer());",
4780
+ "importPath": "@threenative/ueformat",
4781
+ "kind": "function",
4782
+ "overrides": [],
4783
+ "package": "@threenative/ueformat",
4784
+ "requires": ["npm i @threenative/ueformat"],
4785
+ "signature": "export function parseUEModel( input: ArrayBuffer | ArrayBufferView, options: IParseUEModelOptions = { … }",
4786
+ "situations": [
4787
+ "parse a mesh exported from an Unreal package without Unreal installed",
4788
+ "inspect the LODs, skeleton, sockets, and collision inside a .uemodel file"
4789
+ ],
4790
+ "summary": "Parses a UEFormat v10 `.uemodel` body — the interchange format CUE4Parse and FModel export from Unreal packages — into validated, plain mesh data without building any Three.js objects.",
4791
+ "supersedes": [],
4792
+ "symbol": "parseUEModel"
4793
+ },
4794
+ {
4795
+ "aliases": [],
4796
+ "constraints": [
4797
+ "the summary reflects one already-parsed model; it does not read files itself"
4798
+ ],
4799
+ "example": "const summary = summarizeUEModel(parseUEModel(buffer));",
4800
+ "importPath": "@threenative/ueformat",
4801
+ "kind": "function",
4802
+ "overrides": [],
4803
+ "package": "@threenative/ueformat",
4804
+ "requires": ["npm i @threenative/ueformat"],
4805
+ "signature": "export function summarizeUEModel(model: IUEModelData): IUEModelSummary { … }",
4806
+ "situations": [
4807
+ "report what a UEFormat model contains without dumping its vertex data",
4808
+ "validate a .uemodel file before building geometry from it"
4809
+ ],
4810
+ "summary": "Summarizes a parsed `.uemodel` — LOD, material, skeleton, collision, and unknown-attribute counts — without dumping vertex arrays, for logs, validation, and build reports.",
4811
+ "supersedes": [],
4812
+ "symbol": "summarizeUEModel"
4813
+ },
4814
+ {
4815
+ "aliases": [],
4816
+ "constraints": [
4817
+ "every parse and geometry failure surfaces as this error; nothing malformed is silently skipped"
4818
+ ],
4819
+ "example": "catch (error) { if (error instanceof UEFormatError) log(error.code, error.offset); }",
4820
+ "importPath": "@threenative/ueformat",
4821
+ "kind": "class",
4822
+ "overrides": [],
4823
+ "package": "@threenative/ueformat",
4824
+ "requires": ["npm i @threenative/ueformat"],
4825
+ "signature": "export class UEFormatError extends Error { … }",
4826
+ "situations": [
4827
+ "tell why a .uemodel file failed to load",
4828
+ "report a malformed Unreal export with its byte offset instead of a generic error"
4829
+ ],
4830
+ "summary": "The error thrown for every malformed, truncated, or unsupported `.uemodel` input, carrying a stable `code` and the byte offset where validation stopped.",
4831
+ "supersedes": [],
4832
+ "symbol": "UEFormatError"
4833
+ },
4834
+ {
4835
+ "aliases": [],
4836
+ "constraints": [
4837
+ "ZSTD-compressed bodies require an injected `zstdDecoder` in the parse options"
4838
+ ],
4839
+ "example": "const model = new UEFormatLoader(manager).parse(data);",
4840
+ "importPath": "@threenative/ueformat",
4841
+ "kind": "class",
4842
+ "overrides": [],
4843
+ "package": "@threenative/ueformat",
4844
+ "requires": ["npm i @threenative/ueformat"],
4845
+ "signature": "export class UEFormatLoader extends Loader { … }",
4846
+ "situations": [
4847
+ "load a .uemodel asset in the browser with the standard three.js loader protocol",
4848
+ "hand a game's Unreal-exported meshes to the framework's asset loading"
4849
+ ],
4850
+ "summary": "Loads a `.uemodel` file as a Three.js loader — `load(url)` for the browser, `parse(data)` for bytes you already hold — with the parser and three-adapter options passed straight through.",
4851
+ "supersedes": [],
4852
+ "symbol": "UEFormatLoader"
3233
4853
  },
3234
4854
  {
4855
+ "aliases": [],
3235
4856
  "constraints": [],
3236
- "example": "<DebugOverlay game={game} />",
4857
+ "example": "<DebugOverlay />",
3237
4858
  "importPath": "@threenative/ui",
3238
4859
  "kind": "function",
3239
4860
  "overrides": [],
@@ -3248,6 +4869,7 @@
3248
4869
  "symbol": "DebugOverlay"
3249
4870
  },
3250
4871
  {
4872
+ "aliases": [],
3251
4873
  "constraints": ["keep the portable game entry free of React DOM code"],
3252
4874
  "example": "<GameCanvas game={game} />",
3253
4875
  "importPath": "@threenative/ui",
@@ -3264,6 +4886,7 @@
3264
4886
  "symbol": "GameCanvas"
3265
4887
  },
3266
4888
  {
4889
+ "aliases": [],
3267
4890
  "constraints": ["mark every control the player touches with data-tn-interactive"],
3268
4891
  "example": "<UiLayer><Hud /></UiLayer>",
3269
4892
  "importPath": "@threenative/ui",
@@ -3280,6 +4903,7 @@
3280
4903
  "symbol": "UiLayer"
3281
4904
  },
3282
4905
  {
4906
+ "aliases": [],
3283
4907
  "constraints": ["use this hook only from the web UI entry"],
3284
4908
  "example": "const score = useGameState(game, (state) => state.score);",
3285
4909
  "importPath": "@threenative/ui",
@@ -3296,6 +4920,7 @@
3296
4920
  "symbol": "useGameState"
3297
4921
  },
3298
4922
  {
4923
+ "aliases": [],
3299
4924
  "constraints": ["the game decides what each intent name means; it may ignore one"],
3300
4925
  "example": "const send = useUiIntent(); send(\"restart\");",
3301
4926
  "importPath": "@threenative/ui",
@@ -3312,8 +4937,9 @@
3312
4937
  "symbol": "useUiIntent"
3313
4938
  },
3314
4939
  {
4940
+ "aliases": [],
3315
4941
  "constraints": ["returns undefined until the game publishes its first state"],
3316
- "example": "const score = useUiState((state) => state.score);",
4942
+ "example": "const score = useUiState<GameState, number>((state) => state.score);",
3317
4943
  "importPath": "@threenative/ui",
3318
4944
  "kind": "function",
3319
4945
  "overrides": [],
@@ -3327,20 +4953,105 @@
3327
4953
  "supersedes": [],
3328
4954
  "symbol": "useUiState"
3329
4955
  },
4956
+ {
4957
+ "symbol": "WorldEnvironment",
4958
+ "package": "three",
4959
+ "importPath": "src/render/worldEnvironment.ts",
4960
+ "kind": "class",
4961
+ "signature": "class WorldEnvironment",
4962
+ "summary": "The generated file that composes every lighting stage and prints TN_RENDER_CHAIN naming each one as applied or refused with a reason. It is the game's source, not the framework's — edit it.",
4963
+ "situations": [
4964
+ "turn a lighting or post-processing effect on or off",
4965
+ "find out why an effect you enabled is not visible",
4966
+ "change how the scene is lit, graded, or tonemapped",
4967
+ "match a reference image's lighting"
4968
+ ],
4969
+ "example": "src/render/postprocessing.ts — edit the preset it passes to WorldEnvironment",
4970
+ "constraints": [
4971
+ "Read the TN_RENDER_CHAIN line before assuming a stage ran: it names every stage as applied or dropped, with the reason it was dropped.",
4972
+ "A stage reported `applied` can still be invisible if its own inputs are wrong — the chain reports whether it built, not whether you can see it.",
4973
+ "Appearance belongs here, in generated game source. Nothing in packages/ decides how the scene looks."
4974
+ ],
4975
+ "overrides": [],
4976
+ "supersedes": [],
4977
+ "aliases": []
4978
+ },
4979
+ {
4980
+ "symbol": "bloom",
4981
+ "package": "three",
4982
+ "importPath": "three/addons/tsl/display/BloomNode.js",
4983
+ "kind": "function",
4984
+ "signature": "bloom(node, strength, radius, threshold)",
4985
+ "summary": "Glow around bright pixels. Already wired as the `bloom` stage.",
4986
+ "situations": ["make a bright opening or a lamp glow", "bloom, glare, light spill"],
4987
+ "example": "src/render/postprocessing.ts — edit the preset it passes to WorldEnvironment",
4988
+ "constraints": [
4989
+ "Strength above ~0.3 on an interior washes the mid-tones; the reference-matching band is lower than it looks."
4990
+ ],
4991
+ "overrides": [],
4992
+ "supersedes": [],
4993
+ "aliases": []
4994
+ },
3330
4995
  {
3331
4996
  "constraints": [
3332
4997
  "Use the running WebGPU renderer and keep appearance choices in template render source."
3333
4998
  ],
3334
- "example": "DenoiseNode(...)",
4999
+ "example": "denoise(...)",
3335
5000
  "importPath": "three/addons/tsl/display/DenoiseNode.js",
3336
- "kind": "class",
5001
+ "kind": "function",
3337
5002
  "overrides": [],
3338
5003
  "package": "three",
3339
- "signature": "class DenoiseNode",
5004
+ "signature": "function denoise",
3340
5005
  "situations": ["denoise a noisy screen-space pass"],
3341
5006
  "supersedes": [],
3342
- "summary": "ThreeNative equivalent for realism-effects DenoiseNode.",
3343
- "symbol": "DenoiseNode"
5007
+ "summary": "ThreeNative equivalent for realism-effects denoise.",
5008
+ "symbol": "denoise",
5009
+ "aliases": []
5010
+ },
5011
+ {
5012
+ "symbol": "godrays",
5013
+ "package": "three",
5014
+ "importPath": "three/addons/tsl/display/GodraysNode.js",
5015
+ "kind": "function",
5016
+ "signature": "godrays(textureNode, light, shadowMap, params)",
5017
+ "summary": "Raymarched shafts of light. Already wired as the `godRays` stage of the render chain; turn it on with `godraysEnabled` in src/render/postprocessing.ts.",
5018
+ "situations": [
5019
+ "draw a visible shaft of light through a window or a hole in a roof",
5020
+ "god rays, sun shafts, light beams, crepuscular rays",
5021
+ "make sunlight visible in dusty or misty air indoors",
5022
+ "light a cave or a hall through an opening above",
5023
+ "volumetric lighting without adding cone geometry"
5024
+ ],
5025
+ "example": "src/render/postprocessing.ts — edit the preset it passes to WorldEnvironment",
5026
+ "constraints": [
5027
+ "Needs a shadow-casting DirectionalLight passed as `godraysLight`, and `renderer.shadowMap.enabled = true` — without the shadow map the stage refuses and the whole chain reports it dropped.",
5028
+ "`godraysFloor` is what separates beams from fog: it subtracts out-of-beam scatter before `godraysIntensity` multiplies. Raising intensity with a floor near zero brightens the haze over the whole room instead of the beams.",
5029
+ "Do not author cone geometry for beams. A hand-built additive cone draws its own silhouette and reads as a plastic tube; this stage is the supported route.",
5030
+ "Measured band on an interior scene: density 0.7, floor 0.08, intensity 3.0, maxDensity 0.6. Above ~0.8 density the haze stops being confined to the beams and the room fogs."
5031
+ ],
5032
+ "overrides": [],
5033
+ "supersedes": [],
5034
+ "aliases": []
5035
+ },
5036
+ {
5037
+ "symbol": "ao",
5038
+ "package": "three",
5039
+ "importPath": "three/addons/tsl/display/GTAONode.js",
5040
+ "kind": "function",
5041
+ "signature": "ao(scene, camera, resolution, radius, intensity)",
5042
+ "summary": "Ground-truth ambient occlusion. Already wired as the `ambientOcclusion` stage; turn it on with `gtaoEnabled`.",
5043
+ "situations": [
5044
+ "darken the contact where an object meets the floor",
5045
+ "stop props looking like they float",
5046
+ "ambient occlusion, contact shadows, crevice darkening"
5047
+ ],
5048
+ "example": "src/render/postprocessing.ts — edit the preset it passes to WorldEnvironment",
5049
+ "constraints": [
5050
+ "Radius is in metres; a radius sized for a room reads as a smudge on a prop."
5051
+ ],
5052
+ "overrides": [],
5053
+ "supersedes": [],
5054
+ "aliases": []
3344
5055
  },
3345
5056
  {
3346
5057
  "constraints": [
@@ -3355,112 +5066,120 @@
3355
5066
  "situations": ["blur motion using a velocity buffer"],
3356
5067
  "supersedes": [],
3357
5068
  "summary": "ThreeNative equivalent for realism-effects motionBlur.",
3358
- "symbol": "motionBlur"
5069
+ "symbol": "motionBlur",
5070
+ "aliases": []
3359
5071
  },
3360
5072
  {
3361
5073
  "constraints": [
3362
5074
  "Use the running WebGPU renderer and keep appearance choices in template render source."
3363
5075
  ],
3364
- "example": "RecurrentDenoiseNode(...)",
5076
+ "example": "recurrentDenoise(...)",
3365
5077
  "importPath": "three/addons/tsl/display/RecurrentDenoiseNode.js",
3366
- "kind": "class",
5078
+ "kind": "function",
3367
5079
  "overrides": [],
3368
5080
  "package": "three",
3369
- "signature": "class RecurrentDenoiseNode",
5081
+ "signature": "function recurrentDenoise",
3370
5082
  "situations": ["denoise a noisy screen-space pass"],
3371
5083
  "supersedes": [],
3372
- "summary": "ThreeNative equivalent for realism-effects RecurrentDenoiseNode.",
3373
- "symbol": "RecurrentDenoiseNode"
5084
+ "summary": "ThreeNative equivalent for realism-effects recurrentDenoise.",
5085
+ "symbol": "recurrentDenoise",
5086
+ "aliases": []
3374
5087
  },
3375
5088
  {
3376
5089
  "constraints": [
3377
5090
  "Use the running WebGPU renderer and keep appearance choices in template render source."
3378
5091
  ],
3379
- "example": "SharpenNode(...)",
5092
+ "example": "sharpen(...)",
3380
5093
  "importPath": "three/addons/tsl/display/SharpenNode.js",
3381
- "kind": "class",
5094
+ "kind": "function",
3382
5095
  "overrides": [],
3383
5096
  "package": "three",
3384
- "signature": "class SharpenNode",
5097
+ "signature": "function sharpen",
3385
5098
  "situations": ["make the image sharper"],
3386
5099
  "supersedes": [],
3387
- "summary": "ThreeNative equivalent for realism-effects SharpenNode.",
3388
- "symbol": "SharpenNode"
5100
+ "summary": "ThreeNative equivalent for realism-effects sharpen.",
5101
+ "symbol": "sharpen",
5102
+ "aliases": []
3389
5103
  },
3390
5104
  {
3391
5105
  "constraints": [
3392
5106
  "Use the running WebGPU renderer and keep appearance choices in template render source."
3393
5107
  ],
3394
- "example": "SSAAPassNode(...)",
5108
+ "example": "ssaaPass(...)",
3395
5109
  "importPath": "three/addons/tsl/display/SSAAPassNode.js",
3396
- "kind": "class",
5110
+ "kind": "function",
3397
5111
  "overrides": [],
3398
5112
  "package": "three",
3399
- "signature": "class SSAAPassNode",
5113
+ "signature": "function ssaaPass",
3400
5114
  "situations": ["anti-alias still and moving scenes"],
3401
5115
  "supersedes": [],
3402
- "summary": "ThreeNative equivalent for realism-effects SSAAPassNode.",
3403
- "symbol": "SSAAPassNode"
5116
+ "summary": "ThreeNative equivalent for realism-effects ssaaPass.",
5117
+ "symbol": "ssaaPass",
5118
+ "aliases": []
3404
5119
  },
3405
5120
  {
3406
5121
  "constraints": [
3407
5122
  "Use the running WebGPU renderer and keep appearance choices in template render source."
3408
5123
  ],
3409
- "example": "SSGINode(...)",
5124
+ "example": "ssgi(...)",
3410
5125
  "importPath": "three/addons/tsl/display/SSGINode.js",
3411
- "kind": "class",
5126
+ "kind": "function",
3412
5127
  "overrides": [],
3413
5128
  "package": "three",
3414
- "signature": "class SSGINode",
5129
+ "signature": "function ssgi",
3415
5130
  "situations": ["add screen-space global illumination"],
3416
5131
  "supersedes": [],
3417
- "summary": "ThreeNative equivalent for realism-effects SSGINode.",
3418
- "symbol": "SSGINode"
5132
+ "summary": "ThreeNative equivalent for realism-effects ssgi.",
5133
+ "symbol": "ssgi",
5134
+ "aliases": []
3419
5135
  },
3420
5136
  {
3421
5137
  "constraints": [
3422
5138
  "Use the running WebGPU renderer and keep appearance choices in template render source."
3423
5139
  ],
3424
- "example": "SSRNode(...)",
5140
+ "example": "ssr(...)",
3425
5141
  "importPath": "three/addons/tsl/display/SSRNode.js",
3426
- "kind": "class",
5142
+ "kind": "function",
3427
5143
  "overrides": [],
3428
5144
  "package": "three",
3429
- "signature": "class SSRNode",
5145
+ "signature": "function ssr",
3430
5146
  "situations": ["add screen-space reflections"],
3431
5147
  "supersedes": [],
3432
- "summary": "ThreeNative equivalent for realism-effects SSRNode.",
3433
- "symbol": "SSRNode"
5148
+ "summary": "ThreeNative equivalent for realism-effects ssr.",
5149
+ "symbol": "ssr",
5150
+ "aliases": []
3434
5151
  },
3435
5152
  {
3436
5153
  "constraints": [
3437
5154
  "Use the running WebGPU renderer and keep appearance choices in template render source."
3438
5155
  ],
3439
- "example": "TemporalReprojectNode(...)",
5156
+ "example": "temporalReproject(...)",
3440
5157
  "importPath": "three/addons/tsl/display/TemporalReprojectNode.js",
3441
- "kind": "class",
5158
+ "kind": "function",
3442
5159
  "overrides": [],
3443
5160
  "package": "three",
3444
- "signature": "class TemporalReprojectNode",
5161
+ "signature": "function temporalReproject",
3445
5162
  "situations": ["reproject a temporal history"],
3446
5163
  "supersedes": [],
3447
- "summary": "ThreeNative equivalent for realism-effects TemporalReprojectNode.",
3448
- "symbol": "TemporalReprojectNode"
5164
+ "summary": "ThreeNative equivalent for realism-effects temporalReproject.",
5165
+ "symbol": "temporalReproject",
5166
+ "aliases": []
3449
5167
  },
3450
5168
  {
3451
5169
  "constraints": [
3452
5170
  "Use the running WebGPU renderer and keep appearance choices in template render source."
3453
5171
  ],
3454
- "example": "TRAANode(...)",
5172
+ "example": "traa(...)",
3455
5173
  "importPath": "three/addons/tsl/display/TRAANode.js",
3456
- "kind": "class",
5174
+ "kind": "function",
3457
5175
  "overrides": [],
3458
5176
  "package": "three",
3459
- "signature": "class TRAANode",
5177
+ "signature": "function traa",
3460
5178
  "situations": ["temporally resolve a moving image"],
3461
5179
  "supersedes": [],
3462
- "summary": "ThreeNative equivalent for realism-effects TRAANode.",
3463
- "symbol": "TRAANode"
5180
+ "summary": "ThreeNative equivalent for realism-effects traa.",
5181
+ "symbol": "traa",
5182
+ "aliases": []
3464
5183
  },
3465
5184
  {
3466
5185
  "constraints": [
@@ -3475,7 +5194,8 @@
3475
5194
  "situations": ["provide depth to screen-space effects"],
3476
5195
  "supersedes": [],
3477
5196
  "summary": "ThreeNative equivalent for realism-effects depth.",
3478
- "symbol": "depth"
5197
+ "symbol": "depth",
5198
+ "aliases": []
3479
5199
  },
3480
5200
  {
3481
5201
  "constraints": [
@@ -3490,22 +5210,24 @@
3490
5210
  "situations": ["provision velocity, normal, and depth render targets"],
3491
5211
  "supersedes": [],
3492
5212
  "summary": "ThreeNative equivalent for realism-effects mrt.",
3493
- "symbol": "mrt"
5213
+ "symbol": "mrt",
5214
+ "aliases": []
3494
5215
  },
3495
5216
  {
3496
5217
  "constraints": [
3497
5218
  "Use the running WebGPU renderer and keep appearance choices in template render source."
3498
5219
  ],
3499
- "example": "normal(...)",
5220
+ "example": "normalView(...)",
3500
5221
  "importPath": "three/tsl",
3501
5222
  "kind": "function",
3502
5223
  "overrides": [],
3503
5224
  "package": "three",
3504
- "signature": "function normal",
5225
+ "signature": "function normalView",
3505
5226
  "situations": ["provide normals to screen-space effects"],
3506
5227
  "supersedes": [],
3507
- "summary": "ThreeNative equivalent for realism-effects normal.",
3508
- "symbol": "normal"
5228
+ "summary": "ThreeNative equivalent for realism-effects normalView.",
5229
+ "symbol": "normalView",
5230
+ "aliases": []
3509
5231
  },
3510
5232
  {
3511
5233
  "constraints": [
@@ -3520,7 +5242,8 @@
3520
5242
  "situations": ["provide motion vectors to temporal effects"],
3521
5243
  "supersedes": [],
3522
5244
  "summary": "ThreeNative equivalent for realism-effects velocity.",
3523
- "symbol": "velocity"
5245
+ "symbol": "velocity",
5246
+ "aliases": []
3524
5247
  },
3525
5248
  {
3526
5249
  "constraints": [
@@ -3535,8 +5258,35 @@
3535
5258
  "situations": ["provide motion vectors to temporal effects"],
3536
5259
  "supersedes": [],
3537
5260
  "summary": "ThreeNative equivalent for realism-effects VelocityNode.",
3538
- "symbol": "VelocityNode"
5261
+ "symbol": "VelocityNode",
5262
+ "aliases": []
5263
+ }
5264
+ ],
5265
+ "notOwned": [
5266
+ {
5267
+ "guidance": "The framework owns no save/load system. Write a save module in your project's src/ using your own plain state shape (for example, ctx.state), and read agent-docs/gameplay-recipes.md for the template recipe.",
5268
+ "id": "save-load",
5269
+ "situations": [
5270
+ "persist a player's progress between sessions",
5271
+ "save player progress between sessions",
5272
+ "load a saved game state"
5273
+ ]
5274
+ },
5275
+ {
5276
+ "guidance": "The framework owns no inventory system. Write inventory state in your project's src/ with plain objects under ctx.state, and read agent-docs/gameplay-recipes.md for the template recipe.",
5277
+ "id": "inventory",
5278
+ "situations": ["inventory system", "manage inventory contents"]
5279
+ },
5280
+ {
5281
+ "guidance": "The framework owns no dialogue system. Write the conversation data and state in your project's src/; render it with the template UI (starter uses src/ui/), and read agent-docs/gameplay-recipes.md.",
5282
+ "id": "dialogue",
5283
+ "situations": ["NPC dialogue system", "write conversation choices for an NPC"]
5284
+ },
5285
+ {
5286
+ "guidance": "The framework owns the optional authenticated transport seam at @threenative/core/net. Import connect with an HTTPS endpoint and a game-issued credential; it validates channels, message sizes, and bounded queues, but reliable overflow returns false and native qualification depends on the installed bridge (iOS remains unverified). Write authoritative replication, snapshots, prediction, interpolation, and rejoin policy in your project's src/ and server code.",
5287
+ "id": "networked-multiplayer",
5288
+ "situations": ["authoritative replication", "client prediction"]
3539
5289
  }
3540
5290
  ],
3541
- "version": 1
5291
+ "version": 2
3542
5292
  }