@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,836 @@
1
+ import { registerBuiltin } from '../chunk-S4AJTLLN.js';
2
+ import * as THREE from 'three';
3
+ import { SimplexNoise } from 'three/addons/math/SimplexNoise.js';
4
+ import { mergeVertices } from 'three/addons/utils/BufferGeometryUtils.js';
5
+ import { PMREMGenerator, MeshStandardNodeMaterial } from 'three/webgpu';
6
+ import { positionWorld, positionLocal, float, sin, atan, mix, color, smoothstep, fract, oneMinus, min, normalize, asin, max, pow, vec3, mx_worley_noise_float, dot, saturate, mx_fractal_noise_float, abs, normalView, positionViewDirection, cos } from 'three/tsl';
7
+
8
+ registerBuiltin(
9
+ { uuid: positionWorld.uuid },
10
+ { op: "position", params: () => ({ space: "world" }) }
11
+ );
12
+ var SHAPE_KINDS = [
13
+ "sphere",
14
+ "blob",
15
+ "pebble",
16
+ "torus",
17
+ "ring",
18
+ "knot",
19
+ "capsule",
20
+ "box"
21
+ ];
22
+ var SHAPE_FINISHES = [
23
+ "glow",
24
+ "glass",
25
+ "matte",
26
+ "satin",
27
+ "metal",
28
+ "rim",
29
+ "nebula",
30
+ "beacon",
31
+ "iris",
32
+ "scan",
33
+ "magma",
34
+ "holo",
35
+ "aurora",
36
+ "topo",
37
+ "spiral"
38
+ ];
39
+ var MOTION_KINDS = [
40
+ "spin",
41
+ "tumble",
42
+ "pulse",
43
+ "bob",
44
+ "orbit",
45
+ "drift",
46
+ "glow",
47
+ "tint",
48
+ "frost"
49
+ ];
50
+ var DEFAULT_STRENGTH = {
51
+ glow: 5,
52
+ rim: 4,
53
+ nebula: 3,
54
+ beacon: 5,
55
+ scan: 6,
56
+ magma: 6,
57
+ holo: 6,
58
+ aurora: 2,
59
+ topo: 6,
60
+ glass: 0,
61
+ matte: 0,
62
+ satin: 0,
63
+ metal: 0,
64
+ iris: 0,
65
+ spiral: 0
66
+ };
67
+ var DEFAULT_NOISE = {
68
+ sphere: 0,
69
+ blob: 0.5,
70
+ pebble: 0.25,
71
+ torus: 0,
72
+ ring: 0,
73
+ knot: 0,
74
+ capsule: 0,
75
+ box: 0
76
+ };
77
+ var ROUGHNESS = {
78
+ glow: 0.55,
79
+ glass: 0.03,
80
+ matte: 0.85,
81
+ satin: 0.4,
82
+ metal: 0.22,
83
+ rim: 0.6,
84
+ nebula: 0.6,
85
+ beacon: 0.45,
86
+ iris: 0.16,
87
+ scan: 0.5,
88
+ magma: 0.8,
89
+ holo: 0.5,
90
+ aurora: 0.6,
91
+ topo: 0.5,
92
+ spiral: 0.35
93
+ };
94
+ var GRAPH_FINISHES = /* @__PURE__ */ new Set([
95
+ "rim",
96
+ "nebula",
97
+ "beacon",
98
+ "iris",
99
+ "scan",
100
+ "magma",
101
+ "holo",
102
+ "aurora",
103
+ "topo",
104
+ "spiral"
105
+ ]);
106
+ var EMISSION_COVERAGE = {
107
+ scan: 0.22,
108
+ magma: 0.07,
109
+ holo: 0.2,
110
+ aurora: 0.5,
111
+ topo: 0.16
112
+ };
113
+ function motionSuits(kind, finish) {
114
+ if (kind === "glow") return finish === "glow";
115
+ if (kind === "frost")
116
+ return finish === "glass" || finish === "metal" || finish === "satin";
117
+ if (kind === "tint") return !GRAPH_FINISHES.has(finish);
118
+ return true;
119
+ }
120
+ var GLOW_LIGHT = Math.PI / 4;
121
+ function mulberry32(seed) {
122
+ let a = Math.floor(seed) >>> 0 || 2654435769;
123
+ return () => {
124
+ a = a + 1831565813 >>> 0;
125
+ let t = a;
126
+ t = Math.imul(t ^ t >>> 15, t | 1);
127
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
128
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
129
+ };
130
+ }
131
+ function hashString(s) {
132
+ let h = 2166136261;
133
+ for (let i = 0; i < s.length; i++) {
134
+ h ^= s.charCodeAt(i);
135
+ h = Math.imul(h, 16777619);
136
+ }
137
+ return h >>> 0;
138
+ }
139
+ function primitive(kind, noisy) {
140
+ switch (kind) {
141
+ case "sphere":
142
+ return mergeVertices(new THREE.IcosahedronGeometry(0.5, noisy ? 5 : 4));
143
+ case "blob":
144
+ return mergeVertices(new THREE.IcosahedronGeometry(0.5, 5));
145
+ case "pebble": {
146
+ const g = mergeVertices(new THREE.IcosahedronGeometry(0.5, 5));
147
+ g.scale(1, 0.62, 0.85);
148
+ return g;
149
+ }
150
+ case "torus":
151
+ return mergeVertices(new THREE.TorusGeometry(0.36, 0.14, 48, 112));
152
+ case "ring":
153
+ return mergeVertices(new THREE.TorusGeometry(0.45, 0.05, 24, 160));
154
+ case "knot":
155
+ return mergeVertices(new THREE.TorusKnotGeometry(0.3, 0.1, 256, 32));
156
+ case "capsule":
157
+ return mergeVertices(new THREE.CapsuleGeometry(0.22, 0.56, 16, 40));
158
+ case "box":
159
+ return noisy ? mergeVertices(new THREE.BoxGeometry(1, 1, 1, 18, 18, 18)) : new THREE.BoxGeometry(1, 1, 1, 18, 18, 18);
160
+ }
161
+ }
162
+ function displace(geometry, amount, size, seed) {
163
+ geometry.computeVertexNormals();
164
+ const random = mulberry32(seed);
165
+ const simplex = new SimplexNoise({ random });
166
+ const offset = new THREE.Vector3(
167
+ random() * 100,
168
+ random() * 100,
169
+ random() * 100
170
+ );
171
+ const frequency = 1.9 / size;
172
+ const amplitude = amount * 0.2 * size;
173
+ const positions = geometry.attributes.position;
174
+ const normals = geometry.attributes.normal;
175
+ const p = new THREE.Vector3();
176
+ const n = new THREE.Vector3();
177
+ const fbm = (x, y, z) => (simplex.noise3d(x, y, z) + 0.5 * simplex.noise3d(x * 2.1, y * 2.1, z * 2.1) + 0.25 * simplex.noise3d(x * 4.3, y * 4.3, z * 4.3)) / 1.75;
178
+ for (let i = 0; i < positions.count; i++) {
179
+ p.fromBufferAttribute(positions, i);
180
+ n.fromBufferAttribute(normals, i);
181
+ const v = fbm(
182
+ p.x * frequency + offset.x,
183
+ p.y * frequency + offset.y,
184
+ p.z * frequency + offset.z
185
+ );
186
+ p.addScaledVector(n, v * amplitude);
187
+ positions.setXYZ(i, p.x, p.y, p.z);
188
+ }
189
+ positions.needsUpdate = true;
190
+ geometry.computeVertexNormals();
191
+ }
192
+ function shapeGeometry(shape, compositionSeed) {
193
+ const noise = shape.noise ?? DEFAULT_NOISE[shape.kind];
194
+ const geometry = primitive(shape.kind, noise > 0);
195
+ geometry.computeBoundingBox();
196
+ const extent = geometry.boundingBox.getSize(new THREE.Vector3());
197
+ const longest = Math.max(extent.x, extent.y, extent.z) || 1;
198
+ geometry.scale(
199
+ shape.size / longest,
200
+ shape.size / longest,
201
+ shape.size / longest
202
+ );
203
+ if (noise > 0)
204
+ displace(
205
+ geometry,
206
+ noise,
207
+ shape.size,
208
+ (compositionSeed ^ hashString(shape.id)) >>> 0
209
+ );
210
+ geometry.computeBoundingSphere();
211
+ return geometry;
212
+ }
213
+ function rimMaterial(c, strength) {
214
+ const material = new MeshStandardNodeMaterial();
215
+ material.name = "bakery3-shape-rim";
216
+ material.roughness = ROUGHNESS.rim;
217
+ material.metalness = 0;
218
+ material.emissive.set(0);
219
+ material.emissiveIntensity = 1;
220
+ const facing = saturate(abs(dot(normalView, positionViewDirection)));
221
+ const rim = pow(oneMinus(facing), 2.5);
222
+ material.colorNode = color(c.clone().multiplyScalar(0.06));
223
+ material.emissiveNode = color(c).mul(rim).mul(float(strength));
224
+ return material;
225
+ }
226
+ function nebulaMaterial(c, strength, size, seed) {
227
+ const material = new MeshStandardNodeMaterial();
228
+ material.name = "bakery3-shape-nebula";
229
+ material.roughness = ROUGHNESS.nebula;
230
+ material.metalness = 0;
231
+ material.emissive.set(0);
232
+ material.emissiveIntensity = 1;
233
+ const random = mulberry32(seed);
234
+ const offset = vec3(random() * 40, random() * 40, random() * 40);
235
+ const n = mx_fractal_noise_float(
236
+ positionLocal.mul(float(3.2 / size)).add(offset),
237
+ 3,
238
+ 2,
239
+ 0.5
240
+ );
241
+ const mask = smoothstep(-0.05, 0.55, n);
242
+ material.colorNode = color(c.clone().multiplyScalar(0.08));
243
+ material.emissiveNode = mix(
244
+ color(c.clone().multiplyScalar(0.12)),
245
+ color(c),
246
+ mask
247
+ ).mul(float(strength));
248
+ return material;
249
+ }
250
+ var BEACON = { points: 7, inner: 7, outer: 13 };
251
+ var BEACON_COVERAGE = BEACON.points * (1 - Math.cos(THREE.MathUtils.degToRad((BEACON.inner + BEACON.outer) / 2))) / 2;
252
+ function beaconPoints(seed) {
253
+ const random = mulberry32(seed);
254
+ const turn = new THREE.Euler(
255
+ random() * Math.PI * 2,
256
+ random() * Math.PI * 2,
257
+ random() * Math.PI * 2
258
+ );
259
+ const golden = Math.PI * (3 - Math.sqrt(5));
260
+ const v = new THREE.Vector3();
261
+ return Array.from({ length: BEACON.points }, (_, i) => {
262
+ const y = 1 - 2 * (i + 0.5) / BEACON.points;
263
+ const r = Math.sqrt(1 - y * y);
264
+ v.set(Math.cos(golden * i) * r, y, Math.sin(golden * i) * r).applyEuler(
265
+ turn
266
+ );
267
+ return [v.x, v.y, v.z];
268
+ });
269
+ }
270
+ function beaconMaterial(c, strength, seed) {
271
+ const material = new MeshStandardNodeMaterial();
272
+ material.name = "bakery3-shape-beacon";
273
+ material.roughness = ROUGHNESS.beacon;
274
+ material.metalness = 0;
275
+ material.emissive.set(0);
276
+ material.emissiveIntensity = 1;
277
+ const direction = normalize(positionLocal);
278
+ const dark = Math.cos(THREE.MathUtils.degToRad(BEACON.outer));
279
+ const lit = Math.cos(THREE.MathUtils.degToRad(BEACON.inner));
280
+ let mask = float(0);
281
+ for (const p of beaconPoints(seed))
282
+ mask = mask.add(
283
+ smoothstep(dark, lit, dot(direction, vec3(p[0], p[1], p[2])))
284
+ );
285
+ material.colorNode = color(c.clone().multiplyScalar(0.04));
286
+ material.emissiveNode = color(c).mul(saturate(mask)).mul(float(strength / BEACON_COVERAGE));
287
+ return material;
288
+ }
289
+ function graphMaterial(finish) {
290
+ const material = new MeshStandardNodeMaterial();
291
+ material.name = `bakery3-shape-${finish}`;
292
+ material.roughness = ROUGHNESS[finish];
293
+ material.metalness = 0;
294
+ material.emissive.set(0);
295
+ material.emissiveIntensity = 1;
296
+ return material;
297
+ }
298
+ var facingEye = () => saturate(abs(dot(normalView, positionViewDirection)));
299
+ var COMPANION_HUE = 0.72;
300
+ function companion(c) {
301
+ const hsl = c.getHSL({ h: 0, s: 0, l: 0 });
302
+ const away = (COMPANION_HUE - hsl.h + 1.5) % 1 - 0.5;
303
+ const turn = Math.abs(away) < 0.06 ? -0.17 : Math.sign(away) * Math.min(Math.abs(away), 0.2);
304
+ return c.clone().offsetHSL(turn, 0, 0);
305
+ }
306
+ var IRIS = { turns: 1.15, along: 0.35 };
307
+ function irisMaterial(c, size, seed) {
308
+ const material = graphMaterial("iris");
309
+ material.metalness = 1;
310
+ const random = mulberry32(seed);
311
+ const phase = facingEye().mul(IRIS.turns).add(positionLocal.y.mul(IRIS.along / size)).add(random());
312
+ const channel = (offset) => cos(phase.add(offset).mul(TAU)).mul(0.5).add(0.5);
313
+ const film = vec3(channel(0), channel(1 / 3), channel(2 / 3));
314
+ material.colorNode = mix(color(c), film, 0.72);
315
+ material.emissiveNode = film.mul(pow(oneMinus(facingEye()), 2)).mul(0.3);
316
+ return material;
317
+ }
318
+ var SCAN = { lines: 5, width: 0.17 };
319
+ function scanMaterial(c, strength, size) {
320
+ const material = graphMaterial("scan");
321
+ const f = fract(positionWorld.y.mul(SCAN.lines / size));
322
+ const w = SCAN.width;
323
+ const band = smoothstep(0.5 - w, 0.5 - w * 0.45, f).mul(
324
+ oneMinus(smoothstep(0.5 + w * 0.45, 0.5 + w, f))
325
+ );
326
+ material.colorNode = color(c.clone().multiplyScalar(0.05));
327
+ material.emissiveNode = color(c).mul(band).mul(float(strength));
328
+ return material;
329
+ }
330
+ var MAGMA = { cells: 5, from: 0.5, to: 0.7 };
331
+ function magmaMaterial(c, strength, size, seed) {
332
+ const material = graphMaterial("magma");
333
+ const random = mulberry32(seed);
334
+ const offset = vec3(random() * 40, random() * 40, random() * 40);
335
+ const d = mx_worley_noise_float(
336
+ positionLocal.mul(float(MAGMA.cells / size)).add(offset),
337
+ float(1)
338
+ );
339
+ const seam = smoothstep(MAGMA.from, MAGMA.to, d);
340
+ material.colorNode = color(c.clone().multiplyScalar(0.03).addScalar(0.012));
341
+ material.emissiveNode = mix(color(c), color(16777215), pow(seam, 5).mul(0.25)).mul(seam).mul(float(strength));
342
+ return material;
343
+ }
344
+ var HOLO = { parallels: 9, meridians: 14, width: 0.07 };
345
+ function holoMaterial(c, strength) {
346
+ const material = graphMaterial("holo");
347
+ const n = normalize(positionLocal);
348
+ const latitude = asin(n.y).mul(HOLO.parallels / Math.PI);
349
+ const longitude = atan(n.z, n.x).mul(HOLO.meridians / TAU);
350
+ const line = (cells) => {
351
+ const f = fract(cells);
352
+ return oneMinus(
353
+ smoothstep(HOLO.width * 0.45, HOLO.width, min(f, oneMinus(f)))
354
+ );
355
+ };
356
+ const grid = max(line(latitude), line(longitude));
357
+ const edge = pow(oneMinus(facingEye()), 3).mul(0.45);
358
+ material.colorNode = color(c.clone().multiplyScalar(0.03));
359
+ material.emissiveNode = color(c).mul(grid.add(edge)).mul(float(strength));
360
+ return material;
361
+ }
362
+ function auroraMaterial(c, strength, size, seed) {
363
+ const material = graphMaterial("aurora");
364
+ const random = mulberry32(seed);
365
+ const [a, b, d] = [random() * TAU, random() * TAU, random() * TAU];
366
+ const p = positionLocal.mul(float(1 / size));
367
+ const fold = sin(p.x.mul(7.3).add(a)).mul(sin(p.z.mul(6.1).add(b)));
368
+ const veil = smoothstep(
369
+ 0.2,
370
+ 0.9,
371
+ sin(p.y.mul(17).add(fold.mul(2.6)).add(d)).mul(0.5).add(0.5)
372
+ );
373
+ const trade = sin(p.y.mul(4.1).add(fold).add(a)).mul(0.5).add(0.5);
374
+ material.colorNode = color(c.clone().multiplyScalar(0.05));
375
+ material.emissiveNode = mix(color(companion(c)), color(c), trade).mul(mix(float(0.06), float(1), veil)).mul(float(strength));
376
+ return material;
377
+ }
378
+ var TOPO = { lines: 11, wobble: 0.05, width: 0.09 };
379
+ function topoMaterial(c, strength, size, seed) {
380
+ const material = graphMaterial("topo");
381
+ const random = mulberry32(seed);
382
+ const [a, b] = [random() * TAU, random() * TAU];
383
+ const p = positionLocal.mul(float(1 / size));
384
+ const height = p.y.add(
385
+ sin(p.x.mul(6.3).add(a)).mul(sin(p.z.mul(5.7).add(b))).mul(TOPO.wobble)
386
+ );
387
+ const f = fract(height.mul(TOPO.lines));
388
+ const line = oneMinus(
389
+ smoothstep(TOPO.width * 0.45, TOPO.width, min(f, oneMinus(f)))
390
+ );
391
+ material.colorNode = color(c.clone().multiplyScalar(0.05));
392
+ material.emissiveNode = color(c).mul(line).mul(float(strength));
393
+ return material;
394
+ }
395
+ var SPIRAL = { arms: 4, twist: 7 };
396
+ function spiralMaterial(c, size, seed) {
397
+ const material = graphMaterial("spiral");
398
+ const random = mulberry32(seed);
399
+ const p = positionLocal.mul(float(1 / size));
400
+ const wind = sin(
401
+ atan(p.z, p.x).mul(SPIRAL.arms).add(p.y.mul(SPIRAL.twist)).add(random() * TAU)
402
+ );
403
+ material.colorNode = mix(
404
+ color(c),
405
+ color(15921909),
406
+ smoothstep(-0.08, 0.08, wind)
407
+ );
408
+ return material;
409
+ }
410
+ function materialFor(shape, c, strength, seed) {
411
+ switch (shape.finish) {
412
+ case "glow":
413
+ return new THREE.MeshStandardMaterial({
414
+ color: c.clone().multiplyScalar(0.1),
415
+ emissive: c,
416
+ emissiveIntensity: strength,
417
+ roughness: ROUGHNESS.glow,
418
+ metalness: 0
419
+ });
420
+ case "glass":
421
+ return new THREE.MeshPhysicalMaterial({
422
+ color: c,
423
+ transmission: 1,
424
+ ior: 1.5,
425
+ thickness: shape.size * 0.5,
426
+ attenuationColor: c,
427
+ attenuationDistance: shape.size,
428
+ roughness: ROUGHNESS.glass,
429
+ metalness: 0,
430
+ specularIntensity: 1
431
+ });
432
+ case "matte":
433
+ return new THREE.MeshStandardMaterial({
434
+ color: c,
435
+ roughness: ROUGHNESS.matte,
436
+ metalness: 0
437
+ });
438
+ case "satin":
439
+ return new THREE.MeshStandardMaterial({
440
+ color: c,
441
+ roughness: ROUGHNESS.satin,
442
+ metalness: 0
443
+ });
444
+ case "metal":
445
+ return new THREE.MeshStandardMaterial({
446
+ color: c,
447
+ roughness: ROUGHNESS.metal,
448
+ metalness: 1
449
+ });
450
+ case "rim":
451
+ return rimMaterial(c, strength);
452
+ case "nebula":
453
+ return nebulaMaterial(c, strength, shape.size, seed);
454
+ case "beacon":
455
+ return beaconMaterial(c, strength, seed);
456
+ case "iris":
457
+ return irisMaterial(c, shape.size, seed);
458
+ case "scan":
459
+ return scanMaterial(c, strength, shape.size);
460
+ case "magma":
461
+ return magmaMaterial(c, strength, shape.size, seed);
462
+ case "holo":
463
+ return holoMaterial(c, strength);
464
+ case "aurora":
465
+ return auroraMaterial(c, strength, shape.size, seed);
466
+ case "topo":
467
+ return topoMaterial(c, strength, shape.size, seed);
468
+ case "spiral":
469
+ return spiralMaterial(c, shape.size, seed);
470
+ }
471
+ }
472
+ function createComposition(spec, at = [0, 0, 0]) {
473
+ const seed = spec.seed ?? 1;
474
+ const group = new THREE.Group();
475
+ group.name = "bakery3-composition";
476
+ group.position.set(at[0], at[1], at[2]);
477
+ const shapes = [];
478
+ for (const shape of spec.shapes) {
479
+ const c = new THREE.Color(shape.color);
480
+ const strength = shape.strength ?? DEFAULT_STRENGTH[shape.finish];
481
+ const shapeSeed = (seed ^ hashString(shape.id)) >>> 0;
482
+ const mesh = new THREE.Mesh(
483
+ shapeGeometry(shape, seed),
484
+ materialFor(shape, c, strength, shapeSeed)
485
+ );
486
+ mesh.name = `shape-${shape.id}`;
487
+ mesh.position.set(shape.position[0], shape.position[1], shape.position[2]);
488
+ const rotation = [
489
+ THREE.MathUtils.degToRad(shape.rotation?.[0] ?? 0),
490
+ THREE.MathUtils.degToRad(shape.rotation?.[1] ?? 0),
491
+ THREE.MathUtils.degToRad(shape.rotation?.[2] ?? 0)
492
+ ];
493
+ mesh.rotation.set(rotation[0], rotation[1], rotation[2]);
494
+ mesh.castShadow = true;
495
+ mesh.receiveShadow = true;
496
+ group.add(mesh);
497
+ const built = {
498
+ spec: shape,
499
+ mesh,
500
+ base: {
501
+ position: [...shape.position],
502
+ rotation,
503
+ strength,
504
+ roughness: ROUGHNESS[shape.finish],
505
+ color: c.clone()
506
+ }
507
+ };
508
+ const worth = glowWorth(shape.finish, strength);
509
+ if (worth > 0) {
510
+ const light = new THREE.PointLight(
511
+ c,
512
+ worth * shape.size * shape.size * GLOW_LIGHT,
513
+ 0,
514
+ 2
515
+ );
516
+ light.name = `glow-${shape.id}`;
517
+ light.castShadow = false;
518
+ light.userData.bakery3 = { exclude: true };
519
+ mesh.add(light);
520
+ built.light = light;
521
+ }
522
+ shapes.push(built);
523
+ }
524
+ return { group, shapes };
525
+ }
526
+ function glowWorth(finish, strength) {
527
+ if (finish === "glow" || finish === "beacon") return strength;
528
+ return strength * (EMISSION_COVERAGE[finish] ?? 0);
529
+ }
530
+ function followGlow(built) {
531
+ for (const shape of built.shapes) {
532
+ if (!shape.light) continue;
533
+ const material = shape.mesh.material;
534
+ const size2 = shape.spec.size * shape.spec.size;
535
+ if (GRAPH_FINISHES.has(shape.spec.finish)) {
536
+ const level = shape.mesh.scale.x;
537
+ shape.light.intensity = glowWorth(shape.spec.finish, shape.base.strength) * size2 * GLOW_LIGHT * level;
538
+ if (shape.halo) shape.halo.material.opacity = haloGain(shape) * level;
539
+ continue;
540
+ }
541
+ shape.light.intensity = material.emissiveIntensity * material.opacity * size2 * GLOW_LIGHT;
542
+ shape.light.color.copy(material.emissive);
543
+ if (shape.halo) {
544
+ shape.halo.material.opacity = haloGain(shape) * material.emissiveIntensity * material.opacity / Math.max(shape.base.strength, 1e-6);
545
+ shape.halo.material.color.copy(material.emissive);
546
+ }
547
+ }
548
+ }
549
+ function haloGain(shape) {
550
+ return shape.halo?.userData.gain ?? 0;
551
+ }
552
+ var REFLECTIVE = /* @__PURE__ */ new Set([
553
+ "glass",
554
+ "metal",
555
+ "satin",
556
+ "matte",
557
+ "iris",
558
+ "spiral"
559
+ ]);
560
+ var EMITTERS = /* @__PURE__ */ new Set([
561
+ "glow",
562
+ "rim",
563
+ "nebula",
564
+ "beacon",
565
+ "scan",
566
+ "magma",
567
+ "holo",
568
+ "aurora",
569
+ "topo"
570
+ ]);
571
+ function emitterPoses(built) {
572
+ const world = new THREE.Vector3();
573
+ return built.shapes.filter((s) => EMITTERS.has(s.spec.finish)).map((s) => {
574
+ s.mesh.getWorldPosition(world);
575
+ const material = s.mesh.material;
576
+ return {
577
+ id: s.spec.id,
578
+ position: [world.x, world.y, world.z],
579
+ strength: (material.emissiveIntensity ?? 1) * material.opacity * s.mesh.scale.x
580
+ };
581
+ });
582
+ }
583
+ function emittersMoved(before, after) {
584
+ if (before.length !== after.length) return true;
585
+ for (let i = 0; i < before.length; i++) {
586
+ const a = before[i];
587
+ const b = after[i];
588
+ if (a.id !== b.id) return true;
589
+ const d = Math.hypot(
590
+ a.position[0] - b.position[0],
591
+ a.position[1] - b.position[1],
592
+ a.position[2] - b.position[2]
593
+ );
594
+ if (d > 0.01) return true;
595
+ if (Math.abs(a.strength - b.strength) > 0.05 * Math.max(Math.abs(a.strength), 1e-6))
596
+ return true;
597
+ }
598
+ return false;
599
+ }
600
+ var FOLLOW_INTERVAL_MS = 100;
601
+ async function snapshotReflections(renderer, scene, built, center) {
602
+ const none = {
603
+ shapes: 0,
604
+ refresh: async () => {
605
+ },
606
+ follow: () => {
607
+ },
608
+ busy: false,
609
+ settle: async () => {
610
+ },
611
+ dispose: () => {
612
+ }
613
+ };
614
+ if (scene.environment) return none;
615
+ const targets = built.shapes.filter((s) => REFLECTIVE.has(s.spec.finish));
616
+ if (!targets.length) return none;
617
+ const position = new THREE.Vector3(center[0], center[1], center[2]);
618
+ let current;
619
+ let retired;
620
+ let last = [];
621
+ let lastAt = 0;
622
+ let busy;
623
+ let disposed = false;
624
+ const generator = new PMREMGenerator(renderer);
625
+ const take = async () => {
626
+ const hidden = targets.map((s) => [s.mesh, s.mesh.visible]);
627
+ for (const [mesh] of hidden) mesh.visible = false;
628
+ try {
629
+ last = emitterPoses(built);
630
+ lastAt = performance.now();
631
+ const target = await generator.fromSceneAsync(scene, 0.03, 0.1, 100, {
632
+ position,
633
+ ...current ? { renderTarget: current } : {}
634
+ });
635
+ if (disposed) {
636
+ if (target !== current) target.dispose();
637
+ return;
638
+ }
639
+ if (target !== current) {
640
+ for (const shape of targets) {
641
+ const material = shape.mesh.material;
642
+ material.envMap = target.texture;
643
+ material.envMapIntensity = 1;
644
+ material.needsUpdate = true;
645
+ }
646
+ retired?.dispose();
647
+ retired = current;
648
+ current = target;
649
+ }
650
+ } finally {
651
+ for (const [mesh, visible] of hidden) mesh.visible = visible;
652
+ }
653
+ };
654
+ const refresh = () => {
655
+ if (!busy) busy = take().finally(() => busy = void 0);
656
+ return busy;
657
+ };
658
+ await refresh();
659
+ return {
660
+ shapes: targets.length,
661
+ refresh,
662
+ follow() {
663
+ if (disposed || busy || performance.now() - lastAt < FOLLOW_INTERVAL_MS)
664
+ return;
665
+ if (emittersMoved(last, emitterPoses(built))) void refresh();
666
+ },
667
+ get busy() {
668
+ return busy !== void 0;
669
+ },
670
+ async settle() {
671
+ if (busy) await busy;
672
+ if (!disposed && emittersMoved(last, emitterPoses(built)))
673
+ await refresh();
674
+ },
675
+ dispose() {
676
+ disposed = true;
677
+ for (const shape of targets) {
678
+ const material = shape.mesh.material;
679
+ material.envMap = null;
680
+ material.needsUpdate = true;
681
+ }
682
+ current?.dispose();
683
+ retired?.dispose();
684
+ current = void 0;
685
+ retired = void 0;
686
+ generator.dispose();
687
+ }
688
+ };
689
+ }
690
+ var TAU = Math.PI * 2;
691
+ var easeInOut = (u) => u < 0.5 ? 2 * u * u : 1 - Math.pow(-2 * u + 2, 2) / 2;
692
+ var smoothstep01 = (x) => x <= 0 ? 0 : x >= 1 ? 1 : x * x * (3 - 2 * x);
693
+ var LOOP_FADE_SECONDS = 1.5;
694
+ function motionLoops(m) {
695
+ switch (m.kind) {
696
+ case "spin":
697
+ case "tumble":
698
+ case "orbit":
699
+ return Number.isInteger(m.turns ?? 1);
700
+ case "pulse":
701
+ case "glow":
702
+ return Number.isInteger(m.cycles ?? 2);
703
+ case "bob":
704
+ return Number.isInteger(m.cycles ?? 1);
705
+ case "drift":
706
+ case "tint":
707
+ case "frost":
708
+ return false;
709
+ }
710
+ }
711
+ function compositionLoop(spec, clip) {
712
+ const camera = clip.camera ?? {};
713
+ const cameraLoops = (camera.orbitY ?? 0) % 360 === 0 && !camera.orbitX && !camera.dolly;
714
+ const motionsLoop = spec.shapes.every(
715
+ (s) => (s.motion ?? []).every(
716
+ (m) => !motionSuits(m.kind, s.finish) || motionLoops(m)
717
+ )
718
+ );
719
+ if (cameraLoops && motionsLoop) return { fade: 0, start: 0 };
720
+ const frames = Math.max(1, Math.round(clip.seconds * clip.fps));
721
+ const fade = Math.min(LOOP_FADE_SECONDS, clip.seconds / 4);
722
+ return { fade, start: Math.min(frames - 1, Math.ceil(fade * clip.fps)) };
723
+ }
724
+ function loopPresence(time, duration, fade) {
725
+ if (fade <= 0) return 1;
726
+ return Math.min(
727
+ smoothstep01(time / fade),
728
+ smoothstep01((duration - time) / fade)
729
+ );
730
+ }
731
+ var fadesByScale = (finish) => GRAPH_FINISHES.has(finish);
732
+ function poseAt(shape, u) {
733
+ const b = shape.base;
734
+ const pose = {
735
+ position: [...b.position],
736
+ rotation: [...b.rotation],
737
+ scale: 1,
738
+ strength: b.strength,
739
+ roughness: b.roughness,
740
+ color: b.color.clone(),
741
+ opacity: 1
742
+ };
743
+ for (const m of shape.spec.motion ?? []) {
744
+ if (!motionSuits(m.kind, shape.spec.finish)) continue;
745
+ switch (m.kind) {
746
+ case "spin": {
747
+ const axis = m.axis === "x" ? 0 : m.axis === "z" ? 2 : 1;
748
+ pose.rotation[axis] += (m.turns ?? 1) * TAU * u;
749
+ break;
750
+ }
751
+ case "tumble":
752
+ pose.rotation[0] += (m.turns ?? 1) * TAU * u;
753
+ pose.rotation[2] += (m.turns ?? 1) * TAU * u;
754
+ break;
755
+ case "pulse":
756
+ pose.scale *= 1 + (m.amount ?? 0.12) * Math.sin(TAU * (m.cycles ?? 2) * u);
757
+ break;
758
+ case "bob":
759
+ pose.position[1] += (m.amount ?? 0.12) * Math.sin(TAU * (m.cycles ?? 1) * u);
760
+ break;
761
+ case "orbit": {
762
+ const radius = m.radius ?? Math.hypot(b.position[0], b.position[2]);
763
+ const start = Math.atan2(b.position[2], b.position[0]);
764
+ const angle = start + (m.turns ?? 1) * TAU * u;
765
+ pose.position[0] = Math.cos(angle) * radius;
766
+ pose.position[2] = Math.sin(angle) * radius;
767
+ break;
768
+ }
769
+ case "drift": {
770
+ const e = easeInOut(u);
771
+ for (let i = 0; i < 3; i++)
772
+ pose.position[i] = b.position[i] + (m.to[i] - b.position[i]) * e;
773
+ break;
774
+ }
775
+ case "glow":
776
+ pose.strength = b.strength * (1 + (m.amount ?? 0.6) * Math.sin(TAU * (m.cycles ?? 2) * u));
777
+ break;
778
+ case "tint":
779
+ pose.color = b.color.clone().lerp(new THREE.Color(m.to), easeInOut(u));
780
+ break;
781
+ case "frost":
782
+ pose.roughness = b.roughness + ((m.to ?? 0.6) - b.roughness) * easeInOut(u);
783
+ break;
784
+ }
785
+ }
786
+ return pose;
787
+ }
788
+ function touched(shape, fades) {
789
+ const out = /* @__PURE__ */ new Set();
790
+ if (fades) out.add(fadesByScale(shape.spec.finish) ? "scale" : "opacity");
791
+ for (const m of shape.spec.motion ?? []) {
792
+ if (!motionSuits(m.kind, shape.spec.finish)) continue;
793
+ if (m.kind === "spin" || m.kind === "tumble") out.add("rotation");
794
+ else if (m.kind === "pulse") out.add("scale");
795
+ else if (m.kind === "bob" || m.kind === "orbit" || m.kind === "drift")
796
+ out.add("position");
797
+ else if (m.kind === "glow") out.add("emissiveIntensity");
798
+ else if (m.kind === "tint")
799
+ out.add(shape.spec.finish === "glow" ? "emissive" : "color");
800
+ else if (m.kind === "frost") out.add("roughness");
801
+ }
802
+ return out;
803
+ }
804
+ function animateComposition(tl, built, duration, fps, loop = { fade: 0, start: 0 }) {
805
+ const frames = Math.max(1, Math.round(duration * fps));
806
+ const fades = loop.fade > 0;
807
+ let tracks = 0;
808
+ for (const shape of built.shapes) {
809
+ const props = touched(shape, fades);
810
+ if (!props.size) continue;
811
+ const lanes = [...props].map((property) => ({
812
+ property,
813
+ track: tl.track(shape.mesh, property)
814
+ }));
815
+ const byScale = fadesByScale(shape.spec.finish);
816
+ for (let f = 0; f < frames; f++) {
817
+ const time = f / fps;
818
+ const pose = poseAt(shape, duration > 0 ? time / duration : 0);
819
+ if (fades) {
820
+ const presence = loopPresence(time, duration, loop.fade);
821
+ if (byScale) pose.scale *= Math.max(presence, 1e-3);
822
+ else pose.opacity = presence;
823
+ }
824
+ for (const { property, track } of lanes) {
825
+ const value = property === "position" ? pose.position : property === "rotation" ? pose.rotation : property === "scale" ? [pose.scale, pose.scale, pose.scale] : property === "emissiveIntensity" ? [pose.strength] : property === "roughness" ? [pose.roughness] : property === "opacity" ? [pose.opacity] : [pose.color.r, pose.color.g, pose.color.b];
826
+ track.keyframes.push({ time, value: [...value] });
827
+ }
828
+ }
829
+ tracks += lanes.length;
830
+ }
831
+ return tracks;
832
+ }
833
+
834
+ export { MOTION_KINDS, SHAPE_FINISHES, SHAPE_KINDS, animateComposition, compositionLoop, createComposition, followGlow, snapshotReflections };
835
+ //# sourceMappingURL=index.js.map
836
+ //# sourceMappingURL=index.js.map