@oeave/bakery3 0.1.0 → 0.3.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 (77) hide show
  1. package/README.md +10 -10
  2. package/dist/bake/index.d.ts +3 -3
  3. package/dist/bake/index.js +4 -4
  4. package/dist/{bake-DaOlenyx.d.ts → bake-DZ-CJR6f.d.ts} +8 -1
  5. package/dist/catalog/index.d.ts +5 -5
  6. package/dist/catalog/index.js +3 -3
  7. package/dist/{chunk-TGFNQBKC.js → chunk-3T3FJOSD.js} +5 -5
  8. package/dist/chunk-3T3FJOSD.js.map +1 -0
  9. package/dist/{chunk-V3QINEEG.js → chunk-62M6XXNX.js} +58 -3
  10. package/dist/chunk-62M6XXNX.js.map +1 -0
  11. package/dist/{chunk-ARMTTZXZ.js → chunk-6FAMQZXB.js} +8 -8
  12. package/dist/chunk-6FAMQZXB.js.map +1 -0
  13. package/dist/{chunk-54WJDN5R.js → chunk-CSSJRP5W.js} +9 -6
  14. package/dist/chunk-CSSJRP5W.js.map +1 -0
  15. package/dist/{chunk-W6WQ5UP7.js → chunk-EN4ROBYQ.js} +32 -5
  16. package/dist/chunk-EN4ROBYQ.js.map +1 -0
  17. package/dist/chunk-KZLVTSBI.js +191 -0
  18. package/dist/chunk-KZLVTSBI.js.map +1 -0
  19. package/dist/{chunk-MD2U6S4N.js → chunk-LAKXC4WR.js} +218 -142
  20. package/dist/chunk-LAKXC4WR.js.map +1 -0
  21. package/dist/{chunk-HQTUFVMM.js → chunk-NEK5TBEH.js} +3 -3
  22. package/dist/chunk-NEK5TBEH.js.map +1 -0
  23. package/dist/chunk-OPM2L63B.js +253 -0
  24. package/dist/chunk-OPM2L63B.js.map +1 -0
  25. package/dist/{chunk-APBOWWSV.js → chunk-R5IUPOWI.js} +3 -3
  26. package/dist/chunk-R5IUPOWI.js.map +1 -0
  27. package/dist/{chunk-6YVQANMW.js → chunk-STRK4SZN.js} +262 -16
  28. package/dist/chunk-STRK4SZN.js.map +1 -0
  29. package/dist/{chunk-CX4WTVGH.js → chunk-WLEFNUOH.js} +411 -371
  30. package/dist/chunk-WLEFNUOH.js.map +1 -0
  31. package/dist/{chunk-25ZXSVQ3.js → chunk-X6GW43EX.js} +3 -3
  32. package/dist/{chunk-25ZXSVQ3.js.map → chunk-X6GW43EX.js.map} +1 -1
  33. package/dist/{chunk-WBIAFIHV.js → chunk-XK35ANPJ.js} +3 -3
  34. package/dist/{chunk-WBIAFIHV.js.map → chunk-XK35ANPJ.js.map} +1 -1
  35. package/dist/devtools/index.d.ts +3 -3
  36. package/dist/devtools/index.js +10 -9
  37. package/dist/hotspots/index.d.ts +237 -31
  38. package/dist/hotspots/index.js +1013 -118
  39. package/dist/hotspots/index.js.map +1 -1
  40. package/dist/index.d.ts +39 -8
  41. package/dist/index.js +11 -10
  42. package/dist/node/index.cjs +266 -141
  43. package/dist/node/index.cjs.map +1 -1
  44. package/dist/node/index.d.cts +152 -87
  45. package/dist/node/index.d.ts +27 -6
  46. package/dist/node/index.js +52 -3
  47. package/dist/node/index.js.map +1 -1
  48. package/dist/{prepare-C5qVvaw4.d.ts → prepare-BtjY4G3q.d.ts} +1 -1
  49. package/dist/presets/index.d.ts +37 -1
  50. package/dist/presets/index.js +4 -4
  51. package/dist/presets/index.js.map +1 -1
  52. package/dist/r3f/index.d.ts +4 -4
  53. package/dist/r3f/index.js +13 -12
  54. package/dist/r3f/index.js.map +1 -1
  55. package/dist/{room-S5TLCK4F.js → room-BM7Z7NKG.js} +6 -6
  56. package/dist/{room-S5TLCK4F.js.map → room-BM7Z7NKG.js.map} +1 -1
  57. package/dist/{rooms.gen-vhj6sFW5.d.ts → rooms.gen-DItzBR9k.d.ts} +112 -84
  58. package/dist/session-NPVBESWA.js +9 -0
  59. package/dist/{session-YCQS4MRH.js.map → session-NPVBESWA.js.map} +1 -1
  60. package/dist/{testRun-BIPXaVPb.d.ts → testRun-20OARnQr.d.ts} +12 -3
  61. package/dist/tsl/index.d.ts +14 -1
  62. package/dist/tsl/index.js +8 -2
  63. package/dist/tsl/index.js.map +1 -1
  64. package/package.json +1 -1
  65. package/dist/chunk-54WJDN5R.js.map +0 -1
  66. package/dist/chunk-6YVQANMW.js.map +0 -1
  67. package/dist/chunk-AF5BIELI.js +0 -70
  68. package/dist/chunk-AF5BIELI.js.map +0 -1
  69. package/dist/chunk-APBOWWSV.js.map +0 -1
  70. package/dist/chunk-ARMTTZXZ.js.map +0 -1
  71. package/dist/chunk-CX4WTVGH.js.map +0 -1
  72. package/dist/chunk-HQTUFVMM.js.map +0 -1
  73. package/dist/chunk-MD2U6S4N.js.map +0 -1
  74. package/dist/chunk-TGFNQBKC.js.map +0 -1
  75. package/dist/chunk-V3QINEEG.js.map +0 -1
  76. package/dist/chunk-W6WQ5UP7.js.map +0 -1
  77. package/dist/session-YCQS4MRH.js +0 -9
@@ -1,11 +1,12 @@
1
- import { captureCamera } from './chunk-V3QINEEG.js';
2
- import { protocolVersionFor, SDK_VERSION, QUALITY } from './chunk-APBOWWSV.js';
1
+ import { captureCamera } from './chunk-62M6XXNX.js';
2
+ import { protocolVersionFor, SDK_VERSION, QUALITY } from './chunk-R5IUPOWI.js';
3
3
  import { BAKERY_NODE_MARKER, builtinFor, tslRuntimeRegistered, toNodeObject } from './chunk-S4AJTLLN.js';
