@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,145 @@
1
+ // src/errors.ts
2
+ var Bakery3Error = class _Bakery3Error extends Error {
3
+ code;
4
+ why;
5
+ fix;
6
+ docs;
7
+ path;
8
+ retryable;
9
+ constructor(init) {
10
+ super(init.message);
11
+ this.name = "Bakery3Error";
12
+ this.code = init.code;
13
+ this.why = init.why;
14
+ this.fix = init.fix;
15
+ this.docs = init.docs;
16
+ this.path = init.path;
17
+ this.retryable = init.retryable ?? false;
18
+ showFixInStack(this);
19
+ }
20
+ static from(error) {
21
+ return new _Bakery3Error(error);
22
+ }
23
+ /**
24
+ * The multi-line form, for a console or a devtools panel.
25
+ *
26
+ * `Error.message` stays one line so it reads correctly everywhere a message
27
+ * is expected to be one: a log aggregator, a toast, a test name. `stack`
28
+ * starts with this form, so an uncaught error prints its fix.
29
+ */
30
+ toDisplayString() {
31
+ const lines = [this.message];
32
+ if (this.path) lines.push("", "Location:", this.path);
33
+ if (this.why) lines.push("", "Why:", this.why);
34
+ if (this.fix) lines.push("", "Fix:", this.fix);
35
+ if (this.docs) lines.push("", "Docs:", this.docs);
36
+ return lines.join("\n");
37
+ }
38
+ };
39
+ function showFixInStack(error) {
40
+ let raw;
41
+ try {
42
+ raw = error.stack;
43
+ } catch {
44
+ return;
45
+ }
46
+ try {
47
+ Object.defineProperty(error, "stack", {
48
+ configurable: true,
49
+ enumerable: false,
50
+ get() {
51
+ const frames = framesOf(raw, this.message);
52
+ const head = `${this.name}: ${this.toDisplayString()}`;
53
+ return frames ? `${head}
54
+ ${frames}` : head;
55
+ },
56
+ set(value) {
57
+ Object.defineProperty(this, "stack", {
58
+ configurable: true,
59
+ enumerable: false,
60
+ writable: true,
61
+ value
62
+ });
63
+ }
64
+ });
65
+ } catch {
66
+ }
67
+ }
68
+ function framesOf(raw, message) {
69
+ if (!raw) return "";
70
+ const lines = raw.split("\n");
71
+ const first = lines.findIndex((line) => /^\s+at\s/.test(line));
72
+ if (first >= 0) return lines.slice(first).join("\n");
73
+ const header = lines[0] ?? "";
74
+ return /^[\w$.]*:/.test(header) && header.includes(message) ? "" : raw;
75
+ }
76
+ var BUDGET_FIX = {
77
+ render: "Raise maxCost, lower the quality preset, or reduce the output resolution.",
78
+ video: "Raise maxCost, lower the quality preset or the resolution, or render fewer frames.",
79
+ bake: "Raise maxCost, lower the bake quality or the texture size, or bake fewer objects."
80
+ };
81
+ var RenderBudgetExceeded = class extends Bakery3Error {
82
+ /** The ceiling that was set, when known. */
83
+ maxCost;
84
+ estimatedCost;
85
+ /** The ceiling the job would have been accepted under: the number `maxCost` is held against. */
86
+ maximumCost;
87
+ kind;
88
+ constructor(first, quote, kind = "render") {
89
+ const init = typeof first === "number" ? {
90
+ maxCost: first,
91
+ estimatedCost: quote?.estimatedCost,
92
+ maximumCost: quote?.maximumCost,
93
+ kind
94
+ } : first;
95
+ const what = init.kind ?? "render";
96
+ super({
97
+ code: "RenderBudgetExceeded",
98
+ message: init.message || budgetMessage(what, init),
99
+ why: init.why ?? `maxCost is held against the maximum a ${what} can be charged, not its estimate, so that it is a ceiling. The ${what} was refused before any GPU work started, and nothing was charged.`,
100
+ fix: init.fix ?? BUDGET_FIX[what],
101
+ docs: init.docs ?? "https://bakery3.com/docs/cost",
102
+ retryable: false
103
+ });
104
+ this.name = "RenderBudgetExceeded";
105
+ this.maxCost = init.maxCost;
106
+ this.estimatedCost = init.estimatedCost;
107
+ this.maximumCost = init.maximumCost;
108
+ this.kind = what;
109
+ }
110
+ };
111
+ function budgetMessage(kind, init) {
112
+ const usd = (n) => `$${n.toFixed(2)}`;
113
+ const { maxCost, estimatedCost, maximumCost } = init;
114
+ if (maximumCost !== void 0 && maxCost !== void 0) {
115
+ const estimate = estimatedCost !== void 0 ? ` (estimated ${usd(estimatedCost)})` : "";
116
+ return `This ${kind} could cost up to ${usd(maximumCost)}, which exceeds maxCost ${usd(maxCost)}${estimate}`;
117
+ }
118
+ if (maximumCost !== void 0)
119
+ return `This ${kind} could cost up to ${usd(maximumCost)}, which is over its budget.`;
120
+ return `This ${kind} is over its budget.`;
121
+ }
122
+ var BatchPageRefused = class extends Bakery3Error {
123
+ /** The page that was refused whole, still in the batch's buffer. */
124
+ page;
125
+ /** Outcomes of the pages this flush admitted before the refusal. */
126
+ admitted;
127
+ constructor(cause, page, admitted) {
128
+ super({
129
+ code: cause.code,
130
+ message: `${cause.message} ${page.length} item${page.length === 1 ? "" : "s"} still buffered.`,
131
+ why: cause.why ?? "A batch page is admitted whole or not at all, so nothing in this page was priced against your balance.",
132
+ fix: cause.fix ?? (cause.code === "BatchClosed" ? "The batch is sealed; open a new one (a new key) for more items." : "Top up, or raise the ceiling, then call flush() again. The buffer is intact."),
133
+ docs: cause.docs ?? "https://bakery3.com/docs/cost",
134
+ path: cause.path,
135
+ retryable: cause.code !== "BatchClosed"
136
+ });
137
+ this.name = "BatchPageRefused";
138
+ this.page = page;
139
+ this.admitted = admitted;
140
+ }
141
+ };
142
+
143
+ export { Bakery3Error, BatchPageRefused, RenderBudgetExceeded };
144
+ //# sourceMappingURL=chunk-3G5QL4F4.js.map
145
+ //# sourceMappingURL=chunk-3G5QL4F4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts"],"names":[],"mappings":"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","file":"chunk-3G5QL4F4.js","sourcesContent":["/**\n * Errors a developer can act on.\n *\n * \"Render failed\" is a bad error. A traceback is a worse one. Every failure\n * that reaches the developer carries what went wrong, where, why, and what to\n * do about it, and `code` stays stable so the failure can also be branched on\n * in code.\n */\n\nimport type {\n BatchItemOutcome,\n BatchItemRequest,\n RenderErrorCode,\n RenderError,\n} from './protocol/index.js';\n\n/**\n * Codes the SDK can raise that the render protocol does not: a fault on the\n * way (`NetworkError`), a fault before anything left the browser\n * (`CaptureFailed`), the two refusals a batch page can meet as a whole (over\n * the batch's own ceiling, or after it was sealed), and the two ends of a job\n * that are not faults in the scene: it was cancelled (`Cancelled`), or its\n * files were deleted before it was read (`Expired`).\n */\nexport type Bakery3ErrorCode =\n | RenderErrorCode\n | 'NetworkError'\n | 'CaptureFailed'\n | 'BatchBudgetExceeded'\n | 'BatchClosed'\n | 'Cancelled'\n | 'Expired';\n\nexport class Bakery3Error extends Error {\n readonly code: Bakery3ErrorCode;\n readonly why?: string;\n readonly fix?: string;\n readonly docs?: string;\n readonly path?: string;\n readonly retryable: boolean;\n\n constructor(init: {\n code: Bakery3ErrorCode;\n message: string;\n why?: string;\n fix?: string;\n docs?: string;\n path?: string;\n retryable?: boolean;\n }) {\n super(init.message);\n this.name = 'Bakery3Error';\n this.code = init.code;\n this.why = init.why;\n this.fix = init.fix;\n this.docs = init.docs;\n this.path = init.path;\n this.retryable = init.retryable ?? false;\n showFixInStack(this);\n }\n\n static from(error: RenderError): Bakery3Error {\n return new Bakery3Error(error);\n }\n\n /**\n * The multi-line form, for a console or a devtools panel.\n *\n * `Error.message` stays one line so it reads correctly everywhere a message\n * is expected to be one: a log aggregator, a toast, a test name. `stack`\n * starts with this form, so an uncaught error prints its fix.\n */\n toDisplayString(): string {\n const lines = [this.message];\n if (this.path) lines.push('', 'Location:', this.path);\n if (this.why) lines.push('', 'Why:', this.why);\n if (this.fix) lines.push('', 'Fix:', this.fix);\n if (this.docs) lines.push('', 'Docs:', this.docs);\n return lines.join('\\n');\n }\n}\n\n/**\n * Make `stack` carry the whole error, not just its first line.\n *\n * A browser console, React's error overlay and Node all print an uncaught\n * error as its `stack`, which starts with `name: message`. The why, the fix\n * and the docs link would be invisible exactly when they are needed. So the\n * stack starts with `toDisplayString()` instead, followed by the original\n * frames, which stay lines beginning with \" at \" where the engine writes\n * them that way.\n *\n * A getter, not a value: a subclass sets its own `name` after this runs, and\n * its stack must say `RenderBudgetExceeded`, not `Bakery3Error`. Assigning to\n * `stack` still works, for a tool that rewrites it.\n */\nfunction showFixInStack(error: Bakery3Error): void {\n let raw: string | undefined;\n try {\n raw = error.stack;\n } catch {\n return;\n }\n try {\n Object.defineProperty(error, 'stack', {\n configurable: true,\n enumerable: false,\n get(this: Bakery3Error) {\n const frames = framesOf(raw, this.message);\n const head = `${this.name}: ${this.toDisplayString()}`;\n return frames ? `${head}\\n${frames}` : head;\n },\n set(this: Bakery3Error, value: unknown) {\n Object.defineProperty(this, 'stack', {\n configurable: true,\n enumerable: false,\n writable: true,\n value,\n });\n },\n });\n } catch {\n // A frozen or exotic error object keeps the engine's own stack.\n }\n}\n\n/**\n * The frames of an engine's stack, without its header.\n *\n * V8 (Chrome, Node, Edge) and Bun write `Name: message` and then one\n * \" at ...\" line per frame. Safari and Firefox write frames only\n * (`fn@file:1:2`), with no header to remove.\n */\nfunction framesOf(raw: string | undefined, message: string): string {\n if (!raw) return '';\n const lines = raw.split('\\n');\n const first = lines.findIndex((line) => /^\\s+at\\s/.test(line));\n if (first >= 0) return lines.slice(first).join('\\n');\n // No \"at\" lines: either frames in the Safari/Firefox form, or a V8 stack\n // with no frames, which is only its header.\n const header = lines[0] ?? '';\n return /^[\\w$.]*:/.test(header) && header.includes(message) ? '' : raw;\n}\n\n/** What was refused, so the refusal can say which dials bring the price down. */\nexport type BudgetedKind = 'render' | 'video' | 'bake';\n\nconst BUDGET_FIX: Record<BudgetedKind, string> = {\n render:\n 'Raise maxCost, lower the quality preset, or reduce the output resolution.',\n video:\n 'Raise maxCost, lower the quality preset or the resolution, or render fewer frames.',\n bake: 'Raise maxCost, lower the bake quality or the texture size, or bake fewer objects.',\n};\n\n/**\n * What a budget refusal can say. Every field is optional, because a refusal\n * from the API may carry fewer numbers than the SDK's own check knows.\n */\nexport type RenderBudgetInit = {\n message?: string;\n why?: string;\n fix?: string;\n docs?: string;\n /** The ceiling that was set. */\n maxCost?: number;\n estimatedCost?: number;\n maximumCost?: number;\n kind?: BudgetedKind;\n};\n\n/**\n * The budget refusal.\n *\n * Its own class because it is the one failure a developer is expected to\n * catch by type rather than by code: it is a normal, designed outcome of\n * setting `maxCost`, not a fault. Nothing was sent to a renderer and nothing\n * was charged.\n *\n * `instanceof RenderBudgetExceeded` catches both ways it is raised: the SDK's\n * own check before an upload (`new RenderBudgetExceeded(maxCost, quote,\n * kind)`, every number known), and the API's 402 (`new\n * RenderBudgetExceeded({ ... })`, with whatever numbers that answer carried,\n * for example from a browser token that has spent its allowance).\n */\nexport class RenderBudgetExceeded extends Bakery3Error {\n /** The ceiling that was set, when known. */\n readonly maxCost?: number;\n readonly estimatedCost?: number;\n /** The ceiling the job would have been accepted under: the number `maxCost` is held against. */\n readonly maximumCost?: number;\n readonly kind: BudgetedKind;\n\n constructor(\n maxCost: number,\n quote: { estimatedCost: number; maximumCost: number },\n kind?: BudgetedKind,\n );\n constructor(init: RenderBudgetInit);\n constructor(\n first: number | RenderBudgetInit,\n quote?: { estimatedCost: number; maximumCost: number },\n kind: BudgetedKind = 'render',\n ) {\n const init: RenderBudgetInit =\n typeof first === 'number'\n ? {\n maxCost: first,\n estimatedCost: quote?.estimatedCost,\n maximumCost: quote?.maximumCost,\n kind,\n }\n : first;\n const what = init.kind ?? 'render';\n super({\n code: 'RenderBudgetExceeded',\n message: init.message || budgetMessage(what, init),\n why:\n init.why ??\n `maxCost is held against the maximum a ${what} can be charged, not its estimate, so that it is a ceiling. The ${what} was refused before any GPU work started, and nothing was charged.`,\n fix: init.fix ?? BUDGET_FIX[what],\n docs: init.docs ?? 'https://bakery3.com/docs/cost',\n retryable: false,\n });\n this.name = 'RenderBudgetExceeded';\n this.maxCost = init.maxCost;\n this.estimatedCost = init.estimatedCost;\n this.maximumCost = init.maximumCost;\n this.kind = what;\n }\n}\n\n/**\n * The message quotes the maximum, because that is what was compared; the\n * estimate alone can read as under the ceiling. A number that is missing is\n * left out rather than printed as NaN.\n */\nfunction budgetMessage(kind: BudgetedKind, init: RenderBudgetInit): string {\n const usd = (n: number) => `$${n.toFixed(2)}`;\n const { maxCost, estimatedCost, maximumCost } = init;\n if (maximumCost !== undefined && maxCost !== undefined) {\n const estimate =\n estimatedCost !== undefined ? ` (estimated ${usd(estimatedCost)})` : '';\n return `This ${kind} could cost up to ${usd(maximumCost)}, which exceeds maxCost ${usd(maxCost)}${estimate}`;\n }\n if (maximumCost !== undefined)\n return `This ${kind} could cost up to ${usd(maximumCost)}, which is over its budget.`;\n return `This ${kind} is over its budget.`;\n}\n\n/**\n * A whole page of batch items was refused.\n *\n * Admission is per page: the control plane prices the page, checks it against\n * the account's balance and the batch's own `maxCost`, and either admits\n * every item or none. A `402 InsufficientBalance`, a `402 BatchBudgetExceeded`\n * or a `409 BatchClosed` means nothing in the page was admitted. The `Batch`\n * keeps those items buffered, so after a top-up (or a higher ceiling)\n * `flush()` sends exactly the same page again.\n *\n * `admitted` is what earlier pages of the same flush already got through:\n * those items are the server's now, and this error carries their outcomes so\n * a caller does not lose them because a later page was refused.\n */\nexport class BatchPageRefused extends Bakery3Error {\n /** The page that was refused whole, still in the batch's buffer. */\n readonly page: BatchItemRequest[];\n /** Outcomes of the pages this flush admitted before the refusal. */\n readonly admitted: BatchItemOutcome[];\n\n constructor(\n cause: Bakery3Error,\n page: BatchItemRequest[],\n admitted: BatchItemOutcome[],\n ) {\n super({\n code: cause.code,\n message: `${cause.message} ${page.length} item${page.length === 1 ? '' : 's'} still buffered.`,\n why:\n cause.why ??\n 'A batch page is admitted whole or not at all, so nothing in this page was priced against your balance.',\n fix:\n cause.fix ??\n (cause.code === 'BatchClosed'\n ? 'The batch is sealed; open a new one (a new key) for more items.'\n : 'Top up, or raise the ceiling, then call flush() again. The buffer is intact.'),\n docs: cause.docs ?? 'https://bakery3.com/docs/cost',\n path: cause.path,\n retryable: cause.code !== 'BatchClosed',\n });\n this.name = 'BatchPageRefused';\n this.page = page;\n this.admitted = admitted;\n }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ // src/presets/baseUrl.ts
2
+ var baseUrl = "https://cdn.bakery3.com/presets";
3
+ function setPresetBaseUrl(url) {
4
+ baseUrl = url.replace(/\/$/, "");
5
+ }
6
+ function presetBaseUrl() {
7
+ return baseUrl;
8
+ }
9
+
10
+ export { presetBaseUrl, setPresetBaseUrl };
11
+ //# sourceMappingURL=chunk-4E5VV4QY.js.map
12
+ //# sourceMappingURL=chunk-4E5VV4QY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/presets/baseUrl.ts"],"names":[],"mappings":";AAQA,IAAI,OAAA,GAAU,iCAAA;AAOP,SAAS,iBAAiB,GAAA,EAAmB;AAClD,EAAA,OAAA,GAAU,GAAA,CAAI,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AACjC;AAEO,SAAS,aAAA,GAAwB;AACtC,EAAA,OAAO,OAAA;AACT","file":"chunk-4E5VV4QY.js","sourcesContent":["/**\n * Where the preset library is served from.\n *\n * A leaf on purpose: the bake session needs the base URL to fetch a preset\n * room's lightmaps, and importing it from the presets entry would drag the\n * room loader (GLTFLoader, GroundedSkybox) into every bundle that bakes.\n */\n\nlet baseUrl = 'https://cdn.bakery3.com/presets';\n\n/**\n * Point the SDK at another copy of the preset library, for self-hosting or a\n * local mirror. The host must send CORS headers: the SDK reads texture pixels\n * back when it builds a manifest.\n */\nexport function setPresetBaseUrl(url: string): void {\n baseUrl = url.replace(/\\/$/, '');\n}\n\nexport function presetBaseUrl(): string {\n return baseUrl;\n}\n"]}
@@ -0,0 +1,142 @@
1
+ import { Bakery3Error } from './chunk-3G5QL4F4.js';
2
+
3
+ // src/capture/camera.ts
4
+ var FOCUS_DOCS = "https://bakery3.com/docs/cameras#depth-of-field";
5
+ function captureCamera(camera) {
6
+ camera.updateMatrixWorld();
7
+ const position = [0, 0, 0];
8
+ const quaternion = [0, 0, 0, 1];
9
+ const elements = camera.matrixWorld.elements;
10
+ position[0] = elements[12];
11
+ position[1] = elements[13];
12
+ position[2] = elements[14];
13
+ const q = worldQuaternion(camera);
14
+ quaternion[0] = q[0];
15
+ quaternion[1] = q[1];
16
+ quaternion[2] = q[2];
17
+ quaternion[3] = q[3];
18
+ const anyCamera = camera;
19
+ if (anyCamera.isPerspectiveCamera) {
20
+ return {
21
+ type: "perspective",
22
+ fov: anyCamera.fov,
23
+ aspect: anyCamera.aspect,
24
+ near: anyCamera.near,
25
+ far: anyCamera.far,
26
+ zoom: anyCamera.zoom,
27
+ position,
28
+ quaternion,
29
+ ...camera.name ? { name: camera.name } : {},
30
+ ...focusOf(camera, position)
31
+ };
32
+ }
33
+ if (anyCamera.isOrthographicCamera) {
34
+ return {
35
+ type: "orthographic",
36
+ left: anyCamera.left,
37
+ right: anyCamera.right,
38
+ top: anyCamera.top,
39
+ bottom: anyCamera.bottom,
40
+ near: anyCamera.near,
41
+ far: anyCamera.far,
42
+ zoom: anyCamera.zoom,
43
+ position,
44
+ quaternion,
45
+ ...camera.name ? { name: camera.name } : {}
46
+ };
47
+ }
48
+ throw new Bakery3Error({
49
+ code: "InvalidRequest",
50
+ message: `Unsupported camera type: ${camera.type}`,
51
+ why: "The renderer draws a pinhole or an orthographic projection. An array, cube or stereo camera has no single frustum to reproduce.",
52
+ fix: "Pass one PerspectiveCamera or OrthographicCamera to render().",
53
+ docs: "https://bakery3.com/docs/cameras"
54
+ });
55
+ }
56
+ function focusOf(camera, position) {
57
+ const mark = camera.userData?.bakery3?.focus;
58
+ if (mark === void 0 || mark === null || mark === false) return {};
59
+ const focus = mark;
60
+ const fStop = focus.fStop;
61
+ if (typeof fStop !== "number" || !Number.isFinite(fStop) || fStop <= 0) {
62
+ throw focusError(
63
+ `camera.userData.bakery3.focus.fStop must be a positive number, got ${String(fStop)}.`,
64
+ "The f-number decides how much is blurred; without one there is no depth of field to render."
65
+ );
66
+ }
67
+ if (focus.target !== void 0) {
68
+ const t = focus.target;
69
+ const target = Array.isArray(t) ? [t[0], t[1], t[2]] : [
70
+ t.x,
71
+ t.y,
72
+ t.z
73
+ ];
74
+ if (!target.every((v) => typeof v === "number" && Number.isFinite(v))) {
75
+ throw focusError(
76
+ "camera.userData.bakery3.focus.target must be a point: [x, y, z] or a Vector3.",
77
+ "The target is the world point the render keeps sharp."
78
+ );
79
+ }
80
+ const e = camera.matrixWorld.elements;
81
+ const length = Math.hypot(e[8], e[9], e[10]) || 1;
82
+ const depth = -((target[0] - position[0]) * e[8] + (target[1] - position[1]) * e[9] + (target[2] - position[2]) * e[10]) / length;
83
+ if (!(depth > 0)) {
84
+ throw focusError(
85
+ "The focus target is behind the camera.",
86
+ "A lens can only focus on what is in front of it."
87
+ );
88
+ }
89
+ return { focus: { fStop, focalDistance: depth, target } };
90
+ }
91
+ const distance = focus.distance;
92
+ if (typeof distance !== "number" || !Number.isFinite(distance) || distance <= 0) {
93
+ throw focusError(
94
+ "camera.userData.bakery3.focus needs a target or a distance.",
95
+ "The render has to know where the sharp plane is: a world point to keep sharp, or a distance in metres from the camera."
96
+ );
97
+ }
98
+ return { focus: { fStop, focalDistance: distance } };
99
+ }
100
+ function focusError(message, why) {
101
+ return new Bakery3Error({
102
+ code: "InvalidRequest",
103
+ message,
104
+ why,
105
+ fix: "Set camera.userData.bakery3 = { focus: { fStop: 2.8, target: product.position } }, or remove the focus mark for a picture sharp throughout.",
106
+ docs: FOCUS_DOCS
107
+ });
108
+ }
109
+ function worldQuaternion(object) {
110
+ const e = object.matrixWorld.elements;
111
+ const sx = Math.hypot(e[0], e[1], e[2]) || 1;
112
+ const sy = Math.hypot(e[4], e[5], e[6]) || 1;
113
+ const sz = Math.hypot(e[8], e[9], e[10]) || 1;
114
+ const m00 = e[0] / sx;
115
+ const m01 = e[4] / sy;
116
+ const m02 = e[8] / sz;
117
+ const m10 = e[1] / sx;
118
+ const m11 = e[5] / sy;
119
+ const m12 = e[9] / sz;
120
+ const m20 = e[2] / sx;
121
+ const m21 = e[6] / sy;
122
+ const m22 = e[10] / sz;
123
+ const trace = m00 + m11 + m22;
124
+ if (trace > 0) {
125
+ const s2 = 0.5 / Math.sqrt(trace + 1);
126
+ return [(m21 - m12) * s2, (m02 - m20) * s2, (m10 - m01) * s2, 0.25 / s2];
127
+ }
128
+ if (m00 > m11 && m00 > m22) {
129
+ const s2 = 2 * Math.sqrt(1 + m00 - m11 - m22);
130
+ return [0.25 * s2, (m01 + m10) / s2, (m02 + m20) / s2, (m21 - m12) / s2];
131
+ }
132
+ if (m11 > m22) {
133
+ const s2 = 2 * Math.sqrt(1 + m11 - m00 - m22);
134
+ return [(m01 + m10) / s2, 0.25 * s2, (m12 + m21) / s2, (m02 - m20) / s2];
135
+ }
136
+ const s = 2 * Math.sqrt(1 + m22 - m00 - m11);
137
+ return [(m02 + m20) / s, (m12 + m21) / s, 0.25 * s, (m10 - m01) / s];
138
+ }
139
+
140
+ export { captureCamera };
141
+ //# sourceMappingURL=chunk-62M6XXNX.js.map
142
+ //# sourceMappingURL=chunk-62M6XXNX.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/capture/camera.ts"],"names":["s"],"mappings":";;;AA+BA,IAAM,UAAA,GAAa,iDAAA;AAEZ,SAAS,cAAc,MAAA,EAA4B;AAIxD,EAAA,MAAA,CAAO,iBAAA,EAAkB;AACzB,EAAA,MAAM,QAAA,GAAiB,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AAC/B,EAAA,MAAM,UAAA,GAAmB,CAAC,CAAA,EAAG,CAAA,EAAG,GAAG,CAAC,CAAA;AACpC,EAAA,MAAM,QAAA,GAAW,OAAO,WAAA,CAAY,QAAA;AACpC,EAAA,QAAA,CAAS,CAAC,CAAA,GAAI,QAAA,CAAS,EAAE,CAAA;AACzB,EAAA,QAAA,CAAS,CAAC,CAAA,GAAI,QAAA,CAAS,EAAE,CAAA;AACzB,EAAA,QAAA,CAAS,CAAC,CAAA,GAAI,QAAA,CAAS,EAAE,CAAA;AACzB,EAAA,MAAM,CAAA,GAAI,gBAAgB,MAAM,CAAA;AAChC,EAAA,UAAA,CAAW,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AACnB,EAAA,UAAA,CAAW,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AACnB,EAAA,UAAA,CAAW,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AACnB,EAAA,UAAA,CAAW,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AAEnB,EAAA,MAAM,SAAA,GAAY,MAAA;AAElB,EAAA,IAAI,UAAU,mBAAA,EAAqB;AACjC,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,aAAA;AAAA,MACN,KAAK,SAAA,CAAU,GAAA;AAAA,MACf,QAAQ,SAAA,CAAU,MAAA;AAAA,MAClB,MAAM,SAAA,CAAU,IAAA;AAAA,MAChB,KAAK,SAAA,CAAU,GAAA;AAAA,MACf,MAAM,SAAA,CAAU,IAAA;AAAA,MAChB,QAAA;AAAA,MACA,UAAA;AAAA,MACA,GAAI,OAAO,IAAA,GAAO,EAAE,MAAM,MAAA,CAAO,IAAA,KAAS,EAAC;AAAA,MAC3C,GAAG,OAAA,CAAQ,MAAA,EAAQ,QAAQ;AAAA,KAC7B;AAAA,EACF;AAEA,EAAA,IAAI,UAAU,oBAAA,EAAsB;AAClC,IAAA,OAAO;AAAA,MACL,IAAA,EAAM,cAAA;AAAA,MACN,MAAM,SAAA,CAAU,IAAA;AAAA,MAChB,OAAO,SAAA,CAAU,KAAA;AAAA,MACjB,KAAK,SAAA,CAAU,GAAA;AAAA,MACf,QAAQ,SAAA,CAAU,MAAA;AAAA,MAClB,MAAM,SAAA,CAAU,IAAA;AAAA,MAChB,KAAK,SAAA,CAAU,GAAA;AAAA,MACf,MAAM,SAAA,CAAU,IAAA;AAAA,MAChB,QAAA;AAAA,MACA,UAAA;AAAA,MACA,GAAI,OAAO,IAAA,GAAO,EAAE,MAAM,MAAA,CAAO,IAAA,KAAS;AAAC,KAC7C;AAAA,EACF;AAEA,EAAA,MAAM,IAAI,YAAA,CAAa;AAAA,IACrB,IAAA,EAAM,gBAAA;AAAA,IACN,OAAA,EAAS,CAAA,yBAAA,EAA4B,MAAA,CAAO,IAAI,CAAA,CAAA;AAAA,IAChD,GAAA,EAAK,iIAAA;AAAA,IACL,GAAA,EAAK,+DAAA;AAAA,IACL,IAAA,EAAM;AAAA,GACP,CAAA;AACH;AAOA,SAAS,OAAA,CACP,QACA,QAAA,EAGA;AACA,EAAA,MAAM,IAAA,GAAQ,MAAA,CAAO,QAAA,EAAU,OAAA,EAC3B,KAAA;AACJ,EAAA,IAAI,SAAS,MAAA,IAAa,IAAA,KAAS,QAAQ,IAAA,KAAS,KAAA,SAAc,EAAC;AACnE,EAAA,MAAM,KAAA,GAAQ,IAAA;AACd,EAAA,MAAM,QAAQ,KAAA,CAAM,KAAA;AACpB,EAAA,IAAI,OAAO,UAAU,QAAA,IAAY,CAAC,OAAO,QAAA,CAAS,KAAK,CAAA,IAAK,KAAA,IAAS,CAAA,EAAG;AACtE,IAAA,MAAM,UAAA;AAAA,MACJ,CAAA,mEAAA,EAAsE,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA,CAAA;AAAA,MACnF;AAAA,KACF;AAAA,EACF;AACA,EAAA,IAAI,KAAA,CAAM,WAAW,MAAA,EAAW;AAC9B,IAAA,MAAM,IAAI,KAAA,CAAM,MAAA;AAChB,IAAA,MAAM,MAAA,GAAe,KAAA,CAAM,OAAA,CAAQ,CAAC,IAChC,CAAC,CAAA,CAAE,CAAC,CAAA,EAAG,EAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAC,CAAA,GACjB;AAAA,MACG,CAAA,CAAoB,CAAA;AAAA,MACpB,CAAA,CAAoB,CAAA;AAAA,MACpB,CAAA,CAAoB;AAAA,KACvB;AACJ,IAAA,IAAI,CAAC,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA,KAAM,OAAO,CAAA,KAAM,QAAA,IAAY,MAAA,CAAO,QAAA,CAAS,CAAC,CAAC,CAAA,EAAG;AACrE,MAAA,MAAM,UAAA;AAAA,QACJ,+EAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAGA,IAAA,MAAM,CAAA,GAAI,OAAO,WAAA,CAAY,QAAA;AAC7B,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,CAAC,CAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAI,CAAA,CAAE,EAAE,CAAE,CAAA,IAAK,CAAA;AACnD,IAAA,MAAM,KAAA,GACJ,EAAA,CACG,MAAA,CAAO,CAAC,CAAA,GAAI,QAAA,CAAS,CAAC,CAAA,IAAK,CAAA,CAAE,CAAC,CAAA,GAAA,CAC9B,MAAA,CAAO,CAAC,CAAA,GAAI,QAAA,CAAS,CAAC,CAAA,IAAK,CAAA,CAAE,CAAC,CAAA,GAAA,CAC9B,MAAA,CAAO,CAAC,CAAA,GAAI,QAAA,CAAS,CAAC,CAAA,IAAK,CAAA,CAAE,EAAE,CAAA,CAAA,GAC9B,MAAA;AACN,IAAA,IAAI,EAAE,QAAQ,CAAA,CAAA,EAAI;AAChB,MAAA,MAAM,UAAA;AAAA,QACJ,wCAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AACA,IAAA,OAAO,EAAE,KAAA,EAAO,EAAE,OAAO,aAAA,EAAe,KAAA,EAAO,QAAO,EAAE;AAAA,EAC1D;AACA,EAAA,MAAM,WAAW,KAAA,CAAM,QAAA;AACvB,EAAA,IACE,OAAO,aAAa,QAAA,IACpB,CAAC,OAAO,QAAA,CAAS,QAAQ,CAAA,IACzB,QAAA,IAAY,CAAA,EACZ;AACA,IAAA,MAAM,UAAA;AAAA,MACJ,6DAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AACA,EAAA,OAAO,EAAE,KAAA,EAAO,EAAE,KAAA,EAAO,aAAA,EAAe,UAAS,EAAE;AACrD;AAEA,SAAS,UAAA,CAAW,SAAiB,GAAA,EAA2B;AAC9D,EAAA,OAAO,IAAI,YAAA,CAAa;AAAA,IACtB,IAAA,EAAM,gBAAA;AAAA,IACN,OAAA;AAAA,IACA,GAAA;AAAA,IACA,GAAA,EAAK,6IAAA;AAAA,IACL,IAAA,EAAM;AAAA,GACP,CAAA;AACH;AASA,SAAS,gBAAgB,MAAA,EAAsB;AAC7C,EAAA,MAAM,CAAA,GAAI,OAAO,WAAA,CAAY,QAAA;AAE7B,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,CAAC,CAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAI,CAAA,CAAE,CAAC,CAAE,CAAA,IAAK,CAAA;AAC9C,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,CAAC,CAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAI,CAAA,CAAE,CAAC,CAAE,CAAA,IAAK,CAAA;AAC9C,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,CAAC,CAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAI,CAAA,CAAE,EAAE,CAAE,CAAA,IAAK,CAAA;AAC/C,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,CAAC,CAAA,GAAK,EAAA;AACpB,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,CAAC,CAAA,GAAK,EAAA;AACpB,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,CAAC,CAAA,GAAK,EAAA;AACpB,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,CAAC,CAAA,GAAK,EAAA;AACpB,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,CAAC,CAAA,GAAK,EAAA;AACpB,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,CAAC,CAAA,GAAK,EAAA;AACpB,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,CAAC,CAAA,GAAK,EAAA;AACpB,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,CAAC,CAAA,GAAK,EAAA;AACpB,EAAA,MAAM,GAAA,GAAM,CAAA,CAAE,EAAE,CAAA,GAAK,EAAA;AAErB,EAAA,MAAM,KAAA,GAAQ,MAAM,GAAA,GAAM,GAAA;AAC1B,EAAA,IAAI,QAAQ,CAAA,EAAG;AACb,IAAA,MAAMA,EAAAA,GAAI,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,QAAQ,CAAC,CAAA;AACnC,IAAA,OAAO,CAAA,CAAE,GAAA,GAAM,GAAA,IAAOA,EAAAA,EAAAA,CAAI,GAAA,GAAM,GAAA,IAAOA,EAAAA,EAAAA,CAAI,GAAA,GAAM,GAAA,IAAOA,EAAAA,EAAG,IAAA,GAAOA,EAAC,CAAA;AAAA,EACrE;AACA,EAAA,IAAI,GAAA,GAAM,GAAA,IAAO,GAAA,GAAM,GAAA,EAAK;AAC1B,IAAA,MAAMA,KAAI,CAAA,GAAI,IAAA,CAAK,KAAK,CAAA,GAAI,GAAA,GAAM,MAAM,GAAG,CAAA;AAC3C,IAAA,OAAO,CAAC,IAAA,GAAOA,EAAAA,EAAAA,CAAI,GAAA,GAAM,GAAA,IAAOA,EAAAA,EAAAA,CAAI,GAAA,GAAM,GAAA,IAAOA,EAAAA,EAAAA,CAAI,GAAA,GAAM,GAAA,IAAOA,EAAC,CAAA;AAAA,EACrE;AACA,EAAA,IAAI,MAAM,GAAA,EAAK;AACb,IAAA,MAAMA,KAAI,CAAA,GAAI,IAAA,CAAK,KAAK,CAAA,GAAI,GAAA,GAAM,MAAM,GAAG,CAAA;AAC3C,IAAA,OAAO,CAAA,CAAE,GAAA,GAAM,GAAA,IAAOA,EAAAA,EAAG,IAAA,GAAOA,EAAAA,EAAAA,CAAI,GAAA,GAAM,GAAA,IAAOA,EAAAA,EAAAA,CAAI,GAAA,GAAM,GAAA,IAAOA,EAAC,CAAA;AAAA,EACrE;AACA,EAAA,MAAM,IAAI,CAAA,GAAI,IAAA,CAAK,KAAK,CAAA,GAAI,GAAA,GAAM,MAAM,GAAG,CAAA;AAC3C,EAAA,OAAO,CAAA,CAAE,GAAA,GAAM,GAAA,IAAO,CAAA,EAAA,CAAI,GAAA,GAAM,GAAA,IAAO,CAAA,EAAG,IAAA,GAAO,CAAA,EAAA,CAAI,GAAA,GAAM,GAAA,IAAO,CAAC,CAAA;AACrE","file":"chunk-62M6XXNX.js","sourcesContent":["/**\n * The active camera, in full.\n *\n * It is written out as data rather than referenced into the GLB by name\n * because the live camera is often not in the graph the exporter walks: R3F\n * holds the default camera outside the scene, drei's controls swap it, and a\n * configurator often animates a camera that was never added as a child of\n * anything.\n */\n\nimport type { Camera, OrthographicCamera, PerspectiveCamera } from 'three';\nimport type { CameraSpec, Quat, Vec3 } from '../protocol/index.js';\nimport { Bakery3Error } from '../errors.js';\n\n/**\n * Depth of field, marked on a perspective camera as\n * `camera.userData.bakery3 = { focus: { fStop: 2.8, target: [0, 0.4, 0] } }`.\n *\n * three has no aperture: its depth of field is a post-processing pass, so the\n * render cannot read it off the camera and the developer says it here.\n * `fStop` is a full-frame camera's f-number at the camera's own `fov`, so a\n * smaller number blurs more. `target` is the world point that stays sharp\n * and the render keeps it sharp through a clip as the camera moves;\n * `distance` is a fixed focus distance in metres instead. One of the two.\n */\nexport type CameraFocus = {\n fStop: number;\n target?: Vec3 | { x: number; y: number; z: number };\n distance?: number;\n};\n\nconst FOCUS_DOCS = 'https://bakery3.com/docs/cameras#depth-of-field';\n\nexport function captureCamera(camera: Camera): CameraSpec {\n // World, not local. A camera parented to a rig (an orbit pivot, a\n // turntable, a vehicle) has a local transform that means nothing on its\n // own, and that is exactly the case a configurator is in.\n camera.updateMatrixWorld();\n const position: Vec3 = [0, 0, 0];\n const quaternion: Quat = [0, 0, 0, 1];\n const elements = camera.matrixWorld.elements;\n position[0] = elements[12]!;\n position[1] = elements[13]!;\n position[2] = elements[14]!;\n const q = worldQuaternion(camera);\n quaternion[0] = q[0];\n quaternion[1] = q[1];\n quaternion[2] = q[2];\n quaternion[3] = q[3];\n\n const anyCamera = camera as PerspectiveCamera & OrthographicCamera;\n\n if (anyCamera.isPerspectiveCamera) {\n return {\n type: 'perspective',\n fov: anyCamera.fov,\n aspect: anyCamera.aspect,\n near: anyCamera.near,\n far: anyCamera.far,\n zoom: anyCamera.zoom,\n position,\n quaternion,\n ...(camera.name ? { name: camera.name } : {}),\n ...focusOf(camera, position),\n };\n }\n\n if (anyCamera.isOrthographicCamera) {\n return {\n type: 'orthographic',\n left: anyCamera.left,\n right: anyCamera.right,\n top: anyCamera.top,\n bottom: anyCamera.bottom,\n near: anyCamera.near,\n far: anyCamera.far,\n zoom: anyCamera.zoom,\n position,\n quaternion,\n ...(camera.name ? { name: camera.name } : {}),\n };\n }\n\n throw new Bakery3Error({\n code: 'InvalidRequest',\n message: `Unsupported camera type: ${camera.type}`,\n why: 'The renderer draws a pinhole or an orthographic projection. An array, cube or stereo camera has no single frustum to reproduce.',\n fix: 'Pass one PerspectiveCamera or OrthographicCamera to render().',\n docs: 'https://bakery3.com/docs/cameras',\n });\n}\n\n/**\n * The camera's focus mark as the manifest carries it. A target is sent as\n * the point and as its depth from the camera now: the depth is the focus of a\n * still, and the point is what a clip's focus follows.\n */\nfunction focusOf(\n camera: Camera,\n position: Vec3,\n): {\n focus?: NonNullable<Extract<CameraSpec, { type: 'perspective' }>['focus']>;\n} {\n const mark = (camera.userData?.bakery3 as { focus?: unknown } | undefined)\n ?.focus;\n if (mark === undefined || mark === null || mark === false) return {};\n const focus = mark as Partial<CameraFocus>;\n const fStop = focus.fStop;\n if (typeof fStop !== 'number' || !Number.isFinite(fStop) || fStop <= 0) {\n throw focusError(\n `camera.userData.bakery3.focus.fStop must be a positive number, got ${String(fStop)}.`,\n 'The f-number decides how much is blurred; without one there is no depth of field to render.',\n );\n }\n if (focus.target !== undefined) {\n const t = focus.target;\n const target: Vec3 = Array.isArray(t)\n ? [t[0], t[1], t[2]]\n : [\n (t as { x: number }).x,\n (t as { y: number }).y,\n (t as { z: number }).z,\n ];\n if (!target.every((v) => typeof v === 'number' && Number.isFinite(v))) {\n throw focusError(\n 'camera.userData.bakery3.focus.target must be a point: [x, y, z] or a Vector3.',\n 'The target is the world point the render keeps sharp.',\n );\n }\n // Depth along the view axis, which is what a lens focuses at: the\n // camera looks down its local -z, the third column of its world matrix.\n const e = camera.matrixWorld.elements;\n const length = Math.hypot(e[8]!, e[9]!, e[10]!) || 1;\n const depth =\n -(\n (target[0] - position[0]) * e[8]! +\n (target[1] - position[1]) * e[9]! +\n (target[2] - position[2]) * e[10]!\n ) / length;\n if (!(depth > 0)) {\n throw focusError(\n 'The focus target is behind the camera.',\n 'A lens can only focus on what is in front of it.',\n );\n }\n return { focus: { fStop, focalDistance: depth, target } };\n }\n const distance = focus.distance;\n if (\n typeof distance !== 'number' ||\n !Number.isFinite(distance) ||\n distance <= 0\n ) {\n throw focusError(\n 'camera.userData.bakery3.focus needs a target or a distance.',\n 'The render has to know where the sharp plane is: a world point to keep sharp, or a distance in metres from the camera.',\n );\n }\n return { focus: { fStop, focalDistance: distance } };\n}\n\nfunction focusError(message: string, why: string): Bakery3Error {\n return new Bakery3Error({\n code: 'InvalidRequest',\n message,\n why,\n fix: 'Set camera.userData.bakery3 = { focus: { fStop: 2.8, target: product.position } }, or remove the focus mark for a picture sharp throughout.',\n docs: FOCUS_DOCS,\n });\n}\n\n/**\n * The world-space rotation, decomposed by hand.\n *\n * `getWorldQuaternion` would allocate a `Quaternion` and pull three's class\n * into this module's import graph for one value; the matrix is already\n * up to date and the extraction is nine multiplies.\n */\nfunction worldQuaternion(object: Camera): Quat {\n const e = object.matrixWorld.elements;\n // Strip scale, or a camera under a scaled rig reads as a rotation it is not.\n const sx = Math.hypot(e[0]!, e[1]!, e[2]!) || 1;\n const sy = Math.hypot(e[4]!, e[5]!, e[6]!) || 1;\n const sz = Math.hypot(e[8]!, e[9]!, e[10]!) || 1;\n const m00 = e[0]! / sx;\n const m01 = e[4]! / sy;\n const m02 = e[8]! / sz;\n const m10 = e[1]! / sx;\n const m11 = e[5]! / sy;\n const m12 = e[9]! / sz;\n const m20 = e[2]! / sx;\n const m21 = e[6]! / sy;\n const m22 = e[10]! / sz;\n\n const trace = m00 + m11 + m22;\n if (trace > 0) {\n const s = 0.5 / Math.sqrt(trace + 1);\n return [(m21 - m12) * s, (m02 - m20) * s, (m10 - m01) * s, 0.25 / s];\n }\n if (m00 > m11 && m00 > m22) {\n const s = 2 * Math.sqrt(1 + m00 - m11 - m22);\n return [0.25 * s, (m01 + m10) / s, (m02 + m20) / s, (m21 - m12) / s];\n }\n if (m11 > m22) {\n const s = 2 * Math.sqrt(1 + m11 - m00 - m22);\n return [(m01 + m10) / s, 0.25 * s, (m12 + m21) / s, (m02 - m20) / s];\n }\n const s = 2 * Math.sqrt(1 + m22 - m00 - m11);\n return [(m02 + m20) / s, (m12 + m21) / s, 0.25 * s, (m10 - m01) / s];\n}\n"]}