@oeave/bakery3 0.0.0-stage → 0.2.0

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 (86) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +562 -2
  3. package/dist/animation-B1h0Ryvj.d.ts +97 -0
  4. package/dist/bake/index.d.ts +369 -0
  5. package/dist/bake/index.js +9 -0
  6. package/dist/bake/index.js.map +1 -0
  7. package/dist/bake-DZ-CJR6f.d.ts +1364 -0
  8. package/dist/catalog/index.d.ts +100 -0
  9. package/dist/catalog/index.js +154 -0
  10. package/dist/catalog/index.js.map +1 -0
  11. package/dist/catalog.gen-BM-aNf7n.d.ts +733 -0
  12. package/dist/chunk-3G5QL4F4.js +145 -0
  13. package/dist/chunk-3G5QL4F4.js.map +1 -0
  14. package/dist/chunk-4E5VV4QY.js +12 -0
  15. package/dist/chunk-4E5VV4QY.js.map +1 -0
  16. package/dist/chunk-62M6XXNX.js +142 -0
  17. package/dist/chunk-62M6XXNX.js.map +1 -0
  18. package/dist/chunk-6FYI6AJM.js +1157 -0
  19. package/dist/chunk-6FYI6AJM.js.map +1 -0
  20. package/dist/chunk-6NYR73Y7.js +832 -0
  21. package/dist/chunk-6NYR73Y7.js.map +1 -0
  22. package/dist/chunk-APWUCEEB.js +118 -0
  23. package/dist/chunk-APWUCEEB.js.map +1 -0
  24. package/dist/chunk-HNMSWQU7.js +1709 -0
  25. package/dist/chunk-HNMSWQU7.js.map +1 -0
  26. package/dist/chunk-JFYUDERE.js +1412 -0
  27. package/dist/chunk-JFYUDERE.js.map +1 -0
  28. package/dist/chunk-KNUAOILG.js +551 -0
  29. package/dist/chunk-KNUAOILG.js.map +1 -0
  30. package/dist/chunk-KZLVTSBI.js +191 -0
  31. package/dist/chunk-KZLVTSBI.js.map +1 -0
  32. package/dist/chunk-LAKXC4WR.js +2028 -0
  33. package/dist/chunk-LAKXC4WR.js.map +1 -0
  34. package/dist/chunk-NXBAZGNB.js +1107 -0
  35. package/dist/chunk-NXBAZGNB.js.map +1 -0
  36. package/dist/chunk-QRCT5UGZ.js +3286 -0
  37. package/dist/chunk-QRCT5UGZ.js.map +1 -0
  38. package/dist/chunk-S4AJTLLN.js +23 -0
  39. package/dist/chunk-S4AJTLLN.js.map +1 -0
  40. package/dist/chunk-UWBP7B54.js +92 -0
  41. package/dist/chunk-UWBP7B54.js.map +1 -0
  42. package/dist/chunk-XK35ANPJ.js +346 -0
  43. package/dist/chunk-XK35ANPJ.js.map +1 -0
  44. package/dist/chunk-Z7IYVH22.js +4781 -0
  45. package/dist/chunk-Z7IYVH22.js.map +1 -0
  46. package/dist/chunk-ZEBVAIJJ.js +156 -0
  47. package/dist/chunk-ZEBVAIJJ.js.map +1 -0
  48. package/dist/devtools/index.d.ts +536 -0
  49. package/dist/devtools/index.js +15 -0
  50. package/dist/devtools/index.js.map +1 -0
  51. package/dist/environments/index.d.ts +93 -0
  52. package/dist/environments/index.js +382 -0
  53. package/dist/environments/index.js.map +1 -0
  54. package/dist/hotspots/index.d.ts +111 -0
  55. package/dist/hotspots/index.js +285 -0
  56. package/dist/hotspots/index.js.map +1 -0
  57. package/dist/index.d.ts +975 -0
  58. package/dist/index.js +15 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/node/index.cjs +5240 -0
  61. package/dist/node/index.cjs.map +1 -0
  62. package/dist/node/index.d.cts +4927 -0
  63. package/dist/node/index.d.ts +597 -0
  64. package/dist/node/index.js +1328 -0
  65. package/dist/node/index.js.map +1 -0
  66. package/dist/prepare-BtjY4G3q.d.ts +112 -0
  67. package/dist/presets/index.d.ts +562 -0
  68. package/dist/presets/index.js +14 -0
  69. package/dist/presets/index.js.map +1 -0
  70. package/dist/r3f/index.d.ts +159 -0
  71. package/dist/r3f/index.js +592 -0
  72. package/dist/r3f/index.js.map +1 -0
  73. package/dist/room-FS26KAPQ.js +9 -0
  74. package/dist/room-FS26KAPQ.js.map +1 -0
  75. package/dist/rooms.gen-DItzBR9k.d.ts +1462 -0
  76. package/dist/session-VCIQEO26.js +9 -0
  77. package/dist/session-VCIQEO26.js.map +1 -0
  78. package/dist/shapes/index.d.ts +222 -0
  79. package/dist/shapes/index.js +836 -0
  80. package/dist/shapes/index.js.map +1 -0
  81. package/dist/testRun-20OARnQr.d.ts +1139 -0
  82. package/dist/timeline-ChwgD7bT.d.ts +470 -0
  83. package/dist/tsl/index.d.ts +165 -0
  84. package/dist/tsl/index.js +310 -0
  85. package/dist/tsl/index.js.map +1 -0
  86. package/package.json +170 -4