4
- import { findPresetRooms, sha256, environmentSourceFor, isPresetEnvironment, roomPresetSpecOf, roomPresetFactsOf, roomPresetAssetsOf } from './chunk-AF5BIELI.js';
5
- import { idOf, shouldExclude, captureFog, readUserData, scenePath, captureLights, captureRuntime, stampIds, captureEnvironmentSettings, excludedItself, bakeCandidates, resolveProbe, defaultIncludeIds, quantizeBakeView, bakeBounds, isBakeWrittenUv } from './chunk-HQTUFVMM.js';
6
- import { MAX_BAKE_OBJECTS, MAX_BAKE_TEXELS, roomIsPrebaked, roomPrebakeChanges, MAX_BAKE_SIMPLIFY, BAKE_TEXTURE_SIZES, MAX_BAKE_SIMPLIFY_TRIANGLES, BAKE_ATLAS_SIZES } from './chunk-W6WQ5UP7.js';
4
+ import { sha256, environmentSourceFor, isPresetEnvironment } from './chunk-KZLVTSBI.js';
5
+ import { idOf, shouldExclude, captureFog, scenePath, captureLights, captureRuntime, stampIds, captureEnvironmentSettings, excludedItself, readUserData, bakeCandidates, resolveProbe, defaultIncludeIds, quantizeBakeView, bakeBounds, isBakeWrittenUv, ID_KEY } from './chunk-NEK5TBEH.js';
6
+ import { findPresetRooms, roomShownBaked, roomPresetFactsOf, roomPresetSpecOf, roomPresetAssetsOf, MAX_BAKE_OBJECTS, MAX_BAKE_TEXELS, roomIsPrebaked, roomPrebakeChanges, MAX_BAKE_SIMPLIFY, BAKE_TEXTURE_SIZES, MAX_BAKE_SIMPLIFY_TRIANGLES, BAKE_ATLAS_SIZES } from './chunk-EN4ROBYQ.js';
7
7
  import { Bakery3Error } from './chunk-3G5QL4F4.js';
8
- import { Vector3, Vector2, Matrix4, Quaternion } from 'three';
8
+ import { readCameraLookAt, propertyDefinition, CAMERA_PROPERTIES, OBJECT_PROPERTIES, hexToLinear } from './chunk-OPM2L63B.js';
9
+ import { Vector3, Vector2, Matrix4, Quaternion, Color, MeshPhysicalMaterial, MeshStandardMaterial, LinearSRGBColorSpace } from 'three';
9
10
  import { GLTFExporter } from 'three/examples/jsm/exporters/GLTFExporter.js';
10
11
 
11
12
  // src/timeline/easing.ts
@@ -163,256 +164,6 @@ function normalize(v) {
163
164
  return length === 0 ? [0, 0, 0] : [v[0] / length, v[1] / length, v[2] / length];
164
165
  }
165
166
 
