@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,470 @@
1
+ import { Camera, Scene, Object3D } from 'three';
2
+ import { A as AnimationSpec } from './animation-B1h0Ryvj.js';
3
+
4
+ /**
5
+ * Easing, in one implementation.
6
+ *
7
+ * The named easings are the CSS cubic-bezier control points, not hand-rolled
8
+ * polynomials, so `'ease-in-out'` here means what it means in every stylesheet
9
+ * and in gsap: a motion tuned in CSS comes back from the render as the same
10
+ * curve.
11
+ *
12
+ * This is also the only place easing exists. The renderer never sees a curve:
13
+ * the SDK samples the timeline at every output frame and ships the numbers,
14
+ * which is what keeps the browser preview and the rendered frame agreeing on
15
+ * where things are.
16
+ */
17
+ /** A CSS easing: one of the four names, or the four control points of a
18
+ * cubic-bezier, `[x1, y1, x2, y2]`, exactly as a stylesheet writes them. */
19
+ type Easing = 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | [number, number, number, number];
20
+
21
+ /**
22
+ * Orbits, and the lookAt → quaternion conversion the wire format needs.
23
+ *
24
+ * A camera move between two points has two honest answers and they look
25
+ * nothing alike. Lerping the positions drives the camera through the middle
26
+ * of the product; interpolating in spherical coordinates around the thing
27
+ * being looked at swings around it at a constant distance. The second one is
28
+ * what everybody means by "orbit the camera 90°", so it is a first-class path
29
+ * type rather than something you have to build out of forty keyframes.
30
+ *
31
+ * Angles here are in radians and are not wrapped. An orbit of +370° is a full
32
+ * turn plus ten degrees, not minus ten: wrapping it into ±180° would silently
33
+ * reverse a turntable.
34
+ */
35
+ type Vec3 = [number, number, number];
36
+ /** glTF order (x, y, z, w), matching the protocol's `Quat` and three's own
37
+ * `Quaternion.toArray()`. Nothing on this side of the wire reorders. */
38
+ type Quat = [number, number, number, number];
39
+
40
+ /**
41
+ * What can be animated, how to read it off the live object, and how to put it
42
+ * back.
43
+ *
44
+ * One table, because three consumers must agree exactly: the panel (which
45
+ * offers a list), `seek()` (which drives the live three scene, so the browser
46
+ * is the preview) and `bake()` (which writes the numbers the renderer plays).
47
+ * A property that reads differently from how it writes is a preview that lies
48
+ * about the render.
49
+ *
50
+ * Everything is duck-typed rather than `instanceof Mesh`. three is a peer
51
+ * dependency with no runtime import here, and duck typing is what three does
52
+ * internally anyway, so this keeps working across a version that adds a type.
53
+ */
54
+
55
+ /** Values are always arrays, scalars included. One interpolation path, one
56
+ * storage shape, and `size` is then simply `value.length`. */
57
+ type PropertyValue = number[];
58
+
59
+ /**
60
+ * A timeline you author in keyframes and ship as frames.
61
+ *
62
+ * const tl = createTimeline({ duration: 5, fps: 30, camera, scene });
63
+ *
64
+ * tl.push({ object: 'camera', orbitY: 90 });
65
+ * tl.to(mesh, { color: '#ff2d95' }, { at: 1, duration: 2, easing: 'ease-in-out' });
66
+ *
67
+ * tl.seek(2.5); // the live scene is the preview
68
+ * await bakery3.renderVideo({ timeline: tl });
69
+ *
70
+ * It looks like gsap and differs from it in two ways, because a shot has a
71
+ * known length rather than being a queue of tweens:
72
+ *
73
+ * - `at` defaults to 0 and `duration` to the rest of the timeline, so
74
+ * `tl.push({ object: 'camera', orbitY: 15 })` on a five-second timeline is
75
+ * a five-second move. Nothing appends itself to the end.
76
+ * - `seek()` drives your actual three objects. There is no shadow copy of
77
+ * the scene, so what you scrub to is what gets rendered.
78
+ *
79
+ * Everything that interpolates lives here, in easing.ts and in orbit.ts. The
80
+ * renderer sees none of it: `bake()` samples this evaluator at every output
81
+ * frame and ships the numbers.
82
+ */
83
+
84
+ /** `'camera'` rather than the camera object, because a live R3F camera is
85
+ * frequently swapped out from under the application and an id that survives
86
+ * that is worth more than a reference that does not. */
87
+ type TrackTarget = 'camera' | Object3D;
88
+ /** One value, at one time, on one track. Times are seconds from the start of
89
+ * the timeline, never relative to the keyframe before, so retiming one
90
+ * keyframe cannot cascade through the rest of the lane. */
91
+ type Keyframe = {
92
+ time: number;
93
+ value: PropertyValue;
94
+ /** Governs the segment ending here: the ease passed to the `.to()` that
95
+ * created this keyframe. */
96
+ easing?: Easing;
97
+ path?: 'line' | 'orbit';
98
+ /**
99
+ * Where an orbit segment ends, in spherical coordinates about `center`.
100
+ *
101
+ * Carried alongside the position rather than instead of it, so a consumer
102
+ * that does not understand orbits (the panel's diamonds, a JSON reader)
103
+ * still sees the right endpoint. `yaw` is unwrapped: +370° means a full turn
104
+ * plus ten degrees.
105
+ */
106
+ orbit?: {
107
+ center: Vec3;
108
+ radius: number;
109
+ yaw: number;
110
+ pitch: number;
111
+ };
112
+ };
113
+ /** One property of one target, over time: a lane in the panel and a channel
114
+ * in the bake. One track per (target, property) pair, always: two lanes
115
+ * driving one property would fight over the live object on every `seek()`. */
116
+ type Track = {
117
+ id: string;
118
+ target: TrackTarget;
119
+ property: string;
120
+ size: number;
121
+ /** What the panel shows. Falls back to the object's name or type. */
122
+ label: string;
123
+ keyframes: Keyframe[];
124
+ };
125
+ /**
126
+ * What a panel can listen for.
127
+ *
128
+ * `time` fires on every `seek()`, sixty times a second while playing, so a
129
+ * listener must be cheap. `change` is structural (a keyframe, the duration,
130
+ * the fps) and also fires the `time` listeners, because every readout that
131
+ * watches the playhead also wants to know the lanes moved underneath it.
132
+ */
133
+ type TimelineEvent = 'change' | 'time' | 'play' | 'pause';
134
+ /** Everything a timeline needs to know before anything is authored on it.
135
+ * All optional: a timeline with no scene and no camera is still a valid
136
+ * document, which is what makes one testable without a renderer. */
137
+ type TimelineOptions = {
138
+ /** Seconds. Default 5. */
139
+ duration?: number;
140
+ /** Frames per second the bake samples at. Default 30. */
141
+ fps?: number;
142
+ camera?: Camera;
143
+ scene?: Scene;
144
+ /**
145
+ * What camera orbits turn around and lookAt tracks default to. Defaults to
146
+ * the center of the scene's bounding box, which is what "orbit the product"
147
+ * usually means.
148
+ */
149
+ lookAt?: Vec3;
150
+ loop?: boolean;
151
+ /** The host's orbit-controls target, when it has one. Read on keyframe
152
+ * capture so the After Effects flow (frame it with the mouse, press the
153
+ * button) records the point you were actually orbiting. */
154
+ controlsTarget?: () => Vec3;
155
+ };
156
+ /** Where a `.to()`, `.fromTo()` or `.orbit()` sits on the timeline. */
157
+ type SegmentOptions = {
158
+ /** Seconds from the start of the timeline. Default 0. */
159
+ at?: number;
160
+ /** Seconds. Default: the rest of the timeline. */
161
+ duration?: number;
162
+ easing?: Easing;
163
+ };
164
+ /** A camera swing. Everything is relative to where the camera already is,
165
+ * except `radius`: an orbit is a nudge from the pose you framed, not a jump
166
+ * to coordinates you would have to work out first. */
167
+ type OrbitOptions = SegmentOptions & {
168
+ /** Degrees about the up axis. Not wrapped: -540 is one and a half turns. */
169
+ yaw?: number;
170
+ /** Degrees of elevation change. */
171
+ pitch?: number;
172
+ /** Absolute end distance from the center. */
173
+ radius?: number;
174
+ /** Distance change, relative to where the camera starts. */
175
+ dolly?: number;
176
+ lookAt?: Vec3 | Object3D;
177
+ };
178
+ /** The one-call shorthand: `tl.push({ object: 'camera', orbitY: +15 })`. */
179
+ type PushSpec = SegmentOptions & {
180
+ object: TrackTarget;
181
+ /** Degrees, horizontal. Positive swings the camera to its right. */
182
+ orbitY?: number;
183
+ /** Degrees, vertical. Positive lifts the camera. */
184
+ orbitX?: number;
185
+ /** Distance change, relative to where the camera starts. */
186
+ dolly?: number;
187
+ lookAt?: Vec3 | Object3D;
188
+ } & Record<string, unknown>;
189
+ /** Anything `.to()` accepts as a value: a number, a vector, a hex color, or
190
+ * a three Vector3/Color/Euler read straight off the scene. */
191
+ type AuthoredValue = number | number[] | string | {
192
+ x: number;
193
+ y: number;
194
+ z: number;
195
+ } | {
196
+ r: number;
197
+ g: number;
198
+ b: number;
199
+ };
200
+ /** Keyframes in, frames out. The file header has the two places this differs
201
+ * from gsap. */
202
+ declare class Timeline {
203
+ private _duration;
204
+ private _fps;
205
+ private _time;
206
+ private _tracks;
207
+ private _playing;
208
+ private _raf;
209
+ private _lastTick;
210
+ private _listeners;
211
+ private _center;
212
+ private _nextId;
213
+ /** Playback only. A bake is always exactly one pass of the duration, so
214
+ * looping in the panel never changes what a video contains. */
215
+ loop: boolean;
216
+ private _camera?;
217
+ private _scene?;
218
+ /** The host's orbit-controls target, when it has one. */
219
+ controlsTarget?: () => Vec3;
220
+ constructor(options?: TimelineOptions);
221
+ /**
222
+ * What `seek()` drives and `captureCameraKeyframe()` reads. Settable after
223
+ * construction because an R3F camera is frequently swapped out from under
224
+ * the application. A timeline from `bakery3.timeline()` that was given no
225
+ * camera reads the client's attached one each time it needs it.
226
+ */
227
+ get camera(): Camera | undefined;
228
+ set camera(camera: Camera | undefined);
229
+ /** Used to find the orbit center, and to check at bake time that every
230
+ * animated object is actually in what gets exported. Read from the
231
+ * client's attachment, like `camera`, when it was not given. */
232
+ get scene(): Scene | undefined;
233
+ set scene(scene: Scene | undefined);
234
+ get duration(): number;
235
+ /**
236
+ * Setting this moves the end, not the keyframes.
237
+ *
238
+ * Existing keyframes keep their absolute times, because the common reason to
239
+ * change the duration is "I need two more seconds at the end", and silently
240
+ * rescaling every ease you already tuned would be the opposite of that.
241
+ * `scaleToFit()` is the other intent, spelled out.
242
+ */
243
+ set duration(seconds: number);
244
+ get fps(): number;
245
+ set fps(value: number);
246
+ get time(): number;
247
+ get playing(): boolean;
248
+ get tracks(): readonly Track[];
249
+ /** Frames a bake at the current settings will produce. */
250
+ get frameCount(): number;
251
+ /** Proportionally rescale every keyframe into a new duration. */
252
+ scaleToFit(seconds: number): this;
253
+ /**
254
+ * The point orbits turn around.
255
+ *
256
+ * Resolved lazily so a timeline created before the model finished loading
257
+ * still centers on it. `createTimeline()` at mount is the normal case, and
258
+ * an empty scene's bounding box is the origin, which would be wrong for
259
+ * every model that is not at the origin.
260
+ */
261
+ get center(): Vec3;
262
+ set center(value: Vec3);
263
+ /**
264
+ * Tween to a value from wherever the target is at `at`.
265
+ *
266
+ * "Wherever it is at `at`" means the timeline's own value if something else
267
+ * already animates that property, and the live object's value if not, so
268
+ * chaining two `.to()` calls on one property does what it looks like.
269
+ */
270
+ to(target: TrackTarget, props: Record<string, AuthoredValue>, options?: SegmentOptions): this;
271
+ /** Both ends stated. Nothing is read off the live object. */
272
+ fromTo(target: TrackTarget, from: Record<string, AuthoredValue>, to: Record<string, AuthoredValue>, options?: SegmentOptions): this;
273
+ /**
274
+ * Swing the camera around what it is looking at.
275
+ *
276
+ * The lookAt point is pinned for the whole segment. That is the difference
277
+ * between an orbit and a camera drifting sideways past the product, and it
278
+ * is why this writes a `lookAt` track as well as a `position` one.
279
+ */
280
+ orbit(camera: TrackTarget, options?: OrbitOptions): this;
281
+ /**
282
+ * One-call shorthand:
283
+ *
284
+ * tl.push({ object: 'camera', orbitY: +15 });
285
+ *
286
+ * The camera starts where it is now and ends fifteen degrees round its
287
+ * current lookAt, holding that lookAt, over the whole timeline. Any other
288
+ * key is treated as if it had been passed to `.to()`.
289
+ */
290
+ push(spec: PushSpec): this;
291
+ /**
292
+ * Save a property where it is right now.
293
+ *
294
+ * The After Effects flow: put the playhead somewhere, pose the scene, press
295
+ * the button. Both arguments default to exactly that: the playhead, and the
296
+ * live value.
297
+ */
298
+ keyframe(target: TrackTarget, property: string, time?: number, value?: AuthoredValue): Keyframe;
299
+ /**
300
+ * The camera, as the developer framed it.
301
+ *
302
+ * Position and the point it is aimed at, because a camera keyframe that
303
+ * records only position leaves the render free to aim it somewhere else.
304
+ * The aim comes from the host's orbit controls when there are any (that is
305
+ * the point you were dragging around), and is otherwise projected along the
306
+ * camera's own forward axis, never assumed to be the origin.
307
+ */
308
+ captureCameraKeyframe(time?: number, lookAt?: Vec3): void;
309
+ removeKeyframe(trackId: string, index: number): void;
310
+ /** Retime one keyframe, clamped into the timeline. A keyframe dragged past
311
+ * the end would still be baked, at a frame nobody renders, so it is pinned
312
+ * to the duration rather than allowed to leave the shot. */
313
+ moveKeyframe(trackId: string, index: number, time: number): void;
314
+ /** Re-curve the segment ending at this keyframe, the same convention `.to()`
315
+ * writes, so the panel's dropdown and the authoring API mean the same thing
316
+ * by "the ease on this diamond". */
317
+ setEasing(trackId: string, index: number, easing: Easing): void;
318
+ /** Drop a lane and everything on it. The live object keeps whatever value it
319
+ * last had: removing a track stops driving a property, it does not restore
320
+ * what the property was before the timeline touched it. */
321
+ removeTrack(trackId: string): void;
322
+ /**
323
+ * Re-attach tracks to the scene as it is now, and report what could not be.
324
+ *
325
+ * An application that rebuilds part of its graph (a configurator swapping a
326
+ * variant, R3F remounting a subtree) leaves tracks pointing at Object3Ds
327
+ * that are no longer in the scene, even though an object that is for every
328
+ * purpose "the same one" is standing right there. Rather than fail at
329
+ * export, look for that object: first by the identity you pinned
330
+ * (`userData.bakery3Id`, which is exactly what survives a rebuild), then by
331
+ * an unambiguous name match.
332
+ *
333
+ * Nothing is dropped silently. Every track that could not be healed is
334
+ * returned, so the caller can say what happened; that is the difference
335
+ * between repairing a timeline and quietly losing a motion you authored.
336
+ */
337
+ reconcile(scene: Object3D): {
338
+ healed: Array<{
339
+ trackId: string;
340
+ property: string;
341
+ label: string;
342
+ }>;
343
+ stale: Array<{
344
+ trackId: string;
345
+ property: string;
346
+ label: string;
347
+ reason: string;
348
+ }>;
349
+ };
350
+ /** Find or create a lane. Public because the panel's "add track" picker
351
+ * needs to create one without also writing a keyframe. */
352
+ track(target: TrackTarget, property: string): Track;
353
+ /**
354
+ * Evaluate every track and drive the live scene.
355
+ *
356
+ * The same evaluator `bake()` samples, which is the whole design: what you
357
+ * scrub to and what the renderer traces cannot drift apart, because there is
358
+ * only one of them.
359
+ */
360
+ seek(time: number): this;
361
+ play(): this;
362
+ pause(): this;
363
+ /** Pause and rewind. */
364
+ stop(): this;
365
+ /** Stop the clock and forget every listener. The scene is left exactly where
366
+ * the playhead left it: a timeline being torn down should not also move
367
+ * your camera back. */
368
+ dispose(): void;
369
+ private tick;
370
+ /** The value of one track at a time, without touching the scene. Exposed
371
+ * because the bake samples it. */
372
+ valueAt(track: Track, time: number): PropertyValue | undefined;
373
+ /** What the timeline says everything is at `time`, for a panel readout or a
374
+ * test: the same numbers `seek()` applies. */
375
+ sample(time: number): Array<{
376
+ track: Track;
377
+ value: PropertyValue;
378
+ }>;
379
+ /** The camera pose at a time: position and the rotation the wire format
380
+ * carries. Shared by `seek()` and `bake()` so the preview cannot aim
381
+ * somewhere the render does not. */
382
+ cameraPoseAt(time: number): {
383
+ position: Vec3;
384
+ lookAt: Vec3;
385
+ quaternion: Quat;
386
+ } | undefined;
387
+ private apply;
388
+ /**
389
+ * Every track, sampled at every output frame. The wire format is flat
390
+ * samples, so the renderer needs no evaluator of its own.
391
+ */
392
+ bake(options?: {
393
+ scene?: Scene;
394
+ fps?: number;
395
+ duration?: number;
396
+ }): AnimationSpec;
397
+ /** The timeline as a storable document. See `TimelineJSON`, and `fromJSON`
398
+ * for how stored ids find their live objects again. */
399
+ toJSON(): TimelineJSON;
400
+ /**
401
+ * Rebuild a timeline against a live scene.
402
+ *
403
+ * `resolve` maps a stored object id back to a live object. An id that does
404
+ * not resolve is refused rather than skipped: a track that silently
405
+ * disappears is a video missing a motion you authored, and you would find
406
+ * out by watching the finished render.
407
+ */
408
+ static fromJSON(json: TimelineJSON, context?: {
409
+ resolve?: (objectId: string) => Object3D | undefined;
410
+ camera?: Camera;
411
+ scene?: Scene;
412
+ }): Timeline;
413
+ /** Subscribe. Returns the unsubscribe, so a panel's teardown is one call and
414
+ * a forgotten listener cannot keep a disposed scene alive. */
415
+ on(event: TimelineEvent, listener: (payload: never) => void): () => void;
416
+ private emit;
417
+ /** The live value of a property, read through the shared property table. */
418
+ live(target: TrackTarget, property: string): PropertyValue | undefined;
419
+ private find;
420
+ private normalizeTarget;
421
+ private span;
422
+ /** Make sure a segment has something to start from at `at`. */
423
+ private anchor;
424
+ private insert;
425
+ private requireCamera;
426
+ /**
427
+ * The camera, when one is needed. A client's timeline that has none by then
428
+ * refuses, because the move it was asked for would otherwise be authored
429
+ * from a made-up pose, or silently drive nothing. A standalone timeline
430
+ * with no camera is a document that can still be read and sampled.
431
+ */
432
+ private cameraOrThrow;
433
+ }
434
+ /**
435
+ * A timeline as a document.
436
+ *
437
+ * Targets travel as object ids rather than references, so this survives a page
438
+ * reload, a database column and a git diff. `version` is here so a stored
439
+ * timeline can be migrated rather than silently misread, the same reason the
440
+ * manifest carries `protocolVersion`.
441
+ */
442
+ type TimelineJSON = {
443
+ version: 1;
444
+ duration: number;
445
+ fps: number;
446
+ center?: Vec3;
447
+ tracks: Array<{
448
+ target: {
449
+ type: 'camera';
450
+ } | {
451
+ type: 'object';
452
+ objectId: string;
453
+ };
454
+ property: string;
455
+ label?: string;
456
+ keyframes: Keyframe[];
457
+ }>;
458
+ };
459
+ /**
460
+ * A timeline, standing on its own.
461
+ *
462
+ * `bakery3.timeline()` is the same call with the attached scene and camera
463
+ * filled in, and is what an application should normally use. This one exists
464
+ * for the cases where there is no Bakery3 instance yet (a test, a timeline
465
+ * built at module scope and handed to the panel), because authoring a camera
466
+ * move should not need an API key.
467
+ */
468
+ declare function createTimeline(options?: TimelineOptions): Timeline;
469
+
470
+ export { type AuthoredValue as A, type Easing as E, type Keyframe as K, type OrbitOptions as O, type PushSpec as P, type SegmentOptions as S, Timeline as T, type TimelineOptions as a, type Track as b, createTimeline as c, type TrackTarget as d, type TimelineEvent as e, type TimelineJSON as f };
@@ -0,0 +1,165 @@
1
+ import { float, vec3, vec4 } from 'three/tsl';
2
+
3
+ /**
4
+ * @oeave/bakery3/tsl: the renderer's shading vocabulary, usable from TSL.
5
+ *
6
+ * Two things happen here, and importing this module is what turns both on:
7
+ *
8
+ * 1. Registration. TSL's anonymous singletons (`positionWorld`, `time`,
9
+ * `cameraPosition`) carry no recognizable structure, so the extractor can
10
+ * only know them by being introduced. This module imports them from
11
+ * `three/tsl` and registers them by uuid. It is its own entry point
12
+ * because it needs three r170 (one of the nodes it imports is not
13
+ * exported before that); the core SDK keeps working for anyone older.
14
+ *
15
+ * 2. Renderer-only nodes. The renderer has procedural textures and shading
16
+ * inputs a browser cannot compute: traced ambient occlusion, shade-time
17
+ * bevel, pointiness, the classic noise textures. Each function below
18
+ * returns a real TSL node that draws an approximation in the WebGPU
19
+ * viewport and carries a marker the extractor serializes exactly for the
20
+ * render. The viewport is the sketch; the render is the real one.
21
+ * `check()` reports their use as info, never as an error.
22
+ *
23
+ * Everything accepts plain numbers for its dials, and a TSL expression for
24
+ * its coordinate input. Dials are baked into the manifest, so a dial driven
25
+ * by another node is not accepted, rather than accepted and ignored.
26
+ */
27
+
28
+ type TSLExpr = ReturnType<typeof float>;
29
+ type Coord = TSLExpr | null | undefined;
30
+ /** A float node: a mask, a factor, a texture's fac output. */
31
+ type FloatNode = ReturnType<typeof float>;
32
+ /** A three-component node: a color or a normal. */
33
+ type Vec3Node = ReturnType<typeof vec3>;
34
+ /** A color with alpha. */
35
+ type Vec4Node = ReturnType<typeof vec4>;
36
+ type NoiseTextureOptions = {
37
+ scale?: number;
38
+ detail?: number;
39
+ roughness?: number;
40
+ lacunarity?: number;
41
+ distortion?: number;
42
+ dimensions?: 2 | 3 | 4;
43
+ };
44
+ /**
45
+ * The renderer's fractal noise texture. Preview: MaterialX fractal noise,
46
+ * the same character on a different lattice.
47
+ */
48
+ declare function bakeryNoiseTexture(coord?: Coord, options?: NoiseTextureOptions): FloatNode;
49
+ type VoronoiTextureOptions = {
50
+ scale?: number;
51
+ randomness?: number;
52
+ feature?: 'F1' | 'F2' | 'SMOOTH_F1' | 'DISTANCE_TO_EDGE';
53
+ metric?: 'EUCLIDEAN' | 'MANHATTAN' | 'CHEBYCHEV';
54
+ dimensions?: 2 | 3 | 4;
55
+ };
56
+ /** The renderer's Voronoi texture (distance output). Preview: MaterialX Worley. */
57
+ declare function bakeryVoronoiTexture(coord?: Coord, options?: VoronoiTextureOptions): FloatNode;
58
+ type WaveTextureOptions = {
59
+ scale?: number;
60
+ distortion?: number;
61
+ detail?: number;
62
+ detailScale?: number;
63
+ detailRoughness?: number;
64
+ phase?: number;
65
+ type?: 'BANDS' | 'RINGS';
66
+ direction?: 'X' | 'Y' | 'Z' | 'DIAGONAL';
67
+ profile?: 'SIN' | 'SAW' | 'TRI';
68
+ };
69
+ /** The renderer's wave texture. Preview: a sine along the chosen axis. */
70
+ declare function bakeryWaveTexture(coord?: Coord, options?: WaveTextureOptions): FloatNode;
71
+ type MagicTextureOptions = {
72
+ scale?: number;
73
+ distortion?: number;
74
+ depth?: number;
75
+ };
76
+ /** The renderer's interference "magic" texture. Preview: interfering sines,
77
+ * the flavor and not the math. */
78
+ declare function bakeryMagicTexture(coord?: Coord, options?: MagicTextureOptions): FloatNode;
79
+ type GradientType = 'LINEAR' | 'QUADRATIC' | 'EASING' | 'DIAGONAL' | 'SPHERICAL' | 'QUADRATIC_SPHERE' | 'RADIAL';
80
+ type GradientTextureOptions = {
81
+ type?: GradientType;
82
+ };
83
+ /** The renderer's gradient texture. Preview: the linear ramp. */
84
+ declare function bakeryGradientTexture(coord?: Coord, options?: GradientTextureOptions): FloatNode;
85
+ type BrickTextureOptions = {
86
+ offset?: number;
87
+ offsetFrequency?: number;
88
+ squash?: number;
89
+ squashFrequency?: number;
90
+ scale?: number;
91
+ mortarSize?: number;
92
+ mortarSmooth?: number;
93
+ bias?: number;
94
+ brickWidth?: number;
95
+ rowHeight?: number;
96
+ };
97
+ /** The renderer's brick texture (fac output, the mortar mask). Preview: a grid. */
98
+ declare function bakeryBrickTexture(coord?: Coord, options?: BrickTextureOptions): FloatNode;
99
+ /** White noise, a hash of the coordinate. Preview: cell noise. */
100
+ declare function bakeryWhiteNoise(coord?: Coord, options?: {
101
+ dimensions?: 2 | 3 | 4;
102
+ }): FloatNode;
103
+ /**
104
+ * Traced ambient occlusion. The browser has no rays, so the preview is plain
105
+ * white, which is exactly what an unoccluded surface reads as. The render
106
+ * traces the real thing.
107
+ */
108
+ declare function bakeryAmbientOcclusion(options?: {
109
+ distance?: number;
110
+ samples?: number;
111
+ onlyLocal?: boolean;
112
+ }): FloatNode;
113
+ /**
114
+ * Shade-time edge rounding. Preview: the unrounded normal, so geometry looks
115
+ * crisp in the viewport and gets the worn edge in the render.
116
+ */
117
+ declare function bakeryBevel(options?: {
118
+ radius?: number;
119
+ samples?: number;
120
+ }): Vec3Node;
121
+ /** Surface curvature: concave 0, flat 0.5, convex 1. Preview: flat 0.5. */
122
+ declare function bakeryPointiness(): FloatNode;
123
+ /** 1 on triangle edges. Preview: 0, no wires in the viewport. */
124
+ declare function bakeryWireframe(options?: {
125
+ size?: number;
126
+ pixelSize?: boolean;
127
+ }): FloatNode;
128
+ /** Physically correct fresnel. Preview: Schlick's approximation, close enough
129
+ * that the viewport and the render agree on where the rim light lives. */
130
+ declare function bakeryFresnel(ior?: number): FloatNode;
131
+ /** A facing/fresnel layer weight. Preview: the facing term it is built from. */
132
+ declare function bakeryLayerWeight(blend?: number, options?: {
133
+ output?: 'FRESNEL' | 'FACING';
134
+ }): FloatNode;
135
+ type ColorRampStop = {
136
+ position: number;
137
+ color: [number, number, number] | [number, number, number, number];
138
+ };
139
+ /**
140
+ * A color ramp. Preview: the same ramp, rebuilt from mix chains; for LINEAR
141
+ * and CONSTANT interpolation the viewport matches the render.
142
+ */
143
+ declare function bakeryColorRamp(fac: TSLExpr, stops: ColorRampStop[], options?: {
144
+ interpolation?: 'LINEAR' | 'CONSTANT';
145
+ }): Vec4Node;
146
+ /** Blackbody temperature to color. Preview: a two-anchor tint, warm below
147
+ * and cool above. */
148
+ declare function bakeryBlackbody(kelvin?: number): Vec3Node;
149
+ /** A gamma curve. The preview is the same math. */
150
+ declare function bakeryGamma(color: TSLExpr, gamma?: number): Vec3Node;
151
+ /** Brightness/contrast. Preview: the same formula the render uses. */
152
+ declare function bakeryBrightnessContrast(color: TSLExpr, options?: {
153
+ brightness?: number;
154
+ contrast?: number;
155
+ }): Vec3Node;
156
+ /** Hue/saturation/value. Preview: value and saturation only; a hue rotation
157
+ * in the viewport is not worth a hand-rolled HSV conversion. */
158
+ declare function bakeryHueSaturation(color: TSLExpr, options?: {
159
+ hue?: number;
160
+ saturation?: number;
161
+ value?: number;
162
+ fac?: number;
163
+ }): Vec3Node;
164
+
165
+ export { type BrickTextureOptions, type ColorRampStop, type GradientTextureOptions, type GradientType, type MagicTextureOptions, type NoiseTextureOptions, type VoronoiTextureOptions, type WaveTextureOptions, bakeryAmbientOcclusion, bakeryBevel, bakeryBlackbody, bakeryBrickTexture, bakeryBrightnessContrast, bakeryColorRamp, bakeryFresnel, bakeryGamma, bakeryGradientTexture, bakeryHueSaturation, bakeryLayerWeight, bakeryMagicTexture, bakeryNoiseTexture, bakeryPointiness, bakeryVoronoiTexture, bakeryWaveTexture, bakeryWhiteNoise, bakeryWireframe };