@oeave/bakery3 0.0.0-stage → 0.1.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-DaOlenyx.d.ts +1357 -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-25ZXSVQ3.js +1107 -0
  13. package/dist/chunk-25ZXSVQ3.js.map +1 -0
  14. package/dist/chunk-3G5QL4F4.js +145 -0
  15. package/dist/chunk-3G5QL4F4.js.map +1 -0
  16. package/dist/chunk-4E5VV4QY.js +12 -0
  17. package/dist/chunk-4E5VV4QY.js.map +1 -0
  18. package/dist/chunk-54WJDN5R.js +3286 -0
  19. package/dist/chunk-54WJDN5R.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-6YVQANMW.js +1463 -0
  23. package/dist/chunk-6YVQANMW.js.map +1 -0
  24. package/dist/chunk-AF5BIELI.js +70 -0
  25. package/dist/chunk-AF5BIELI.js.map +1 -0
  26. package/dist/chunk-APBOWWSV.js +92 -0
  27. package/dist/chunk-APBOWWSV.js.map +1 -0
  28. package/dist/chunk-ARMTTZXZ.js +1157 -0
  29. package/dist/chunk-ARMTTZXZ.js.map +1 -0
  30. package/dist/chunk-CX4WTVGH.js +4492 -0
  31. package/dist/chunk-CX4WTVGH.js.map +1 -0
  32. package/dist/chunk-HQTUFVMM.js +1412 -0
  33. package/dist/chunk-HQTUFVMM.js.map +1 -0
  34. package/dist/chunk-MD2U6S4N.js +1952 -0
  35. package/dist/chunk-MD2U6S4N.js.map +1 -0
  36. package/dist/chunk-S4AJTLLN.js +23 -0
  37. package/dist/chunk-S4AJTLLN.js.map +1 -0
  38. package/dist/chunk-TGFNQBKC.js +551 -0
  39. package/dist/chunk-TGFNQBKC.js.map +1 -0
  40. package/dist/chunk-V3QINEEG.js +87 -0
  41. package/dist/chunk-V3QINEEG.js.map +1 -0
  42. package/dist/chunk-W6WQ5UP7.js +91 -0
  43. package/dist/chunk-W6WQ5UP7.js.map +1 -0
  44. package/dist/chunk-WBIAFIHV.js +346 -0
  45. package/dist/chunk-WBIAFIHV.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 +944 -0
  58. package/dist/index.js +15 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/node/index.cjs +5115 -0
  61. package/dist/node/index.cjs.map +1 -0
  62. package/dist/node/index.d.cts +4862 -0
  63. package/dist/node/index.d.ts +576 -0
  64. package/dist/node/index.js +1279 -0
  65. package/dist/node/index.js.map +1 -0
  66. package/dist/prepare-C5qVvaw4.d.ts +112 -0
  67. package/dist/presets/index.d.ts +526 -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-S5TLCK4F.js +9 -0
  74. package/dist/room-S5TLCK4F.js.map +1 -0
  75. package/dist/rooms.gen-vhj6sFW5.d.ts +1434 -0
  76. package/dist/session-YCQS4MRH.js +9 -0
  77. package/dist/session-YCQS4MRH.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-BIPXaVPb.d.ts +1130 -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,592 @@
