@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.
- package/LICENSE +21 -0
- package/README.md +562 -2
- package/dist/animation-B1h0Ryvj.d.ts +97 -0
- package/dist/bake/index.d.ts +369 -0
- package/dist/bake/index.js +9 -0
- package/dist/bake/index.js.map +1 -0
- package/dist/bake-DaOlenyx.d.ts +1357 -0
- package/dist/catalog/index.d.ts +100 -0
- package/dist/catalog/index.js +154 -0
- package/dist/catalog/index.js.map +1 -0
- package/dist/catalog.gen-BM-aNf7n.d.ts +733 -0
- package/dist/chunk-25ZXSVQ3.js +1107 -0
- package/dist/chunk-25ZXSVQ3.js.map +1 -0
- package/dist/chunk-3G5QL4F4.js +145 -0
- package/dist/chunk-3G5QL4F4.js.map +1 -0
- package/dist/chunk-4E5VV4QY.js +12 -0
- package/dist/chunk-4E5VV4QY.js.map +1 -0
- package/dist/chunk-54WJDN5R.js +3286 -0
- package/dist/chunk-54WJDN5R.js.map +1 -0
- package/dist/chunk-6NYR73Y7.js +832 -0
- package/dist/chunk-6NYR73Y7.js.map +1 -0
- package/dist/chunk-6YVQANMW.js +1463 -0
- package/dist/chunk-6YVQANMW.js.map +1 -0
- package/dist/chunk-AF5BIELI.js +70 -0
- package/dist/chunk-AF5BIELI.js.map +1 -0
- package/dist/chunk-APBOWWSV.js +92 -0
- package/dist/chunk-APBOWWSV.js.map +1 -0
- package/dist/chunk-ARMTTZXZ.js +1157 -0
- package/dist/chunk-ARMTTZXZ.js.map +1 -0
- package/dist/chunk-CX4WTVGH.js +4492 -0
- package/dist/chunk-CX4WTVGH.js.map +1 -0
- package/dist/chunk-HQTUFVMM.js +1412 -0
- package/dist/chunk-HQTUFVMM.js.map +1 -0
- package/dist/chunk-MD2U6S4N.js +1952 -0
- package/dist/chunk-MD2U6S4N.js.map +1 -0
- package/dist/chunk-S4AJTLLN.js +23 -0
- package/dist/chunk-S4AJTLLN.js.map +1 -0
- package/dist/chunk-TGFNQBKC.js +551 -0
- package/dist/chunk-TGFNQBKC.js.map +1 -0
- package/dist/chunk-V3QINEEG.js +87 -0
- package/dist/chunk-V3QINEEG.js.map +1 -0
- package/dist/chunk-W6WQ5UP7.js +91 -0
- package/dist/chunk-W6WQ5UP7.js.map +1 -0
- package/dist/chunk-WBIAFIHV.js +346 -0
- package/dist/chunk-WBIAFIHV.js.map +1 -0
- package/dist/chunk-ZEBVAIJJ.js +156 -0
- package/dist/chunk-ZEBVAIJJ.js.map +1 -0
- package/dist/devtools/index.d.ts +536 -0
- package/dist/devtools/index.js +15 -0
- package/dist/devtools/index.js.map +1 -0
- package/dist/environments/index.d.ts +93 -0
- package/dist/environments/index.js +382 -0
- package/dist/environments/index.js.map +1 -0
- package/dist/hotspots/index.d.ts +111 -0
- package/dist/hotspots/index.js +285 -0
- package/dist/hotspots/index.js.map +1 -0
- package/dist/index.d.ts +944 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/node/index.cjs +5115 -0
- package/dist/node/index.cjs.map +1 -0
- package/dist/node/index.d.cts +4862 -0
- package/dist/node/index.d.ts +576 -0
- package/dist/node/index.js +1279 -0
- package/dist/node/index.js.map +1 -0
- package/dist/prepare-C5qVvaw4.d.ts +112 -0
- package/dist/presets/index.d.ts +526 -0
- package/dist/presets/index.js +14 -0
- package/dist/presets/index.js.map +1 -0
- package/dist/r3f/index.d.ts +159 -0
- package/dist/r3f/index.js +592 -0
- package/dist/r3f/index.js.map +1 -0
- package/dist/room-S5TLCK4F.js +9 -0
- package/dist/room-S5TLCK4F.js.map +1 -0
- package/dist/rooms.gen-vhj6sFW5.d.ts +1434 -0
- package/dist/session-YCQS4MRH.js +9 -0
- package/dist/session-YCQS4MRH.js.map +1 -0
- package/dist/shapes/index.d.ts +222 -0
- package/dist/shapes/index.js +836 -0
- package/dist/shapes/index.js.map +1 -0
- package/dist/testRun-BIPXaVPb.d.ts +1130 -0
- package/dist/timeline-ChwgD7bT.d.ts +470 -0
- package/dist/tsl/index.d.ts +165 -0
- package/dist/tsl/index.js +310 -0
- package/dist/tsl/index.js.map +1 -0
- package/package.json +170 -4
|
@@ -0,0 +1,536 @@
|
|
|
1
|
+
import { Object3D, Scene, Camera } from 'three';
|
|
2
|
+
import { a as BakeQuality, B as BakeTextureSize, e as BakeSpec, j as BakeBundle, Q as QualityPreset } from '../bake-DaOlenyx.js';
|
|
3
|
+
import { CapturedScene, Bakery3, RenderOptions, RenderJob, CaptureOptions } from '../index.js';
|
|
4
|
+
import { T as Timeline } from '../timeline-ChwgD7bT.js';
|
|
5
|
+
import { BakeSession } from '../bake/index.js';
|
|
6
|
+
import '../animation-B1h0Ryvj.js';
|
|
7
|
+
import '../testRun-BIPXaVPb.js';
|
|
8
|
+
import '../prepare-C5qVvaw4.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The timeline panel: a floating strip, not an editor.
|
|
12
|
+
*
|
|
13
|
+
* The developer orbits their product with the mouse, presses +, scrubs,
|
|
14
|
+
* presses + again, and presses Render video, without leaving the page. It is
|
|
15
|
+
* vanilla DOM and imports nothing but the timeline itself, so a plain three.js
|
|
16
|
+
* app and, through the thin wrapper in r3f/, a React app mount exactly the
|
|
17
|
+
* same panel.
|
|
18
|
+
*
|
|
19
|
+
* import { mountTimelinePanel } from '@oeave/bakery3/devtools';
|
|
20
|
+
*
|
|
21
|
+
* const panel = mountTimelinePanel({
|
|
22
|
+
* timeline,
|
|
23
|
+
* targets: [{ object: hero, label: 'hero' }],
|
|
24
|
+
* onPlaybackChange: (active) => { controls.enabled = !active; },
|
|
25
|
+
* onRenderVideo: (tl) => renderVideo(tl),
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* `onPlaybackChange` is the one that matters. Orbit controls rewrite the
|
|
29
|
+
* camera every frame, so a timeline that owns the camera and controls that
|
|
30
|
+
* also own it fight, and the developer sees a stuttering preview. The host
|
|
31
|
+
* suspends them; capture still reads the camera the developer framed with the
|
|
32
|
+
* controls.
|
|
33
|
+
*
|
|
34
|
+
* `buildTimelineBody` is the same UI without the shell, because the dev panel
|
|
35
|
+
* (./devPanel.ts) shows it as its Video tab. `mountTimelinePanel` is the
|
|
36
|
+
* floating shell around that body.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
/** An object the developer can add a lane for. The label is what the picker
|
|
40
|
+
* shows: a three `name` is often empty or generated, and "Mesh" three times
|
|
41
|
+
* in a dropdown is not a choice anybody can make. */
|
|
42
|
+
type TimelinePanelTarget = {
|
|
43
|
+
object: Object3D;
|
|
44
|
+
label: string;
|
|
45
|
+
};
|
|
46
|
+
/** What the host supplies. Only `timeline` is required; the Render-video
|
|
47
|
+
* button appears only when there is something for it to call. */
|
|
48
|
+
type TimelinePanelOptions = {
|
|
49
|
+
timeline: Timeline;
|
|
50
|
+
/** Objects offered in the "add track" picker. The camera is always there. */
|
|
51
|
+
targets?: TimelinePanelTarget[];
|
|
52
|
+
/** Shows the "Render video" button when given. */
|
|
53
|
+
onRenderVideo?: (timeline: Timeline) => void | Promise<void>;
|
|
54
|
+
/** Fired when the timeline takes the camera, and when it gives it back. */
|
|
55
|
+
onPlaybackChange?: (active: boolean) => void;
|
|
56
|
+
container?: HTMLElement;
|
|
57
|
+
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
58
|
+
defaultOpen?: boolean;
|
|
59
|
+
};
|
|
60
|
+
/** The handle a host keeps. Small on purpose: the panel reads everything else
|
|
61
|
+
* it needs off the timeline and its events, so there is no second copy of the
|
|
62
|
+
* state to keep in sync. */
|
|
63
|
+
type TimelinePanel = {
|
|
64
|
+
/** Rebuild the lanes, after loading a different scene, say. */
|
|
65
|
+
refresh(): void;
|
|
66
|
+
/** One line under the transport: "tracing frame 12/48". */
|
|
67
|
+
setStatus(message: string, tone?: 'info' | 'error'): void;
|
|
68
|
+
dispose(): void;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Attach the panel to the page.
|
|
72
|
+
*
|
|
73
|
+
* It appends one fixed-position element to `container` (the body by default)
|
|
74
|
+
* and owns nothing else: no globals, no stylesheet, no listener outside its
|
|
75
|
+
* own subtree and the timeline's events. `dispose()` puts the page back
|
|
76
|
+
* exactly as it was, which is what makes it safe to mount from a hot-reloading
|
|
77
|
+
* dev server.
|
|
78
|
+
*/
|
|
79
|
+
declare function mountTimelinePanel(options: TimelinePanelOptions): TimelinePanel;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The dev panel: one floating thing that renders, films and bakes.
|
|
83
|
+
*
|
|
84
|
+
* A 48px mark in the corner of the developer's own app, which opens into a
|
|
85
|
+
* card with up to three tabs and a price. Four things about it are contracts
|
|
86
|
+
* and the rest is layout:
|
|
87
|
+
*
|
|
88
|
+
* 1. The cost is visible before the money is spent. Beside every primary
|
|
89
|
+
* button is a quiet line, `98% compatible ≈ $0.12`: hover the price for
|
|
90
|
+
* what it is made of (`96 frames × $0.039`, at most $5.00), click the
|
|
91
|
+
* figure for the objects that render differently. The price refreshes
|
|
92
|
+
* when the settings change, when the tab changes, and when the scene
|
|
93
|
+
* changes; never on a clock, so a price that has not moved is not fetched
|
|
94
|
+
* again. A key or a balance that will refuse the render is said in the
|
|
95
|
+
* status line then, not when Render is pressed.
|
|
96
|
+
* 2. Every refusal is in place. An object that cannot be baked appears in the
|
|
97
|
+
* list with a ⚠ and its reason and fix on hover, next to the ones that
|
|
98
|
+
* can. Nothing is silently missing.
|
|
99
|
+
* 3. Hold to compare. Pointer down shows the live scene, pointer up puts the
|
|
100
|
+
* bake back, both within a frame and both lossless, because the session
|
|
101
|
+
* keeps the patch and just switches it off.
|
|
102
|
+
* 4. The lock explains itself. Downloads are the one gated action, and the
|
|
103
|
+
* locked state says what kind of key unlocks it and where to put it.
|
|
104
|
+
*
|
|
105
|
+
* A tab only exists if its options were supplied. A vanilla three app with
|
|
106
|
+
* no timeline gets a two-tab panel, not a Video tab that does nothing.
|
|
107
|
+
*
|
|
108
|
+
* import { mountDevPanel } from '@oeave/bakery3/devtools';
|
|
109
|
+
*
|
|
110
|
+
* const panel = mountDevPanel({
|
|
111
|
+
* estimate: (request) => post('/api/estimate', request),
|
|
112
|
+
* render: { onRender: (settings) => runRender(settings) },
|
|
113
|
+
* bake: { session, onBake: (settings) => runBake(settings) },
|
|
114
|
+
* });
|
|
115
|
+
*/
|
|
116
|
+
|
|
117
|
+
type DevPanelTab = 'render' | 'video' | 'bake';
|
|
118
|
+
/** What the panel asks the host to price. */
|
|
119
|
+
type DevPanelEstimateRequest = {
|
|
120
|
+
kind: 'render';
|
|
121
|
+
quality: string;
|
|
122
|
+
width: number;
|
|
123
|
+
height: number;
|
|
124
|
+
} | {
|
|
125
|
+
kind: 'video';
|
|
126
|
+
quality: string;
|
|
127
|
+
width: number;
|
|
128
|
+
height: number;
|
|
129
|
+
frames: number;
|
|
130
|
+
fps: number;
|
|
131
|
+
format: 'mp4' | 'webm';
|
|
132
|
+
} | {
|
|
133
|
+
kind: 'bake';
|
|
134
|
+
quality: BakeQuality;
|
|
135
|
+
textureSize: number;
|
|
136
|
+
objects: number;
|
|
137
|
+
texels: number;
|
|
138
|
+
/** The ticked objects, as objectIds. */
|
|
139
|
+
include: string[];
|
|
140
|
+
};
|
|
141
|
+
type DevPanelEstimate = {
|
|
142
|
+
/** The price beside the button. */
|
|
143
|
+
usd: number;
|
|
144
|
+
/** The most it can be charged: the breakdown's `at most` line. */
|
|
145
|
+
maximum?: number;
|
|
146
|
+
/**
|
|
147
|
+
* A line of your own under the breakdown, which already lists the
|
|
148
|
+
* settings, the count the price is made of (`96 frames × $0.039`) and the
|
|
149
|
+
* maximum: `on the local worker`.
|
|
150
|
+
*/
|
|
151
|
+
detail?: string;
|
|
152
|
+
/** False when the price is exact rather than an estimate: no `≈`. */
|
|
153
|
+
approximate?: boolean;
|
|
154
|
+
};
|
|
155
|
+
/** One past artifact, as the host's history lists it. */
|
|
156
|
+
type DevPanelHistoryEntry = {
|
|
157
|
+
id: string;
|
|
158
|
+
kind: DevPanelTab;
|
|
159
|
+
createdAt: string;
|
|
160
|
+
/** When `artifact` and `thumbnail` stop working (signed URLs do). The
|
|
161
|
+
* panel's own history drops an entry then. */
|
|
162
|
+
expiresAt?: string;
|
|
163
|
+
cacheKey?: string;
|
|
164
|
+
cached?: boolean;
|
|
165
|
+
meta?: {
|
|
166
|
+
width?: number;
|
|
167
|
+
height?: number;
|
|
168
|
+
format?: string;
|
|
169
|
+
frames?: number;
|
|
170
|
+
fps?: number;
|
|
171
|
+
quality?: string;
|
|
172
|
+
textureSize?: number;
|
|
173
|
+
objects?: number;
|
|
174
|
+
skipped?: number;
|
|
175
|
+
/** What it was charged, in dollars. */
|
|
176
|
+
cost?: number;
|
|
177
|
+
};
|
|
178
|
+
thumbnail?: string;
|
|
179
|
+
artifact?: string;
|
|
180
|
+
};
|
|
181
|
+
/** What a finished action gives the panel to show. `entry` is what makes the
|
|
182
|
+
* result's Download button real: downloads go through the same gated path
|
|
183
|
+
* as history, never round an alternative route. */
|
|
184
|
+
type DevPanelActionResult = {
|
|
185
|
+
url?: string;
|
|
186
|
+
meta?: string;
|
|
187
|
+
isVideo?: boolean;
|
|
188
|
+
entry?: DevPanelHistoryEntry;
|
|
189
|
+
/** The job's id, so the panel's own history does not list it twice. */
|
|
190
|
+
id?: string;
|
|
191
|
+
/** The output's size: the result area holds the image's shape before the
|
|
192
|
+
* image has loaded, so nothing below it moves when it does. */
|
|
193
|
+
width?: number;
|
|
194
|
+
height?: number;
|
|
195
|
+
quality?: string;
|
|
196
|
+
format?: string;
|
|
197
|
+
frames?: number;
|
|
198
|
+
/** Dollars charged, for the history line. */
|
|
199
|
+
cost?: number;
|
|
200
|
+
/** Millisecond epoch at which `url` stops working. */
|
|
201
|
+
expiresAt?: number;
|
|
202
|
+
};
|
|
203
|
+
type DevPanelRenderSettings = {
|
|
204
|
+
quality: string;
|
|
205
|
+
width: number;
|
|
206
|
+
height: number;
|
|
207
|
+
};
|
|
208
|
+
type DevPanelRenderOptions = {
|
|
209
|
+
onRender: (settings: DevPanelRenderSettings) => void | DevPanelActionResult | Promise<void | DevPanelActionResult>;
|
|
210
|
+
qualities?: string[];
|
|
211
|
+
/** Long edges to offer. The short edge follows `aspect`. */
|
|
212
|
+
sizes?: number[];
|
|
213
|
+
/**
|
|
214
|
+
* Width ÷ height of the frame the host renders: 4/3 for a 640×480 room
|
|
215
|
+
* shot, or a function that reads the camera, so a wide viewport renders
|
|
216
|
+
* wide. Read each time the panel prices or renders. Defaults to 1, a
|
|
217
|
+
* square.
|
|
218
|
+
*/
|
|
219
|
+
aspect?: number | (() => number);
|
|
220
|
+
defaultQuality?: string;
|
|
221
|
+
defaultSize?: number;
|
|
222
|
+
};
|
|
223
|
+
type DevPanelVideoSettings = DevPanelRenderSettings & {
|
|
224
|
+
format: 'mp4' | 'webm';
|
|
225
|
+
timeline: Timeline;
|
|
226
|
+
};
|
|
227
|
+
type DevPanelVideoOptions = {
|
|
228
|
+
timeline: Timeline;
|
|
229
|
+
targets?: TimelinePanelTarget[];
|
|
230
|
+
/**
|
|
231
|
+
* The live scene, read whenever `sceneVersion` reports a change.
|
|
232
|
+
*
|
|
233
|
+
* Supplying it lets the panel re-attach tracks whose objects were rebuilt
|
|
234
|
+
* (a variant swap, an r3f remount) instead of letting the timeline refuse at
|
|
235
|
+
* export. Without it the panel still works; stale tracks just survive until
|
|
236
|
+
* something else catches them.
|
|
237
|
+
*/
|
|
238
|
+
scene?: () => Object3D | undefined;
|
|
239
|
+
/** Passed straight through to the timeline body: the orbit-controls
|
|
240
|
+
* handshake that keeps the camera from being driven twice. */
|
|
241
|
+
onPlaybackChange?: (active: boolean) => void;
|
|
242
|
+
onRenderVideo: (settings: DevPanelVideoSettings) => void | DevPanelActionResult | Promise<void | DevPanelActionResult>;
|
|
243
|
+
qualities?: string[];
|
|
244
|
+
/** Long edges to offer. The short edge follows `aspect`. */
|
|
245
|
+
sizes?: number[];
|
|
246
|
+
/** As the Render tab's. Video sizes are rounded to even numbers, which is
|
|
247
|
+
* what a video encoder takes. */
|
|
248
|
+
aspect?: number | (() => number);
|
|
249
|
+
formats?: Array<'mp4' | 'webm'>;
|
|
250
|
+
defaultQuality?: string;
|
|
251
|
+
defaultSize?: number;
|
|
252
|
+
defaultFormat?: 'mp4' | 'webm';
|
|
253
|
+
};
|
|
254
|
+
type DevPanelBakeSettings = {
|
|
255
|
+
quality: BakeQuality;
|
|
256
|
+
textureSize: BakeTextureSize;
|
|
257
|
+
/** The ticked boxes, as objectIds. */
|
|
258
|
+
include: string[];
|
|
259
|
+
};
|
|
260
|
+
type DevPanelBakeResult = {
|
|
261
|
+
/** Index of the generation the host added, when it added one. The panel
|
|
262
|
+
* reads the session for everything else. */
|
|
263
|
+
generation?: number;
|
|
264
|
+
entry?: DevPanelHistoryEntry;
|
|
265
|
+
};
|
|
266
|
+
type DevPanelBakeOptions = {
|
|
267
|
+
session: BakeSession;
|
|
268
|
+
onBake: (settings: DevPanelBakeSettings) => void | DevPanelBakeResult | Promise<void | DevPanelBakeResult>;
|
|
269
|
+
qualities?: BakeQuality[];
|
|
270
|
+
sizes?: BakeTextureSize[];
|
|
271
|
+
defaultQuality?: BakeQuality;
|
|
272
|
+
defaultSize?: BakeTextureSize;
|
|
273
|
+
};
|
|
274
|
+
/** The shape of `bakery3.check()`, structurally, so the panel does not have
|
|
275
|
+
* to import the compatibility analyzer to display its verdict. */
|
|
276
|
+
type DevPanelCompatibility = {
|
|
277
|
+
score: number;
|
|
278
|
+
issues: Array<{
|
|
279
|
+
severity: string;
|
|
280
|
+
message: string;
|
|
281
|
+
/** `<Car>/<Body>/<Paint>`: the panel lists the issue under `Paint`. */
|
|
282
|
+
path?: string;
|
|
283
|
+
/** Linked beside the issue. */
|
|
284
|
+
docs?: string;
|
|
285
|
+
}>;
|
|
286
|
+
};
|
|
287
|
+
type DevPanelHistoryOptions = {
|
|
288
|
+
list: () => Promise<DevPanelHistoryEntry[]>;
|
|
289
|
+
/** Omit it and no download buttons are drawn at all, which is better than
|
|
290
|
+
* a button that cannot work. */
|
|
291
|
+
download?: (entry: DevPanelHistoryEntry, part?: 'glb') => void | Promise<void>;
|
|
292
|
+
};
|
|
293
|
+
/**
|
|
294
|
+
* A render the panel shows in its jobs strip: what is tracing now and what
|
|
295
|
+
* waits behind it. A job in a terminal state is not drawn; what finished is
|
|
296
|
+
* the Recent list's to show. States use the protocol's RenderState names
|
|
297
|
+
* (`queued`, `preparing`, `rendering_preview`, `rendering`, `completed`,
|
|
298
|
+
* `failed`, `cancelled`) so an SDK job and a host's own queue read alike.
|
|
299
|
+
*/
|
|
300
|
+
type DevPanelJob = {
|
|
301
|
+
id: string;
|
|
302
|
+
label: string;
|
|
303
|
+
state: string;
|
|
304
|
+
/** Overall, 0–1. Omit for an honest indeterminate. */
|
|
305
|
+
progress?: number;
|
|
306
|
+
/** The renderer's own words: `48% of samples`, `frame 12/48`. */
|
|
307
|
+
detail?: string;
|
|
308
|
+
/** The low-sample preview, the moment it exists: the row's thumbnail
|
|
309
|
+
* until `resultUrl` replaces it. */
|
|
310
|
+
previewUrl?: string;
|
|
311
|
+
resultUrl?: string;
|
|
312
|
+
seconds?: number;
|
|
313
|
+
/** Drawn as × on a job that is not finished. */
|
|
314
|
+
onCancel?: () => void;
|
|
315
|
+
};
|
|
316
|
+
/** What a tracked job's listeners receive: the union of RenderJob's payloads,
|
|
317
|
+
* loosely, so the panel can read them without importing the client. */
|
|
318
|
+
type TrackedJobPayload = {
|
|
319
|
+
percent?: number;
|
|
320
|
+
state?: string;
|
|
321
|
+
url?: string;
|
|
322
|
+
result?: {
|
|
323
|
+
url: string;
|
|
324
|
+
width?: number;
|
|
325
|
+
height?: number;
|
|
326
|
+
format?: string;
|
|
327
|
+
cost?: number;
|
|
328
|
+
expiresAt?: number;
|
|
329
|
+
};
|
|
330
|
+
error?: {
|
|
331
|
+
message?: string;
|
|
332
|
+
};
|
|
333
|
+
/** Every RenderJob payload carries the record; the strip does not read it,
|
|
334
|
+
* but naming it keeps this an honest structural match for all five events. */
|
|
335
|
+
render?: unknown;
|
|
336
|
+
};
|
|
337
|
+
/**
|
|
338
|
+
* What `trackJob` needs from an SDK `RenderJob`, structurally, so the panel
|
|
339
|
+
* never imports the client and any object with these members works.
|
|
340
|
+
*/
|
|
341
|
+
type TrackableJob = {
|
|
342
|
+
id: string;
|
|
343
|
+
status: string;
|
|
344
|
+
progress: number;
|
|
345
|
+
previewUrl?: string;
|
|
346
|
+
on(event: 'progress' | 'preview' | 'complete' | 'failed' | 'cancelled', listener: (payload: TrackedJobPayload) => void): () => void;
|
|
347
|
+
cancel?(): void | Promise<void>;
|
|
348
|
+
};
|
|
349
|
+
type DevPanelOptions = {
|
|
350
|
+
container?: HTMLElement;
|
|
351
|
+
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
352
|
+
defaultOpen?: boolean;
|
|
353
|
+
defaultTab?: DevPanelTab;
|
|
354
|
+
/** A name beside the mark in the header, for a host with a panel of its
|
|
355
|
+
* own to tell apart. None by default: the mark says whose panel it is. */
|
|
356
|
+
title?: string;
|
|
357
|
+
/** Fired when the FAB is opened or the card collapsed. A host that
|
|
358
|
+
* remounts the panel (switching scenes, say) uses it to come back open. */
|
|
359
|
+
onOpenChange?: (open: boolean) => void;
|
|
360
|
+
/**
|
|
361
|
+
* A cheap fingerprint of what is in the scene: its objects, which of them
|
|
362
|
+
* are visible, their geometry and materials. When it changes, the price,
|
|
363
|
+
* the Bake tab's object list and the compatibility verdict follow, because
|
|
364
|
+
* a developer who just added a wall should not be looking at the price of
|
|
365
|
+
* the room without it.
|
|
366
|
+
*
|
|
367
|
+
* three.js has no event for most of that (a swapped geometry, a hidden
|
|
368
|
+
* mesh), so the panel compares this on animation frames a few times a
|
|
369
|
+
* second while it is open, and never while the tab is in the background.
|
|
370
|
+
* Keep it to a walk over the scene; it can be as approximate as you like.
|
|
371
|
+
*/
|
|
372
|
+
sceneVersion?: () => string | number;
|
|
373
|
+
/**
|
|
374
|
+
* A cheap fingerprint of where things are: the camera's position, and the
|
|
375
|
+
* objects' if they move. How walled in the camera is moves a price, so a
|
|
376
|
+
* camera carried into a room is priced again, once it has come to rest. A
|
|
377
|
+
* view that never rests (an auto-rotating orbit, a scene that animates)
|
|
378
|
+
* keeps the price it had; `sceneVersion` still re-prices what is added to
|
|
379
|
+
* it meanwhile.
|
|
380
|
+
*/
|
|
381
|
+
viewVersion?: () => string | number;
|
|
382
|
+
estimate?: (request: DevPanelEstimateRequest) => Promise<DevPanelEstimate | null> | DevPanelEstimate | null;
|
|
383
|
+
/**
|
|
384
|
+
* The free, local, offline compatibility check, shown beside the button as
|
|
385
|
+
* `98% compatible`, which opens the issues object by object. Read on open,
|
|
386
|
+
* when the scene changes and on every `refresh()`; returning `null` hides
|
|
387
|
+
* it.
|
|
388
|
+
*/
|
|
389
|
+
compatibility?: () => DevPanelCompatibility | null;
|
|
390
|
+
history?: DevPanelHistoryOptions;
|
|
391
|
+
render?: DevPanelRenderOptions;
|
|
392
|
+
video?: DevPanelVideoOptions;
|
|
393
|
+
bake?: DevPanelBakeOptions;
|
|
394
|
+
};
|
|
395
|
+
type DevPanel = {
|
|
396
|
+
open(): void;
|
|
397
|
+
close(): void;
|
|
398
|
+
setTab(tab: DevPanelTab): void;
|
|
399
|
+
/** Re-read candidates, generations and history and repaint. */
|
|
400
|
+
refresh(): void;
|
|
401
|
+
/** Ask for a fresh estimate now. */
|
|
402
|
+
refreshCost(): void;
|
|
403
|
+
setStatus(message: string, tone?: 'info' | 'error' | 'ok'): void;
|
|
404
|
+
/** The host drives per-object progress:
|
|
405
|
+
* `setProgress('Baking pedestal · 3/12', 3/12)`. `null` clears it. */
|
|
406
|
+
setProgress(text: string | null, fraction?: number): void;
|
|
407
|
+
/**
|
|
408
|
+
* The jobs strip, replaced wholesale. A host with its own queue (a local
|
|
409
|
+
* worker, a batch script) reports what is tracing now and what waits
|
|
410
|
+
* behind it. Finished jobs are dropped from the strip; with no active job
|
|
411
|
+
* it hides.
|
|
412
|
+
*/
|
|
413
|
+
setJobs(jobs: DevPanelJob[]): void;
|
|
414
|
+
/**
|
|
415
|
+
* Follow an SDK render job into the strip (progress, the preview the
|
|
416
|
+
* moment it lands) with nothing to translate on the host's side. The row
|
|
417
|
+
* leaves the strip when the job ends; the untrack function detaches the
|
|
418
|
+
* listeners.
|
|
419
|
+
*/
|
|
420
|
+
trackJob(job: TrackableJob, label?: string): () => void;
|
|
421
|
+
/**
|
|
422
|
+
* A row in the jobs strip from the moment an action starts, before there
|
|
423
|
+
* is a job to follow: `update()` says what is happening (capturing the
|
|
424
|
+
* scene, uploading), `follow()` hands the same row to the job once it
|
|
425
|
+
* exists, and `end()` takes it away. One row from the click to the result,
|
|
426
|
+
* where it would otherwise be a bar that vanishes and a row that appears.
|
|
427
|
+
*/
|
|
428
|
+
startJob(label: string): DevPanelJobHandle;
|
|
429
|
+
dispose(): void;
|
|
430
|
+
};
|
|
431
|
+
/** What `startJob` returns. See there. */
|
|
432
|
+
type DevPanelJobHandle = {
|
|
433
|
+
/** `state` names a step after the job itself is done (`applying`), which
|
|
434
|
+
* keeps the row up while the action finishes. */
|
|
435
|
+
update(detail: string, progress?: number, state?: string): void;
|
|
436
|
+
follow(job: TrackableJob): void;
|
|
437
|
+
end(): void;
|
|
438
|
+
};
|
|
439
|
+
/**
|
|
440
|
+
* Mount the panel. Appends one fixed-position element to `container` (the
|
|
441
|
+
* body by default) and owns nothing else; `dispose()` puts the page back.
|
|
442
|
+
*/
|
|
443
|
+
declare function mountDevPanel(options: DevPanelOptions): DevPanel;
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* `mountBakery3Devtools`: the panel, wired to your client, in one call.
|
|
447
|
+
*
|
|
448
|
+
* `mountDevPanel` underneath it takes callbacks and knows nothing about an
|
|
449
|
+
* account. This function supplies those callbacks from a `createBakery3()`
|
|
450
|
+
* client, so the estimate, render, video and bake plumbing is written once
|
|
451
|
+
* for a vanilla three.js app and for React alike (`<Bakery3Devtools />` is a
|
|
452
|
+
* shell over this same function, see ../r3f/Devtools.tsx).
|
|
453
|
+
*
|
|
454
|
+
* import { createBakery3 } from '@oeave/bakery3';
|
|
455
|
+
* import { mountBakery3Devtools } from '@oeave/bakery3/devtools';
|
|
456
|
+
*
|
|
457
|
+
* const bakery3 = createBakery3({ token: mintToken });
|
|
458
|
+
* const panel = mountBakery3Devtools({ bakery3, scene, camera, renderer });
|
|
459
|
+
*
|
|
460
|
+
* By default the Bake tab goes through `bakery3.bake()`: the same capture,
|
|
461
|
+
* upload and `/v1/bakes` round trip a render takes, with the bundle's
|
|
462
|
+
* textures coming back on signed URLs. A `bakeTransport` replaces that with
|
|
463
|
+
* a function of your own that turns a `BakeSpec` into a `BakeBundle` (a local
|
|
464
|
+
* worker, or a bake farm you already run), and nothing else about the panel
|
|
465
|
+
* changes.
|
|
466
|
+
*/
|
|
467
|
+
|
|
468
|
+
/** What turns a prepared bake into a bundle. See the file header. */
|
|
469
|
+
type BakeTransport = (spec: BakeSpec, assets: CapturedScene['assets']) => Promise<BakeBundle>;
|
|
470
|
+
/**
|
|
471
|
+
* The part of the client the panel uses.
|
|
472
|
+
*
|
|
473
|
+
* Structural rather than `Bakery3` itself so that a host wrapping the client
|
|
474
|
+
* (to add its own telemetry, or to swap in a fake in a test) is not shut out
|
|
475
|
+
* of the panel for it. A real `createBakery3()` satisfies it as-is.
|
|
476
|
+
*/
|
|
477
|
+
type Bakery3DevtoolsClient = Pick<Bakery3, 'check' | 'estimate' | 'renderVideo'> & {
|
|
478
|
+
/** One render, one job: the panel never asks for a set of cameras. */
|
|
479
|
+
render(options?: RenderOptions): Promise<RenderJob>;
|
|
480
|
+
} &
|
|
481
|
+
/** Present on every real client; a host that fakes one and gives no
|
|
482
|
+
* `bakeTransport` is told so when the Bake button is pressed. */
|
|
483
|
+
Partial<Pick<Bakery3, 'bake'>>;
|
|
484
|
+
type Bakery3DevtoolsOptions = {
|
|
485
|
+
bakery3: Bakery3DevtoolsClient;
|
|
486
|
+
/**
|
|
487
|
+
* The live scene the panel checks, prices, renders and bakes. Read each
|
|
488
|
+
* time it is used, so a getter works; the Bake tab's session belongs to the
|
|
489
|
+
* scene this is when the panel mounts.
|
|
490
|
+
*/
|
|
491
|
+
scene: Scene;
|
|
492
|
+
/** Read each time it is used, so a getter can follow a camera that is
|
|
493
|
+
* swapped (R3F does) without remounting the panel. Its aspect is the
|
|
494
|
+
* aspect of every render and video the panel starts. */
|
|
495
|
+
camera: Camera;
|
|
496
|
+
/**
|
|
497
|
+
* The live `WebGLRenderer`, so the capture carries your color space and
|
|
498
|
+
* tone mapping instead of guessing them. Optional but wanted: an app that
|
|
499
|
+
* tone-maps and does not say so gets a render that is faithful to the
|
|
500
|
+
* manifest and not to the viewport.
|
|
501
|
+
*/
|
|
502
|
+
renderer?: CaptureOptions['renderer'];
|
|
503
|
+
/** Where the panel mounts. Defaults to `document.body`. */
|
|
504
|
+
container?: HTMLElement;
|
|
505
|
+
position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
|
|
506
|
+
defaultQuality?: QualityPreset;
|
|
507
|
+
defaultOpen?: boolean;
|
|
508
|
+
defaultTab?: DevPanelTab;
|
|
509
|
+
/** A name beside the mark in the header. None by default. */
|
|
510
|
+
title?: string;
|
|
511
|
+
onOpenChange?: (open: boolean) => void;
|
|
512
|
+
/**
|
|
513
|
+
* The timeline the Video tab films. Without one the panel makes its own,
|
|
514
|
+
* empty, on the live scene and camera: frame a shot, press Keyframe camera,
|
|
515
|
+
* move the playhead and press it again.
|
|
516
|
+
*/
|
|
517
|
+
timeline?: Timeline;
|
|
518
|
+
/** Objects offered in the timeline's "add track" picker. */
|
|
519
|
+
timelineTargets?: TimelinePanelTarget[];
|
|
520
|
+
/** Fired when the timeline takes the camera and when it gives it back.
|
|
521
|
+
* Suspend your orbit controls here. */
|
|
522
|
+
onPlaybackChange?: (active: boolean) => void;
|
|
523
|
+
/** Your own bake worker instead of the hosted `/v1/bakes`. */
|
|
524
|
+
bakeTransport?: BakeTransport;
|
|
525
|
+
/** Where a bundle's relative uris resolve against, when it has any. */
|
|
526
|
+
bakeBaseUrl?: string;
|
|
527
|
+
/** Zero the realtime lights when a generation is applied. Off by default:
|
|
528
|
+
* the session already replaces diffuse lighting with the lightmap (see
|
|
529
|
+
* bake/shading.ts), so muting only removes the lamps' highlights. It is a
|
|
530
|
+
* look to switch on from the panel, not a correction. */
|
|
531
|
+
muteLightsOnApply?: boolean;
|
|
532
|
+
history?: DevPanelHistoryOptions;
|
|
533
|
+
};
|
|
534
|
+
declare function mountBakery3Devtools(options: Bakery3DevtoolsOptions): DevPanel;
|
|
535
|
+
|
|
536
|
+
export { type BakeTransport, type Bakery3DevtoolsClient, type Bakery3DevtoolsOptions, type DevPanel, type DevPanelActionResult, type DevPanelBakeOptions, type DevPanelBakeResult, type DevPanelBakeSettings, type DevPanelCompatibility, type DevPanelEstimate, type DevPanelEstimateRequest, type DevPanelHistoryEntry, type DevPanelHistoryOptions, type DevPanelJob, type DevPanelJobHandle, type DevPanelOptions, type DevPanelRenderOptions, type DevPanelRenderSettings, type DevPanelTab, type DevPanelVideoOptions, type DevPanelVideoSettings, type TimelinePanel, type TimelinePanelOptions, type TimelinePanelTarget, type TrackableJob, type TrackedJobPayload, mountBakery3Devtools, mountDevPanel, mountTimelinePanel };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { mountBakery3Devtools, mountDevPanel, mountTimelinePanel } from '../chunk-54WJDN5R.js';
|
|
2
|
+
import '../chunk-CX4WTVGH.js';
|
|
3
|
+
import '../chunk-V3QINEEG.js';
|
|
4
|
+
import '../chunk-APBOWWSV.js';
|
|
5
|
+
import '../chunk-S4AJTLLN.js';
|
|
6
|
+
import '../chunk-AF5BIELI.js';
|
|
7
|
+
import '../chunk-TGFNQBKC.js';
|
|
8
|
+
import '../chunk-HQTUFVMM.js';
|
|
9
|
+
import '../chunk-4E5VV4QY.js';
|
|
10
|
+
import '../chunk-W6WQ5UP7.js';
|
|
11
|
+
import '../chunk-6NYR73Y7.js';
|
|
12
|
+
import '../chunk-MD2U6S4N.js';
|
|
13
|
+
import '../chunk-3G5QL4F4.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Group, Object3D } from 'three';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The implementation behind `@oeave/bakery3/environments`. `index.ts` lists
|
|
5
|
+
* what is public.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
declare const ENVIRONMENT_SHAPES: readonly ["sphere", "groundSphere", "floor"];
|
|
9
|
+
declare const ENVIRONMENT_SHADERS: readonly ["gradient", "bands", "blobs", "horizon"];
|
|
10
|
+
/**
|
|
11
|
+
* `dark`: an ink dome with colored light in it, over a dark, glossy ground,
|
|
12
|
+
* the brand's own look. `colorful`: the same ground under more of that light.
|
|
13
|
+
* `light`: a pale dome with soft color, over a warm matte ground.
|
|
14
|
+
*/
|
|
15
|
+
declare const ENVIRONMENT_MODES: readonly ["dark", "colorful", "light"];
|
|
16
|
+
type EnvironmentShape = (typeof ENVIRONMENT_SHAPES)[number];
|
|
17
|
+
type EnvironmentShader = (typeof ENVIRONMENT_SHADERS)[number];
|
|
18
|
+
type EnvironmentMode = (typeof ENVIRONMENT_MODES)[number];
|
|
19
|
+
type EnvironmentOptions = {
|
|
20
|
+
/**
|
|
21
|
+
* `sphere`: an inward-facing dome of `radius` around the origin.
|
|
22
|
+
* `groundSphere`: the same dome with its lower part flattened onto y = 0,
|
|
23
|
+
* so shadows land on it. `floor`: a disc of `radius` at y = 0 whose color
|
|
24
|
+
* and opacity fade with distance, so its edge never shows.
|
|
25
|
+
*/
|
|
26
|
+
shape: EnvironmentShape;
|
|
27
|
+
shader: EnvironmentShader;
|
|
28
|
+
/**
|
|
29
|
+
* Which palette and ground the environment defaults to. `dark` unless told
|
|
30
|
+
* otherwise. A `palette` overrides the colors; the ground still follows
|
|
31
|
+
* the mode.
|
|
32
|
+
*/
|
|
33
|
+
mode?: EnvironmentMode;
|
|
34
|
+
/**
|
|
35
|
+
* Two to four CSS hex colors, darkest first. Each shader has a default
|
|
36
|
+
* per mode. What each slot means:
|
|
37
|
+
*
|
|
38
|
+
* - `gradient`: bottom to top (center to rim on a floor)
|
|
39
|
+
* - `bands`: the base, then the band colors in turn
|
|
40
|
+
* - `blobs`: the base, then the blob colors in turn
|
|
41
|
+
* - `horizon`: the dome, the horizon ring, the key glow
|
|
42
|
+
*/
|
|
43
|
+
palette?: string[];
|
|
44
|
+
/**
|
|
45
|
+
* Emission strength, in the units the renderer traces with: a dome at
|
|
46
|
+
* `1` emits the radiance an HDRI pixel of value 1 would. Meaningless for
|
|
47
|
+
* the `floor` shape, which is lit, not lit from. Defaults per mode: a dark
|
|
48
|
+
* dome needs its few bright patches to carry the whole scene, so it emits
|
|
49
|
+
* harder (`3` dark, `2.5` colorful, `1.2` light).
|
|
50
|
+
*/
|
|
51
|
+
intensity?: number;
|
|
52
|
+
/** Dome or disc radius in meters. Default `12`. */
|
|
53
|
+
radius?: number;
|
|
54
|
+
/** Seeds blob placement and the key glow's side. Default `1`. */
|
|
55
|
+
seed?: number;
|
|
56
|
+
/**
|
|
57
|
+
* A phase, in seconds, baked into the shader when it is built: it turns
|
|
58
|
+
* the bands and rotates the blobs, and is the same number in the viewport
|
|
59
|
+
* and in the render. Default `0`.
|
|
60
|
+
*/
|
|
61
|
+
time?: number;
|
|
62
|
+
/**
|
|
63
|
+
* Add a viewport-only fill light. The dome is a real light in the render,
|
|
64
|
+
* but a rasterizer takes no light from an emissive mesh, so without a fill
|
|
65
|
+
* a product under a dark dome previews black. The fill is a hemisphere
|
|
66
|
+
* light in the dome's own colors (sky and ground from the palette, white
|
|
67
|
+
* over warm ground in light mode), marked `userData.bakery3.exclude` so it
|
|
68
|
+
* never reaches the manifest. The two halves differ on the product on
|
|
69
|
+
* purpose (a flat two-tone fill live, the dome's own light in the render).
|
|
70
|
+
* The dome is the same in both; the glossy ground of a dark or colorful
|
|
71
|
+
* dome is not, because in the render it reflects the dome (a colorful
|
|
72
|
+
* horizon lays a band of its color across it) and a rasterizer reflects
|
|
73
|
+
* no mesh. Default `false`.
|
|
74
|
+
*/
|
|
75
|
+
fill?: boolean;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* The options an environment was built with, defaults filled in. The fill is
|
|
79
|
+
* not part of it: it is a viewport aid, not the environment.
|
|
80
|
+
*/
|
|
81
|
+
type EnvironmentSpec = Required<Omit<EnvironmentOptions, 'fill'>>;
|
|
82
|
+
/**
|
|
83
|
+
* Build an environment. Returns a `Group` holding one mesh, named
|
|
84
|
+
* `bakery3-environment-<shape>-<shader>`, with the resolved options on
|
|
85
|
+
* `userData.bakery3Preset.environment`. The product stands at the origin,
|
|
86
|
+
* on y = 0.
|
|
87
|
+
*/
|
|
88
|
+
declare function createEnvironment(options: EnvironmentOptions): Group;
|
|
89
|
+
/** The spec a `createEnvironment()` group was built with, or `undefined`
|
|
90
|
+
* for anything else. */
|
|
91
|
+
declare function environmentSpecOf(object: Object3D): EnvironmentSpec | undefined;
|
|
92
|
+
|
|
93
|
+
export { ENVIRONMENT_MODES, ENVIRONMENT_SHADERS, ENVIRONMENT_SHAPES, type EnvironmentMode, type EnvironmentOptions, type EnvironmentShader, type EnvironmentShape, type EnvironmentSpec, createEnvironment, environmentSpecOf };
|