166
- // src/timeline/properties.ts
167
- function hemisphereOf(object) {
168
- const light = object;
169
- return light.isHemisphereLight ? light : void 0;
170
- }
171
- function sceneOf(object) {
172
- const scene = object;
173
- return scene.isScene ? scene : void 0;
174
- }
175
- function aimedLight(object) {
176
- const light = object;
177
- return (light.isDirectionalLight || light.isSpotLight) && light.target ? light : void 0;
178
- }
179
- function materialOf(object) {
180
- const material = object.material;
181
- if (!material) return void 0;
182
- return Array.isArray(material) ? material[0] : material;
183
- }
184
- function readVector(v) {
185
- return v ? [v.x, v.y, v.z] : void 0;
186
- }
187
- function scalar(get, set) {
188
- return {
189
- size: 1,
190
- read(object) {
191
- const material = materialOf(object);
192
- const value = material ? get(material) : void 0;
193
- return typeof value === "number" ? [value] : void 0;
194
- },
195
- write(object, value) {
196
- const material = materialOf(object);
197
- if (material) set(material, value[0]);
198
- }
199
- };
200
- }
201
- function colorProperty(pick) {
202
- return {
203
- size: 3,
204
- color: true,
205
- read(object) {
206
- const target = pick(object);
207
- return target ? [target.r, target.g, target.b] : void 0;
208
- },
209
- write(object, value) {
210
- const target = pick(object);
211
- if (!target) return;
212
- if (target.setRGB) target.setRGB(value[0], value[1], value[2]);
213
- else Object.assign(target, { r: value[0], g: value[1], b: value[2] });
214
- }
215
- };
216
- }
217
- var OBJECT_PROPERTIES = {
218
- position: {
219
- size: 3,
220
- read: (object) => readVector(object.position),
221
- write: (object, value) => object.position.set(value[0], value[1], value[2])
222
- },
223
- rotation: {
224
- size: 3,
225
- channel: "quaternion",
226
- read: (object) => readVector(
227
- object.rotation
228
- ),
229
- write: (object, value) => object.rotation.set(value[0], value[1], value[2])
230
- },
231
- scale: {
232
- size: 3,
233
- read: (object) => readVector(object.scale),
234
- write: (object, value) => object.scale.set(value[0], value[1], value[2])
235
- },
236
- // A light's own color (the worker drives the lamp, or for an ambient or
237
- // hemisphere light the dome), and a mesh's material's.
238
- color: colorProperty(
239
- (object) => object.isLight ? object.color : materialOf(object)?.color
240
- ),
241
- emissive: colorProperty((object) => materialOf(object)?.emissive),
242
- emissiveIntensity: scalar(
243
- (material) => material.emissiveIntensity,
244
- (material, value) => {
245
- material.emissiveIntensity = value;
246
- }
247
- ),
248
- roughness: scalar(
249
- (material) => material.roughness,
250
- (material, value) => {
251
- material.roughness = value;
252
- }
253
- ),
254
- metalness: scalar(
255
- (material) => material.metalness,
256
- (material, value) => {
257
- material.metalness = value;
258
- }
259
- ),
260
- opacity: scalar(
261
- (material) => material.opacity,
262
- (material, value) => {
263
- material.opacity = value;
264
- if (value < 1 && !material.transparent) {
265
- material.transparent = true;
266
- material.needsUpdate = true;
267
- }
268
- }
269
- ),
270
- intensity: {
271
- size: 1,
272
- read(object) {
273
- const light = object;
274
- return light.isLight && typeof light.intensity === "number" ? [light.intensity] : void 0;
275
- },
276
- write(object, value) {
277
- const light = object;
278
- if (light.isLight) light.intensity = value[0];
279
- }
280
- },
281
- /** A HemisphereLight's color from below. Its `color` is the sky. */
282
- groundColor: {
283
- ...colorProperty((object) => hemisphereOf(object)?.groundColor),
284
- appliesTo: (object) => hemisphereOf(object) !== void 0
285
- },
286
- /**
287
- * The scene's own `environmentIntensity`, on the Scene as a target: the
288
- * environment's `intensity` channel. It scales the HDRI only, as in three.
289
- */
290
- environmentIntensity: {
291
- size: 1,
292
- appliesTo: (object) => sceneOf(object) !== void 0,
293
- read(object) {
294
- const value = sceneOf(object)?.environmentIntensity;
295
- return typeof value === "number" ? [value] : void 0;
296
- },
297
- write(object, value) {
298
- const scene = sceneOf(object);
299
- if (scene) scene.environmentIntensity = value[0];
300
- }
301
- },
302
- /**
303
- * The scene's `environmentRotation`, radians, XYZ, as three holds it: the
304
- * environment's `rotation` channel. Unlike an object's rotation it stays
305
- * an euler on the wire, because that is what the environment carries.
306
- */
307
- environmentRotation: {
308
- size: 3,
309
- appliesTo: (object) => sceneOf(object) !== void 0,
310
- read: (object) => readVector(sceneOf(object)?.environmentRotation),
311
- write(object, value) {
312
- sceneOf(object)?.environmentRotation?.set(
313
- value[0],
314
- value[1],
315
- value[2]
316
- );
317
- }
318
- },
319
- /**
320
- * Where a directional or spot light aims: its `target`'s WORLD position,
321
- * which is what three aims it at and what the channel carries. Written
322
- * back through the target's parent, if it has one, so the light points at
323
- * the same place in the viewport as in the render.
324
- */
325
- target: {
326
- size: 3,
327
- appliesTo: (object) => aimedLight(object) !== void 0,
328
- read(object) {
329
- const target = aimedLight(object)?.target;
330
- if (!target) return void 0;
331
- target.updateMatrixWorld();
332
- const e = target.matrixWorld.elements;
333
- return [e[12], e[13], e[14]];
334
- },
335
- write(object, value) {
336
- const target = aimedLight(object)?.target;
337
- if (!target) return;
338
- target.position.set(value[0], value[1], value[2]);
339
- target.parent?.worldToLocal(target.position);
340
- target.updateMatrixWorld();
341
- }
342
- }
343
- };
344
- var CAMERA_PROPERTIES = {
345
- position: OBJECT_PROPERTIES.position,
346
- lookAt: {
347
- size: 3,
348
- // There is no live "lookAt" to read; the timeline supplies its own center
349
- // when a keyframe is captured. Returning undefined keeps the panel from
350
- // offering a capture button that would silently record the wrong thing.
351
- read: () => void 0,
352
- // Applied together with position by the timeline, never alone: aiming at a
353
- // point before moving to the position it was computed for produces one
354
- // frame of visible swing.
355
- write: () => void 0
356
- },
357
- fov: {
358
- size: 1,
359
- read(object) {
360
- const camera = object;
361
- return typeof camera.fov === "number" ? [camera.fov] : void 0;
362
- },
363
- write(object, value) {
364
- const camera = object;
365
- if (typeof camera.fov !== "number") return;
366
- camera.fov = value[0];
367
- camera.updateProjectionMatrix?.();
368
- }
369
- }
370
- };
371
- function propertyDefinition(target, property) {
372
- return target === "camera" ? CAMERA_PROPERTIES[property] : OBJECT_PROPERTIES[property];
373
- }
374
- function readCameraLookAt(camera, center) {
375
- camera.updateMatrixWorld();
376
- const e = camera.matrixWorld.elements;
377
- const position = [e[12], e[13], e[14]];
378
- const forward = normalize2([-e[8], -e[9], -e[10]]);
379
- const distance = Math.hypot(
380
- position[0] - center[0],
381
- position[1] - center[1],
382
- position[2] - center[2]
383
- ) || 1;
384
- return [
385
- position[0] + forward[0] * distance,
386
- position[1] + forward[1] * distance,
387
- position[2] + forward[2] * distance
388
- ];
389
- }
390
- function normalize2(v) {
391
- const length = Math.hypot(v[0], v[1], v[2]);
392
- return length === 0 ? [0, 0, -1] : [v[0] / length, v[1] / length, v[2] / length];
393
- }
394
- function hexToLinear(hex) {
395
- const value = hex.trim().replace(/^#/, "");
396
- const full = value.length === 3 ? value.split("").map((c) => c + c).join("") : value;
397
- const int = Number.parseInt(full, 16);
398
- if (!Number.isFinite(int)) return [1, 1, 1];
399
- return [
400
- srgbToLinear((int >> 16 & 255) / 255),
401
- srgbToLinear((int >> 8 & 255) / 255),
402
- srgbToLinear((int & 255) / 255)
403
- ];
404
- }
405
- function srgbToLinear(c) {
406
- return c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4);
407
- }
408
- function linearToSrgbHex(value) {
409
- const channel = (v) => {
410
- const srgb = v < 31308e-7 ? v * 12.92 : 1.055 * Math.pow(Math.max(v, 0), 0.41666) - 0.055;
411
- return Math.round(Math.max(0, Math.min(1, srgb)) * 255).toString(16).padStart(2, "0");
412
- };
413
- return `#${channel(value[0] ?? 0)}${channel(value[1] ?? 0)}${channel(value[2] ?? 0)}`;
414
- }
415
-
416
167
  // src/protocol/animation.ts