@@ -0,0 +1,1364 @@
1
+ import { A as AnimationSpec } from './animation-B1h0Ryvj.js';
2
+
3
+ /**
4
+ * Room presets: a staged interior the renderer rebuilds by itself.
5
+ *
6
+ * A room preset is a whole set: walls with windows, a floor, a pedestal,
7
+ * the furniture along the walls, the foliage outside the glass that dapples
8
+ * the sunlight, a designed lighting rig per mode. The browser shows a
9
+ * compressed stand-in of it (one small GLB from the preset library) so the
10
+ * developer can frame their product inside it; none of that geometry is
11
+ * captured. The manifest carries only this record (which room, which build
12
+ * of it, which lighting, which surfaces, which stand, where it sits), and
13
+ * the worker rebuilds the room from its own full-resolution copy of the
14
+ * definition. A room render uploads exactly what a bare product render
15
+ * uploads: the product.
16
+ *
17
+ * Two versions guard the pixels. `build` is the content hash of the
18
+ * published room definition the SDK previewed; a worker whose copy hashes
19
+ * differently refuses rather than rendering a room that is not the one on
20
+ * screen. `ROOM_PRESET_VERSION` covers the worker's room builder.
21
+ */
22
+
23
+ declare const ROOM_LIGHTING_MODES: readonly ["day", "golden", "overcast", "night"];
24
+ type RoomLightingMode = (typeof ROOM_LIGHTING_MODES)[number];
25
+ /** A preset material plus an optional sRGB hex tint multiplied into albedo. */
26
+ type RoomSurfaceChoice = {
27
+ material: string;
28
+ /** `#rrggbb`. Plaster and paint take a tint well; a plank floor less so. */
29
+ color?: string;
30
+ };
31
+ /**
32
+ * What the manifest says about the room. Every field except `name`, `build`,
33
+ * `lighting` and `matrix` is an override on the published defaults; absent
34
+ * means "the room's own".
35
+ */
36
+ type RoomPresetSpec = {
37
+ /** The published room, e.g. `loft_golden`. */
38
+ name: string;
39
+ /** Content hash (12 hex) of the published definition. See above. */
40
+ build: string;
41
+ lighting: RoomLightingMode;
42
+ surfaces?: {
43
+ floor?: RoomSurfaceChoice;
44
+ walls?: RoomSurfaceChoice;
45
+ ceiling?: RoomSurfaceChoice;
46
+ /** Window sills: stone or timber. No tint; sills are never painted. */
47
+ sill?: {
48
+ material: string;
49
+ };
50
+ };
51
+ /**
52
+ * What the product stands on. `null` puts nothing under it (the developer
53
+ * placed their own stand, or the product sits on the floor); absent keeps
54
+ * the room's stand. `material` applies to a baked pedestal only; a table
55
+ * used as a stand keeps the finish it came with.
56
+ */
57
+ pedestal?: {
58
+ type: string;
59
+ material?: string;
60
+ } | null;
61
+ /**
62
+ * How much of the room the browser shipped, so the worker does not build
63
+ * it twice. Normally none of the room's geometry crosses the wire.
64
+ *
65
+ * `true`: the whole stand-in is in the GLB, the shell, the stand and the
66
+ * furniture. A bake can then lightmap the room's own surfaces, because a
67
+ * lightmap has to land on a mesh the page holds. The worker builds only
68
+ * what the stand-in cannot carry: the sky, the sun, the portals, the
69
+ * foliage outside the glass, the fixtures' light and the panes.
70
+ *
71
+ * `'stand'`: only the stand is in the GLB, and the worker builds the room
72
+ * around it at full quality. This is what a bake into a prebaked room
73
+ * asks for: that bake lightmaps nothing of the room but the stand, so the
74
+ * light bouncing around the product should come off the real room, not
75
+ * off the browser's compressed preview of it.
76
+ */
77
+ standIn?: boolean | 'stand';
78
+ /**
79
+ * The HDRI outside the windows: an `HDRI_PRESETS` name to put another map
80
+ * there than the room's published one for this mode, turned so its sun
81
+ * sits where the room's sun is; `null` for nothing outside (the mode's
82
+ * plain sky); absent keeps the room's own. In day and golden the room's
83
+ * sun lamp still casts the direct light; the map is the sky's light and
84
+ * the view, projected onto the ground.
85
+ */
86
+ hdri?: string | null;
87
+ /**
88
+ * Pictures of the developer's own in the room's frames, one entry per
89
+ * picture the room hangs, in the order it hangs them. A `sha256:` asset
90
+ * hash puts that image in that frame; `null` or a short list leaves the
91
+ * rest as published.
92
+ *
93
+ * The frame does not move. A picture's moulding, its passepartout and the
94
+ * opening they leave were built to the published image's shape, and the
95
+ * browser shows that geometry while the developer frames the shot, so a
96
+ * replacement is cropped to fill the opening (the way `object-fit: cover`
97
+ * fills a box) rather than resizing the frame around it.
98
+ */
99
+ pictures?: (string | null)[];
100
+ /** The room group's world matrix, three.js column-major. */
101
+ matrix: Matrix4;
102
+ };
103
+
104
+ /**
105
+ * One node. `inputs` are ids of earlier nodes: the array arrives
106
+ * topologically sorted, so the worker builds it in one pass. Constants are
107
+ * nodes too, so every input is a reference and nothing is written twice.
108
+ */
109
+ type ShaderGraphNode = {
110
+ id: string;
111
+ op: string;
112
+ inputs?: string[];
113
+ params?: Record<string, number | string | boolean | number[]>;
114
+ };
115
+ /**
116
+ * Which BSDF slot a graph output drives. Everything not listed here falls
117
+ * back to the material's static properties.
118
+ */
119
+ type ShaderSlot = 'color' | 'opacity' | 'alphaTest' | 'roughness' | 'metalness' | 'normal' | 'emissive' | 'ao' | 'clearcoat' | 'clearcoatRoughness' | 'sheen' | 'sheenRoughness' | 'iridescence' | 'iridescenceIOR' | 'iridescenceThickness' | 'transmission' | 'thickness' | 'ior' | 'specularIntensity' | 'specularColor' | 'anisotropy';
120
+ type ShaderGraph = {
121
+ version: number;
122
+ /** Topologically sorted: a node's inputs always precede it. */
123
+ nodes: ShaderGraphNode[];
124
+ /** Which node feeds which BSDF slot. */
125
+ outputs: Partial<Record<ShaderSlot, string>>;
126
+ };
127
+ /**
128
+ * The static, non-graph half of the material: plain PBR values for every
129
+ * slot no node drives. Captured in full because the glTF exporter does not
130
+ * understand node materials, so the worker rebuilds this material from
131
+ * scratch rather than patching whatever the exporter guessed.
132
+ */
133
+ type ShaderMaterialProperties = {
134
+ color?: string;
135
+ roughness?: number;
136
+ metalness?: number;
137
+ emissive?: string;
138
+ emissiveIntensity?: number;
139
+ opacity?: number;
140
+ transparent?: boolean;
141
+ alphaTest?: number;
142
+ ior?: number;
143
+ transmission?: number;
144
+ thickness?: number;
145
+ attenuationColor?: string;
146
+ attenuationDistance?: number;
147
+ clearcoat?: number;
148
+ clearcoatRoughness?: number;
149
+ sheen?: number;
150
+ sheenColor?: string;
151
+ sheenRoughness?: number;
152
+ specularIntensity?: number;
153
+ specularColor?: string;
154
+ iridescence?: number;
155
+ iridescenceIOR?: number;
156
+ anisotropy?: number;
157
+ doubleSided?: boolean;
158
+ };
159
+ /**
160
+ * One node material, ready to rebuild. Matched to the mesh by the material's
161
+ * uuid, which the SDK stamps through the exporter the same way object ids
162
+ * are.
163
+ */
164
+ type MaterialShaderSpec = {
165
+ materialId: string;
166
+ name?: string;
167
+ /** Which BSDF family the material declared. */
168
+ base: 'standard' | 'physical' | 'basic';
169
+ properties?: ShaderMaterialProperties;
170
+ graph: ShaderGraph;
171
+ };
172
+
173
+ /**
174
+ * The scene manifest: a GLB plus a versioned sidecar.
175
+ *
176
+ * glTF carries geometry, materials, textures, cameras, lights, skins and
177
+ * morph targets well. What it does not carry is the state the running
178
+ * application was in at the moment somebody pressed Render: which objects
179
+ * were hidden, which of four cameras was live, what the renderer's tone
180
+ * mapping was set to, which materials the SDK could not translate and what
181
+ * the developer wants done about them. So the GLB is an asset and this is
182
+ * the contract. `protocolVersion` is versioned independently of the SDK, of
183
+ * the renderer and of the material translator, which is what makes a render
184
+ * from six months ago reproducible.
185
+ *
186
+ * Everything here is JSON (no class instances, no functions) because it
187
+ * travels from the browser through the control plane to the render worker
188
+ * and is stored verbatim for replay.
189
+ */
190
+
191
+ /** `sha256:<64 hex>`: how every immutable blob is named. See asset.ts. */
192
+ type AssetHash = string;
193
+ type Vec3 = [number, number, number];
194
+ /** glTF order: x, y, z, w. Any conversion to another order happens in the worker. */
195
+ type Quat = [number, number, number, number];
196
+ type Matrix4 = number[];
197
+ /**
198
+ * The active camera.
199
+ *
200
+ * Written out in full rather than referenced into the GLB by name: a live
201
+ * R3F camera is frequently not in the scene graph the exporter walked (it
202
+ * is held by `useThree`, or by drei's controls), so it travels as data.
203
+ */
204
+ type CameraSpec = {
205
+ type: 'perspective';
206
+ /** Vertical FOV in degrees, matching three's `PerspectiveCamera.fov`. */
207
+ fov: number;
208
+ /**
209
+ * The viewport's aspect ratio at capture time.
210
+ *
211
+ * The render matches vertical fov, so a wider output shows more at the
212
+ * sides rather than cropping the top and bottom. Recorded so the
213
+ * control plane can default the output to the viewport's own shape.
214
+ */
215
+ aspect?: number;
216
+ near: number;
217
+ far: number;
218
+ position: Vec3;
219
+ quaternion: Quat;
220
+ /** three's `.zoom`, which scales the projection and is easy to forget. */
221
+ zoom?: number;
222
+ /** Present when the developer named a camera; only ever a label. */
223
+ name?: string;
224
+ /**
225
+ * Depth of field, off unless present. `fStop` is a full-frame f-number
226
+ * at this `fov`; `focalDistance` is in metres along the view axis.
227
+ * `target` is the world point it was measured to: a worker that reads
228
+ * it keeps that point sharp on every frame of a clip, and one that
229
+ * does not still focuses the first frame right.
230
+ */
231
+ focus?: {
232
+ fStop: number;
233
+ focalDistance: number;
234
+ target?: Vec3;
235
+ };
236
+ } | {
237
+ type: 'orthographic';
238
+ left: number;
239
+ right: number;
240
+ top: number;
241
+ bottom: number;
242
+ near: number;
243
+ far: number;
244
+ position: Vec3;
245
+ quaternion: Quat;
246
+ zoom?: number;
247
+ name?: string;
248
+ };
249
+ /**
250
+ * What the application had done to the scene by render time.
251
+ *
252
+ * Visibility is an explicit hidden list rather than "export only what is
253
+ * visible" on purpose: the GLB is content-addressed and cached, and a
254
+ * configurator that toggles one part between renders would otherwise miss
255
+ * the cache every time. Ship one GLB with every variant in it, then hide
256
+ * per render: the first render uploads the model, the next one uploads a
257
+ * few KB.
258
+ */
259
+ type RuntimeState = {
260
+ /** Object ids (see `objectId` in capture) the SDK found with `visible === false`. */
261
+ hiddenObjectIds?: string[];
262
+ /**
263
+ * Transform overrides, for objects the application moved after export or
264
+ * that were exported from a shared cached GLB.
265
+ */
266
+ transforms?: Array<{
267
+ objectId: string;
268
+ position?: Vec3;
269
+ quaternion?: Quat;
270
+ scale?: Vec3;
271
+ }>;
272
+ /** Morph target influences, by object. */
273
+ morphs?: Array<{
274
+ objectId: string;
275
+ influences: number[];
276
+ }>;
277
+ /** Current skeletal pose as bone-local matrices. */
278
+ poses?: Array<{
279
+ objectId: string;
280
+ boneMatrices: Matrix4[];
281
+ }>;
282
+ /**
283
+ * `InstancedMesh` transforms. Written here rather than baked into the GLB
284
+ * so changing a layout does not re-upload the geometry.
285
+ *
286
+ * `matrices` is flat: `count * 16` numbers, column-major, exactly as three
287
+ * stores `instanceMatrix.array`. Nested arrays would add two bytes of JSON
288
+ * per instance, which for a large scatter is a measurable part of the
289
+ * manifest.
290
+ */
291
+ instances?: Array<{
292
+ objectId: string;
293
+ count: number;
294
+ matrices: number[];
295
+ }>;
296
+ /**
297
+ * Opaque application state, echoed back on the render record. Never read
298
+ * by the renderer; it exists so a stored render can say which sofa.
299
+ */
300
+ productState?: Record<string, unknown>;
301
+ };
302
+ type EnvironmentSpec = {
303
+ /** An HDRI/EXR the SDK found on `scene.environment`, content-addressed. */
304
+ hdri?: AssetHash;
305
+ /** three's `Scene.environmentIntensity`. */
306
+ intensity?: number;
307
+ /** three's `Scene.environmentRotation`, radians, XYZ euler. */
308
+ rotation?: Vec3;
309
+ /**
310
+ * The scene's `AmbientLight`s as one flat term. It ADDS to the HDRI, as it
311
+ * does in three, and like three's it lights diffuse surfaces only: a
312
+ * mirror reflects the environment and nothing of this.
313
+ */
314
+ ambient?: {
315
+ color: string;
316
+ intensity: number;
317
+ };
318
+ /**
319
+ * Background. `transparent` is the default: a still that composites is
320
+ * worth more to a catalog pipeline than one with a baked backdrop.
321
+ */
322
+ background?: {
323
+ type: 'transparent';
324
+ } | {
325
+ type: 'color';
326
+ color: string;
327
+ } | {
328
+ type: 'environment';
329
+ blurriness?: number;
330
+ };
331
+ /** The scene's fog, when it has one the renderer can trace. */
332
+ fog?: FogSpec;
333
+ };
334
+ /**
335
+ * three's `FogExp2`, which the renderer traces as a volume filling the scene:
336
+ * air that scatters the light passing through it, so a lamp or an emissive
337
+ * mesh sits in a glow and throws visible beams.
338
+ *
339
+ * `density` is three's own number. three fades a surface by
340
+ * `exp(-(density · d)²)`; a real volume thins light by `exp(-σ · d)`. The
341
+ * two cannot agree at every distance, so the renderer uses σ = `density`,
342
+ * which makes them agree where three's fog has taken all but 1/e of the
343
+ * surface: nearer than that the render is a little foggier than the
344
+ * viewport, further a little clearer.
345
+ *
346
+ * `color` is the fog's TINT (`#rrggbb`, as three holds it): its hue colors
347
+ * the scattered light, its brightness is ignored. How bright traced fog
348
+ * looks is decided by the light in it, which a rasterizer's fog color has to
349
+ * guess. A linear `Fog` has no volume it corresponds to and is not carried;
350
+ * the compatibility report says so.
351
+ */
352
+ type FogSpec = {
353
+ color: string;
354
+ density: number;
355
+ };
356
+ /**
357
+ * Lights the SDK lifted out of the scene graph.
358
+ *
359
+ * Exported here as well as in the GLB because glTF's punctual-lights
360
+ * extension has no notion of three's intensity-unit drift, no area lights
361
+ * and no IES. The sidecar is where the good version lives and the GLB copy
362
+ * is the fallback.
363
+ */
364
+ type LightSpec = {
365
+ objectId: string;
366
+ type: 'directional' | 'point' | 'spot' | 'area' | 'hemisphere';
367
+ color: string;
368
+ /**
369
+ * three's own value, unconverted. The worker owns the unit conversion so
370
+ * the physics is written down in one place.
371
+ */
372
+ intensity: number;
373
+ /**
374
+ * World position. A hemisphere light's is its up axis instead (three
375
+ * normalizes it; absent is `[0, 1, 0]`).
376
+ */
377
+ position?: Vec3;
378
+ /**
379
+ * World point a directional, spot or area light aims at, as three's
380
+ * `light.target` (or `lookAt`) does. Absent aims a directional or spot
381
+ * light at the origin and leaves an area light facing straight down.
382
+ */
383
+ target?: Vec3;
384
+ /**
385
+ * Hemisphere lights only: the color from below (`groundColor`). `color` is
386
+ * the sky. Absent is black, a sky with no ground bounce.
387
+ */
388
+ groundColor?: string;
389
+ distance?: number;
390
+ decay?: number;
391
+ angle?: number;
392
+ penumbra?: number;
393
+ /** Area lights only, in world units. */
394
+ size?: {
395
+ width: number;
396
+ height: number;
397
+ };
398
+ /** Angular diameter in degrees: the shadow-softness dial for a sun. */
399
+ angleDeg?: number;
400
+ /** An IES profile, content-addressed. */
401
+ ies?: AssetHash;
402
+ castShadow?: boolean;
403
+ };
404
+ /**
405
+ * The renderer's own color settings, copied verbatim.
406
+ *
407
+ * This is the difference between a render that looks like the developer's
408
+ * app and one that is subtly, unfixably wrong. three's defaults changed in
409
+ * r152 and again in r155; reading the live renderer beats assuming any of
410
+ * them.
411
+ */
412
+ type ColorSpec = {
413
+ outputColorSpace: 'srgb' | 'srgb-linear' | 'display-p3';
414
+ toneMapping: 'none' | 'linear' | 'reinhard' | 'cineon' | 'aces-filmic' | 'agx' | 'neutral';
415
+ toneMappingExposure: number;
416
+ };
417
+ /**
418
+ * What to do with a material the renderer cannot be given honestly.
419
+ *
420
+ * Arbitrary GLSL does not translate, and the answer is to say so rather
421
+ * than quietly render gray. A fallback is the developer's explicit
422
+ * override, from `<Bakery3Material render={...}>` or from
423
+ * `material.userData.bakery3.fallback`.
424
+ */
425
+ type MaterialFallback = {
426
+ /** The material's uuid in the exported GLB. */
427
+ materialId: string;
428
+ type: 'physical';
429
+ color?: string;
430
+ metalness?: number;
431
+ roughness?: number;
432
+ clearcoat?: number;
433
+ clearcoatRoughness?: number;
434
+ transmission?: number;
435
+ thickness?: number;
436
+ ior?: number;
437
+ emissive?: string;
438
+ emissiveIntensity?: number;
439
+ opacity?: number;
440
+ sheen?: number;
441
+ sheenColor?: string;
442
+ iridescence?: number;
443
+ anisotropy?: number;
444
+ };
445
+ type CompatibilitySeverity = 'info' | 'warning' | 'error';
446
+ /**
447
+ * One thing the SDK could not promise to reproduce: what it is, where it
448
+ * lives in the tree, why, and the fix, without opening a debugger.
449
+ */
450
+ type CompatibilityIssue = {
451
+ code: string;
452
+ severity: CompatibilitySeverity;
453
+ message: string;
454
+ /** `<Car>/<Body>/<Paint>`: the path a developer can actually find. */
455
+ path?: string;
456
+ objectId?: string;
457
+ materialId?: string;
458
+ materialName?: string;
459
+ materialType?: string;
460
+ /** Deep link into the docs. */
461
+ docs?: string;
462
+ };
463
+ type CompatibilityReport = {
464
+ /** 0 to 1. Objects that will render faithfully, weighted by triangle count. */
465
+ score: number;
466
+ issues: CompatibilityIssue[];
467
+ /** Rolled up for the devtools panel and the render record. */
468
+ counts: {
469
+ info: number;
470
+ warning: number;
471
+ error: number;
472
+ };
473
+ };
474
+ /** Presets, not raw renderer settings. Most scenes need only these. */
475
+ type QualityPreset = 'preview' | 'studio' | 'ultra';
476
+ type OutputFormat = 'png' | 'jpeg' | 'webp' | 'exr' | 'mp4' | 'webm' | 'png-sequence';
477
+ /** `frames.json`, at the head of a `png-sequence` tar. */
478
+ type FrameSequenceIndex = {
479
+ fps: number;
480
+ frameCount: number;
481
+ width: number;
482
+ height: number;
483
+ bitDepth: 8 | 16;
484
+ /** In frame order, one per frame: `frameFileName(0)` onwards. */
485
+ files: string[];
486
+ };
487
+ type OutputSpec = {
488
+ width: number;
489
+ height: number;
490
+ format: OutputFormat;
491
+ /** JPEG/WebP only, 1 to 100. */
492
+ quality?: number;
493
+ /**
494
+ * PNG and `png-sequence` only: bits per channel, 16 unless 8 is asked
495
+ * for (`PNG_BIT_DEPTH_DEFAULT`).
496
+ */
497
+ bitDepth?: 8 | 16;
498
+ /** Force an opaque background even when the environment is transparent. */
499
+ opaque?: boolean;
500
+ };
501
+ /**
502
+ * Escape hatch under the presets. Present so an expert is never blocked,
503
+ * absent from the quickstart so a beginner is never asked to become a
504
+ * rendering expert to get one image.
505
+ */
506
+ type AdvancedRenderSettings = {
507
+ samples?: number;
508
+ maxBounces?: number;
509
+ diffuseBounces?: number;
510
+ glossyBounces?: number;
511
+ transmissionBounces?: number;
512
+ /** Adaptive sampling noise floor: the real cost dial once denoising is on. */
513
+ adaptiveThreshold?: number;
514
+ denoise?: boolean;
515
+ denoiser?: 'OPTIX' | 'OPENIMAGEDENOISE';
516
+ /** Pays for itself with many emitters, costs overhead with few. */
517
+ lightTree?: boolean;
518
+ /**
519
+ * Light that reaches a surface through glass: the bright pool under a
520
+ * tumbler, the focus line beneath a lens. Off by default: with no caustic
521
+ * paths a transmissive object casts a solid shadow, which is also what the
522
+ * viewport's shadow maps draw, and tracing them costs samples a product
523
+ * shot rarely needs.
524
+ *
525
+ * `'soft'` lets the path tracer find caustic paths itself, with the glossy
526
+ * filter and the indirect clamp (both of which exist to hide caustics)
527
+ * switched off. Unbiased, and slow to converge: a hard light through
528
+ * curved glass stays grainy at studio samples.
529
+ *
530
+ * `'sharp'` adds a dedicated shadow-caustic solver on top: every scene
531
+ * lamp casts caustics, every transmissive mesh is a caster, and every
532
+ * other mesh (the shadow catcher included) receives them. This is what
533
+ * makes a glass on a table converge at normal sample counts. It handles a
534
+ * single refractive object between a lamp and a surface; light from an
535
+ * HDRI or an emissive mesh still goes the `'soft'` way.
536
+ *
537
+ * The solver takes over lamp light through a caster rather than adding to
538
+ * the traced paths, and it only follows light that goes straight through.
539
+ * A faceted stone, whose light leaves after internal reflections, comes
540
+ * back under `'sharp'` with no caustic at all. Cut gems want `'soft'`.
541
+ *
542
+ * Absent is off. There is no boolean on purpose: `caustics: true` would
543
+ * have to mean one of the two. Changes pixels, so it is in the cache key.
544
+ */
545
+ caustics?: 'soft' | 'sharp';
546
+ /**
547
+ * A ceiling on how bright one indirect sample may be, in scene radiance.
548
+ * Absent is the renderer's own default, which `caustics` switches off: a
549
+ * caustic's focus is a very bright indirect sample, and capping it dims
550
+ * the focus. That is right for a still and wrong for a clip, because the
551
+ * rare uncapped hit lands on different pixels every frame, the denoiser
552
+ * smears each one into a soft patch, and the patches boil. For caustics
553
+ * in motion, start at 30 (the pool under a lens is still its full
554
+ * brightness there) and trace larger than you publish.
555
+ *
556
+ * Set, it wins over what `caustics` would have chosen. Changes pixels, so
557
+ * it is in the cache key, present only when set.
558
+ */
559
+ clampIndirect?: number;
560
+ /**
561
+ * Multiplies the converted energy of every light lifted from the scene
562
+ * graph (directional, point, spot, area and the ambient dome) and leaves
563
+ * the HDRI environment alone. The worker's unit table is physics and stays
564
+ * fixed; this dial is for the residual gap, where a viewport (legacy-lights
565
+ * intensities, usually) reads brighter than the physically converted lamps
566
+ * do. One scalar, so the ratio between the scene's lights is preserved.
567
+ * Default 1. Changes pixels, so it is in the cache key.
568
+ */
569
+ lightScale?: number;
570
+ /**
571
+ * Ground the product with a traced shadow catcher. Defaults on for
572
+ * transparent/solid output and off for a visible environment background.
573
+ */
574
+ shadowCatcher?: boolean;
575
+ /** Catcher size, as a multiple of the model's largest dimension. */
576
+ shadowPad?: number;
577
+ /**
578
+ * The renderer's view transform override. Changes pixels, so it is in the
579
+ * cache key. Pinning one also switches off `toneCurveEmulation`: an
580
+ * explicit name is a statement about what the render should look like.
581
+ */
582
+ viewTransform?: string;
583
+ /**
584
+ * Reproduce three's tone mapping exactly instead of substituting the
585
+ * nearest native view transform. On by default, and it is what makes a
586
+ * traced frame the same color as the viewport it came from.
587
+ *
588
+ * Turn it off to get the substitution: a wider, more forgiving curve for a
589
+ * scene whose viewport was never the reference. Changes pixels, so it is
590
+ * in the cache key.
591
+ */
592
+ toneCurveEmulation?: boolean;
593
+ /** Seconds. The worker stops the render rather than billing an unbounded job. */
594
+ timeoutSeconds?: number;
595
+ };
596
+ /**
597
+ * Everything one render needs, minus the bytes.
598
+ *
599
+ * Typically a few KB. The heavy things (the GLB, textures, the HDRI) are
600
+ * `sha256:` references that the control plane resolves against storage the
601
+ * SDK already filled (see asset.ts).
602
+ */
603
+ type SceneManifest = {
604
+ protocolVersion: string;
605
+ sdkVersion: string;
606
+ /** The exported GLB. */
607
+ sceneAsset: AssetHash;
608
+ /**
609
+ * Extra blobs this scene needs that are not inside the GLB: an HDRI, an
610
+ * IES profile, a texture the SDK stripped out to keep the GLB cacheable.
611
+ */
612
+ assets?: AssetHash[];
613
+ camera: CameraSpec;
614
+ runtime?: RuntimeState;
615
+ environment?: EnvironmentSpec;
616
+ lights?: LightSpec[];
617
+ color: ColorSpec;
618
+ fallbacks?: MaterialFallback[];
619
+ /**
620
+ * Node materials, as portable shader graphs (see shader.ts). The GLB still
621
+ * carries the mesh; the material the exporter wrote for it is a stand-in
622
+ * that the worker replaces wholesale with the rebuilt graph.
623
+ */
624
+ shaders?: MaterialShaderSpec[];
625
+ /**
626
+ * Baked per-frame motion (see animation.ts). Present only for a video,
627
+ * and its presence is what makes this a 3.0 manifest.
628
+ *
629
+ * Not inside `runtime` on purpose: runtime is the one state the
630
+ * application was in when Render was pressed, and every field in it is a
631
+ * single value. A sequence is a different kind of thing.
632
+ */
633
+ animation?: AnimationSpec;
634
+ /**
635
+ * A room preset around the product (see room.ts). Its geometry, lights
636
+ * and sky are not in the GLB or in `lights`: the worker rebuilds all of it
637
+ * from the published definition, so a product in a room uploads only the
638
+ * product. Presence makes this a 4.0 manifest.
639
+ */
640
+ room?: RoomPresetSpec;
641
+ compatibility?: CompatibilityReport;
642
+ /**
643
+ * What the scene weighs, measured by the SDK at capture. The control plane
644
+ * prices with it (a dense scene traces slower per pixel and unwraps slower
645
+ * per object), so the quote a job is accepted under is the same one
646
+ * `estimate()` gave with the same numbers. Operational, not visual: it is
647
+ * outside every cache key.
648
+ */
649
+ stats?: {
650
+ triangles: number;
651
+ /** Bytes of texture the manifest's shader graphs sample, when known. */
652
+ textureBytes?: number;
653
+ /**
654
+ * Distinct materials that emit light: a standard material with a
655
+ * non-black emissive color, an unlit material (rendered as emission), or
656
+ * a node material with an emission graph. The worker turns its light
657
+ * tree on from this. Only the SDK can count them, since the GLB's
658
+ * materials are opaque to the control plane.
659
+ */
660
+ emitters?: number;
661
+ /**
662
+ * How much of the sky above the camera the scene's geometry hides, 0 for
663
+ * an open set and 1 inside a closed room (`SceneComplexity`). Walls keep
664
+ * light bouncing, which is most of what makes an interior slow to render,
665
+ * so the quote reads it. A preset room's stand-in counts, though it is not
666
+ * uploaded: it stands for the room the renderer builds.
667
+ */
668
+ enclosure?: number;
669
+ /** Meshes the scene draws, instances counted: how full it is. */
670
+ objects?: number;
671
+ };
672
+ /**
673
+ * Where the scene came from. Diagnostics only, but "which three version"
674
+ * is the first question every support conversation starts with.
675
+ */
676
+ source?: {
677
+ three?: string;
678
+ r3f?: string;
679
+ renderer?: string;
680
+ userAgent?: string;
681
+ };
682
+ };
683
+ /** A manifest plus what to make from it. This is the render request body. */
684
+ type RenderSpec = {
685
+ manifest: SceneManifest;
686
+ quality: QualityPreset;
687
+ output: OutputSpec;
688
+ advanced?: AdvancedRenderSettings;
689
+ /**
690
+ * Hard ceiling in USD. Exceeded at estimate time means the job is refused
691
+ * before it is admitted: `RenderBudgetExceeded`, not a surprise bill.
692
+ */
693
+ maxCost?: number;
694
+ /** Emit a low-sample preview partway through. On by default for `studio`. */
695
+ preview?: boolean;
696
+ /** Echoed on the render record and every webhook. */
697
+ metadata?: Record<string, unknown>;
698
+ /**
699
+ * A resubmit with the same key returns the existing render while it is
700
+ * running or once it has completed, never a second charge. This is what
701
+ * makes the SDK's own retries safe. A key whose render failed, was
702
+ * cancelled or expired is free again: nothing was charged, and the
703
+ * resubmit renders.
704
+ */
705
+ idempotencyKey?: string;
706
+ /**
707
+ * `high` puts this render ahead of the account's other waiting work in
708
+ * the same lane: the hero shot before the rest of the queue. It never
709
+ * jumps a lane; a person waiting still goes first.
710
+ */
711
+ priority?: 'normal' | 'high';
712
+ };
713
+
714
+ /**
715
+ * The texel ceiling for one bake, enforced at estimate time before any GPU
716
+ * time is bought. Texels drive a bake's cost the way frames drive a video's;
717
+ * 32M texels is a full room at sensible resolutions.
718
+ */
719
+ declare const MAX_BAKE_TEXELS: number;
720
+ /**
721
+ * The object-count ceiling for one bake job. A request past it is refused,
722
+ * never sampled down.
723
+ */
724
+ declare const MAX_BAKE_OBJECTS = 256;
725
+ /**
726
+ * How good a bake should be. The worker chooses sample counts and margins
727
+ * from this, the way `QualityPreset` maps to `QualitySettings`.
728
+ */
729
+ type BakeQuality = 'preview' | 'standard' | 'high';
730
+ /** The sides a lightmap or a stand-in texture may have, in texels. */
731
+ declare const BAKE_TEXTURE_SIZES: readonly [256, 512, 1024, 2048];
732
+ type BakeTextureSize = (typeof BAKE_TEXTURE_SIZES)[number];
733
+ /** Atlas sides. 4096² is 16.8M texels, inside the texel ceiling on its own. */
734
+ declare const BAKE_ATLAS_SIZES: readonly [1024, 2048, 4096];
735
+ type BakeAtlasSize = (typeof BAKE_ATLAS_SIZES)[number];
736
+ /**
737
+ * One lightmap for every baked object, rather than one each.
738
+ *
739
+ * A room of sixty objects lit from sixty textures is sixty texture binds and
740
+ * sixty downloads; lit from one atlas it is one of each, which is what an
741
+ * interactive scene wants. The atlas holds the same texels the separate maps
742
+ * would, and is priced as they are.
743
+ *
744
+ * Every object is baked into a square of its own: the side its world-space
745
+ * surface earns, capped by `textureSize` and `sizes` as usual, times the
746
+ * square root of its `weight`, rounded to a power of two. The squares are
747
+ * laid into the map with no waste, and the map is filled: when the squares
748
+ * would cover under a quarter of it every side doubles, and when they would
749
+ * not fit the largest are halved until they do. So `textureSize`, `sizes`
750
+ * and `weights` set relative shares, kept to within a power of two, and
751
+ * `size` sets the texels there are to share.
752
+ *
753
+ * A hero product is `weights: { [heroId]: 4 }`: twice the side and four times
754
+ * the area its surface alone would earn. Weights round to the nearest power
755
+ * of two in side: 1.5 to 2.8 doubles it, 2.9 to 5.6 quadruples it.
756
+ */
757
+ type BakeAtlas = {
758
+ size: BakeAtlasSize;
759
+ /** Per-object density multipliers, keyed by objectId. Default 1. */
760
+ weights?: Record<string, number>;
761
+ };
762
+ /**
763
+ * What a group of objects is replaced with in the baked scene.
764
+ *
765
+ * A lightmap keeps the developer's geometry and changes its light. That is
766
+ * right for a product and wrong for a bookcase of forty books at the back of
767
+ * the room: forty draw calls, forty lightmaps and forty unwraps to light
768
+ * something the viewer reads as one lit shape. A stand-in is that one shape,
769
+ * with the detail it lost baked on: the color of the surface it replaces, a
770
+ * normal map for the relief it no longer has, and the irradiance traced at
771
+ * the real surface. The real objects stay in the traced scene, so they still
772
+ * cast their shadows and bounce their light onto everything else; they are
773
+ * only absent from what is delivered.
774
+ *
775
+ * `'lowpoly'` the objects, shrink-wrapped into one skin and reduced to
776
+ * `triangles`. The default.
777
+ * `'box'` the box round them, turned about the vertical to fit.
778
+ * Right for anything that reads as a box from where it is
779
+ * seen: a bookcase, a cabinet, a radiator.
780
+ * `'billboard'` one upright picture of them that turns to face the
781
+ * camera. For a potted plant: half a million triangles of
782
+ * leaves that no lightmap suits and no box resembles.
783
+ * `{ objectId }` a mesh of the developer's own, in the captured scene and
784
+ * hidden (so nothing traces it), used as the stand-in's
785
+ * shape exactly as authored.
786
+ * `'decimate'` one object, the same object with fewer triangles: its own
787
+ * parts, silhouette, texture uvs and materials kept, reduced
788
+ * to `triangles` by collapsing edges. For the product itself
789
+ * (a 146k-triangle shoe), where a skin would melt laces and
790
+ * eyelets together and a baked color would turn metal and
791
+ * gloss into paint. Only its light is baked, in one pass at
792
+ * the real surface; the stand-in wears the replaced object's
793
+ * own materials at their own resolution. One entry per
794
+ * object.
795
+ */
796
+ type BakeSimplifyTo = 'lowpoly' | 'box' | 'billboard' | 'decimate' | {
797
+ objectId: string;
798
+ };
799
+ type BakeSimplify = {
800
+ /**
801
+ * objectIds the stand-in replaces. They are not in `include`: a replaced
802
+ * object gets no lightmap of its own, which is where the saving is.
803
+ */
804
+ objects: string[];
805
+ to: BakeSimplifyTo;
806
+ /** `'lowpoly'` only: the triangle budget. Default `BAKE_SIMPLIFY_TRIANGLES`. */
807
+ triangles?: number;
808
+ /** The stand-in's texture side. Default `textureSize`. */
809
+ textureSize?: BakeTextureSize;
810
+ };
811
+ /**
812
+ * A plane under the baked objects carrying the difference they make to the
813
+ * light on it, and nothing else.
814
+ *
815
+ * A preset room is the same room for every customer, so its lightmaps are a
816
+ * library asset, baked once and served from the preset library
817
+ * (`BakeBundle.room`). What that prebaked room cannot know is the product
818
+ * standing in it: the contact shadow under a vase is what makes it look like
819
+ * it is in the room rather than pasted over it.
820
+ *
821
+ * So the bake traces one small plane just above the floor twice, with the
822
+ * product and its stand present and again with them hidden, and ships the
823
+ * ratio: 1 where they changed nothing, darker where they blocked light. The
824
+ * viewer lays it over the floor and multiplies. A ratio, not irradiance,
825
+ * because it has to compose with a floor lightmap traced at another time and
826
+ * another resolution.
827
+ *
828
+ * It only darkens. Light the product throws onto the floor (a red vase's
829
+ * bounce) is in neither the prebaked room nor this plane; that is the
830
+ * approximation this mode makes.
831
+ */
832
+ type BakeShadow = {
833
+ /**
834
+ * Scene units, Y-up: the plane's centre, on the surface it lies over.
835
+ *
836
+ * Absent is the usual case: the worker measures the footprint of whatever
837
+ * casts, then finds the surface beneath with rays cast straight down and
838
+ * the casters hidden. A plinth is often modelled a centimetre into the
839
+ * floor, so the bottom of its bounds is inside the slab, where a plane
840
+ * would be lit in neither trace.
841
+ */
842
+ center?: [number, number, number];
843
+ /**
844
+ * Metres. Absent takes the casters' footprint plus the room a shadow needs
845
+ * to spread into.
846
+ */
847
+ width?: number;
848
+ height?: number;
849
+ /**
850
+ * How far above the surface the plane sits, in metres. Small enough to
851
+ * read as contact, large enough that nothing z-fights with the floor.
852
+ */
853
+ lift?: number;
854
+ /** Texels a side. Default `BAKE_SHADOW_SIZE`. */
855
+ textureSize?: BakeTextureSize;
856
+ /**
857
+ * objectIds whose shadow this is: hidden for the second trace. Absent
858
+ * means every object the bake includes.
859
+ */
860
+ cast?: string[];
861
+ /**
862
+ * objectIds the plane is placed beneath and sized to cover. Absent means
863
+ * the casters, which is the usual case.
864
+ *
865
+ * The two lists come apart when a product stands on something this bake is
866
+ * lightmapping anyway. A vase on a plinth casts on the plinth's top, and
867
+ * the plinth's own lightmap carries that. What the plinth must not do is
868
+ * cast into this plane: the prebaked room was lit with the plinth standing
869
+ * in it, so its shadow is already on that floor, and casting it again
870
+ * would lay it down twice.
871
+ *
872
+ * So the plinth spans but does not cast. It is present in both traces and
873
+ * divides out of the ratio exactly, leaving only what the vase adds; and
874
+ * because it is hidden while the surface beneath is looked for, the plane
875
+ * still lands on the floor rather than on the plinth's top.
876
+ */
877
+ spans?: string[];
878
+ };
879
+ /**
880
+ * What the bake produced for `BakeSettings.shadow`.
881
+ *
882
+ * `uri` is a ratio in 0..1 per channel, linear, one value per texel: what
883
+ * fraction of the light still arrives with the product there. Lay the plane
884
+ * at `center` + `lift` on its up axis, map this across it, and multiply.
885
+ */
886
+ type BakedShadow = {
887
+ uri: string;
888
+ format: 'exr' | 'png';
889
+ size: number;
890
+ center: [number, number, number];
891
+ width: number;
892
+ height: number;
893
+ lift: number;
894
+ /**
895
+ * The darkest ratio in the map, for a panel and for a sanity check: a
896
+ * shadow that came out 1.0 everywhere means nothing was cast.
897
+ */
898
+ darkest: number;
899
+ };
900
+ /**
901
+ * What to bake and how well.
902
+ *
903
+ * `include` is explicit and authoritative: the SDK decides which objects can
904
+ * take a lightmap (it can see the live materials; the worker cannot) and the
905
+ * worker bakes exactly that list. An id the worker cannot find is a refusal
906
+ * with the id and a fix, never a silent skip.
907
+ */
908
+ type BakeSettings = {
909
+ quality: BakeQuality;
910
+ /**
911
+ * Per-object resolution ceiling. The worker may choose a smaller size for
912
+ * a small object (by world-space surface area) so a screw does not cost
913
+ * what a wall costs. It never chooses larger.
914
+ */
915
+ textureSize: BakeTextureSize;
916
+ /** objectIds to bake, from the same id space as `RuntimeState`. */
917
+ include: string[];
918
+ /** Per-object override of `textureSize`, keyed by objectId. */
919
+ sizes?: Record<string, BakeTextureSize>;
920
+ /**
921
+ * Bake every object into one shared lightmap of `atlas.size`² texels
922
+ * instead of one texture each: see `BakeAtlas`. `textureSize` and `sizes`
923
+ * then set each object's relative share of the map rather than its own
924
+ * texture.
925
+ */
926
+ atlas?: BakeAtlas;
927
+ /** Seam dilation in pixels. Default 4. */
928
+ margin?: number;
929
+ /**
930
+ * Also produce the portable baked GLB: every baked object with an unlit
931
+ * material (`KHR_materials_unlit`) whose one texture is the finished
932
+ * surface (color, direct and bounced light, reflections as seen from
933
+ * `view`, through the scene's tone curve). Loads anywhere with no lights
934
+ * and no SDK. A second bake pass per object, so it roughly doubles GPU
935
+ * time and is opt-in.
936
+ */
937
+ deliverGlb?: boolean;
938
+ /**
939
+ * Objects whose `uv1` is the developer's own layout, not one a previous
940
+ * bake wrote. Present, the worker may use an object's own layout instead
941
+ * of unwrapping it: its `uv1` when listed here, its texture `uv` when the
942
+ * mesh is too fragmented or too dense to unwrap well. Either is used only
943
+ * when it passes the worker's test (inside the unit square, no stacked
944
+ * islands, enough texels an island, an even density), and the result says
945
+ * so with `BakeUv` `channel`. Absent, every object is unwrapped.
946
+ */
947
+ existingUv?: {
948
+ uv1: string[];
949
+ };
950
+ /**
951
+ * Where the scene is looked at from, for seam placement only.
952
+ *
953
+ * The unwrap puts island boundaries on the side of each object that faces
954
+ * away from this point, on its underside, or where it is hidden behind
955
+ * other geometry, never across the surface this viewpoint sees. Nothing
956
+ * about the lighting depends on it.
957
+ *
958
+ * It is not the manifest camera. The camera is excluded from the bake
959
+ * cache key so that orbiting and baking again is free, and a seam layout
960
+ * that followed the exact camera would make every orbit a re-cut. The SDK
961
+ * sends the camera quantized (`quantizeBakeView`): direction in 30° steps,
962
+ * distance in octaves around the baked objects, so nearby viewpoints share
963
+ * a bake and only a real change of side re-cuts.
964
+ *
965
+ * Absent: seams prefer the underside and hard edges alone.
966
+ */
967
+ view?: BakeView;
968
+ /**
969
+ * Where the reflection probe is taken, and what is hidden from it.
970
+ *
971
+ * Every bake delivers one. The lightmap replaces a baked surface's
972
+ * diffuse, but the objects the bake is for (the product kept live on its
973
+ * plinth, so it can turn and change finish) still reflect the scene's own
974
+ * environment map, which in a baked room is not the room. The probe is the
975
+ * room as seen from where those objects stand, with those objects hidden
976
+ * so they do not reflect themselves, and the SDK puts it on their
977
+ * materials as `envMap`.
978
+ *
979
+ * The SDK decides both fields: the objects it hides are the ones that
980
+ * could have been baked and were deliberately left out. An object that
981
+ * cannot take a lightmap at all (a glass sphere, an instanced hedge) is
982
+ * scenery and stays in the map, so the product reflects the glass beside
983
+ * it. Absent, the worker takes the probe from the center of the baked
984
+ * objects and hides nothing.
985
+ */
986
+ probe?: BakeProbe;
987
+ /**
988
+ * Groups of objects to deliver as a stand-in rather than light as they
989
+ * are: see `BakeSimplify`. In request order; stand-in `n` of the bundle is
990
+ * entry `n` here.
991
+ */
992
+ simplify?: BakeSimplify[];
993
+ /**
994
+ * Trace a shadow plane under the baked objects: see `BakeShadow`. What a
995
+ * bake of a product standing in a prebaked room needs, and the only part
996
+ * of that room the bake has to pay for.
997
+ */
998
+ shadow?: BakeShadow;
999
+ /**
1000
+ * How a preset room in the scene is lit.
1001
+ *
1002
+ * `'full'` (the default) bakes the room's own surfaces along with
1003
+ * everything else.
1004
+ *
1005
+ * `'preset'` says the room is unmodified, so its lightmaps are a library
1006
+ * asset and this bake covers only what the library cannot know: the
1007
+ * product, the stand it is on, and the shadow it casts. The SDK only asks
1008
+ * for it when the room really is unmodified, and the worker records which
1009
+ * room the result stands on (`BakeBundle.room`).
1010
+ */
1011
+ room?: 'full' | 'preset';
1012
+ };
1013
+ /** A viewpoint, in the scene's own (Y-up, meters) coordinates. */
1014
+ type BakeView = {
1015
+ position: [number, number, number];
1016
+ };
1017
+ /** The reflection probe's request: where, and what not to see. */
1018
+ type BakeProbe = {
1019
+ /** Scene units, Y-up: the center of the objects the probe is for. */
1020
+ position: [number, number, number];
1021
+ /** objectIds hidden from the probe: the objects it will be applied to. */
1022
+ hide: string[];
1023
+ };
1024
+ /**
1025
+ * A manifest plus what to bake from it: the bake request body. The manifest
1026
+ * is the ordinary capture, camera included but unused by the bake itself, so
1027
+ * two captures that differ only by viewpoint hit the same bake cache entry.
1028
+ */
1029
+ type BakeSpec = {
1030
+ manifest: SceneManifest;
1031
+ bake: BakeSettings;
1032
+ advanced?: {
1033
+ timeoutSeconds?: number;
1034
+ };
1035
+ /**
1036
+ * Triangles in the objects `bake.include` names, for the quote only.
1037
+ *
1038
+ * The estimate has two triangle terms: syncing the whole scene (priced from
1039
+ * the manifest's own count) and unwrapping the objects being baked (priced
1040
+ * from this). Without it the unwrap term is priced against the whole
1041
+ * scene, which over-quotes a partial bake of a big room. The SDK sends it;
1042
+ * a request without it is quoted the higher way.
1043
+ *
1044
+ * Deliberately not inside `bake`: that object is the bake cache key, and a
1045
+ * number that only moves a price must not move what is cached.
1046
+ */
1047
+ bakedTriangles?: number;
1048
+ /**
1049
+ * Hard ceiling in USD, refused at estimate time. The same contract as
1050
+ * `RenderSpec.maxCost`.
1051
+ */
1052
+ maxCost?: number;
1053
+ metadata?: Record<string, unknown>;
1054
+ idempotencyKey?: string;
1055
+ };
1056
+ /**
1057
+ * The second UV set for one object, in the live geometry's own vertex order.
1058
+ *
1059
+ * `values` alone: `2 * vertexCount` floats, writable straight into a `uv1`
1060
+ * BufferAttribute on the existing geometry. The common case, and the one
1061
+ * that leaves the developer's geometry object untouched.
1062
+ *
1063
+ * `topology`: the unwrap needed vertex splits. `vertexSource[i]` names the
1064
+ * original vertex that new vertex `i` was copied from, so every original
1065
+ * attribute (custom ones included) can be gathered through it and nothing
1066
+ * the developer authored is lost in the rebuild. `index` is the new triangle
1067
+ * list over the new vertices.
1068
+ */
1069
+ type BakeUv = {
1070
+ values: number[];
1071
+ } | {
1072
+ topology: {
1073
+ vertexSource: number[];
1074
+ index: number[];
1075
+ values: number[];
1076
+ };
1077
+ }
1078
+ /**
1079
+ * The lightmap is laid on a uv set the mesh already has: `0` is its
1080
+ * texture uv (three's `uv`, glTF `TEXCOORD_0`), `1` its second set (`uv1`,
1081
+ * `TEXCOORD_1`). Nothing is shipped and nothing is rebuilt: the SDK points
1082
+ * the lightmap at that attribute (`texture.channel`). Such a lightmap is
1083
+ * written in the glTF orientation (v = 0 at the top), the one the
1084
+ * attribute is in; every unwrap the worker ships itself is bottom-up.
1085
+ * Only sent to an SDK that asked for it (`BakeSettings.existingUv`).
1086
+ */
1087
+ | {
1088
+ channel: 0 | 1;
1089
+ };
1090
+ /**
1091
+ * One baked object. `uri` is resolved against the bundle's own location: a
1092
+ * relative path on disk, an absolute URL from a server.
1093
+ */
1094
+ type BakedObject = {
1095
+ objectId: string;
1096
+ /** The object's name at capture time, for humans reading a bundle. */
1097
+ name?: string;
1098
+ /** HDR diffuse irradiance (direct + indirect, no albedo), linear. */
1099
+ lightmap: {
1100
+ uri: string;
1101
+ format: 'exr' | 'png';
1102
+ size: number;
1103
+ };
1104
+ /** Small LDR thumbnail for pickers and panels. */
1105
+ preview?: {
1106
+ uri: string;
1107
+ };
1108
+ uv: BakeUv;
1109
+ /**
1110
+ * How the surface was cut, measured by the worker, so a panel can say
1111
+ * "2 islands, seams out of view" and mean it.
1112
+ *
1113
+ * `cut: 'hidden'` is the viewpoint-aware layout; `'angle'` is the plain
1114
+ * angle-limited fallback, used when the hidden-seam layout failed its
1115
+ * checks for this object (the job log says so too). `seamsInView` is the
1116
+ * fraction of seam length across smooth surface whose both sides face
1117
+ * `BakeSettings.view`; 0 is the goal. Seams on creases are not counted,
1118
+ * because they do not show.
1119
+ */
1120
+ layout?: {
1121
+ islands: number;
1122
+ seamsInView?: number;
1123
+ /**
1124
+ * `'uv0'`/`'uv1'`: the object's own uv set, chosen over an unwrap
1125
+ * because it passed the worker's layout test.
1126
+ */
1127
+ cut: 'hidden' | 'angle' | 'uv0' | 'uv1';
1128
+ };
1129
+ /**
1130
+ * In an atlas bake: the fraction of the shared map this object's islands
1131
+ * cover, which is what its budget and weight actually bought it.
1132
+ */
1133
+ atlasShare?: number;
1134
+ };
1135
+ /**
1136
+ * One stand-in, ready to be put in the scene: see `BakeSimplify`.
1137
+ *
1138
+ * A mesh carries its geometry inline, in the scene's own coordinates (world
1139
+ * space, Y-up, meters), because it is a few hundred vertices and a loader
1140
+ * for it would weigh more than it does. `uv` is the one unwrap every map
1141
+ * uses. `tangent` (xyzw) is the frame the normal map was baked in; a viewer
1142
+ * that derives tangents from uv derivatives instead will be close, not
1143
+ * exact. `color` is an sRGB PNG and `normal` a linear one, both the right
1144
+ * way up for an ordinary image loader (`flipY` on); `lightmap` follows the
1145
+ * lightmap contract above.
1146
+ *
1147
+ * A billboard is an upright rectangle `width` by `height` centered on
1148
+ * `center`, to be turned about the vertical to face the camera, and `map` is
1149
+ * linear radiance with alpha: the objects as traced from `BakeSettings.view`'s
1150
+ * side, lit by the whole scene, with everything else cut away. It goes
1151
+ * through the viewer's own tone mapping like everything around it.
1152
+ */
1153
+ type BakedProxy = {
1154
+ kind: 'mesh';
1155
+ /** Index into `settings.simplify`. */
1156
+ index: number;
1157
+ replaces: string[];
1158
+ name?: string;
1159
+ geometry: {
1160
+ position: number[];
1161
+ normal: number[];
1162
+ uv: number[];
1163
+ tangent?: number[];
1164
+ index: number[];
1165
+ };
1166
+ color: {
1167
+ uri: string;
1168
+ };
1169
+ normal: {
1170
+ uri: string;
1171
+ };
1172
+ lightmap: {
1173
+ uri: string;
1174
+ format: 'exr';
1175
+ size: number;
1176
+ };
1177
+ /** The replaced surfaces' roughness and metalness, area weighted. */
1178
+ roughness: number;
1179
+ metalness: number;
1180
+ layout?: BakedObject['layout'];
1181
+ } | {
1182
+ /** `to: 'decimate'`: the replaced object with fewer triangles. */
1183
+ kind: 'decimated';
1184
+ index: number;
1185
+ /** The one object it replaces, whose materials it wears. */
1186
+ replaces: [string];
1187
+ name?: string;
1188
+ /**
1189
+ * In the scene's frame, like a mesh stand-in's. `uv` is the object's
1190
+ * own texture uv, carried through the decimation, in the glTF
1191
+ * orientation its texture maps expect; `uv1` is present when the
1192
+ * lightmap needed an unwrap of its own. `groups` are its material
1193
+ * slots, in the order of the replaced mesh's materials.
1194
+ */
1195
+ geometry: {
1196
+ position: number[];
1197
+ normal: number[];
1198
+ uv: number[];
1199
+ uv1?: number[];
1200
+ /** Its vertex colors (glTF COLOR_0), linear RGB, when it had them. */
1201
+ color?: number[];
1202
+ index: number[];
1203
+ groups?: Array<{
1204
+ start: number;
1205
+ count: number;
1206
+ materialIndex: number;
1207
+ }>;
1208
+ };
1209
+ lightmap: {
1210
+ uri: string;
1211
+ format: 'exr';
1212
+ size: number;
1213
+ };
1214
+ /** The uv set the lightmap reads: 0 is `uv`, 1 is `uv1`. */
1215
+ lightmapChannel: 0 | 1;
1216
+ triangles: {
1217
+ from: number;
1218
+ to: number;
1219
+ };
1220
+ layout?: BakedObject['layout'];
1221
+ } | {
1222
+ kind: 'billboard';
1223
+ index: number;
1224
+ replaces: string[];
1225
+ name?: string;
1226
+ center: [number, number, number];
1227
+ width: number;
1228
+ height: number;
1229
+ map: {
1230
+ uri: string;
1231
+ format: 'exr';
1232
+ width: number;
1233
+ height: number;
1234
+ };
1235
+ };
1236
+ /**
1237
+ * An object the bake did not produce, with the reason and the fix, per
1238
+ * object: "the bake finished" must never quietly mean "except for the glass
1239
+ * and the instanced chairs".
1240
+ */
1241
+ type BakeSkip = {
1242
+ objectId: string;
1243
+ name?: string;
1244
+ code: string;
1245
+ message: string;
1246
+ why?: string;
1247
+ fix?: string;
1248
+ /**
1249
+ * The object was baked; this is a complaint about how well.
1250
+ *
1251
+ * An ordinary entry here means a lightmap was not made and the object is
1252
+ * still lit the way it was. A `warning` means one was made and is worse
1253
+ * than it should be. `BakeCoarseUnwrap` is the case: a surface whose
1254
+ * geometry is far finer than the map it earns cuts into more islands than
1255
+ * the map has room for, and the result is padding with a little light in
1256
+ * it.
1257
+ */
1258
+ warning?: true;
1259
+ };
1260
+ /**
1261
+ * Everything one bake produced. The bundle file is written last, so an
1262
+ * interrupted bake never looks finished.
1263
+ */
1264
+ type BakeBundle = {
1265
+ bundleVersion: 1;
1266
+ /** The `BAKE_VERSION` that produced this. */
1267
+ bakeVersion: number;
1268
+ settings: BakeSettings;
1269
+ objects: BakedObject[];
1270
+ skipped: BakeSkip[];
1271
+ /**
1272
+ * When `settings.atlas` was set: the one lightmap every object's
1273
+ * `lightmap.uri` names, so a loader can fetch it once and share it. Each
1274
+ * object's `uv` is already in the atlas's space.
1275
+ */
1276
+ atlas?: {
1277
+ uri: string;
1278
+ format: 'exr' | 'png';
1279
+ size: number;
1280
+ preview?: {
1281
+ uri: string;
1282
+ };
1283
+ /** Fraction of the map's texels some island maps to: packing efficiency. */
1284
+ coverage?: number;
1285
+ };
1286
+ /**
1287
+ * The stand-ins `settings.simplify` asked for. One that could not be built
1288
+ * is in `skipped` under the id `simplify[n]`, and the objects it would have
1289
+ * replaced are left as they were.
1290
+ */
1291
+ proxies?: BakedProxy[];
1292
+ /** The shadow plane `settings.shadow` asked for. */
1293
+ shadow?: BakedShadow;
1294
+ /**
1295
+ * The prebaked room this bake stands its objects in: an unmodified preset
1296
+ * room whose own lightmaps are a library asset, not something this bake
1297
+ * paid for. The SDK fetches that bundle and applies it underneath this
1298
+ * one. Absent from an ordinary bake, which lights everything it covers.
1299
+ */
1300
+ room?: {
1301
+ /** The preset and the lighting it was baked under. */
1302
+ name: string;
1303
+ lighting: string;
1304
+ /**
1305
+ * The published room's build hash, which is what makes the prebake this
1306
+ * room and not a later edit of it.
1307
+ */
1308
+ build: string;
1309
+ /** Where the prebaked bundle is, on the preset library. */
1310
+ uri: string;
1311
+ };
1312
+ /** The portable unlit GLB, when `deliverGlb` was set. */
1313
+ glb?: {
1314
+ uri: string;
1315
+ };
1316
+ /**
1317
+ * The reflection probe: a linear HDR equirectangular map of the scene from
1318
+ * `position`, in three's own equirect convention (load it, set
1319
+ * `EquirectangularReflectionMapping`, and it is an `envMap`). `hidden` are
1320
+ * the objects it was taken without, which are the ones to put it on.
1321
+ */
1322
+ probe?: {
1323
+ uri: string;
1324
+ format: 'exr';
1325
+ width: number;
1326
+ height: number;
1327
+ position: [number, number, number];
1328
+ hidden: string[];
1329
+ /**
1330
+ * The probe as an LDR picture, for a panel, a drawer or a figure: the
1331
+ * same map through `exposure` (chosen by the worker to put its mean at
1332
+ * middle gray), Reinhard and sRGB. A label on the file, not something to
1333
+ * light with.
1334
+ */
1335
+ preview?: {
1336
+ uri: string;
1337
+ exposure?: number;
1338
+ };
1339
+ };
1340
+ stats?: {
1341
+ texels: number;
1342
+ gpuSeconds?: number;
1343
+ /**
1344
+ * Where those seconds went, by step (`scene`, `probe`, `unwrap`,
1345
+ * `trace`, `repair`, `denoise`, `export`, `standIns`), summed over the
1346
+ * objects.
1347
+ */
1348
+ seconds?: Record<string, number>;
1349
+ };
1350
+ };
1351
+ /**
1352
+ * A bundle without its uv arrays and stand-in geometry: what a job result
1353
+ * carries once the files are in storage. The arrays are the bulk of a bundle
1354
+ * (a dense room's are megabytes) and belong in `bundle.json`, which the SDK
1355
+ * reads from storage.
1356
+ */
1357
+ type BakeBundleSummary = Omit<BakeBundle, 'objects' | 'proxies'> & {
1358
+ objects: Array<Omit<BakedObject, 'uv'>>;
1359
+ /** Stand-ins without their geometry, for the same reason. */
1360
+ proxies?: Array<DistributiveOmit<BakedProxy, 'geometry'>>;
1361
+ };
1362
+ type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
1363
+
1364
+ export { type AssetHash as A, type BakeTextureSize as B, type ColorSpec as C, type EnvironmentSpec as E, type FrameSequenceIndex as F, type MaterialShaderSpec as M, type OutputSpec as O, type QualityPreset as Q, type RenderSpec as R, type SceneManifest as S, type Vec3 as V, type BakeQuality as a, type BakeAtlas as b, type BakeView as c, type CompatibilityReport as d, type BakeSpec as e, type BakeBundleSummary as f, type CameraSpec as g, type CompatibilityIssue as h, type BakeSettings as i, type BakeBundle as j, type ShaderSlot as k, type BakeSkip as l, type BakeUv as m, type BakedObject as n, type OutputFormat as o, type ShaderGraph as p, type ShaderGraphNode as q, BAKE_TEXTURE_SIZES as r, MAX_BAKE_OBJECTS as s, MAX_BAKE_TEXELS as t };