@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,975 @@
1
+ import { Scene, Camera, Texture, Object3D } from 'three';
2
+ import { E as EnvironmentSpec, S as SceneManifest, V as Vec3, d as CompatibilityReport, j as BakeBundle, M as MaterialShaderSpec, k as ShaderSlot, h as CompatibilityIssue, Q as QualityPreset, O as OutputSpec, R as RenderSpec } from './bake-DZ-CJR6f.js';
3
+ export { a as BakeQuality, i as BakeSettings, l as BakeSkip, e as BakeSpec, B as BakeTextureSize, m as BakeUv, n as BakedObject, F as FrameSequenceIndex, o as OutputFormat, p as ShaderGraph, q as ShaderGraphNode } from './bake-DZ-CJR6f.js';
4
+ export { a as AnimationChannel, A as AnimationSpec, b as AnimationTarget } from './animation-B1h0Ryvj.js';
5
+ import { y as AssetDescriptor, z as RenderState, D as RenderError, d as Bakery3Client, e as RenderRecord, v as RenderResult, c as Bakery3Error, C as CostEstimate, B as BatchProgress, E as BakeRecord, G as BakeResult, j as RenderSet, V as VariantsQuote, T as TestRunOptions, f as BatchOpenRequest, b as Batch, H as ClientOptions } from './testRun-20OARnQr.js';
6
+ export { I as Bakery3ErrorCode, J as BatchAction, k as BatchAddRequest, l as BatchAddResponse, K as BatchCost, L as BatchCounts, m as BatchExportLine, n as BatchItemOutcome, o as BatchItemRecord, p as BatchItemRequest, q as BatchItemsPage, r as BatchPageRefused, a as BatchRecord, M as BatchState, N as BudgetedKind, O as ClientAuth, F as FlushOptions, P as MintedToken, R as Recorded, x as RenderBudgetExceeded, Q as RenderBudgetInit, s as RenderSetFailure, t as RenderSetImage, S as RenderSetRefusal, U as RenderSetRefused, i as RetryPolicy, w as TokenProvider, u as WaitOptions } from './testRun-20OARnQr.js';
7
+ import { d as TrackTarget, T as Timeline, a as TimelineOptions } from './timeline-ChwgD7bT.js';
8
+ export { A as AuthoredValue, E as Easing, K as Keyframe, O as OrbitOptions, P as PushSpec, S as SegmentOptions, e as TimelineEvent, f as TimelineJSON, b as Track, c as createTimeline } from './timeline-ChwgD7bT.js';
9
+ import { P as PrepareBakeSettings } from './prepare-BtjY4G3q.js';
10
+ export { B as BakeSimplifyInput } from './prepare-BtjY4G3q.js';
11
+
12
+ /**
13
+ * What leaves the browser: a scene as one GLB plus a manifest.
14
+ *
15
+ * The SDK reads the live scene graph and writes one binary and one small
16
+ * manifest. The manifest holds everything glTF cannot say (camera, lights,
17
+ * color management, the environment, shader graphs, the compatibility report)
18
+ * and names every asset by its sha256. The only URL a manifest may carry is a
19
+ * preset environment on the preset library.
20
+ *
21
+ * Nothing here changes the caller's scene beyond the id stamps, and those are
22
+ * removed in a `finally`: a render must be invisible to the application that
23
+ * asked for it.
24
+ */
25
+
26
+ /**
27
+ * What a capture is made from.
28
+ *
29
+ * By the time an HDRI is on `scene.environment` it has usually been through
30
+ * PMREM and is a GPU render target: the original equirectangular pixels are
31
+ * gone, and reading them back would give a blurred cubemap rather than the
32
+ * map the renderer wants. So the SDK asks to be told once, at load:
33
+ *
34
+ * const hdri = await new RGBELoader().loadAsync('/studio.hdr');
35
+ * rememberEnvironmentSource(hdri, '/studio.hdr');
36
+ *
37
+ * `@oeave/bakery3/r3f` does this automatically for drei's `<Environment files>`.
38
+ * Without it the render still happens; it falls back to the flat ambient term
39
+ * and says so in the compatibility report rather than guessing.
40
+ */
41
+ type CaptureOptions = {
42
+ scene: Scene;
43
+ camera: Camera;
44
+ renderer?: {
45
+ outputColorSpace?: string;
46
+ toneMapping?: number;
47
+ toneMappingExposure?: number;
48
+ };
49
+ /**
50
+ * An HDRI to light with, when the SDK cannot recover the one in the scene.
51
+ * A URL the page can fetch, or the file's bytes.
52
+ */
53
+ environment?: string | ArrayBuffer;
54
+ /** Opaque application state, stored with the render. Never rendered. */
55
+ productState?: Record<string, unknown>;
56
+ /** Override the transparent-background default. */
57
+ background?: EnvironmentSpec['background'];
58
+ };
59
+ type CapturedScene = {
60
+ manifest: SceneManifest;
61
+ /** Every blob this manifest refers to, ready to be hashed against storage. */
62
+ assets: Array<AssetDescriptor & {
63
+ bytes: number;
64
+ data: ArrayBuffer;
65
+ }>;
66
+ };
67
+
68
+ /**
69
+ * gsap and Theatre.js, without a dependency on either.
70
+ *
71
+ * The adapters sample through, they do not translate. Neither library's eases
72
+ * are parsed, no plugin surface is reimplemented, nothing is inspected beyond
73
+ * "can this thing be told to go to time t". The adapter seeks the foreign
74
+ * timeline frame by frame and writes down where the named objects ended up.
75
+ *
76
+ * That is a trade. It loses the ability to re-time the result later, and it
77
+ * wins exactness: whatever gsap does (a custom ease, a stagger, a plugin
78
+ * nobody here has heard of) is what gets rendered, because the numbers came
79
+ * out of gsap itself.
80
+ *
81
+ * Both return a plain `Timeline`, so the panel, `seek()` and `renderVideo()`
82
+ * do not know or care where the motion came from.
83
+ */
84
+
85
+ /** One property of one object to record. `'camera'` is allowed and behaves
86
+ * the way it does everywhere else in the timeline. */
87
+ type SampledTrack = {
88
+ object: TrackTarget;
89
+ property: string;
90
+ label?: string;
91
+ };
92
+ type AdapterOptions = {
93
+ /** Sampling rate. Also the timeline's own fps unless overridden at bake. */
94
+ fps?: number;
95
+ /** Seconds. Required when the foreign timeline cannot report its own. */
96
+ duration?: number;
97
+ /**
98
+ * What to record. Required, and there is no "everything" option: the adapter
99
+ * cannot ask gsap what it animates without reimplementing gsap, so a list it
100
+ * guessed would be a video quietly missing whatever was not guessed.
101
+ */
102
+ tracks: SampledTrack[];
103
+ /** Needed for any camera track: the pose is read off the live camera at
104
+ * each sampled frame, not out of the source timeline. */
105
+ camera?: Camera;
106
+ scene?: Scene;
107
+ };
108
+ /**
109
+ * A gsap timeline or tween.
110
+ *
111
+ * `seek(t, suppressEvents)` is gsap 3's API; `time(t)` is the older shape and
112
+ * is still what a few wrappers expose, so both are tried. Events are
113
+ * suppressed where the library allows it: sampling should not fire your
114
+ * `onUpdate` two hundred times.
115
+ */
116
+ declare function timelineFromGsap(gsapTimeline: unknown, options: AdapterOptions): Timeline;
117
+ /**
118
+ * A Theatre.js sequence (`sheet.sequence`).
119
+ *
120
+ * Theatre drives time by assignment (`sequence.position = t`) rather than by a
121
+ * method, and reports its length on `.length` when the project defines one.
122
+ */
123
+ declare function timelineFromTheatre(sequence: unknown, options: AdapterOptions): Timeline;
124
+
125
+ type JobEvents = {
126
+ queued: {
127
+ render: RenderRecord;
128
+ };
129
+ preparing: {
130
+ render: RenderRecord;
131
+ };
132
+ preview: {
133
+ url: string;
134
+ render: RenderRecord;
135
+ };
136
+ progress: {
137
+ percent: number;
138
+ state: RenderState;
139
+ render: RenderRecord;
140
+ };
141
+ complete: {
142
+ result: RenderResult;
143
+ render: RenderRecord;
144
+ };
145
+ failed: {
146
+ error: Bakery3Error;
147
+ render: RenderRecord;
148
+ };
149
+ cancelled: {
150
+ render: RenderRecord;
151
+ };
152
+ };
153
+ /** How long to wait for a job, and when to stop waiting. */
154
+ type JobResultOptions = {
155
+ /**
156
+ * Stops this wait: the promise rejects with the signal's reason. The job
157
+ * keeps polling while anything else still waits on it or listens to it,
158
+ * and the render itself is not cancelled.
159
+ */
160
+ signal?: AbortSignal;
161
+ };
162
+ /** What every job's record has: a render's and a bake's alike. */
163
+ type JobRecord = {
164
+ id: string;
165
+ state: RenderState;
166
+ progress: number;
167
+ result?: unknown;
168
+ error?: RenderError;
169
+ };
170
+ /**
171
+ * The polling, the events and the waiting that a render job and a bake job
172
+ * share. Not public API: `RenderJob` and `BakeJob` are.
173
+ *
174
+ * Polling starts on the first `on()` or `result()`, and stops when the job
175
+ * ends, when `stop()` is called, or when nothing is waiting on it or
176
+ * listening to it any more (a later `on()` or `result()` picks it up again).
177
+ */
178
+ declare abstract class PolledJob<R extends JobRecord, Out, E extends {
179
+ failed: unknown;
180
+ cancelled: unknown;
181
+ }> {
182
+ readonly id: string;
183
+ protected record: R;
184
+ protected readonly client: Bakery3Client;
185
+ private readonly subscribers;
186
+ /** The last payload of each replayed event, for a listener added late. */
187
+ private readonly lastPayloads;
188
+ private pending;
189
+ /** `result()` calls still waiting. */
190
+ private waiting;
191
+ /** The running poll loop's switch, or null when no loop runs. */
192
+ private poller;
193
+ /** Set once the job has settled, for good: a terminal state or a verdict. */
194
+ private hasEnded;
195
+ /** "render" or "bake", for messages. */
196
+ protected abstract readonly jobNoun: 'render' | 'bake';
197
+ protected abstract readonly pollSchedule: readonly number[];
198
+ /** Events a late listener is handed the latest of. */
199
+ protected abstract readonly replayedEvents: ReadonlyArray<keyof E>;
200
+ /** One poll. */
201
+ protected abstract readRecord(signal: AbortSignal): Promise<R>;
202
+ /** The events a new record raises before any terminal handling. */
203
+ protected abstract observeRecord(record: R): void;
204
+ /** A completed record into its output; emits `complete`. May throw. */
205
+ protected abstract completeRecord(record: R): Promise<Out>;
206
+ /** The record under the payload's own name: `{ render }` or `{ bake }`. */
207
+ protected abstract recordPayload(record: R): object;
208
+ constructor(client: Bakery3Client, record: R);
209
+ get status(): RenderState;
210
+ get progress(): number;
211
+ /**
212
+ * Listen for an event. Starts polling if nothing has yet.
213
+ *
214
+ * A listener added after an event already fired is called with the latest
215
+ * one, on the next microtask: the latest `preview` and `progress`, and
216
+ * `complete`, `failed` or `cancelled` once the job has ended. Returns the
217
+ * unsubscribe function, so a React effect can clean up without a second
218
+ * API.
219
+ */
220
+ on<K extends keyof E>(event: K, listener: (payload: E[K]) => void): () => void;
221
+ /**
222
+ * The finished output. Starts polling if nothing has yet.
223
+ *
224
+ * Several callers may await the same job (a component, a devtools panel,
225
+ * an analytics hook) and share one polling loop. Rejects with a
226
+ * `Bakery3Error` when the job fails (after `failed` is emitted), with code
227
+ * `Cancelled` when it was cancelled, and with an `AbortError` when the wait
228
+ * was stopped by `stop()` or by `signal`.
229
+ */
230
+ result(options?: JobResultOptions): Promise<Out>;
231
+ /**
232
+ * Stop polling, here, now. The job is NOT cancelled on the server: it
233
+ * keeps running and is still charged, and `getRender(id)` or `getBake(id)`
234
+ * reads it later. A pending `result()` rejects with an `AbortError`, and a
235
+ * later `on()` or `result()` starts polling again.
236
+ *
237
+ * `cancel()` is the other one: it asks the server to stop the job, which
238
+ * then ends as `cancelled`.
239
+ */
240
+ stop(): void;
241
+ /** Apply a record read from the API, and settle if it is the last one. */
242
+ protected applyRecord(record: R): void;
243
+ protected emitEvent<K extends keyof E>(event: K, payload: E[K]): void;
244
+ private pendingOutcome;
245
+ private isWatched;
246
+ private startPolling;
247
+ private pollLoop;
248
+ /** Settle on the record's terminal state. Once. */
249
+ private settleEnd;
250
+ /** Emit `failed`, then reject. Every failure goes through here. */
251
+ private settleFailure;
252
+ private expiredError;
253
+ }
254
+ declare class RenderJob extends PolledJob<RenderRecord, RenderResult, JobEvents> {
255
+ protected readonly jobNoun = "render";
256
+ protected readonly pollSchedule: number[];
257
+ protected readonly replayedEvents: ReadonlyArray<keyof JobEvents>;
258
+ private previewSeen;
259
+ private lastState;
260
+ constructor(client: Bakery3Client, record: RenderRecord);
261
+ get previewUrl(): string | undefined;
262
+ /** The estimate this render was accepted under. */
263
+ get estimate(): CostEstimate | undefined;
264
+ /**
265
+ * Ask the server to stop the render. It ends as `cancelled`: `cancelled`
266
+ * is emitted and `result()` rejects with code `Cancelled`. To stop
267
+ * watching without stopping the render, call `stop()`.
268
+ */
269
+ cancel(): Promise<void>;
270
+ protected readRecord(signal: AbortSignal): Promise<RenderRecord>;
271
+ protected observeRecord(record: RenderRecord): void;
272
+ protected completeRecord(record: RenderRecord): Promise<RenderResult>;
273
+ protected recordPayload(record: RenderRecord): {
274
+ render: RenderRecord;
275
+ };
276
+ }
277
+
278
+ /**
279
+ * Upload only what the service does not already have.
280
+ *
281
+ * The whole flow, and the reason a second render feels instant:
282
+ *
283
+ * hash locally -> which of these exist? -> PUT only the misses
284
+ *
285
+ * First render Uploaded: 148 MB
286
+ * Camera moves Uploaded: 2 KB
287
+ * Texture change Uploaded: 6 MB
288
+ *
289
+ * Bytes go from the browser to object storage directly, on a presigned PUT.
290
+ * The control plane never touches them, so the upload runs as fast as the
291
+ * developer's connection allows.
292
+ */
293
+
294
+ type UploadProgress = {
295
+ /** Assets that were already in storage: the cache hit. */
296
+ cached: number;
297
+ /** Assets uploaded this time. */
298
+ uploaded: number;
299
+ bytesUploaded: number;
300
+ bytesTotal: number;
301
+ };
302
+
303
+ /**
304
+ * One capture, many pictures: the pure pieces.
305
+ *
306
+ * A capture is one GLB with every finish inside it and a few KB of manifest.
307
+ * A picture of it is that manifest with another camera and another hidden
308
+ * list, and nothing else. `render({ cameras })`, `renderVariants()` and the
309
+ * catalog recorder all build their items from these, and they are exported
310
+ * from `@oeave/bakery3/catalog` so a recorder that writes `manifests.jsonl`
311
+ * instead of submitting builds exactly the same ones.
312
+ */
313
+
314
+ type CatalogCamera = {
315
+ id: string;
316
+ position: Vec3;
317
+ target: Vec3;
318
+ /** Vertical field of view in degrees, as `PerspectiveCamera.fov`. */
319
+ fov: number;
320
+ };
321
+ type CatalogFinish = {
322
+ id: string;
323
+ /** Object names this finish shows. Anything another finish claims and this
324
+ * one does not is hidden; anything no finish claims stays as it is. */
325
+ show: string[];
326
+ };
327
+
328
+ /**
329
+ * Many pictures from one call.
330
+ *
331
+ * // every camera of the scene you have
332
+ * const shots = await bakery3.render({ cameras: ['hero', 'front', 'detail'] });
333
+ * const images = await shots.result();
334
+ *
335
+ * // every variant, from every camera
336
+ * const run = await bakery3.renderVariants({
337
+ * key: 'fall-2026',
338
+ * variants: products,
339
+ * apply: (product) => configurator.show(product),
340
+ * cameras: ['hero', 'front', 'detail'],
341
+ * maxCost: 600,
342
+ * });
343
+ * await run.wait();
344
+ * for await (const image of run.images()) save(image.variant, image.camera, image.url);
345
+ *
346
+ * Both record into a batch and hand back a `RenderSet`, so a set of three
347
+ * and a catalog of six thousand are the same object with the same
348
+ * guarantees: one ceiling for all of it, one poll for all of it, and a
349
+ * re-run that adopts what already rendered.
350
+ *
351
+ * What this file is careful about is the customer's machine. A catalog is
352
+ * recorded in a browser tab, and a tab that holds two hundred products, or
353
+ * two hundred exported GLBs, or six thousand result records, is a tab that
354
+ * dies at product 140 with nothing to show for it. So:
355
+ *
356
+ * - One variant resident. A variant is applied, captured, uploaded, turned
357
+ * into items, flushed and let go of before the next is touched. The
358
+ * exported GLB is the largest thing a run holds, and it holds one.
359
+ * - The list need not exist. `variants` is any iterable or async iterable: a
360
+ * generator, a database cursor, a paged fetch. It is pulled one at a time
361
+ * and never collected.
362
+ * - One capture, many pictures. Cameras and finishes multiply items, not
363
+ * exports: each is the same few-KB manifest with another camera and
364
+ * another hidden list (`variant.ts`).
365
+ * - Nothing uploads twice. Assets are content addressed; a variant that
366
+ * changed no geometry uploads nothing, and one whose hashes this run has
367
+ * already sent does not even ask.
368
+ * - Results are walked, not held. `images()` and `failures()` read the
369
+ * ledger a page at a time by cursor. `result()` collects, and says so: it
370
+ * is for a handful of cameras.
371
+ */
372
+
373
+ /**
374
+ * A camera to photograph from:
375
+ *
376
+ * - a **name**: a camera in the scene with that `name`. Looked up again for
377
+ * every variant, after `apply`, so a camera that ships inside a product's
378
+ * own GLB, or rides a rig the variant moves, is read where it then stands.
379
+ * - a **Camera**: read as it stands at capture. Its `name` is its id.
380
+ * - a **declaration**: `{ id, position, target, fov }`, for a shot no camera
381
+ * object exists for. Its aspect is the output's.
382
+ */
383
+ type ViewCamera = string | Camera | CatalogCamera;
384
+ /** What `apply` may hand back: how to undo it. Called before the next variant, and when a run stops. */
385
+ type VariantCleanup = () => void | Promise<void>;
386
+ type VariantProgress = BatchProgress & {
387
+ /** The variant just recorded. */
388
+ variant: string;
389
+ /** Variants recorded so far, this one included. */
390
+ variants: number;
391
+ /** Pictures recorded so far: variants × finishes × cameras. */
392
+ images: number;
393
+ /** What this variant's capture uploaded. Usually nothing after the first. */
394
+ upload?: UploadProgress;
395
+ };
396
+
397
+ declare function rememberEnvironmentSource(texture: Texture, source: string | ArrayBuffer, options?: {
398
+ preset?: boolean;
399
+ }): void;
400
+
401
+ /**
402
+ * The compatibility checker.
403
+ *
404
+ * three.js can express things the renderer cannot reproduce faithfully. Those
405
+ * are never rendered gray in silence: an unsupported material produces a
406
+ * named, located, actionable issue, and the developer decides.
407
+ *
408
+ * It runs entirely in the page and costs nothing, so "will my scene work?"
409
+ * can be answered before creating an account.
410
+ */
411
+
412
+ type AnalyzeResult = CompatibilityReport & {
413
+ /** Triangles the exporter will write. Feeds the size warning and estimate. */
414
+ triangles: number;
415
+ /** Distinct textures found, and their largest dimension. */
416
+ textures: {
417
+ count: number;
418
+ maxDimension: number;
419
+ };
420
+ /** Distinct materials that emit light; see `SceneManifest.stats.emitters`. */
421
+ emitters: number;
422
+ };
423
+ declare function analyzeScene(root: Object3D): AnalyzeResult;
424
+
425
+ /** What `await job.result()` gives back. */
426
+ type BakeOutput = Omit<BakeResult, 'summary'> & {
427
+ /** The full bundle, uv arrays included, with every uri already a URL. */
428
+ bundle: BakeBundle;
429
+ };
430
+ type BakeJobEvents = {
431
+ queued: {
432
+ bake: BakeRecord;
433
+ };
434
+ progress: {
435
+ percent: number;
436
+ state: RenderState;
437
+ bake: BakeRecord;
438
+ };
439
+ complete: {
440
+ output: BakeOutput;
441
+ bake: BakeRecord;
442
+ };
443
+ failed: {
444
+ error: Bakery3Error;
445
+ bake: BakeRecord;
446
+ };
447
+ cancelled: {
448
+ bake: BakeRecord;
449
+ };
450
+ };
451
+ /**
452
+ * Polling starts on the first `on()` or `result()`; a listener added late
453
+ * hears the latest `progress` and how the bake ended. `stop()` stops watching
454
+ * and `cancel()` stops the bake, as for a render (see `RenderJob`).
455
+ */
456
+ declare class BakeJob extends PolledJob<BakeRecord, BakeOutput, BakeJobEvents> {
457
+ protected readonly jobNoun = "bake";
458
+ protected readonly pollSchedule: number[];
459
+ protected readonly replayedEvents: ReadonlyArray<keyof BakeJobEvents>;
460
+ private readonly fetchImpl;
461
+ private lastState;
462
+ constructor(client: Bakery3Client, record: BakeRecord, fetchImpl?: typeof fetch);
463
+ /** The estimate this bake was accepted under. */
464
+ get estimate(): CostEstimate | undefined;
465
+ /**
466
+ * Ask the server to stop the bake. It ends as `cancelled`: `cancelled` is
467
+ * emitted and `result()` rejects with code `Cancelled`. To stop watching
468
+ * without stopping the bake, call `stop()`.
469
+ */
470
+ cancel(): Promise<void>;
471
+ protected readRecord(signal: AbortSignal): Promise<BakeRecord>;
472
+ protected observeRecord(record: BakeRecord): void;
473
+ protected completeRecord(record: BakeRecord): Promise<BakeOutput>;
474
+ protected recordPayload(record: BakeRecord): {
475
+ bake: BakeRecord;
476
+ };
477
+ /**
478
+ * bundle.json from storage, every uri replaced by its signed URL.
479
+ *
480
+ * A name the bundle uses that the control plane signed nothing for is a
481
+ * refusal here, with the name: never a bundle that quietly points at a
482
+ * texture the browser will 403 on ten seconds later.
483
+ */
484
+ private resolve;
485
+ }
486
+
487
+ /** The published version. Must equal the version in package.json. */
488
+ declare const SDK_VERSION = "0.2.0";
489
+
490
+ /**
491
+ * TSL to a renderer-neutral shader graph.
492
+ *
493
+ * A `MeshStandardNodeMaterial` is already a graph of small typed operations.
494
+ * This walks that live graph structurally and writes it down as the
495
+ * protocol's shader graph (see `protocol/shader.ts`), naming every
496
+ * node it cannot translate instead of skipping or approximating it.
497
+ *
498
+ * Structural, not nominal. Nothing here imports from three: `instanceof`
499
+ * would tie `check()` to `three/tsl`, which only exists from r167, and the
500
+ * checker must run for everyone. TSL nodes are recognized the way three
501
+ * recognizes them internally, by their `.type` string and their `isX` flags,
502
+ * which also keeps this working across three versions.
503
+ *
504
+ * Two things need more than structure:
505
+ * - anonymous singletons (`positionWorld`, `time`) are recognized by uuid,
506
+ * registered when the developer imports `@oeave/bakery3/tsl`
507
+ * - `Fn()` calls are expanded by running their JS function, which works for
508
+ * the pure composition functions TSL libraries are made of and fails
509
+ * safely (a named issue, not a crash) for anything builder-dependent.
510
+ *
511
+ * Uniforms are baked to the value they held at capture. A still render is a
512
+ * snapshot of the application; `time`-driven shaders render the moment the
513
+ * button was pressed, and the report says so.
514
+ */
515
+
516
+ /** A texture the graph samples; capture hashes its pixels and fills the id. */
517
+ type ShaderTextureRef = {
518
+ texture: Texture;
519
+ /** Every graph node param waiting for this texture's asset hash. */
520
+ apply: (image: string) => void;
521
+ };
522
+ type ExtractedShader = {
523
+ /** Null when nothing was extractable at all. */
524
+ spec: MaterialShaderSpec | null;
525
+ /** Slot names that translated cleanly. */
526
+ supportedSlots: ShaderSlot[];
527
+ /** Slot names that had to be dropped, with why in `issues`. */
528
+ failedSlots: ShaderSlot[];
529
+ issues: Omit<CompatibilityIssue, 'path' | 'materialId' | 'materialName' | 'materialType'>[];
530
+ textures: ShaderTextureRef[];
531
+ };
532
+ /** The material properties this file reads, structurally. */
533
+ type AnyNodeMaterial = {
534
+ uuid: string;
535
+ name?: string;
536
+ type?: string;
537
+ isNodeMaterial?: boolean;
538
+ isMeshStandardNodeMaterial?: boolean;
539
+ isMeshPhysicalNodeMaterial?: boolean;
540
+ isMeshBasicNodeMaterial?: boolean;
541
+ [key: string]: unknown;
542
+ };
543
+ declare function isNodeMaterial(material: unknown): material is AnyNodeMaterial;
544
+ /**
545
+ * Extract one node material.
546
+ *
547
+ * Slots fail independently: a material whose color graph translates but
548
+ * whose roughness graph uses `dFdx` renders with the color graph and the
549
+ * static roughness value, and two issues say exactly that.
550
+ */
551
+ declare function extractMaterialShader(material: AnyNodeMaterial): ExtractedShader;
552
+
553
+ /**
554
+ * The active camera, in full.
555
+ *
556
+ * It is written out as data rather than referenced into the GLB by name
557
+ * because the live camera is often not in the graph the exporter walks: R3F
558
+ * holds the default camera outside the scene, drei's controls swap it, and a
559
+ * configurator often animates a camera that was never added as a child of
560
+ * anything.
561
+ */
562
+
563
+ /**
564
+ * Depth of field, marked on a perspective camera as
565
+ * `camera.userData.bakery3 = { focus: { fStop: 2.8, target: [0, 0.4, 0] } }`.
566
+ *
567
+ * three has no aperture: its depth of field is a post-processing pass, so the
568
+ * render cannot read it off the camera and the developer says it here.
569
+ * `fStop` is a full-frame camera's f-number at the camera's own `fov`, so a
570
+ * smaller number blurs more. `target` is the world point that stays sharp
571
+ * and the render keeps it sharp through a clip as the camera moves;
572
+ * `distance` is a fixed focus distance in metres instead. One of the two.
573
+ */
574
+ type CameraFocus = {
575
+ fStop: number;
576
+ target?: Vec3 | {
577
+ x: number;
578
+ y: number;
579
+ z: number;
580
+ };
581
+ distance?: number;
582
+ };
583
+
584
+ /**
585
+ * Walking the scene: ids, runtime state, lights, and what to skip.
586
+ *
587
+ * Everything here reads the live graph and writes plain JSON. Nothing mutates
588
+ * the developer's scene except `stampIds`, which is reversed before the
589
+ * capture returns: a render must never leave a visible mark on the
590
+ * application it was called from.
591
+ */
592
+
593
+ /**
594
+ * Which objects the exporter should skip.
595
+ *
596
+ * Not the same set as "hidden". A hidden object still ships in the GLB and is
597
+ * hidden per render, so a configurator toggling parts keeps hitting the asset
598
+ * cache. This is only for things that must never reach the renderer at all:
599
+ * helpers, gizmos, the developer's own opt-outs, and anything transient the
600
+ * app draws over the top.
601
+ */
602
+ declare function shouldExclude(object: Object3D): boolean;
603
+
604
+ /**
605
+ * @oeave/bakery3: ray trace the Three.js scene you're already rendering.
606
+ *
607
+ * import { createBakery3 } from '@oeave/bakery3';
608
+ *
609
+ * const bakery3 = createBakery3({
610
+ * token: () => fetch('/api/bakery3-token', { method: 'POST' }).then(r => r.json()),
611
+ * });
612
+ *
613
+ * const job = await bakery3.render({ scene, camera, quality: 'studio' });
614
+ * const image = await job.result();
615
+ *
616
+ * Everything else in this package exists to make those five lines true from
617
+ * inside a real application: no manual GLB export, no 3D suite, no dashboard
618
+ * upload, no re-creating configurator state.
619
+ *
620
+ * While you are still finding out whether this works at all, there is a
621
+ * shorter version that needs no server:
622
+ *
623
+ * const bakery3 = createBakery3({ apiKey: 'bk_sk_…' });
624
+ *
625
+ * It renders, and it prints a console warning telling you to move the key
626
+ * behind a token endpoint before you ship: from a browser, `apiKey` is
627
+ * readable by every visitor.
628
+ */
629
+
630
+ type Bakery3Options = ClientOptions & {
631
+ /**
632
+ * Defaults folded into every `render()`, `renderVideo()`, `estimate()` and
633
+ * variants run. Set once at the provider so a render button stays one
634
+ * line. A size given to a call replaces the default size as a whole.
635
+ */
636
+ defaults?: {
637
+ quality?: QualityPreset;
638
+ output?: Partial<OutputSpec>;
639
+ maxCost?: number;
640
+ };
641
+ };
642
+ type RenderOptions = Partial<CaptureOptions> & {
643
+ scene?: Scene;
644
+ camera?: Camera;
645
+ quality?: QualityPreset;
646
+ /**
647
+ * Leave both out for the preset's long edge in the camera's shape (a 16:9
648
+ * viewport renders 16:9). Give one and the other follows the camera's
649
+ * aspect; give both for exactly that size.
650
+ */
651
+ width?: number;
652
+ height?: number;
653
+ format?: OutputSpec['format'];
654
+ /** JPEG/WebP only, 1–100. */
655
+ imageQuality?: number;
656
+ /** Refuse the render rather than exceed this, in USD. */
657
+ maxCost?: number;
658
+ /** Ask for a low-sample preview. Defaults to the quality preset's own answer. */
659
+ preview?: boolean;
660
+ advanced?: RenderSpec['advanced'];
661
+ metadata?: Record<string, unknown>;
662
+ /** A resubmit with the same key returns the existing render, never a second
663
+ * charge, which is what makes your own retry button safe. */
664
+ idempotencyKey?: string;
665
+ /**
666
+ * `high` puts this render ahead of the account's other waiting work in
667
+ * the same lane: the hero shot before the rest. It never jumps a lane, so
668
+ * a person waiting in a configurator still goes first.
669
+ */
670
+ priority?: RenderSpec['priority'];
671
+ /** Called while assets upload. Most renders after the first report 0 bytes. */
672
+ onUpload?: (progress: UploadProgress) => void;
673
+ };
674
+ /**
675
+ * `render()` from several cameras at once: one capture, one upload, one
676
+ * picture per camera. Everything else means what it means for one render,
677
+ * except `maxCost`, which is the ceiling for the whole set, and
678
+ * `idempotencyKey`, which names the set: a resubmit under the same key
679
+ * returns the same pictures and never a second charge.
680
+ */
681
+ type RenderCamerasOptions = Omit<RenderOptions, 'camera' | 'priority'> & {
682
+ /** Names of cameras in the scene, Camera objects, or `{ id, position, target, fov }`. */
683
+ cameras: ViewCamera[];
684
+ };
685
+ /** How every picture of a variants run is traced: the same settings `render()` takes. */
686
+ type PictureOptions = Pick<RenderOptions, 'scene' | 'quality' | 'width' | 'height' | 'format' | 'imageQuality' | 'preview' | 'advanced' | 'renderer' | 'environment' | 'productState' | 'background'>;
687
+ /**
688
+ * Every variant, from every camera.
689
+ *
690
+ * A variant is whatever your configurator calls one: a row from the product
691
+ * database, a SKU, a `{ model, color }`. `apply` puts your scene in that
692
+ * state, exactly as a customer clicking would, and the SDK photographs it.
693
+ * One variant is resident at a time, and `variants` may be a generator or an
694
+ * async cursor, so neither the scene nor the list has to fit in memory.
695
+ */
696
+ type RenderVariantsOptions<V> = PictureOptions & {
697
+ /**
698
+ * Names the run. Stable across re-runs: the same key re-opens the same
699
+ * run while it is unfinished, so a recorder that died at variant 140 is
700
+ * resumed by calling this again.
701
+ */
702
+ key: string;
703
+ name?: string;
704
+ /** An array, a generator, an async cursor. Pulled one at a time, never collected. */
705
+ variants: Iterable<V> | AsyncIterable<V>;
706
+ /**
707
+ * Put the scene in this variant's state. Return a function to undo it
708
+ * (remove the model, dispose what it held); it runs before the next
709
+ * variant is applied. Leave `apply` out when the variants differ only by
710
+ * `finishes`.
711
+ */
712
+ apply?: (variant: V) => void | VariantCleanup | Promise<void | VariantCleanup>;
713
+ /** Default: `variant.id`, `.sku` or `.key`, or the variant itself when it is a string. */
714
+ id?: (variant: V, index: number) => string;
715
+ /**
716
+ * Finishes that are all inside the model already, told apart by which
717
+ * objects show. Each becomes its own picture from the variant's one
718
+ * capture: no second export, no second upload.
719
+ */
720
+ finishes?: (variant: V) => CatalogFinish[] | undefined;
721
+ /** Default: the live camera. */
722
+ cameras?: ViewCamera[];
723
+ /** Echoed on every picture, its webhooks and the ledger, beside `variant`, `finish` and `camera`. */
724
+ metadata?: (variant: V) => Record<string, unknown>;
725
+ /**
726
+ * Appended to every picture's key as `@version`. A picture is adopted, at
727
+ * no cost, when its key already rendered, so bump this when the pictures
728
+ * must be traced again: a new room, a new look.
729
+ */
730
+ version?: string;
731
+ /** The ceiling for the whole run, in dollars. `quoteVariants()` gives the number to set it from. */
732
+ maxCost: number;
733
+ /** A ceiling for each picture, under the run's. One over it is refused alone. */
734
+ maxCostPerImage?: number;
735
+ /** `batch` (the default) never runs ahead of a person in a configurator. */
736
+ lane?: 'batch' | 'normal';
737
+ /** Fewer pictures at once than the plan allows. */
738
+ maxParallel?: number;
739
+ /** After every variant is recorded. For progress while they render, `run.wait({ onProgress })`. */
740
+ onProgress?: (progress: VariantProgress) => void;
741
+ /** Stops between variants. What was recorded stays admitted; call again to go on. */
742
+ signal?: AbortSignal;
743
+ };
744
+ /**
745
+ * What `capture()` returns: the manifest and the blobs it names, plus the
746
+ * ids the manifest uses, by object name, so a caller can build variants of
747
+ * one capture (hide these, look from there) without a second export.
748
+ */
749
+ type Capture = CapturedScene & {
750
+ /**
751
+ * Object name → the id the manifest addresses it by (`hiddenObjectIds`,
752
+ * `transforms`, lights). Unnamed objects are absent; when two objects
753
+ * share a name the first in traversal order wins, so name what you mean
754
+ * to address.
755
+ */
756
+ objects: Record<string, string>;
757
+ /** What `uploadAssets()` uploaded, once it has run. */
758
+ upload?: UploadProgress;
759
+ };
760
+ /** The batch half of the SDK. */
761
+ type BatchesApi = {
762
+ /**
763
+ * Open a batch, or re-open it: the same `key` returns the same batch
764
+ * while it is not terminal, and items already completed under their keys
765
+ * are adopted rather than rendered again.
766
+ */
767
+ open(request: BatchOpenRequest): Promise<Batch>;
768
+ /** A batch by id, with its latest counts. */
769
+ get(id: string): Promise<Batch>;
770
+ };
771
+ type EstimateOptions = {
772
+ scene?: Scene;
773
+ /**
774
+ * The camera the render would use. An interior is priced as one from
775
+ * where the camera stands (how much of it is walled in), so the default is
776
+ * the client's own camera.
777
+ */
778
+ camera?: Camera;
779
+ quality?: QualityPreset;
780
+ /** The same rule as `render()`: the camera's shape when left out. */
781
+ width?: number;
782
+ height?: number;
783
+ advanced?: RenderSpec['advanced'];
784
+ /** Quote a clip: how many frames. A frame in a clip costs less than a still. */
785
+ frames?: number;
786
+ /**
787
+ * Quote a bake instead of a render: the same `settings` `bake()` takes.
788
+ * The scene is read the way the bake reads it (the include list, a preset
789
+ * room, stand-ins from `simplify` and from `userData.bakery3.simplify`),
790
+ * so the quote is the one the bake is accepted under.
791
+ */
792
+ bake?: PrepareBakeSettings;
793
+ };
794
+ /**
795
+ * What `bake()` takes: the capture, plus what to bake and how well.
796
+ *
797
+ * `settings` is the same object `estimate({ bake })` takes, so a quote and
798
+ * the bake it prices cover the same objects. By default: every object that
799
+ * can hold a lightmap, at 1024², `standard` quality, seams hidden from the
800
+ * camera you pass.
801
+ */
802
+ type BakeOptions = Partial<CaptureOptions> & {
803
+ scene?: Scene;
804
+ camera?: Camera;
805
+ settings?: PrepareBakeSettings;
806
+ /** Refuse the bake rather than exceed this, in USD. */
807
+ maxCost?: number;
808
+ metadata?: Record<string, unknown>;
809
+ idempotencyKey?: string;
810
+ onUpload?: (progress: UploadProgress) => void;
811
+ };
812
+ /** Everything `render()` takes, plus the move. */
813
+ type RenderVideoOptions = RenderOptions & {
814
+ /** The motion to trace. Baked into the manifest at submit time. */
815
+ timeline: Timeline;
816
+ /** Overrides the timeline's own rate for this render only. */
817
+ fps?: number;
818
+ /**
819
+ * Default `'mp4'`. `'mp4'` and `'webm'` are opaque: no codec here carries
820
+ * alpha, and supporting it in one container only would mean the same
821
+ * manifest producing two visibly different videos.
822
+ *
823
+ * `'png-sequence'` keeps the alpha: every frame is the PNG a still of it
824
+ * would be (transparent background, the shadow in alpha), all of them in
825
+ * one uncompressed tar with `frames.json` first, for compositing the
826
+ * product between layers of your own. The result's `url` is the tar.
827
+ */
828
+ format?: 'mp4' | 'webm' | 'png-sequence';
829
+ /**
830
+ * `'png-sequence'` only: bits per channel, 16 (the default, as a still's
831
+ * PNG is) or 8, whose frames are less than half the size.
832
+ */
833
+ bitDepth?: 8 | 16;
834
+ };
835
+ type Bakery3 = {
836
+ /**
837
+ * Capture the current scene, upload what is missing, start the render.
838
+ *
839
+ * With `cameras`, the same capture photographed from each of them: one
840
+ * export, one upload, a `RenderSet` of pictures back.
841
+ *
842
+ * const shots = await bakery3.render({ cameras: ['hero', 'front', 'detail'] });
843
+ * const [hero, front, detail] = await shots.result();
844
+ *
845
+ * `result()` gives one picture per camera, in order, or rejects: with
846
+ * `RenderSetRefused` (its `refusals` name the cameras and the reasons)
847
+ * when a picture was turned down at submission, so a destructured array
848
+ * never shifts. Every picture is one size, in the first camera's shape.
849
+ */
850
+ render(options: RenderCamerasOptions): Promise<RenderSet>;
851
+ render(options?: RenderOptions): Promise<RenderJob>;
852
+ /**
853
+ * Every variant, from every camera, however many there are.
854
+ *
855
+ * const run = await bakery3.renderVariants({
856
+ * key: 'fall-2026',
857
+ * variants: products,
858
+ * apply: (product) => configurator.show(product),
859
+ * cameras: ['hero', 'front', 'detail'],
860
+ * maxCost: 600,
861
+ * });
862
+ * await run.wait();
863
+ * for await (const image of run.images()) save(image);
864
+ *
865
+ * Resolves once every variant is recorded and the run is sealed; the
866
+ * pictures render on from there whether or not the page stays open.
867
+ * Calling it again with the same `key` resumes a recording that stopped
868
+ * and adopts every picture that already rendered.
869
+ */
870
+ renderVariants<V>(options: RenderVariantsOptions<V>): Promise<RenderSet>;
871
+ /**
872
+ * What `renderVariants()` would cost, to the picture: the same walk, with
873
+ * nothing uploaded, admitted or reserved.
874
+ *
875
+ * The pages are priced on a batch of their own, keyed `${key}:quote` and
876
+ * cancelled once the quote is in, never on the run's: the run's batch is
877
+ * opened by `renderVariants()`, with its `maxCost`, and nothing else.
878
+ * Pictures that already rendered under their keys are quoted as adopted,
879
+ * at nothing, so this is the price of a re-run too.
880
+ */
881
+ quoteVariants<V>(options: Omit<RenderVariantsOptions<V>, 'maxCost'> & {
882
+ maxCost?: number;
883
+ }): Promise<VariantsQuote>;
884
+ /**
885
+ * Look before paying: three variants (the first, the middle and the last
886
+ * of an array; the first three of anything else) from every camera and in
887
+ * every finish, at preview quality and a small size, in the ordinary lane
888
+ * so they come back in a minute. Same options as `renderVariants()`. The
889
+ * test has its own keys, so the real run never adopts these previews.
890
+ *
891
+ * const test = await bakery3.testVariants(options);
892
+ * for (const image of await test.result()) show(image.variant, image.camera, image.url);
893
+ */
894
+ testVariants<V>(options: Omit<RenderVariantsOptions<V>, 'maxCost'> & {
895
+ maxCost?: number;
896
+ }, test?: TestRunOptions): Promise<RenderSet>;
897
+ /** A set by id: after a reload, in another tab, from a webhook. */
898
+ getRenderSet(id: string): Promise<RenderSet>;
899
+ /**
900
+ * A timeline bound to the attached scene and camera.
901
+ *
902
+ * const tl = bakery3.timeline({ duration: 4 });
903
+ * tl.push({ object: 'camera', orbitY: 90 });
904
+ * const job = await bakery3.renderVideo({ timeline: tl });
905
+ *
906
+ * The scene and camera are read from `attach()` when the timeline needs
907
+ * them, so one made before the attachment still drives the camera
908
+ * attached later. A camera move with no camera by then is refused.
909
+ */
910
+ timeline(options?: TimelineOptions): Timeline;
911
+ /**
912
+ * The same capture as `render()`, plus the baked timeline, as a video.
913
+ *
914
+ * A clip is priced by its frame count: one start-up floor, then every
915
+ * frame at a fraction of a still, because one session traces them all.
916
+ * `estimate({ frames })` gives the same quote the clip is accepted under,
917
+ * and `maxCost` is checked against it before anything uploads.
918
+ */
919
+ renderVideo(options: RenderVideoOptions): Promise<RenderJob>;
920
+ /**
921
+ * Path-traced lighting for the scene you are already rendering.
922
+ *
923
+ * const job = await bakery3.bake();
924
+ * const { bundle } = await job.result();
925
+ * const session = createBakeSession({ scene }); // @oeave/bakery3/bake
926
+ * await session.apply(session.addGeneration(bundle));
927
+ *
928
+ * The same capture as `render()`, the same asset upload, and a bundle of
929
+ * lightmaps back (one per object, or one atlas) with its textures on
930
+ * signed URLs the session loads directly.
931
+ */
932
+ bake(options?: BakeOptions): Promise<BakeJob>;
933
+ /** A bake by id, for fresh URLs after the old ones expired. */
934
+ getBake(id: string): Promise<BakeJob>;
935
+ /**
936
+ * A render by id: after a reload, in another tab, from a webhook. Its
937
+ * `result()` signs fresh URLs when the old ones have expired.
938
+ */
939
+ getRender(id: string): Promise<RenderJob>;
940
+ /** What this would cost, before anything expensive happens. */
941
+ estimate(options?: EstimateOptions): Promise<CostEstimate>;
942
+ /**
943
+ * Local, free, offline: what would and would not translate.
944
+ *
945
+ * No account needed and no bytes leave the browser, so "will my scene
946
+ * work?" can be answered before signing up.
947
+ */
948
+ check(scene?: Scene): CompatibilityReport;
949
+ /** The captured manifest, without rendering. For debugging, and for seeing exactly what leaves the browser. */
950
+ inspect(options?: RenderOptions): Promise<SceneManifest>;
951
+ /**
952
+ * The same capture `render()` starts from, handed back instead of
953
+ * submitted: the manifest, its assets, and the object ids by name. What a
954
+ * catalog recorder builds its variants from: one export per product,
955
+ * a few KB of manifest per still.
956
+ */
957
+ capture(options?: RenderOptions): Promise<Capture>;
958
+ /**
959
+ * Upload a capture's assets that storage does not already have. Once per
960
+ * capture; every manifest derived from it then names bytes that exist.
961
+ */
962
+ uploadAssets(capture: Pick<Capture, 'assets'>, onProgress?: (progress: UploadProgress) => void): Promise<UploadProgress>;
963
+ /** Batches: a declared body of work, admitted in pages, one poll for all of it. */
964
+ readonly batches: BatchesApi;
965
+ /** Point the SDK at the app's live scene and camera once, at mount. */
966
+ attach(context: {
967
+ scene: Scene;
968
+ camera: Camera;
969
+ renderer?: CaptureOptions['renderer'];
970
+ }): void;
971
+ readonly version: string;
972
+ };
973
+ declare function createBakery3(options?: Bakery3Options): Bakery3;
974
+
975
+ export { type AdapterOptions, BakeBundle, BakeJob, type BakeJobEvents, type BakeOptions, type BakeOutput, type Bakery3, Bakery3Error, type Bakery3Options, Batch, BatchOpenRequest, BatchProgress, type BatchesApi, type CameraFocus, type Capture, type CaptureOptions, type CapturedScene, type CatalogCamera, type CatalogFinish, ClientOptions, CompatibilityIssue, CompatibilityReport, CostEstimate, type EstimateOptions, type ExtractedShader, type JobEvents, type JobResultOptions, MaterialShaderSpec, OutputSpec, PrepareBakeSettings, QualityPreset, type RenderCamerasOptions, RenderJob, type RenderOptions, RenderRecord, RenderResult, RenderSet, RenderState, type RenderVariantsOptions, type RenderVideoOptions, SDK_VERSION, type SampledTrack, SceneManifest, ShaderSlot, type ShaderTextureRef, TestRunOptions, Timeline, TimelineOptions, TrackTarget, type UploadProgress, type VariantCleanup, type VariantProgress, VariantsQuote, type ViewCamera, analyzeScene, createBakery3, extractMaterialShader, isNodeMaterial, rememberEnvironmentSource, shouldExclude, timelineFromGsap, timelineFromTheatre };