417
168
  var ENVIRONMENT_CHANNEL_SIZES = {
418
169
  intensity: 1,
@@ -1317,7 +1068,7 @@ var Timeline = class _Timeline {
1317
1068
  const { at, end } = this.span(options);
1318
1069
  for (const [property, raw] of Object.entries(props)) {
1319
1070
  const track = this.track(target, property);
1320
- const value = normalize3(raw, track.size, property);
1071
+ const value = normalize2(raw, track.size, property);
1321
1072
  this.anchor(track, at);
1322
1073
  this.insert(track, {
1323
1074
  time: end,
@@ -1337,14 +1088,14 @@ var Timeline = class _Timeline {
1337
1088
  if (start !== void 0) {
1338
1089
  this.insert(track, {
1339
1090
  time: at,
1340
- value: normalize3(start, track.size, property)
1091
+ value: normalize2(start, track.size, property)
1341
1092
  });
1342
1093
  } else {
1343
1094
  this.anchor(track, at);
1344
1095
  }
1345
1096
  this.insert(track, {
1346
1097
  time: end,
1347
- value: normalize3(raw, track.size, property),
1098
+ value: normalize2(raw, track.size, property),
1348
1099
  ...options.easing ? { easing: options.easing } : {}
1349
1100
  });
1350
1101
  }
@@ -1452,7 +1203,7 @@ var Timeline = class _Timeline {
1452
1203
  */
1453
1204
  keyframe(target, property, time = this._time, value) {
1454
1205
  const track = this.track(target, property);
1455
- const resolved = value !== void 0 ? normalize3(value, track.size, property) : this.live(target, property) ?? this.valueAt(track, time);
1206
+ const resolved = value !== void 0 ? normalize2(value, track.size, property) : this.live(target, property) ?? this.valueAt(track, time);
1456
1207
  if (!resolved) {
1457
1208
  throw new Bakery3Error({
1458
1209
  code: "InvalidRequest",
@@ -1925,7 +1676,7 @@ function noCamera(what, bound) {
1925
1676
  function createTimeline(options = {}) {
1926
1677
  return new Timeline(options);
1927
1678
  }
1928
- function normalize3(value, size, property) {
1679
+ function normalize2(value, size, property) {
1929
1680
  const flat = flatten(value, size, property);
1930
1681
  if (flat && flat.length === size && flat.every((n) => Number.isFinite(n)))
1931
1682
  return flat;
@@ -2936,7 +2687,7 @@ function staticProperties(material) {
2936
2687
  properties[key] = `#${value.getHexString()}`;
2937
2688
  }
2938
2689
  };
2939
- const scalar2 = (key, prop) => {
2690
+ const scalar = (key, prop) => {
2940
2691
  const value = material[prop];
2941
2692
  if (typeof value === "number" && Number.isFinite(value)) {
2942
2693
  properties[key] = value;
@@ -2947,23 +2698,23 @@ function staticProperties(material) {
2947
2698
  color("sheenColor", "sheenColor");
2948
2699
  color("specularColor", "specularColor");
2949
2700
  color("attenuationColor", "attenuationColor");
2950
- scalar2("roughness", "roughness");
2951
- scalar2("metalness", "metalness");
2952
- scalar2("emissiveIntensity", "emissiveIntensity");
2953
- scalar2("opacity", "opacity");
2954
- scalar2("alphaTest", "alphaTest");
2955
- scalar2("ior", "ior");
2956
- scalar2("transmission", "transmission");
2957
- scalar2("thickness", "thickness");
2958
- scalar2("attenuationDistance", "attenuationDistance");
2959
- scalar2("clearcoat", "clearcoat");
2960
- scalar2("clearcoatRoughness", "clearcoatRoughness");
2961
- scalar2("sheen", "sheen");
2962
- scalar2("sheenRoughness", "sheenRoughness");
2963
- scalar2("specularIntensity", "specularIntensity");
2964
- scalar2("iridescence", "iridescence");
2965
- scalar2("iridescenceIOR", "iridescenceIOR");
2966
- scalar2("anisotropy", "anisotropy");
2701
+ scalar("roughness", "roughness");
2702
+ scalar("metalness", "metalness");
2703
+ scalar("emissiveIntensity", "emissiveIntensity");
2704
+ scalar("opacity", "opacity");
2705
+ scalar("alphaTest", "alphaTest");
2706
+ scalar("ior", "ior");
2707
+ scalar("transmission", "transmission");
2708
+ scalar("thickness", "thickness");
2709
+ scalar("attenuationDistance", "attenuationDistance");
2710
+ scalar("clearcoat", "clearcoat");
2711
+ scalar("clearcoatRoughness", "clearcoatRoughness");
2712
+ scalar("sheen", "sheen");
2713
+ scalar("sheenRoughness", "sheenRoughness");
2714
+ scalar("specularIntensity", "specularIntensity");
2715
+ scalar("iridescence", "iridescence");
2716
+ scalar("iridescenceIOR", "iridescenceIOR");
2717
+ scalar("anisotropy", "anisotropy");
2967
2718
  if (material.transparent === true) properties.transparent = true;
2968
2719
  if (material.side === 2) properties.doubleSided = true;
2969
2720
  return properties;
@@ -3024,6 +2775,175 @@ function describeNodeType(type) {
3024
2775
  };
3025
2776
  return KNOWN[type] ?? `A "${type}"`;
3026
2777
  }
2778
+ function fallbackFor(material, object) {
2779
+ const own = material.userData?.bakery3?.fallback;
2780
+ if (isRecord(own)) return { values: own, declaredOn: "material" };
2781
+ const objects = readUserData(object).fallback;
2782
+ if (isRecord(objects)) return { values: objects, declaredOn: "object" };
2783
+ return null;
2784
+ }
2785
+ function objectFallbackId(material, object) {
2786
+ return `${idOf(material)}@${idOf(object)}`;
2787
+ }
2788
+ function fallbackMaterialId(material, object, fallback) {
2789
+ return fallback.declaredOn === "object" ? objectFallbackId(material, object) : idOf(material);
2790
+ }
2791
+ function exporterCannotWrite(material) {
2792
+ const m = material;
2793
+ if (m.isShaderMaterial) return true;
2794
+ return typeof m.color?.toArray !== "function";
2795
+ }
2796
+ function fallbackEmits(values) {
2797
+ if (values.emissive === void 0) return false;
2798
+ const intensity = typeof values.emissiveIntensity === "number" ? values.emissiveIntensity : 1;
2799
+ if (!(intensity > 0)) return false;
2800
+ const color = toColor(values.emissive);
2801
+ return Boolean(color && color.r + color.g + color.b > 0);
2802
+ }
2803
+ function materialStandIns(root) {
2804
+ const shared = /* @__PURE__ */ new Map();
2805
+ const standIns = /* @__PURE__ */ new Map();
2806
+ root.traverse((object) => {
2807
+ if (shouldExclude(object)) return;
2808
+ const drawable = object;
2809
+ if (!(drawable.isMesh || drawable.isLine || drawable.isPoints)) return;
2810
+ if (!drawable.material) return;
2811
+ const list = Array.isArray(drawable.material) ? drawable.material : [drawable.material];
2812
+ const own = /* @__PURE__ */ new Map();
2813
+ let changed = false;
2814
+ const written = list.map((material) => {
2815
+ if (!material) return material;
2816
+ const standIn2 = standInFor(material, object, shared, own);
2817
+ if (standIn2 !== material) changed = true;
2818
+ return standIn2;
2819
+ });
2820
+ if (!changed) return;
2821
+ standIns.set(
2822
+ object,
2823
+ Array.isArray(drawable.material) ? written : written[0]
2824
+ );
2825
+ });
2826
+ return standIns;
2827
+ }
2828
+ function standInFor(material, object, shared, own) {
2829
+ const fallback = fallbackFor(material, object);
2830
+ if (fallback?.declaredOn === "object") {
2831
+ let copy2 = own.get(material);
2832
+ if (!copy2) {
2833
+ copy2 = standIn(
2834
+ material,
2835
+ fallback.values,
2836
+ objectFallbackId(material, object)
2837
+ );
2838
+ own.set(material, copy2);
2839
+ }
2840
+ return copy2;
2841
+ }
2842
+ if (!fallback && !exporterCannotWrite(material)) return material;
2843
+ let copy = shared.get(material);
2844
+ if (!copy) {
2845
+ copy = standIn(material, fallback?.values ?? null, idOf(material));
2846
+ shared.set(material, copy);
2847
+ }
2848
+ return copy;
2849
+ }
2850
+ function standIn(material, fallback, id) {
2851
+ const out = fallback ? fromFallback(fallback) : flatGray();
2852
+ out.name = material.name;
2853
+ out.side = material.side;
2854
+ const userData = {
2855
+ ...material.userData,
2856
+ [ID_KEY]: id
2857
+ };
2858
+ if (fallback) {
2859
+ const bakery3 = isRecord(userData.bakery3) ? userData.bakery3 : {};
2860
+ userData.bakery3 = { ...bakery3, fallback };
2861
+ }
2862
+ out.userData = userData;
2863
+ return out;
2864
+ }
2865
+ function flatGray() {
2866
+ const material = new MeshStandardMaterial({ roughness: 1, metalness: 0 });
2867
+ material.color.setRGB(0.8, 0.8, 0.8, LinearSRGBColorSpace);
2868
+ return material;
2869
+ }
2870
+ var NUMBER_FIELDS = [
2871
+ "metalness",
2872
+ "roughness",
2873
+ "clearcoat",
2874
+ "clearcoatRoughness",
2875
+ "transmission",
2876
+ "thickness",
2877
+ "ior",
2878
+ "emissiveIntensity",
2879
+ "opacity",
2880
+ "sheen",
2881
+ "iridescence",
2882
+ "anisotropy"
2883
+ ];
2884
+ function fromFallback(values) {
2885
+ const material = new MeshPhysicalMaterial();
2886
+ const color = toColor(values.color);
2887
+ if (color) material.color.copy(color);
2888
+ const emissive = toColor(values.emissive);
2889
+ if (emissive) material.emissive.copy(emissive);
2890
+ const sheenColor = toColor(values.sheenColor);
2891
+ if (sheenColor) material.sheenColor.copy(sheenColor);
2892
+ const target = material;
2893
+ for (const field of NUMBER_FIELDS) {
2894
+ const value = values[field];
2895
+ if (typeof value === "number" && Number.isFinite(value))
2896
+ target[field] = value;
2897
+ }
2898
+ if (material.opacity < 1) material.transparent = true;
2899
+ return material;
2900
+ }
2901
+ function toColor(value) {
2902
+ if (typeof value !== "string" && typeof value !== "number" && !value?.isColor)
2903
+ return null;
2904
+ return new Color(value);
2905
+ }
2906
+ function substituteMaterials(exporter, standIns) {
2907
+ let undo = () => {
2908
+ };
2909
+ if (standIns.size === 0) return undo;
2910
+ exporter.register((writer) => {
2911
+ const steps = writer;
2912
+ const name = ["processMeshAsync", "processMesh"].find(
2913
+ (key) => typeof steps[key] === "function"
2914
+ );
2915
+ if (name) {
2916
+ const original = steps[name];
2917
+ steps[name] = function(mesh) {
2918
+ const material = standIns.get(mesh);
2919
+ return original.call(
2920
+ this,
2921
+ material ? Object.create(mesh, {
2922
+ material: { value: material, enumerable: true }
2923
+ }) : mesh
2924
+ );
2925
+ };
2926
+ } else {
2927
+ undo = swapOnScene(standIns);
2928
+ }
2929
+ return {};
2930
+ });
2931
+ return () => undo();
2932
+ }
2933
+ function swapOnScene(standIns) {
2934
+ const originals = [];
2935
+ for (const [object, material] of standIns) {
2936
+ const drawable = object;
2937
+ originals.push({ object: drawable, material: drawable.material });
2938
+ drawable.material = material;
2939
+ }
2940
+ return () => {
2941
+ for (const { object, material } of originals) object.material = material;
2942
+ };
2943
+ }
2944
+ function isRecord(value) {
2945
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2946
+ }
3027
2947
 
3028
2948
  // src/compat/analyze.ts
3029
2949
  var DOCS2 = "https://bakery3.com/docs";
@@ -3031,15 +2951,46 @@ var LARGE_TEXTURE_PX = 4096;
3031
2951
  var LARGE_TRIANGLE_COUNT = 1e7;
3032
2952
  var TRANSLATABLE = /* @__PURE__ */ new Set(["MeshStandardMaterial", "MeshPhysicalMaterial"]);
3033
2953
  var APPROXIMATED = {
3034
- MeshBasicMaterial: "Rendered as an emissive surface, since a path tracer has no unlit shading model.",
3035
- MeshLambertMaterial: "Rendered as a rough physically based material. Lambert has no specular term, so highlights will differ.",
3036
- MeshPhongMaterial: "Converted to roughness/metalness. Phong shininess is not a physical parameter, so the specular falloff is an approximation.",
3037
- MeshToonMaterial: "Rendered as flat diffuse. Cel shading is a screen-space stylization with no path-traced equivalent.",
3038
- MeshMatcapMaterial: "Rendered as diffuse using the matcap average. A matcap encodes lighting into a texture, which is exactly what path tracing replaces.",
3039
- MeshNormalMaterial: "Rendered as flat gray. Normal visualization is a debug view, not a surface.",
3040
- MeshDepthMaterial: "Rendered as flat gray. Depth output is a debug view.",
3041
- MeshDistanceMaterial: "Rendered as flat gray. Distance output is a debug view."
2954
+ MeshBasicMaterial: "It shows its color and map unlit, as in the viewport, but it does not light the scene, cast a shadow, or show in reflections or through glass.",
2955
+ MeshLambertMaterial: "It renders as a fully rough, non-metal surface in its color and map.",
2956
+ MeshPhongMaterial: "It renders as a fully rough, non-metal surface in its color and map, like Lambert. Its `shininess` and `specular` are not used, so it has no sharp highlights.",
2957
+ MeshToonMaterial: "It renders as a fully rough, non-metal surface in its color and map, without the cel shading of its `gradientMap`.",
2958
+ MeshMatcapMaterial: "It renders as a fully rough, non-metal surface in its color and map, lit by the scene. The `matcap` texture is not used.",
2959
+ MeshNormalMaterial: "It renders flat gray. It colors a surface by its normals, which is a debug view, not a look.",
2960
+ MeshDepthMaterial: "It renders flat gray. It shows depth, which is a debug view, not a look.",
2961
+ MeshDistanceMaterial: "It renders flat gray. It is made for shadow maps, not for a visible surface."
3042
2962
  };
2963
+ var IGNORED = [
2964
+ {
2965
+ name: "alphaMap",
2966
+ used: (m) => isTexture(m.alphaMap) && Boolean(m.transparent || m.alphaTest > 0 || m.alphaHash),
2967
+ fix: "For a cutout, use the alpha channel of `map`."
2968
+ },
2969
+ {
2970
+ name: "bumpMap",
2971
+ used: (m) => isTexture(m.bumpMap) && m.bumpScale !== 0,
2972
+ fix: "Bake bump detail into a `normalMap`."
2973
+ },
2974
+ {
2975
+ name: "displacementMap",
2976
+ used: (m) => isTexture(m.displacementMap) && m.displacementScale !== 0,
2977
+ fix: "Model the shape, or bake the detail into a `normalMap`."
2978
+ },
2979
+ { name: "specularMap", used: (m) => isTexture(m.specularMap) },
2980
+ { name: "iridescence", used: (m) => m.iridescence > 0 },
2981
+ {
2982
+ name: "iridescenceMap",
2983
+ used: (m) => m.iridescence > 0 && isTexture(m.iridescenceMap)
2984
+ },
2985
+ {
2986
+ name: "iridescenceThicknessMap",
2987
+ used: (m) => m.iridescence > 0 && isTexture(m.iridescenceThicknessMap)
2988
+ },
2989
+ {
2990
+ name: "dispersion",
2991
+ used: (m) => m.dispersion > 0 && m.transmission > 0
2992
+ }
2993
+ ];
3043
2994
  function emitsLight(material) {
3044
2995
  const m = material;
3045
2996
  if (m.isMeshBasicMaterial) return true;
@@ -3052,6 +3003,7 @@ function emitsLight(material) {
3052
3003
  function analyzeScene(root) {
3053
3004
  const issues = [];
3054
3005
  const seenMaterials = /* @__PURE__ */ new Set();
3006
+ const unfaithful = /* @__PURE__ */ new Set();
3055
3007
  const seenTextures = /* @__PURE__ */ new Set();
3056
3008
  let triangles = 0;
3057
3009
  let faithfulTriangles = 0;
@@ -3085,12 +3037,21 @@ function analyzeScene(root) {
3085
3037
  });
3086
3038
  }
3087
3039
  }
3088
- if (seenMaterials.has(material.uuid)) continue;
3089
- seenMaterials.add(material.uuid);
3090
- if (emitsLight(material)) emitters++;
3091
- for (const issue of classifyMaterial(material, object)) {
3040
+ const fallback = fallbackFor(material, object);
3041
+ const key = fallback?.declaredOn === "object" ? `${object.uuid}:${material.uuid}` : material.uuid;
3042
+ if (seenMaterials.has(key)) {
3043
+ if (unfaithful.has(key)) objectIsFaithful = false;
3044
+ continue;
3045
+ }
3046
+ seenMaterials.add(key);
3047
+ if (fallback ? fallbackEmits(fallback.values) : emitsLight(material))
3048
+ emitters++;
3049
+ for (const issue of classifyMaterial(material, object, fallback)) {
3092
3050
  issues.push(issue);
3093
- if (issue.severity === "error") objectIsFaithful = false;
3051
+ if (issue.severity === "error") {
3052
+ objectIsFaithful = false;
3053
+ unfaithful.add(key);
3054
+ }
3094
3055
  }
3095
3056
  }
3096
3057
  if (objectIsFaithful) faithfulTriangles += count;
@@ -3123,98 +3084,142 @@ function collectFallbacks(root) {
3123
3084
  const fallbacks = [];
3124
3085
  const seen = /* @__PURE__ */ new Set();
3125
3086
  root.traverse((object) => {
3087
+ if (shouldExclude(object)) return;
3126
3088
  const mesh = object;
3127
3089
  if (!mesh.isMesh) return;
3128
3090
  const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
3129
3091
  for (const material of materials) {
3130
- if (!material || seen.has(material.uuid)) continue;
3131
- const declared = material.userData?.bakery3?.fallback ?? readUserData(object).fallback;
3132
- if (!declared) continue;
3133
- seen.add(material.uuid);
3092
+ if (!material) continue;
3093
+ const fallback = fallbackFor(material, object);
3094
+ if (!fallback) continue;
3095
+ const materialId = fallbackMaterialId(material, object, fallback);
3096
+ if (seen.has(materialId)) continue;
3097
+ seen.add(materialId);
3134
3098
  fallbacks.push({
3135
- ...declared,
3136
- materialId: idOf(material),
3099
+ ...fallback.values,
3100
+ materialId,
3137
3101
  type: "physical"
3138
3102
  });
3139
3103
  }
3140
3104
  });
3141
3105
  return fallbacks;
3142
3106
  }
3143
- function classifyMaterial(material, object) {
3144
- const hasFallback = Boolean(
3145
- material.userData?.bakery3?.fallback ?? readUserData(object).fallback
3146
- );
3147
- if (isNodeMaterial(material) && !hasFallback) {
3107
+ function classifyMaterial(material, object, fallback) {
3108
+ if (fallback) {
3109
+ return [
3110
+ {
3111
+ code: "material_fallback_used",
3112
+ severity: "info",
3113
+ message: `${labelOf(material)} renders with your declared fallback.`,
3114
+ path: pathOf(object),
3115
+ materialId: fallbackMaterialId(material, object, fallback),
3116
+ materialName: material.name,
3117
+ materialType: material.type,
3118
+ docs: `${DOCS2}/material-fallbacks`
3119
+ }
3120
+ ];
3121
+ }
3122
+ if (isNodeMaterial(material)) {
3148
3123
  const extracted = extractMaterialShader(material);
3149
- return extracted.issues.map((issue) => ({
3124
+ const issues = extracted.issues.map((issue) => ({
3150
3125
  ...issue,
3151
3126
  path: pathOf(object),
3152
3127
  materialId: idOf(material),
3153
3128
  materialName: material.name,
3154
3129
  materialType: material.type
3155
3130
  }));
3131
+ if (!extracted.spec)
3132
+ issues.push(...classicIssues(material, object, classicType(material)));
3133
+ return issues;
3156
3134
  }
3157
- const verdict = classify(material, object, hasFallback);
3158
- return verdict ? [verdict.issue] : [];
3135
+ return classicIssues(material, object, material.type);
3159
3136
  }
3160
- function classify(material, object, hasFallback) {
3161
- if (TRANSLATABLE.has(material.type)) return null;
3162
- if (hasFallback) {
3163
- return {
3164
- issue: {
3165
- code: "material_fallback_used",
3166
- severity: "info",
3167
- message: `${material.type} "${material.name || "unnamed"}" renders with your declared fallback.`,
3168
- path: pathOf(object),
3169
- materialId: idOf(material),
3170
- materialName: material.name,
3171
- materialType: material.type,
3172
- docs: `${DOCS2}/material-fallbacks`
3173
- }
3174
- };
3175
- }
3176
- if (material.type === "ShaderMaterial" || material.type === "RawShaderMaterial") {
3137
+ function classicIssues(material, object, type) {
3138
+ const issues = [];
3139
+ const verdict = classify(material, object, type);
3140
+ if (verdict) issues.push(verdict);
3141
+ if (!exporterCannotWrite(material)) {
3142
+ const ignored = ignoredSlots(material, object);
3143
+ if (ignored) issues.push(ignored);
3144
+ }
3145
+ return issues;
3146
+ }
3147
+ function classify(material, object, type) {
3148
+ if (TRANSLATABLE.has(type)) return null;
3149
+ const about = {
3150
+ path: pathOf(object),
3151
+ materialId: idOf(material),
3152
+ materialName: material.name,
3153
+ materialType: material.type
3154
+ };
3155
+ if (material.isShaderMaterial) {
3177
3156
  return {
3178
- issue: {
3179
- code: "material_custom_shader",
3180
- severity: "error",
3181
- message: `Unsupported material: ${material.name || material.type}`,
3182
- path: pathOf(object),
3183
- materialId: idOf(material),
3184
- materialName: material.name,
3185
- materialType: material.type,
3186
- docs: `${DOCS2}/material-fallbacks`
3187
- }
3157
+ code: "material_custom_shader",
3158
+ severity: "error",
3159
+ message: `${labelOf(material)} renders flat gray, because the render cannot run GLSL. Declare a fallback, or port it to TSL.`,
3160
+ ...about,
3161
+ docs: `${DOCS2}/material-fallbacks`
3188
3162
  };
3189
3163
  }
3190
- const approximation = APPROXIMATED[material.type];
3164
+ const approximation = APPROXIMATED[type];
3191
3165
  if (approximation) {
3192
3166
  return {
3193
- issue: {
3194
- code: "material_approximated",
3195
- severity: "warning",
3196
- message: `${material.type} "${material.name || "unnamed"}" is approximated. ${approximation}`,
3197
- path: pathOf(object),
3198
- materialId: idOf(material),
3199
- materialName: material.name,
3200
- materialType: material.type,
3201
- docs: `${DOCS2}/materials`
3202
- }
3167
+ code: "material_approximated",
3168
+ severity: "warning",
3169
+ message: `${labelOf(material)} is approximated. ${approximation}${emissiveNote(material)}`,
3170
+ ...about,
3171
+ docs: `${DOCS2}/materials`
3203
3172
  };
3204
3173
  }
3174
+ const looks = exporterCannotWrite(material) ? "flat gray" : "as a fully rough, non-metal surface in its color";
3205
3175
  return {
3206
- issue: {
3207
- code: "material_unknown",
3208
- severity: "error",
3209
- message: `Unsupported material: ${material.name || material.type}`,
3210
- path: pathOf(object),
3211
- materialId: idOf(material),
3212
- materialName: material.name,
3213
- materialType: material.type,
3214
- docs: `${DOCS2}/materials`
3215
- }
3176
+ code: "material_unknown",
3177
+ severity: "error",
3178
+ message: `${labelOf(material)} renders ${looks}, because the render does not support this material. Use MeshStandardMaterial or MeshPhysicalMaterial, or declare a fallback.`,
3179
+ ...about,
3180
+ docs: `${DOCS2}/materials`
3216
3181
  };
3217
3182
  }
3183
+ function emissiveNote(material) {
3184
+ const m = material;
3185
+ if (m.isMeshStandardMaterial || !m.emissive) return "";
3186
+ if (m.emissiveIntensity === void 0 || m.emissiveIntensity === 1) return "";
3187
+ if (m.emissive.r + m.emissive.g + m.emissive.b <= 0) return "";
3188
+ return " Its `emissiveIntensity` is not used, so it glows at intensity 1.";
3189
+ }
3190
+ function ignoredSlots(material, object) {
3191
+ const record2 = material;
3192
+ const ignored = IGNORED.filter((slot) => slot.used(record2));
3193
+ if (!ignored.length) return null;
3194
+ const names = ignored.map((slot) => `\`${slot.name}\``);
3195
+ const list = names.length === 1 ? names[0] : `${names.slice(0, -1).join(", ")} and ${names[names.length - 1]}`;
3196
+ const fixes = ignored.flatMap((slot) => slot.fix ? [slot.fix] : []);
3197
+ return {
3198
+ code: "material_map_ignored",
3199
+ severity: "warning",
3200
+ message: [
3201
+ `${labelOf(material)} uses ${list}, which the render ignores.`,
3202
+ ...fixes
3203
+ ].join(" "),
3204
+ path: pathOf(object),
3205
+ materialId: idOf(material),
3206
+ materialName: material.name,
3207
+ materialType: material.type,
3208
+ docs: `${DOCS2}/materials#slots-the-render-ignores`
3209
+ };
3210
+ }
3211
+ function classicType(material) {
3212
+ const m = material;
3213
+ if (m.isMeshPhysicalMaterial) return "MeshPhysicalMaterial";
3214
+ if (m.isMeshStandardMaterial) return "MeshStandardMaterial";
3215
+ return material.type.replace(/NodeMaterial$/, "Material");
3216
+ }
3217
+ function labelOf(material) {
3218
+ return `${material.type} "${material.name || "unnamed"}"`;
3219
+ }
3220
+ function isTexture(value) {
3221
+ return Boolean(value?.isTexture);
3222
+ }
3218
3223
  var TEXTURE_SLOTS = [
3219
3224
  "map",
3220
3225
  "normalMap",
@@ -3268,7 +3273,8 @@ function sceneComplexity(scene, camera) {
3268
3273
  let objects = 0;
3269
3274
  const visit = (object) => {
3270
3275
  if (!object.visible) return;
3271
- if (excludedItself(object) && !rooms.has(object)) return;
3276
+ const shell = Boolean(object.userData?.bakery3RoomShell);
3277
+ if (excludedItself(object) && !rooms.has(object) && !shell) return;
3272
3278
  const mesh = object;
3273
3279
  if (mesh.isMesh && mesh.geometry?.attributes?.position) {
3274
3280
  const position = mesh.geometry.attributes.position;
@@ -3279,7 +3285,7 @@ function sceneComplexity(scene, camera) {
3279
3285
  (_, i) => i % 3 === 0 ? position.getX(i / 3 | 0) : i % 3 === 1 ? position.getY(i / 3 | 0) : position.getZ(i / 3 | 0)
3280
3286
  );
3281
3287
  const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
3282
- const emitter = materials.length > 0 && materials.every((material) => material && emitsLight(material));
3288
+ const emitter = !shell && materials.length > 0 && materials.every((material) => material && emitsLight(material));
3283
3289
  const base = {
3284
3290
  positions,
3285
3291
  indices: index?.array ?? null,
@@ -3297,13 +3303,17 @@ function sceneComplexity(scene, camera) {
3297
3303
  });
3298
3304
  }
3299
3305
  } else {
3300
- objects += 1;
3306
+ if (!shell) objects += 1;
3301
3307
  meshes.push({ ...base, matrix: mesh.matrixWorld.elements });
3302
3308
  }
3303
3309
  }
3304
3310
  for (const child of object.children) visit(child);
3305
3311
  };
3306
3312
  visit(scene);
3313
+ for (const room of rooms) {
3314
+ if (room.visible && roomShownBaked(room))
3315
+ objects += roomPresetFactsOf(room)?.objects ?? 0;
3316
+ }
3307
3317
  const eye = camera.getWorldPosition(new Vector3());
3308
3318
  return complexityOf(meshes, [eye.x, eye.y, eye.z], objects);
3309
3319
  }
@@ -3354,13 +3364,10 @@ async function captureShaders(root) {
3354
3364
  const list = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
3355
3365
  for (const material of list) {
3356
3366
  if (!material || seen.has(material.uuid)) continue;
3367
+ if (!isNodeMaterial(material)) continue;
3368
+ if (fallbackFor(material, object)) continue;
3357
3369
  seen.add(material.uuid);
3358
- const hasFallback = Boolean(
3359
- material.userData?.bakery3?.fallback ?? readUserData(object).fallback
3360
- );
3361
- if (isNodeMaterial(material) && !hasFallback) {
3362
- materials.push({ material, path: pathOf2(object) });
3363
- }
3370
+ materials.push({ material, path: pathOf2(object) });
3364
3371
  }
3365
3372
  });
3366
3373
  for (const { material, path } of materials) {
@@ -3674,8 +3681,10 @@ async function captureScene(options) {
3674
3681
  }
3675
3682
  function exportGLB(scene) {
3676
3683
  const exporter = new GLTFExporter();
3684
+ const standIns = materialStandIns(scene);
3677
3685
  const reattach = detachExcluded(scene);
3678
3686
  const unmute = muteLightWarnings();
3687
+ const unswap = substituteMaterials(exporter, standIns);
3679
3688
  return new Promise((resolve, reject) => {
3680
3689
  exporter.parse(
3681
3690
  scene,
@@ -3709,6 +3718,7 @@ function exportGLB(scene) {
3709
3718
  }
3710
3719
  );
3711
3720
  }).finally(() => {
3721
+ unswap();
3712
3722
  unmute();
3713
3723
  reattach();
3714
3724
  });
@@ -3925,7 +3935,7 @@ function presetRoomBake(scene, candidates, include) {
3925
3935
  const group = rooms[0];
3926
3936
  const room = roomPresetSpecOf(group);
3927
3937
  if (!room) return null;
3928
- if (!roomIsPrebaked(room.name, room.lighting)) {
3938
+ if (!roomShownBaked(group) && !roomIsPrebaked(room.name, room.lighting)) {
3929
3939
  return {
3930
3940
  refused: {
3931
3941
  code: "BakeRoomNotPrebaked",
@@ -4009,15 +4019,31 @@ function isUnder(object, root) {
4009
4019
  function planBake(scene, camera, settings = {}) {
4010
4020
  const quality = settings.quality ?? "standard";
4011
4021
  const textureSize = settings.textureSize ?? 1024;
4012
- const candidates = bakeCandidates({ scene });
4022
+ let candidates = bakeCandidates({ scene });
4013
4023
  let include = resolveInclude(candidates, settings);
4014
4024
  let preset;
4015
4025
  if (settings.room !== "full") {
4016
- const verdict = presetRoomBake(scene, candidates, include);
4026
+ const hide = revealBakedStands(scene);
4027
+ let seen = candidates;
4028
+ let seenInclude = include;
4029
+ if (hide.length) {
4030
+ try {
4031
+ seen = bakeCandidates({ scene });
4032
+ seenInclude = resolveInclude(seen, settings);
4033
+ } finally {
4034
+ for (const undo of hide) undo();
4035
+ }
4036
+ }
4037
+ const verdict = presetRoomBake(scene, seen, seenInclude);
4017
4038
  if (verdict && "ok" in verdict) {
4018
4039
  preset = verdict.ok;
4040
+ candidates = seen;
4019
4041
  const keep = /* @__PURE__ */ new Set([...preset.spanIds]);
4020
- include = include.filter((id) => keep.has(id));
4042
+ include = seenInclude.filter((id) => keep.has(id));
4043
+ if (hide.length) {
4044
+ for (const id of preset.standIds)
4045
+ if (!include.includes(id)) include.push(id);
4046
+ }
4021
4047
  }
4022
4048
  }
4023
4049
  const standIns = resolveSimplify(scene, candidates, settings);
@@ -4202,7 +4228,8 @@ async function prepareBake(options) {
4202
4228
  function holdRoomBack(preset, include) {
4203
4229
  const undo = [];
4204
4230
  const state = preset.group.userData?.bakery3Preset?.roomPreset;
4205
- if (!state?.standIn) return undo;
4231
+ if (!state) return undo;
4232
+ if (!state.standIn && !roomShownBaked(preset.group)) return undo;
4206
4233
  const shipping = new Set(
4207
4234
  include.filter((id) => preset.standIds.includes(id))
4208
4235
  );
@@ -4224,6 +4251,19 @@ function holdRoomBack(preset, include) {
4224
4251
  });
4225
4252
  return undo;
4226
4253
  }
4254
+ function revealBakedStands(scene) {
4255
+ const undo = [];
4256
+ for (const group of findPresetRooms(scene)) {
4257
+ if (!roomShownBaked(group)) continue;
4258
+ const state = group.userData?.bakery3Preset?.roomPreset;
4259
+ if (!state || state.standIn) continue;
4260
+ state.standIn = "stand";
4261
+ undo.push(() => {
4262
+ state.standIn = void 0;
4263
+ });
4264
+ }
4265
+ return undo;
4266
+ }
4227
4267
  function developerUv1(candidates, include) {
4228
4268
  const wanted = new Set(include);
4229
4269
  return candidates.filter((candidate) => {
@@ -4487,6 +4527,6 @@ function resolveInclude(candidates, settings) {
4487
4527
  return resolved;
4488
4528
  }
4489
4529
 
4490
- export { OBJECT_PROPERTIES, Timeline, analyzeScene, aspectOf, bakeQuoteOf, bindTimelineContext, captureScene, createTimeline, extractMaterialShader, isNodeMaterial, linearToSrgbHex, outputSize, prepareBake, quoteBake, resolveOutput, sceneComplexity, timelineFromGsap, timelineFromTheatre, tracedTriangles };
4491
- //# sourceMappingURL=chunk-CX4WTVGH.js.map
4492
- //# sourceMappingURL=chunk-CX4WTVGH.js.map
4530
+ export { Timeline, analyzeScene, aspectOf, bakeQuoteOf, bindTimelineContext, captureScene, createTimeline, extractMaterialShader, isNodeMaterial, outputSize, prepareBake, quoteBake, resolveOutput, sceneComplexity, timelineFromGsap, timelineFromTheatre, tracedTriangles };
4531
+ //# sourceMappingURL=chunk-WLEFNUOH.js.map
4532
+ //# sourceMappingURL=chunk-WLEFNUOH.js.map