1
+ 'use client';import { createBakery3 } from '../chunk-ARMTTZXZ.js';
2
+ import '../chunk-WBIAFIHV.js';
3
+ import '../chunk-25ZXSVQ3.js';
4
+ import '../chunk-ZEBVAIJJ.js';
5
+ import { mountBakery3Devtools, mountTimelinePanel } from '../chunk-54WJDN5R.js';
6
+ export { Timeline, createTimeline } from '../chunk-CX4WTVGH.js';
7
+ import '../chunk-V3QINEEG.js';
8
+ import '../chunk-APBOWWSV.js';
9
+ import '../chunk-S4AJTLLN.js';
10
+ import { rememberEnvironmentSource } from '../chunk-AF5BIELI.js';
11
+ import '../chunk-TGFNQBKC.js';
12
+ import '../chunk-HQTUFVMM.js';
13
+ import '../chunk-4E5VV4QY.js';
14
+ import '../chunk-W6WQ5UP7.js';
15
+ import '../chunk-6NYR73Y7.js';
16
+ import '../chunk-MD2U6S4N.js';
17
+ import { Bakery3Error } from '../chunk-3G5QL4F4.js';
18
+ export { Bakery3Error, RenderBudgetExceeded } from '../chunk-3G5QL4F4.js';
19
+ import { createContext, useContext, useState, useEffect, useMemo, useRef, useSyncExternalStore, useCallback, Children, isValidElement, cloneElement, version } from 'react';
20
+ import { useThree, context, _roots } from '@react-three/fiber';
21
+ import { jsx, Fragment } from 'react/jsx-runtime';
22
+
23
+ // src/r3f/store.ts
24
+ var snapshot = null;
25
+ var listeners = /* @__PURE__ */ new Set();
26
+ var publishers = /* @__PURE__ */ new Map();
27
+ function publish(owner, next) {
28
+ const previous = publishers.get(owner);
29
+ if (previous && previous.bakery3 === next.bakery3 && previous.renders === next.renders && previous.store === next.store) {
30
+ return;
31
+ }
32
+ publishers.set(owner, next);
33
+ settle();
34
+ }
35
+ function unpublish(owner) {
36
+ if (publishers.delete(owner)) settle();
37
+ }
38
+ function settle() {
39
+ let current = null;
40
+ for (const entry of publishers.values()) current = entry;
41
+ if (current === snapshot) return;
42
+ snapshot = current;
43
+ for (const listener of listeners) listener();
44
+ }
45
+ function subscribe(listener) {
46
+ listeners.add(listener);
47
+ return () => listeners.delete(listener);
48
+ }
49
+ function getSnapshot() {
50
+ return snapshot;
51
+ }
52
+ function getServerSnapshot() {
53
+ return null;
54
+ }
55
+ var jobListeners = /* @__PURE__ */ new Set();
56
+ var running = /* @__PURE__ */ new Map();
57
+ function announceJob(job, kind) {
58
+ running.set(job, kind);
59
+ for (const listener of jobListeners) listener(job, kind);
60
+ const done = () => running.delete(job);
61
+ job.result().then(done, done);
62
+ }
63
+ function subscribeJobs(listener) {
64
+ jobListeners.add(listener);
65
+ for (const [job, kind] of running) listener(job, kind);
66
+ return () => jobListeners.delete(listener);
67
+ }
68
+
69
+ // src/r3f/canvas.ts
70
+ function findCanvas(inside, roots, caller) {
71
+ if (inside) return inside;
72
+ if (roots.size === 1) return [...roots.values()][0].store;
73
+ const component = caller.startsWith("<");
74
+ const who = component ? caller : `${caller}()`;
75
+ if (roots.size === 0) {
76
+ throw new Bakery3Error({
77
+ code: "InvalidRequest",
78
+ message: component ? `${who} found no <Canvas> on the page.` : `${who} was called before a <Canvas> mounted.`,
79
+ why: "useBakery3() renders the scene in your <Canvas>, and there is none on the page yet.",
80
+ fix: "Mount the <Canvas> first, or call it from a component inside the <Canvas>.",
81
+ docs: "https://bakery3.com/docs#your-first-render"
82
+ });
83
+ }
84
+ throw new Bakery3Error({
85
+ code: "InvalidRequest",
86
+ message: `${who} cannot tell which of the ${roots.size} canvases on this page to ${component ? "show" : "render"}.`,
87
+ why: component ? `${caller} with apiKey or token finds your scene on its own only when the page has one <Canvas>.` : "useBakery3({ apiKey }) finds your scene on its own only when the page has one <Canvas>.",
88
+ fix: component ? `Put <Bakery3Provider apiKey="\u2026"> inside the <Canvas> you want, and mount ${caller.replace(/>$/, " />")} without apiKey or token.` : 'Put <Bakery3Provider apiKey="\u2026"> inside the <Canvas> you want to render, and call useBakery3() without options.',
89
+ docs: "https://bakery3.com/docs#render-from-several-canvases-or-components"
90
+ });
91
+ }
92
+
93
+ // src/r3f/renderState.ts
94
+ var IDLE = Object.freeze({
95
+ job: null,
96
+ isRendering: false,
97
+ progress: 0,
98
+ previewUrl: void 0,
99
+ result: null,
100
+ error: null
101
+ });
102
+ function createRenderTracker(options = {}) {
103
+ let state = IDLE;
104
+ let latest = 0;
105
+ let detach = [];
106
+ const listeners2 = /* @__PURE__ */ new Set();
107
+ function set(patch) {
108
+ state = { ...state, ...patch };
109
+ for (const listener of listeners2) listener();
110
+ }
111
+ return {
112
+ getState: () => state,
113
+ subscribe(listener) {
114
+ listeners2.add(listener);
115
+ return () => listeners2.delete(listener);
116
+ },
117
+ async watch(start, kind = "render") {
118
+ const mine = ++latest;
119
+ for (const off of detach) off();
120
+ detach = [];
121
+ set({
122
+ job: null,
123
+ isRendering: true,
124
+ progress: 0,
125
+ previewUrl: void 0,
126
+ result: null,
127
+ error: null
128
+ });
129
+ let job;
130
+ try {
131
+ job = await start();
132
+ } catch (cause) {
133
+ if (mine === latest) set({ isRendering: false, error: asError(cause) });
134
+ throw cause;
135
+ }
136
+ if (mine !== latest) return job;
137
+ set({
138
+ job,
139
+ progress: job.progress ?? 0,
140
+ previewUrl: job.previewUrl
141
+ });
142
+ detach = [
143
+ job.on("progress", ({ percent }) => {
144
+ if (mine === latest) set({ progress: percent / 100 });
145
+ }),
146
+ job.on("preview", ({ url }) => {
147
+ if (mine === latest) set({ previewUrl: url });
148
+ })
149
+ ];
150
+ options.onJob?.(job, kind);
151
+ job.result().then(
152
+ (result) => {
153
+ if (mine === latest) {
154
+ set({ isRendering: false, progress: 1, result });
155
+ }
156
+ },
157
+ (cause) => {
158
+ if (mine === latest)
159
+ set({ isRendering: false, error: asError(cause) });
160
+ }
161
+ );
162
+ return job;
163
+ },
164
+ stop() {
165
+ latest++;
166
+ for (const off of detach) off();
167
+ detach = [];
168
+ state.job?.stop?.();
169
+ }
170
+ };
171
+ }
172
+ function asError(cause) {
173
+ return cause instanceof Error ? cause : new Error(String(cause));
174
+ }
175
+ var Bakery3Context = createContext(null);
176
+ function Bakery3Provider({
177
+ children,
178
+ ...options
179
+ }) {
180
+ const scene = useThree((state) => state.scene);
181
+ const camera = useThree((state) => state.camera);
182
+ const gl = useThree((state) => state.gl);
183
+ const store = useContext(context);
184
+ const [renders] = useState(newTracker);
185
+ const [owner] = useState(() => ({}));
186
+ const bakery3 = useClient(options);
187
+ useEffect(() => {
188
+ bakery3.attach({ scene, camera, renderer: gl });
189
+ }, [bakery3, scene, camera, gl]);
190
+ useEffect(() => rememberDreiEnvironment(scene), [scene, scene.environment]);
191
+ const value = useMemo(
192
+ () => ({ bakery3, renders, store }),
193
+ [bakery3, renders, store]
194
+ );
195
+ useEffect(() => () => unpublish(owner), [owner]);
196
+ useEffect(() => () => renders.stop(), [renders]);
197
+ useEffect(() => {
198
+ publish(owner, { bakery3, renders, store });
199
+ }, [owner, bakery3, renders, store]);
200
+ return /* @__PURE__ */ jsx(Bakery3Context.Provider, { value, children });
201
+ }
202
+ function newTracker() {
203
+ return createRenderTracker({ onJob: announceJob });
204
+ }
205
+ function useClient(options) {
206
+ const optionsRef = useRef(options);
207
+ optionsRef.current = options;
208
+ const present = options !== void 0;
209
+ const loose = options ?? {};
210
+ const { apiKey, baseUrl } = loose;
211
+ const keyNamed = options !== void 0 && "apiKey" in options;
212
+ const tokenNamed = options !== void 0 && "token" in options;
213
+ const hasToken = loose.token !== void 0;
214
+ const hasFetch = loose.fetch !== void 0;
215
+ return useMemo(() => {
216
+ if (!optionsRef.current) return null;
217
+ const given = optionsRef.current;
218
+ const { token, apiKey: apiKey2, fetch, ...rest } = given;
219
+ const auth = {
220
+ ..."apiKey" in given ? { apiKey: apiKey2 } : {},
221
+ ..."token" in given ? {
222
+ token: typeof token === "function" ? () => optionsRef.current.token() : token
223
+ } : {}
224
+ };
225
+ const transport = fetch ? {
226
+ fetch: ((input, init) => (optionsRef.current?.fetch ?? globalThis.fetch)(input, init))
227
+ } : {};
228
+ return createBakery3({
229
+ ...dropUndefined(rest),
230
+ ...auth,
231
+ ...transport
232
+ });
233
+ }, [present, apiKey, baseUrl, keyNamed, tokenNamed, hasToken, hasFetch]);
234
+ }
235
+ function dropUndefined(value) {
236
+ return Object.fromEntries(
237
+ Object.entries(value).filter(([, entry]) => entry !== void 0)
238
+ );
239
+ }
240
+ function rememberDreiEnvironment(scene) {
241
+ const texture = scene.environment;
242
+ const url = texture?.userData?.url ?? texture?.userData?.src;
243
+ if (texture && typeof url === "string") {
244
+ rememberEnvironmentSource(texture, url);
245
+ }
246
+ }
247
+ function useBakery3(options) {
248
+ const own = useClient(options);
249
+ const canvas = useContext(context);
250
+ const context$1 = useContext(Bakery3Context);
251
+ const published = useSyncExternalStore(
252
+ subscribe,
253
+ getSnapshot,
254
+ getServerSnapshot
255
+ );
256
+ const [ownRenders] = useState(newTracker);
257
+ useEffect(() => () => ownRenders.stop(), [ownRenders]);
258
+ const shared = own ? null : context$1 ?? published;
259
+ const bakery3 = own ?? shared?.bakery3 ?? null;
260
+ const renders = shared?.renders ?? ownRenders;
261
+ const sharedStore = shared?.store ?? null;
262
+ const state = useSyncExternalStore(
263
+ renders.subscribe,
264
+ renders.getState,
265
+ renders.getState
266
+ );
267
+ const client = useCallback(
268
+ (method) => {
269
+ if (!own) {
270
+ const found = mounted(bakery3, method);
271
+ if (sharedStore) rememberDreiEnvironment(sharedStore.getState().scene);
272
+ return found;
273
+ }
274
+ const { scene, camera, gl } = findCanvas(
275
+ canvas,
276
+ _roots,
277
+ method
278
+ ).getState();
279
+ rememberDreiEnvironment(scene);
280
+ own.attach({ scene, camera, renderer: gl });
281
+ return own;
282
+ },
283
+ [own, canvas, bakery3, sharedStore]
284
+ );
285
+ const watch = useCallback(
286
+ (kind, start) => renders.watch(start, kind),
287
+ [renders]
288
+ );
289
+ return useMemo(
290
+ () => ({
291
+ bakery3,
292
+ job: state.job,
293
+ isRendering: state.isRendering,
294
+ previewUrl: state.previewUrl,
295
+ progress: state.progress,
296
+ result: state.result,
297
+ error: state.error,
298
+ ready: bakery3 !== null,
299
+ check: () => client("check").check(),
300
+ estimate: async (options2) => client("estimate").estimate(options2),
301
+ timeline: (options2) => client("timeline").timeline(options2),
302
+ getRender: async (id) => (own ?? mounted(bakery3, "getRender")).getRender(id),
303
+ // Both go through `watch` so a video reports progress, previews and
304
+ // failures through exactly the same state a still does: a component
305
+ // showing a progress bar should not care which one it is watching.
306
+ render: ((options2) => options2 && "cameras" in options2 && Array.isArray(options2.cameras) ? client("render").render(options2) : watch(
307
+ "render",
308
+ async () => client("render").render(options2)
309
+ )),
310
+ renderVariants: async (options2) => client("renderVariants").renderVariants(options2),
311
+ quoteVariants: async (options2) => client("quoteVariants").quoteVariants(options2),
312
+ testVariants: async (options2, test) => client("testVariants").testVariants(options2, test),
313
+ renderVideo: (options2) => watch("video", async () => client("renderVideo").renderVideo(options2))
314
+ }),
315
+ [own, bakery3, client, watch, state]
316
+ );
317
+ }
318
+ function mounted(bakery3, method) {
319
+ if (bakery3) return bakery3;
320
+ throw new Bakery3Error({
321
+ code: "InvalidRequest",
322
+ message: `${method}() was called before <Bakery3Provider> mounted.`,
323
+ why: "useBakery3() without options reads the client from the provider, and no provider is mounted on this page yet. It belongs inside <Canvas>, which mounts its children after the first frame.",
324
+ fix: "Pass your key to the hook, useBakery3({ apiKey }) or useBakery3({ token }), or put <Bakery3Provider> inside <Canvas> and disable the button until `ready` is true.",
325
+ docs: "https://bakery3.com/docs#render-from-several-canvases-or-components"
326
+ });
327
+ }
328
+ var warned = /* @__PURE__ */ new Set();
329
+ function Bakery3Material({ web, render }) {
330
+ const ref = useRef(null);
331
+ const child = Children.only(web);
332
+ const element = isValidElement(child) ? child : null;
333
+ const theirs = element ? refOf(element) : void 0;
334
+ const merged = useCallback(
335
+ (material) => {
336
+ ref.current = material;
337
+ assignRef(theirs, material);
338
+ },
339
+ [theirs]
340
+ );
341
+ useEffect(() => {
342
+ const material = ref.current;
343
+ if (!material || !material.isMaterial) {
344
+ const message = "[bakery3] <Bakery3Material> could not reach the web material, so the render will not use the fallback. The web element must be a material element, such as <shaderMaterial>, or a component that forwards its ref to one.\n\nDocs: https://bakery3.com/docs/material-fallbacks";
345
+ if (!warned.has(message)) {
346
+ warned.add(message);
347
+ console.warn(message);
348
+ }
349
+ return;
350
+ }
351
+ material.userData = material.userData ?? {};
352
+ material.userData.bakery3 = {
353
+ ...material.userData.bakery3,
354
+ fallback: fallbackFromProps(render.props)
355
+ };
356
+ return () => {
357
+ if (material.userData?.bakery3) delete material.userData.bakery3.fallback;
358
+ };
359
+ }, [render]);
360
+ if (!element) return /* @__PURE__ */ jsx(Fragment, { children: web });
361
+ return cloneElement(element, {
362
+ ref: merged
363
+ });
364
+ }
365
+ function refOf(element) {
366
+ if (Number.parseInt(version, 10) >= 19) {
367
+ return element.props.ref;
368
+ }
369
+ return element.ref ?? void 0;
370
+ }
371
+ function assignRef(target, value) {
372
+ if (typeof target === "function") target(value);
373
+ else if (target) target.current = value;
374
+ }
375
+ var FALLBACK_KEYS = [
376
+ "color",
377
+ "metalness",
378
+ "roughness",
379
+ "clearcoat",
380
+ "clearcoatRoughness",
381
+ "transmission",
382
+ "thickness",
383
+ "ior",
384
+ "emissive",
385
+ "emissiveIntensity",
386
+ "opacity",
387
+ "sheen",
388
+ "sheenColor",
389
+ "iridescence",
390
+ "anisotropy"
391
+ ];
392
+ function fallbackFromProps(props) {
393
+ const out = {};
394
+ for (const key of FALLBACK_KEYS) {
395
+ if (props[key] !== void 0) out[key] = props[key];
396
+ }
397
+ return out;
398
+ }
399
+ var NO_CLIENT_GRACE_MS = 2500;
400
+ var CANVAS_POLL_MS = 500;
401
+ var warned2 = /* @__PURE__ */ new Set();
402
+ function warnOnce(message) {
403
+ if (warned2.has(message)) return;
404
+ warned2.add(message);
405
+ console.warn(`[bakery3] ${message}`);
406
+ }
407
+ function Bakery3Devtools(props) {
408
+ const inside = useContext(context);
409
+ const provider = useContext(Bakery3Context);
410
+ const published = useSyncExternalStore(
411
+ subscribe,
412
+ getSnapshot,
413
+ getServerSnapshot
414
+ );
415
+ const shared = provider ?? published;
416
+ const auth = authOf(props);
417
+ const orphaned = useOrphaned(auth === void 0 && shared === null);
418
+ const own = useClient(auth ?? (orphaned ? transportOf(props) : void 0));
419
+ const canvas = useCanvas(own !== null, inside);
420
+ const bakery3 = own ?? shared?.bakery3 ?? null;
421
+ const store = own ? canvas.store : shared?.store ?? null;
422
+ const latest = useRef(props);
423
+ latest.current = props;
424
+ useEffect(() => {
425
+ if (canvas.error) warnOnce(canvas.error.toDisplayString());
426
+ }, [canvas.error]);
427
+ const shape = `${Boolean(props.bakeTransport)}|${Boolean(props.history)}`;
428
+ useEffect(() => {
429
+ if (!bakery3 || !store) return;
430
+ const live = () => store.getState();
431
+ const panel = mountBakery3Devtools({
432
+ bakery3: rememberingEnvironment(bakery3, () => live().scene),
433
+ // Getters: R3F swaps the camera (a resize, a `makeDefault` camera)
434
+ // without remounting anything, and a remount here is exactly what
435
+ // would close the panel and revert the bake on screen.
436
+ get scene() {
437
+ return live().scene;
438
+ },
439
+ get camera() {
440
+ return live().camera;
441
+ },
442
+ get renderer() {
443
+ return live().gl;
444
+ },
445
+ ...latest.current.position ? { position: latest.current.position } : {},
446
+ ...latest.current.defaultOpen !== void 0 ? { defaultOpen: latest.current.defaultOpen } : {},
447
+ ...latest.current.defaultTab ? { defaultTab: latest.current.defaultTab } : {},
448
+ defaultQuality: latest.current.defaultQuality ?? "studio",
449
+ ...props.timeline ? { timeline: props.timeline } : {},
450
+ ...latest.current.timelineTargets ? { timelineTargets: latest.current.timelineTargets } : {},
451
+ ...latest.current.history ? { history: latest.current.history } : {},
452
+ onPlaybackChange: (active) => latest.current.onPlaybackChange?.(active),
453
+ ...props.bakeTransport ? {
454
+ bakeTransport: (spec, assets) => latest.current.bakeTransport(spec, assets)
455
+ } : {},
456
+ // Getters, because these two are read when a bake finishes rather than
457
+ // when the panel mounts: changing either has to take effect without a
458
+ // remount, and a remount is exactly what would lose the bake it applies
459
+ // to.
460
+ get bakeBaseUrl() {
461
+ return latest.current.bakeBaseUrl;
462
+ },
463
+ get muteLightsOnApply() {
464
+ return latest.current.muteLightsOnApply;
465
+ }
466
+ });
467
+ const untrack = [];
468
+ const offJobs = subscribeJobs((job, kind) => {
469
+ untrack.push(
470
+ panel.trackJob(
471
+ job,
472
+ kind === "video" ? "video from your app" : "render from your app"
473
+ )
474
+ );
475
+ });
476
+ return () => {
477
+ offJobs();
478
+ for (const off of untrack) off();
479
+ panel.dispose();
480
+ };
481
+ }, [bakery3, store, shape, props.timeline]);
482
+ return null;
483
+ }
484
+ function authOf(props) {
485
+ if (!("apiKey" in props) && !("token" in props)) return void 0;
486
+ return {
487
+ ..."apiKey" in props ? { apiKey: props.apiKey } : {},
488
+ ..."token" in props ? { token: props.token } : {},
489
+ ...transportOf(props)
490
+ };
491
+ }
492
+ function transportOf(props) {
493
+ return {
494
+ ...props.baseUrl !== void 0 ? { baseUrl: props.baseUrl } : {},
495
+ ...props.fetch !== void 0 ? { fetch: props.fetch } : {},
496
+ ...props.defaults !== void 0 ? { defaults: props.defaults } : {}
497
+ };
498
+ }
499
+ var NOT_YET = { store: null, error: null };
500
+ function useCanvas(enabled, inside) {
501
+ const [found, setFound] = useState(NOT_YET);
502
+ useEffect(() => {
503
+ if (!enabled) {
504
+ setFound(NOT_YET);
505
+ return;
506
+ }
507
+ const roots = _roots;
508
+ const look = () => {
509
+ let next = NOT_YET;
510
+ if (inside || roots.size > 0) {
511
+ try {
512
+ next = {
513
+ store: findCanvas(inside, roots, "<Bakery3Devtools>"),
514
+ error: null
515
+ };
516
+ } catch (error) {
517
+ next = { store: null, error };
518
+ }
519
+ }
520
+ setFound(
521
+ (previous) => previous.store === next.store && previous.error?.message === next.error?.message ? previous : next
522
+ );
523
+ };
524
+ look();
525
+ if (inside) return;
526
+ const timer = setInterval(look, CANVAS_POLL_MS);
527
+ return () => clearInterval(timer);
528
+ }, [enabled, inside]);
529
+ return found;
530
+ }
531
+ function useOrphaned(missing) {
532
+ const [orphaned, setOrphaned] = useState(false);
533
+ useEffect(() => {
534
+ if (!missing) {
535
+ setOrphaned(false);
536
+ return;
537
+ }
538
+ const timer = setTimeout(() => {
539
+ warnOnce(
540
+ "<Bakery3Devtools> found no client. Pass apiKey or token to it, or put <Bakery3Provider> inside your <Canvas>.\n\nDocs: https://bakery3.com/docs/devtools#mount-it"
541
+ );
542
+ setOrphaned(true);
543
+ }, NO_CLIENT_GRACE_MS);
544
+ return () => clearTimeout(timer);
545
+ }, [missing]);
546
+ return orphaned;
547
+ }
548
+ function rememberingEnvironment(bakery3, scene) {
549
+ const remember = () => rememberDreiEnvironment(scene());
550
+ return {
551
+ check: (target) => bakery3.check(target),
552
+ estimate: (options) => bakery3.estimate(options),
553
+ render: (options) => {
554
+ remember();
555
+ return bakery3.render(options);
556
+ },
557
+ renderVideo: (options) => {
558
+ remember();
559
+ return bakery3.renderVideo(options);
560
+ },
561
+ bake: (options) => {
562
+ remember();
563
+ return bakery3.bake(options);
564
+ }
565
+ };
566
+ }
567
+ function Bakery3Timeline(props) {
568
+ const panel = useRef(null);
569
+ const latest = useRef(props);
570
+ latest.current = props;
571
+ useEffect(() => {
572
+ panel.current = mountTimelinePanel({
573
+ timeline: props.timeline,
574
+ ...latest.current.targets ? { targets: latest.current.targets } : {},
575
+ ...latest.current.position ? { position: latest.current.position } : {},
576
+ ...latest.current.defaultOpen !== void 0 ? { defaultOpen: latest.current.defaultOpen } : {},
577
+ onPlaybackChange: (active) => latest.current.onPlaybackChange?.(active),
578
+ ...latest.current.onRenderVideo ? {
579
+ onRenderVideo: (timeline) => latest.current.onRenderVideo?.(timeline)
580
+ } : {}
581
+ });
582
+ return () => {
583
+ panel.current?.dispose();
584
+ panel.current = null;
585
+ };
586
+ }, [props.timeline]);
587
+ return null;
588
+ }
589
+
590
+ export { Bakery3Devtools, Bakery3Material, Bakery3Provider, Bakery3Timeline, useBakery3 };
591
+ //# sourceMappingURL=index.js.map
592
+ //# sourceMappingURL=index.js.map