@motion-core/motion-gpu 0.4.1 → 0.5.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 (228) hide show
  1. package/README.md +99 -0
  2. package/dist/advanced.d.ts +1 -0
  3. package/dist/advanced.d.ts.map +1 -0
  4. package/dist/advanced.js +14 -6
  5. package/dist/core/advanced.d.ts +1 -0
  6. package/dist/core/advanced.d.ts.map +1 -0
  7. package/dist/core/advanced.js +14 -5
  8. package/dist/core/compute-shader.d.ts +87 -0
  9. package/dist/core/compute-shader.d.ts.map +1 -0
  10. package/dist/core/compute-shader.js +205 -0
  11. package/dist/core/compute-shader.js.map +1 -0
  12. package/dist/core/current-value.d.ts +1 -0
  13. package/dist/core/current-value.d.ts.map +1 -0
  14. package/dist/core/current-value.js +35 -34
  15. package/dist/core/current-value.js.map +1 -0
  16. package/dist/core/error-diagnostics.d.ts +1 -0
  17. package/dist/core/error-diagnostics.d.ts.map +1 -0
  18. package/dist/core/error-diagnostics.js +70 -137
  19. package/dist/core/error-diagnostics.js.map +1 -0
  20. package/dist/core/error-report.d.ts +2 -1
  21. package/dist/core/error-report.d.ts.map +1 -0
  22. package/dist/core/error-report.js +247 -233
  23. package/dist/core/error-report.js.map +1 -0
  24. package/dist/core/frame-registry.d.ts +1 -0
  25. package/dist/core/frame-registry.d.ts.map +1 -0
  26. package/dist/core/frame-registry.js +546 -662
  27. package/dist/core/frame-registry.js.map +1 -0
  28. package/dist/core/index.d.ts +6 -2
  29. package/dist/core/index.d.ts.map +1 -0
  30. package/dist/core/index.js +13 -12
  31. package/dist/core/material-preprocess.d.ts +1 -0
  32. package/dist/core/material-preprocess.d.ts.map +1 -0
  33. package/dist/core/material-preprocess.js +131 -152
  34. package/dist/core/material-preprocess.js.map +1 -0
  35. package/dist/core/material.d.ts +23 -6
  36. package/dist/core/material.d.ts.map +1 -0
  37. package/dist/core/material.js +290 -317
  38. package/dist/core/material.js.map +1 -0
  39. package/dist/core/recompile-policy.d.ts +1 -0
  40. package/dist/core/recompile-policy.d.ts.map +1 -0
  41. package/dist/core/recompile-policy.js +18 -13
  42. package/dist/core/recompile-policy.js.map +1 -0
  43. package/dist/core/render-graph.d.ts +8 -3
  44. package/dist/core/render-graph.d.ts.map +1 -0
  45. package/dist/core/render-graph.js +77 -68
  46. package/dist/core/render-graph.js.map +1 -0
  47. package/dist/core/render-targets.d.ts +1 -0
  48. package/dist/core/render-targets.d.ts.map +1 -0
  49. package/dist/core/render-targets.js +52 -53
  50. package/dist/core/render-targets.js.map +1 -0
  51. package/dist/core/renderer.d.ts +1 -0
  52. package/dist/core/renderer.d.ts.map +1 -0
  53. package/dist/core/renderer.js +1337 -1081
  54. package/dist/core/renderer.js.map +1 -0
  55. package/dist/core/runtime-loop.d.ts +3 -2
  56. package/dist/core/runtime-loop.d.ts.map +1 -0
  57. package/dist/core/runtime-loop.js +353 -362
  58. package/dist/core/runtime-loop.js.map +1 -0
  59. package/dist/core/scheduler-helpers.d.ts +1 -0
  60. package/dist/core/scheduler-helpers.d.ts.map +1 -0
  61. package/dist/core/scheduler-helpers.js +52 -51
  62. package/dist/core/scheduler-helpers.js.map +1 -0
  63. package/dist/core/shader.d.ts +10 -1
  64. package/dist/core/shader.d.ts.map +1 -0
  65. package/dist/core/shader.js +109 -115
  66. package/dist/core/shader.js.map +1 -0
  67. package/dist/core/storage-buffers.d.ts +37 -0
  68. package/dist/core/storage-buffers.d.ts.map +1 -0
  69. package/dist/core/storage-buffers.js +95 -0
  70. package/dist/core/storage-buffers.js.map +1 -0
  71. package/dist/core/texture-loader.d.ts +1 -0
  72. package/dist/core/texture-loader.d.ts.map +1 -0
  73. package/dist/core/texture-loader.js +209 -273
  74. package/dist/core/texture-loader.js.map +1 -0
  75. package/dist/core/textures.d.ts +13 -0
  76. package/dist/core/textures.d.ts.map +1 -0
  77. package/dist/core/textures.js +111 -116
  78. package/dist/core/textures.js.map +1 -0
  79. package/dist/core/types.d.ts +147 -4
  80. package/dist/core/types.d.ts.map +1 -0
  81. package/dist/core/types.js +0 -4
  82. package/dist/core/uniforms.d.ts +1 -0
  83. package/dist/core/uniforms.d.ts.map +1 -0
  84. package/dist/core/uniforms.js +170 -191
  85. package/dist/core/uniforms.js.map +1 -0
  86. package/dist/index.d.ts +1 -0
  87. package/dist/index.d.ts.map +1 -0
  88. package/dist/index.js +13 -6
  89. package/dist/passes/BlitPass.d.ts +1 -0
  90. package/dist/passes/BlitPass.d.ts.map +1 -0
  91. package/dist/passes/BlitPass.js +23 -18
  92. package/dist/passes/BlitPass.js.map +1 -0
  93. package/dist/passes/ComputePass.d.ts +83 -0
  94. package/dist/passes/ComputePass.d.ts.map +1 -0
  95. package/dist/passes/ComputePass.js +92 -0
  96. package/dist/passes/ComputePass.js.map +1 -0
  97. package/dist/passes/CopyPass.d.ts +1 -0
  98. package/dist/passes/CopyPass.d.ts.map +1 -0
  99. package/dist/passes/CopyPass.js +58 -52
  100. package/dist/passes/CopyPass.js.map +1 -0
  101. package/dist/passes/FullscreenPass.d.ts +1 -0
  102. package/dist/passes/FullscreenPass.d.ts.map +1 -0
  103. package/dist/passes/FullscreenPass.js +127 -130
  104. package/dist/passes/FullscreenPass.js.map +1 -0
  105. package/dist/passes/PingPongComputePass.d.ts +104 -0
  106. package/dist/passes/PingPongComputePass.d.ts.map +1 -0
  107. package/dist/passes/PingPongComputePass.js +132 -0
  108. package/dist/passes/PingPongComputePass.js.map +1 -0
  109. package/dist/passes/ShaderPass.d.ts +1 -0
  110. package/dist/passes/ShaderPass.d.ts.map +1 -0
  111. package/dist/passes/ShaderPass.js +41 -37
  112. package/dist/passes/ShaderPass.js.map +1 -0
  113. package/dist/passes/index.d.ts +3 -0
  114. package/dist/passes/index.d.ts.map +1 -0
  115. package/dist/passes/index.js +6 -3
  116. package/dist/react/FragCanvas.d.ts +3 -2
  117. package/dist/react/FragCanvas.d.ts.map +1 -0
  118. package/dist/react/FragCanvas.js +234 -211
  119. package/dist/react/FragCanvas.js.map +1 -0
  120. package/dist/react/MotionGPUErrorOverlay.d.ts +1 -0
  121. package/dist/react/MotionGPUErrorOverlay.d.ts.map +1 -0
  122. package/dist/react/MotionGPUErrorOverlay.js +200 -14
  123. package/dist/react/MotionGPUErrorOverlay.js.map +1 -0
  124. package/dist/react/Portal.d.ts +1 -0
  125. package/dist/react/Portal.d.ts.map +1 -0
  126. package/dist/react/Portal.js +18 -21
  127. package/dist/react/Portal.js.map +1 -0
  128. package/dist/react/advanced.d.ts +1 -0
  129. package/dist/react/advanced.d.ts.map +1 -0
  130. package/dist/react/advanced.js +14 -6
  131. package/dist/react/frame-context.d.ts +1 -0
  132. package/dist/react/frame-context.d.ts.map +1 -0
  133. package/dist/react/frame-context.js +88 -94
  134. package/dist/react/frame-context.js.map +1 -0
  135. package/dist/react/index.d.ts +6 -2
  136. package/dist/react/index.d.ts.map +1 -0
  137. package/dist/react/index.js +12 -9
  138. package/dist/react/motiongpu-context.d.ts +1 -0
  139. package/dist/react/motiongpu-context.d.ts.map +1 -0
  140. package/dist/react/motiongpu-context.js +18 -15
  141. package/dist/react/motiongpu-context.js.map +1 -0
  142. package/dist/react/use-motiongpu-user-context.d.ts +1 -0
  143. package/dist/react/use-motiongpu-user-context.d.ts.map +1 -0
  144. package/dist/react/use-motiongpu-user-context.js +83 -82
  145. package/dist/react/use-motiongpu-user-context.js.map +1 -0
  146. package/dist/react/use-texture.d.ts +1 -0
  147. package/dist/react/use-texture.d.ts.map +1 -0
  148. package/dist/react/use-texture.js +132 -152
  149. package/dist/react/use-texture.js.map +1 -0
  150. package/dist/svelte/FragCanvas.svelte +2 -2
  151. package/dist/svelte/FragCanvas.svelte.d.ts +3 -2
  152. package/dist/svelte/FragCanvas.svelte.d.ts.map +1 -0
  153. package/dist/svelte/MotionGPUErrorOverlay.svelte +137 -7
  154. package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts +1 -0
  155. package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts.map +1 -0
  156. package/dist/svelte/Portal.svelte.d.ts +1 -0
  157. package/dist/svelte/Portal.svelte.d.ts.map +1 -0
  158. package/dist/svelte/advanced.d.ts +1 -0
  159. package/dist/svelte/advanced.d.ts.map +1 -0
  160. package/dist/svelte/advanced.js +13 -6
  161. package/dist/svelte/frame-context.d.ts +1 -0
  162. package/dist/svelte/frame-context.d.ts.map +1 -0
  163. package/dist/svelte/frame-context.js +27 -27
  164. package/dist/svelte/frame-context.js.map +1 -0
  165. package/dist/svelte/index.d.ts +6 -2
  166. package/dist/svelte/index.d.ts.map +1 -0
  167. package/dist/svelte/index.js +12 -9
  168. package/dist/svelte/motiongpu-context.d.ts +1 -0
  169. package/dist/svelte/motiongpu-context.d.ts.map +1 -0
  170. package/dist/svelte/motiongpu-context.js +24 -21
  171. package/dist/svelte/motiongpu-context.js.map +1 -0
  172. package/dist/svelte/use-motiongpu-user-context.d.ts +1 -0
  173. package/dist/svelte/use-motiongpu-user-context.d.ts.map +1 -0
  174. package/dist/svelte/use-motiongpu-user-context.js +69 -70
  175. package/dist/svelte/use-motiongpu-user-context.js.map +1 -0
  176. package/dist/svelte/use-texture.d.ts +1 -0
  177. package/dist/svelte/use-texture.d.ts.map +1 -0
  178. package/dist/svelte/use-texture.js +125 -147
  179. package/dist/svelte/use-texture.js.map +1 -0
  180. package/package.json +12 -7
  181. package/src/lib/advanced.ts +6 -0
  182. package/src/lib/core/advanced.ts +12 -0
  183. package/src/lib/core/compute-shader.ts +326 -0
  184. package/src/lib/core/current-value.ts +64 -0
  185. package/src/lib/core/error-diagnostics.ts +236 -0
  186. package/src/lib/core/error-report.ts +535 -0
  187. package/src/lib/core/frame-registry.ts +1190 -0
  188. package/src/lib/core/index.ts +94 -0
  189. package/src/lib/core/material-preprocess.ts +295 -0
  190. package/src/lib/core/material.ts +748 -0
  191. package/src/lib/core/recompile-policy.ts +31 -0
  192. package/src/lib/core/render-graph.ts +173 -0
  193. package/src/lib/core/render-targets.ts +107 -0
  194. package/src/lib/core/renderer.ts +2161 -0
  195. package/src/lib/core/runtime-loop.ts +537 -0
  196. package/src/lib/core/scheduler-helpers.ts +136 -0
  197. package/src/lib/core/shader.ts +301 -0
  198. package/src/lib/core/storage-buffers.ts +142 -0
  199. package/src/lib/core/texture-loader.ts +482 -0
  200. package/src/lib/core/textures.ts +257 -0
  201. package/src/lib/core/types.ts +743 -0
  202. package/src/lib/core/uniforms.ts +282 -0
  203. package/src/lib/index.ts +6 -0
  204. package/src/lib/passes/BlitPass.ts +54 -0
  205. package/src/lib/passes/ComputePass.ts +136 -0
  206. package/src/lib/passes/CopyPass.ts +80 -0
  207. package/src/lib/passes/FullscreenPass.ts +173 -0
  208. package/src/lib/passes/PingPongComputePass.ts +180 -0
  209. package/src/lib/passes/ShaderPass.ts +89 -0
  210. package/src/lib/passes/index.ts +9 -0
  211. package/src/lib/react/FragCanvas.tsx +345 -0
  212. package/src/lib/react/MotionGPUErrorOverlay.tsx +524 -0
  213. package/src/lib/react/Portal.tsx +34 -0
  214. package/src/lib/react/advanced.ts +36 -0
  215. package/src/lib/react/frame-context.ts +169 -0
  216. package/src/lib/react/index.ts +68 -0
  217. package/src/lib/react/motiongpu-context.ts +88 -0
  218. package/src/lib/react/use-motiongpu-user-context.ts +186 -0
  219. package/src/lib/react/use-texture.ts +233 -0
  220. package/src/lib/svelte/FragCanvas.svelte +249 -0
  221. package/src/lib/svelte/MotionGPUErrorOverlay.svelte +512 -0
  222. package/src/lib/svelte/Portal.svelte +31 -0
  223. package/src/lib/svelte/advanced.ts +32 -0
  224. package/src/lib/svelte/frame-context.ts +87 -0
  225. package/src/lib/svelte/index.ts +68 -0
  226. package/src/lib/svelte/motiongpu-context.ts +97 -0
  227. package/src/lib/svelte/use-motiongpu-user-context.ts +145 -0
  228. package/src/lib/svelte/use-texture.ts +232 -0
@@ -1,6 +1,7 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Portal } from './Portal.js';
3
- const MOTIONGPU_ERROR_OVERLAY_STYLES = `
1
+ import { Portal } from "./Portal.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ //#region src/lib/react/MotionGPUErrorOverlay.tsx
4
+ var MOTIONGPU_ERROR_OVERLAY_STYLES = `
4
5
  .motiongpu-error-overlay {
5
6
  --motiongpu-base-hue: var(--base-hue, 265);
6
7
  --motiongpu-color-background: oklch(0.2178 0.0056 var(--motiongpu-base-hue));
@@ -70,6 +71,19 @@ const MOTIONGPU_ERROR_OVERLAY_STYLES = `
70
71
  border-bottom: 1px solid var(--motiongpu-color-border);
71
72
  }
72
73
 
74
+ .motiongpu-error-header-top {
75
+ display: flex;
76
+ align-items: flex-start;
77
+ gap: 0.75rem;
78
+ }
79
+
80
+ .motiongpu-error-badges {
81
+ display: inline-flex;
82
+ align-items: center;
83
+ gap: 0.4rem;
84
+ flex-wrap: wrap;
85
+ }
86
+
73
87
  .motiongpu-error-badge-wrap {
74
88
  display: inline-flex;
75
89
  align-items: center;
@@ -81,7 +95,7 @@ const MOTIONGPU_ERROR_OVERLAY_STYLES = `
81
95
  background: var(--motiongpu-color-background-muted);
82
96
  }
83
97
 
84
- .motiongpu-error-phase {
98
+ .motiongpu-error-badge {
85
99
  display: inline-flex;
86
100
  align-items: center;
87
101
  margin: 0;
@@ -101,6 +115,20 @@ const MOTIONGPU_ERROR_OVERLAY_STYLES = `
101
115
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.24);
102
116
  }
103
117
 
118
+ .motiongpu-error-recoverable {
119
+ margin: 0;
120
+ font-size: 0.67rem;
121
+ line-height: 1.2;
122
+ letter-spacing: 0.06em;
123
+ text-transform: uppercase;
124
+ color: var(--motiongpu-color-foreground-muted);
125
+ }
126
+
127
+ .motiongpu-error-recoverable span {
128
+ font-family: var(--motiongpu-font-mono);
129
+ color: var(--motiongpu-color-foreground);
130
+ }
131
+
104
132
  .motiongpu-error-title {
105
133
  margin: 0;
106
134
  font-size: clamp(1.02rem, 1vw + 0.72rem, 1.32rem);
@@ -280,6 +308,11 @@ const MOTIONGPU_ERROR_OVERLAY_STYLES = `
280
308
  .motiongpu-error-title {
281
309
  font-size: 1.02rem;
282
310
  }
311
+
312
+ .motiongpu-error-header-top {
313
+ flex-direction: column;
314
+ align-items: flex-start;
315
+ }
283
316
  }
284
317
 
285
318
  @media (prefers-reduced-motion: reduce) {
@@ -289,17 +322,170 @@ const MOTIONGPU_ERROR_OVERLAY_STYLES = `
289
322
  }
290
323
  `;
291
324
  function normalizeErrorText(value) {
292
- return value
293
- .trim()
294
- .replace(/[.:!]+$/g, '')
295
- .toLowerCase();
325
+ return value.trim().replace(/[.:!]+$/g, "").toLowerCase();
296
326
  }
297
327
  function shouldShowErrorMessage(value) {
298
- return normalizeErrorText(value.message) !== normalizeErrorText(value.title);
328
+ return resolveDisplayMessage(value).length > 0;
329
+ }
330
+ function resolveDisplayMessage(value) {
331
+ const rawMessage = value.message.trim();
332
+ if (rawMessage.length === 0) return "";
333
+ if (normalizeErrorText(rawMessage) === normalizeErrorText(value.title)) return "";
334
+ const escapedTitle = value.title.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
335
+ const prefixPattern = new RegExp(`^${escapedTitle}\\s*[:\\-|]\\s*`, "i");
336
+ const stripped = rawMessage.replace(prefixPattern, "").trim();
337
+ return stripped.length > 0 ? stripped : rawMessage;
338
+ }
339
+ function formatRuntimeContext(context) {
340
+ if (!context) return "";
341
+ const indentBlock = (value, spaces = 2) => {
342
+ const prefix = " ".repeat(spaces);
343
+ return value.split("\n").map((line) => `${prefix}${line}`).join("\n");
344
+ };
345
+ const formatMaterialSignature = (value) => {
346
+ const trimmed = value.trim();
347
+ if (trimmed.length === 0) return "<empty>";
348
+ try {
349
+ return JSON.stringify(JSON.parse(trimmed), null, 2);
350
+ } catch {
351
+ return trimmed;
352
+ }
353
+ };
354
+ const lines = [];
355
+ if (context.materialSignature) {
356
+ lines.push("materialSignature:");
357
+ lines.push(indentBlock(formatMaterialSignature(context.materialSignature)));
358
+ }
359
+ if (context.passGraph) {
360
+ lines.push("passGraph:");
361
+ lines.push(` passCount: ${context.passGraph.passCount}`);
362
+ lines.push(` enabledPassCount: ${context.passGraph.enabledPassCount}`);
363
+ lines.push(" inputs:");
364
+ if (context.passGraph.inputs.length === 0) lines.push(" - <none>");
365
+ else for (const input of context.passGraph.inputs) lines.push(` - ${input}`);
366
+ lines.push(" outputs:");
367
+ if (context.passGraph.outputs.length === 0) lines.push(" - <none>");
368
+ else for (const output of context.passGraph.outputs) lines.push(` - ${output}`);
369
+ }
370
+ lines.push("activeRenderTargets:");
371
+ if (context.activeRenderTargets.length === 0) lines.push(" - <none>");
372
+ else for (const target of context.activeRenderTargets) lines.push(` - ${target}`);
373
+ return lines.join("\n");
299
374
  }
300
- export function MotionGPUErrorOverlay({ report }) {
301
- const detailsSummary = report.source ? 'Additional diagnostics' : 'Technical details';
302
- return (_jsxs(Portal, { children: [_jsx("style", { children: MOTIONGPU_ERROR_OVERLAY_STYLES }), _jsx("div", { className: "motiongpu-error-overlay", role: "presentation", children: _jsxs("section", { className: "motiongpu-error-dialog", role: "alertdialog", "aria-live": "assertive", "aria-modal": "true", "data-testid": "motiongpu-error", children: [_jsxs("header", { className: "motiongpu-error-header", children: [_jsx("div", { className: "motiongpu-error-badge-wrap", children: _jsx("p", { className: "motiongpu-error-phase", children: report.phase }) }), _jsx("h2", { className: "motiongpu-error-title", children: report.title })] }), _jsxs("div", { className: "motiongpu-error-body", children: [shouldShowErrorMessage(report) ? (_jsx("p", { className: "motiongpu-error-message", children: report.message })) : null, _jsx("p", { className: "motiongpu-error-hint", children: report.hint })] }), report.source ? (_jsxs("section", { className: "motiongpu-error-source", "aria-label": "Source", children: [_jsx("h3", { className: "motiongpu-error-source-title", children: "Source" }), _jsxs("div", { className: "motiongpu-error-source-frame", role: "presentation", children: [_jsxs("div", { className: "motiongpu-error-source-tabs", role: "tablist", "aria-label": "Source files", children: [_jsxs("span", { className: "motiongpu-error-source-tab motiongpu-error-source-tab-active", role: "tab", "aria-selected": "true", children: [report.source.location, report.source.column ? `, col ${report.source.column}` : ''] }), _jsx("span", { className: "motiongpu-error-source-tab-spacer", "aria-hidden": "true" })] }), _jsx("div", { className: "motiongpu-error-source-snippet", children: report.source.snippet.map((snippetLine) => (_jsxs("div", { className: snippetLine.highlight
303
- ? 'motiongpu-error-source-row motiongpu-error-source-row-active'
304
- : 'motiongpu-error-source-row', children: [_jsx("span", { className: "motiongpu-error-source-line", children: snippetLine.number }), _jsx("span", { className: "motiongpu-error-source-code", children: snippetLine.code || ' ' })] }, `snippet-${snippetLine.number}`))) })] })] })) : null, _jsxs("div", { className: "motiongpu-error-sections", children: [report.details.length > 0 ? (_jsxs("details", { className: "motiongpu-error-details", open: true, children: [_jsx("summary", { children: detailsSummary }), _jsx("pre", { children: report.details.join('\n') })] })) : null, report.stack.length > 0 ? (_jsxs("details", { className: "motiongpu-error-details", children: [_jsx("summary", { children: "Stack trace" }), _jsx("pre", { children: report.stack.join('\n') })] })) : null] })] }) })] }));
375
+ function MotionGPUErrorOverlay({ report }) {
376
+ const detailsSummary = report.source ? "Additional diagnostics" : "Technical details";
377
+ return /* @__PURE__ */ jsxs(Portal, { children: [/* @__PURE__ */ jsx("style", { children: MOTIONGPU_ERROR_OVERLAY_STYLES }), /* @__PURE__ */ jsx("div", {
378
+ className: "motiongpu-error-overlay",
379
+ role: "presentation",
380
+ children: /* @__PURE__ */ jsxs("section", {
381
+ className: "motiongpu-error-dialog",
382
+ role: "alertdialog",
383
+ "aria-live": "assertive",
384
+ "aria-modal": "true",
385
+ "data-testid": "motiongpu-error",
386
+ children: [
387
+ /* @__PURE__ */ jsxs("header", {
388
+ className: "motiongpu-error-header",
389
+ children: [
390
+ /* @__PURE__ */ jsx("div", {
391
+ className: "motiongpu-error-header-top",
392
+ children: /* @__PURE__ */ jsxs("div", {
393
+ className: "motiongpu-error-badges",
394
+ children: [/* @__PURE__ */ jsx("div", {
395
+ className: "motiongpu-error-badge-wrap",
396
+ children: /* @__PURE__ */ jsx("p", {
397
+ className: "motiongpu-error-badge motiongpu-error-badge-phase",
398
+ children: report.phase
399
+ })
400
+ }), /* @__PURE__ */ jsx("div", {
401
+ className: "motiongpu-error-badge-wrap",
402
+ children: /* @__PURE__ */ jsx("p", {
403
+ className: "motiongpu-error-badge motiongpu-error-badge-severity",
404
+ children: report.severity
405
+ })
406
+ })]
407
+ })
408
+ }),
409
+ /* @__PURE__ */ jsx("h2", {
410
+ className: "motiongpu-error-title",
411
+ children: report.title
412
+ }),
413
+ /* @__PURE__ */ jsxs("p", {
414
+ className: "motiongpu-error-recoverable",
415
+ children: ["Recoverable: ", /* @__PURE__ */ jsx("span", { children: report.recoverable ? "yes" : "no" })]
416
+ })
417
+ ]
418
+ }),
419
+ /* @__PURE__ */ jsxs("div", {
420
+ className: "motiongpu-error-body",
421
+ children: [shouldShowErrorMessage(report) ? /* @__PURE__ */ jsx("p", {
422
+ className: "motiongpu-error-message",
423
+ children: resolveDisplayMessage(report)
424
+ }) : null, /* @__PURE__ */ jsx("p", {
425
+ className: "motiongpu-error-hint",
426
+ children: report.hint
427
+ })]
428
+ }),
429
+ report.source ? /* @__PURE__ */ jsxs("section", {
430
+ className: "motiongpu-error-source",
431
+ "aria-label": "Source",
432
+ children: [/* @__PURE__ */ jsx("h3", {
433
+ className: "motiongpu-error-source-title",
434
+ children: "Source"
435
+ }), /* @__PURE__ */ jsxs("div", {
436
+ className: "motiongpu-error-source-frame",
437
+ role: "presentation",
438
+ children: [/* @__PURE__ */ jsxs("div", {
439
+ className: "motiongpu-error-source-tabs",
440
+ role: "tablist",
441
+ "aria-label": "Source files",
442
+ children: [/* @__PURE__ */ jsxs("span", {
443
+ className: "motiongpu-error-source-tab motiongpu-error-source-tab-active",
444
+ role: "tab",
445
+ "aria-selected": "true",
446
+ children: [report.source.location, report.source.column ? `, col ${report.source.column}` : ""]
447
+ }), /* @__PURE__ */ jsx("span", {
448
+ className: "motiongpu-error-source-tab-spacer",
449
+ "aria-hidden": "true"
450
+ })]
451
+ }), /* @__PURE__ */ jsx("div", {
452
+ className: "motiongpu-error-source-snippet",
453
+ children: report.source.snippet.map((snippetLine) => /* @__PURE__ */ jsxs("div", {
454
+ className: snippetLine.highlight ? "motiongpu-error-source-row motiongpu-error-source-row-active" : "motiongpu-error-source-row",
455
+ children: [/* @__PURE__ */ jsx("span", {
456
+ className: "motiongpu-error-source-line",
457
+ children: snippetLine.number
458
+ }), /* @__PURE__ */ jsx("span", {
459
+ className: "motiongpu-error-source-code",
460
+ children: snippetLine.code || " "
461
+ })]
462
+ }, `snippet-${snippetLine.number}`))
463
+ })]
464
+ })]
465
+ }) : null,
466
+ /* @__PURE__ */ jsxs("div", {
467
+ className: "motiongpu-error-sections",
468
+ children: [
469
+ report.details.length > 0 ? /* @__PURE__ */ jsxs("details", {
470
+ className: "motiongpu-error-details",
471
+ open: true,
472
+ children: [/* @__PURE__ */ jsx("summary", { children: detailsSummary }), /* @__PURE__ */ jsx("pre", { children: report.details.join("\n") })]
473
+ }) : null,
474
+ report.stack.length > 0 ? /* @__PURE__ */ jsxs("details", {
475
+ className: "motiongpu-error-details",
476
+ children: [/* @__PURE__ */ jsx("summary", { children: "Stack trace" }), /* @__PURE__ */ jsx("pre", { children: report.stack.join("\n") })]
477
+ }) : null,
478
+ report.context ? /* @__PURE__ */ jsxs("details", {
479
+ className: "motiongpu-error-details",
480
+ children: [/* @__PURE__ */ jsx("summary", { children: "Runtime context" }), /* @__PURE__ */ jsx("pre", { children: formatRuntimeContext(report.context) })]
481
+ }) : null
482
+ ]
483
+ })
484
+ ]
485
+ })
486
+ })] });
305
487
  }
488
+ //#endregion
489
+ export { MotionGPUErrorOverlay };
490
+
491
+ //# sourceMappingURL=MotionGPUErrorOverlay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MotionGPUErrorOverlay.js","names":[],"sources":["../../src/lib/react/MotionGPUErrorOverlay.tsx"],"sourcesContent":["import type { MotionGPUErrorReport } from '../core/error-report.js';\nimport { Portal } from './Portal.js';\n\ninterface MotionGPUErrorOverlayProps {\n\treport: MotionGPUErrorReport;\n}\n\nconst MOTIONGPU_ERROR_OVERLAY_STYLES = `\n.motiongpu-error-overlay {\n\t--motiongpu-base-hue: var(--base-hue, 265);\n\t--motiongpu-color-background: oklch(0.2178 0.0056 var(--motiongpu-base-hue));\n\t--motiongpu-color-background-muted: oklch(0.261 0.007 var(--motiongpu-base-hue));\n\t--motiongpu-color-foreground: oklch(1 0 0);\n\t--motiongpu-color-foreground-muted: oklch(0.6699 0.0081 var(--motiongpu-base-hue));\n\t--motiongpu-color-card: var(--motiongpu-color-background);\n\t--motiongpu-color-accent: oklch(0.6996 0.181959 44.4414);\n\t--motiongpu-color-accent-secondary: oklch(0.5096 0.131959 44.4414);\n\t--motiongpu-color-border: oklch(0.928 0.013 var(--motiongpu-base-hue) / 0.05);\n\t--motiongpu-color-white-fixed: oklch(1 0 0);\n\t--motiongpu-shadow-card: var(\n\t\t--shadow-2xl,\n\t\t0px 1px 1px -0.5px rgba(0, 0, 0, 0.06),\n\t\t0px 3px 3px -1.5px rgba(0, 0, 0, 0.06),\n\t\t0px 6px 6px -3px rgba(0, 0, 0, 0.06),\n\t\t0px 12px 12px -6px rgba(0, 0, 0, 0.06),\n\t\t0px 24px 24px -12px rgba(0, 0, 0, 0.05),\n\t\t0px 48px 48px -24px rgba(0, 0, 0, 0.06)\n\t);\n\t--motiongpu-radius-md: var(--radius-md, 0.5rem);\n\t--motiongpu-radius-lg: var(--radius-lg, 0.75rem);\n\t--motiongpu-radius-xl: var(--radius-xl, 1rem);\n\t--motiongpu-font-sans: var(\n\t\t--font-sans,\n\t\t'Inter',\n\t\t'Segoe UI',\n\t\t'Helvetica Neue',\n\t\tArial,\n\t\tsans-serif\n\t);\n\t--motiongpu-font-mono: var(--font-mono, 'SFMono-Regular', 'Menlo', 'Consolas', monospace);\n\tposition: fixed;\n\tinset: 0;\n\tdisplay: grid;\n\tplace-items: center;\n\tpadding: clamp(0.75rem, 1.4vw, 1.5rem);\n\tbackground: rgba(0, 0, 0, 0.8);\n\tbackdrop-filter: blur(10px);\n\tz-index: 2147483647;\n\tfont-family: var(--motiongpu-font-sans);\n\tcolor-scheme: dark;\n}\n\n.motiongpu-error-dialog {\n\twidth: min(52rem, calc(100vw - 1.5rem));\n\tmax-height: min(84vh, 44rem);\n\toverflow: auto;\n\tmargin: 0;\n\tpadding: 1.1rem;\n\tborder: 1px solid var(--motiongpu-color-border);\n\tborder-radius: var(--motiongpu-radius-xl);\n\tmax-width: calc(100vw - 1.5rem);\n\tbox-sizing: border-box;\n\tfont-size: 0.875rem;\n\tfont-weight: 400;\n\tline-height: 1.45;\n\tbackground: var(--motiongpu-color-card);\n\tcolor: var(--motiongpu-color-foreground);\n\tbox-shadow: var(--motiongpu-shadow-card);\n}\n\n.motiongpu-error-header {\n\tdisplay: grid;\n\tgap: 0.55rem;\n\tpadding-bottom: 0.9rem;\n\tborder-bottom: 1px solid var(--motiongpu-color-border);\n}\n\n.motiongpu-error-header-top {\n\tdisplay: flex;\n\talign-items: flex-start;\n\tgap: 0.75rem;\n}\n\n.motiongpu-error-badges {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 0.4rem;\n\tflex-wrap: wrap;\n}\n\n.motiongpu-error-badge-wrap {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tgap: 0.4rem;\n\twidth: fit-content;\n\tpadding: 0.18rem;\n\tborder-radius: 999px;\n\tborder: 1px solid var(--motiongpu-color-border);\n\tbackground: var(--motiongpu-color-background-muted);\n}\n\n.motiongpu-error-badge {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tmargin: 0;\n\tpadding: 0.22rem 0.56rem;\n\tborder-radius: 999px;\n\tfont-size: 0.66rem;\n\tletter-spacing: 0.08em;\n\tline-height: 1;\n\tfont-weight: 500;\n\ttext-transform: uppercase;\n\tcolor: var(--motiongpu-color-white-fixed);\n\tbackground: linear-gradient(\n\t\t180deg,\n\t\tvar(--motiongpu-color-accent) 0%,\n\t\tvar(--motiongpu-color-accent-secondary) 100%\n\t);\n\tbox-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.24);\n}\n\n.motiongpu-error-recoverable {\n\tmargin: 0;\n\tfont-size: 0.67rem;\n\tline-height: 1.2;\n\tletter-spacing: 0.06em;\n\ttext-transform: uppercase;\n\tcolor: var(--motiongpu-color-foreground-muted);\n}\n\n.motiongpu-error-recoverable span {\n\tfont-family: var(--motiongpu-font-mono);\n\tcolor: var(--motiongpu-color-foreground);\n}\n\n.motiongpu-error-title {\n\tmargin: 0;\n\tfont-size: clamp(1.02rem, 1vw + 0.72rem, 1.32rem);\n\tfont-weight: 500;\n\tline-height: 1.18;\n\tletter-spacing: -0.02em;\n\ttext-wrap: balance;\n\tcolor: var(--motiongpu-color-foreground);\n}\n\n.motiongpu-error-body {\n\tdisplay: grid;\n\tgap: 0.62rem;\n\tmargin-top: 0.92rem;\n}\n\n.motiongpu-error-message {\n\tmargin: 0;\n\tpadding: 0.72rem 0.78rem;\n\tborder: 1px solid color-mix(in oklch, var(--motiongpu-color-accent) 28%, transparent);\n\tborder-radius: var(--motiongpu-radius-md);\n\tbackground: color-mix(in oklch, var(--motiongpu-color-accent) 10%, transparent);\n\tfont-size: 0.82rem;\n\tline-height: 1.4;\n\tfont-weight: 400;\n\tcolor: var(--motiongpu-color-foreground);\n}\n\n.motiongpu-error-hint {\n\tmargin: 0;\n\tfont-size: 0.82rem;\n\tline-height: 1.45;\n\tfont-weight: 400;\n\tcolor: var(--motiongpu-color-foreground-muted);\n}\n\n.motiongpu-error-sections {\n\tdisplay: grid;\n\tgap: 0.62rem;\n\tmargin-top: 0.95rem;\n}\n\n.motiongpu-error-source {\n\tdisplay: grid;\n\tgap: 0.48rem;\n\tmargin-top: 0.96rem;\n}\n\n.motiongpu-error-source-title {\n\tmargin: 0;\n\tfont-size: 0.8rem;\n\tfont-weight: 500;\n\tline-height: 1.3;\n\tletter-spacing: 0.045em;\n\ttext-transform: uppercase;\n\tcolor: var(--motiongpu-color-foreground);\n}\n\n.motiongpu-error-source-frame {\n\tborder: 1px solid var(--motiongpu-color-border);\n\tborder-radius: var(--motiongpu-radius-lg);\n\toverflow: hidden;\n\tbackground: var(--motiongpu-color-background-muted);\n}\n\n.motiongpu-error-source-tabs {\n\tdisplay: flex;\n\talign-items: stretch;\n\tborder-bottom: 1px solid var(--motiongpu-color-border);\n\tbackground: var(--motiongpu-color-background);\n}\n\n.motiongpu-error-source-tab {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tpadding: 0.5rem 0.68rem;\n\tfont-size: 0.76rem;\n\tfont-weight: 400;\n\tline-height: 1.2;\n\tcolor: var(--motiongpu-color-foreground-muted);\n\tborder-right: 1px solid var(--motiongpu-color-border);\n}\n\n.motiongpu-error-source-tab-active {\n\tcolor: var(--motiongpu-color-foreground);\n\tbackground: var(--motiongpu-color-background-muted);\n}\n\n.motiongpu-error-source-tab-spacer {\n\tflex: 1 1 auto;\n}\n\n.motiongpu-error-source-snippet {\n\tdisplay: grid;\n\tbackground: var(--motiongpu-color-background-muted);\n}\n\n.motiongpu-error-source-row {\n\tdisplay: grid;\n\tgrid-template-columns: 2rem minmax(0, 1fr);\n\talign-items: start;\n\tgap: 0.42rem;\n\tpadding: 0.2rem 0.68rem;\n}\n\n.motiongpu-error-source-row-active {\n\tbackground: color-mix(in oklch, var(--motiongpu-color-accent) 10%, transparent);\n}\n\n.motiongpu-error-source-line {\n\tfont-family: var(--motiongpu-font-mono);\n\tfont-size: 0.77rem;\n\tfont-weight: 400;\n\tline-height: 1.3;\n\tfont-variant-numeric: tabular-nums;\n\tfont-feature-settings: 'tnum' 1;\n\tborder-right: 1px solid var(--motiongpu-color-border);\n\tcolor: var(--motiongpu-color-foreground-muted);\n\ttext-align: left;\n}\n\n.motiongpu-error-source-code {\n\tfont-family: var(--motiongpu-font-mono);\n\tfont-size: 0.77rem;\n\tfont-weight: 400;\n\tline-height: 1.3;\n\tcolor: var(--motiongpu-color-foreground);\n\twhite-space: pre-wrap;\n\tword-break: break-word;\n}\n\n.motiongpu-error-details {\n\tborder: 1px solid var(--motiongpu-color-border);\n\tborder-radius: var(--motiongpu-radius-lg);\n\toverflow: hidden;\n\tbackground: var(--motiongpu-color-background);\n}\n\n.motiongpu-error-details summary {\n\tcursor: pointer;\n\tpadding: 0.56rem 0.68rem;\n\tfont-size: 0.7rem;\n\tletter-spacing: 0.07em;\n\tline-height: 1.2;\n\tfont-weight: 500;\n\ttext-transform: uppercase;\n\tcolor: var(--motiongpu-color-foreground);\n}\n\n.motiongpu-error-details[open] summary {\n\tborder-bottom: 1px solid var(--motiongpu-color-border);\n}\n\n.motiongpu-error-details pre {\n\tmargin: 0;\n\tpadding: 0.62rem 0.68rem;\n\twhite-space: pre-wrap;\n\tword-break: break-word;\n\toverflow: auto;\n\tbackground: var(--motiongpu-color-background-muted);\n\tfont-size: 0.74rem;\n\tline-height: 1.4;\n\tfont-weight: 400;\n\tcolor: var(--motiongpu-color-foreground);\n\tfont-family: var(--motiongpu-font-mono);\n}\n\n@media (max-width: 42rem) {\n\t.motiongpu-error-overlay {\n\t\tpadding: 0.62rem;\n\t}\n\n\t.motiongpu-error-dialog {\n\t\tpadding: 0.85rem;\n\t}\n\n\t.motiongpu-error-title {\n\t\tfont-size: 1.02rem;\n\t}\n\n\t.motiongpu-error-header-top {\n\t\tflex-direction: column;\n\t\talign-items: flex-start;\n\t}\n}\n\n@media (prefers-reduced-motion: reduce) {\n\t.motiongpu-error-overlay {\n\t\tbackdrop-filter: none;\n\t}\n}\n`;\n\nfunction normalizeErrorText(value: string): string {\n\treturn value\n\t\t.trim()\n\t\t.replace(/[.:!]+$/g, '')\n\t\t.toLowerCase();\n}\n\nfunction shouldShowErrorMessage(value: MotionGPUErrorReport): boolean {\n\treturn resolveDisplayMessage(value).length > 0;\n}\n\nfunction resolveDisplayMessage(value: MotionGPUErrorReport): string {\n\tconst rawMessage = value.message.trim();\n\tif (rawMessage.length === 0) {\n\t\treturn '';\n\t}\n\n\tconst normalizedMessage = normalizeErrorText(rawMessage);\n\tconst normalizedTitle = normalizeErrorText(value.title);\n\tif (normalizedMessage === normalizedTitle) {\n\t\treturn '';\n\t}\n\n\tconst escapedTitle = value.title.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n\tconst prefixPattern = new RegExp(`^${escapedTitle}\\\\s*[:\\\\-|]\\\\s*`, 'i');\n\tconst stripped = rawMessage.replace(prefixPattern, '').trim();\n\treturn stripped.length > 0 ? stripped : rawMessage;\n}\n\nfunction formatRuntimeContext(context: MotionGPUErrorReport['context']): string {\n\tif (!context) {\n\t\treturn '';\n\t}\n\n\tconst indentBlock = (value: string, spaces = 2): string => {\n\t\tconst prefix = ' '.repeat(spaces);\n\t\treturn value\n\t\t\t.split('\\n')\n\t\t\t.map((line) => `${prefix}${line}`)\n\t\t\t.join('\\n');\n\t};\n\n\tconst formatMaterialSignature = (value: string): string => {\n\t\tconst trimmed = value.trim();\n\t\tif (trimmed.length === 0) {\n\t\t\treturn '<empty>';\n\t\t}\n\t\ttry {\n\t\t\treturn JSON.stringify(JSON.parse(trimmed), null, 2);\n\t\t} catch {\n\t\t\treturn trimmed;\n\t\t}\n\t};\n\n\tconst lines: string[] = [];\n\tif (context.materialSignature) {\n\t\tlines.push('materialSignature:');\n\t\tlines.push(indentBlock(formatMaterialSignature(context.materialSignature)));\n\t}\n\tif (context.passGraph) {\n\t\tlines.push('passGraph:');\n\t\tlines.push(` passCount: ${context.passGraph.passCount}`);\n\t\tlines.push(` enabledPassCount: ${context.passGraph.enabledPassCount}`);\n\t\tlines.push(' inputs:');\n\t\tif (context.passGraph.inputs.length === 0) {\n\t\t\tlines.push(' - <none>');\n\t\t} else {\n\t\t\tfor (const input of context.passGraph.inputs) {\n\t\t\t\tlines.push(` - ${input}`);\n\t\t\t}\n\t\t}\n\t\tlines.push(' outputs:');\n\t\tif (context.passGraph.outputs.length === 0) {\n\t\t\tlines.push(' - <none>');\n\t\t} else {\n\t\t\tfor (const output of context.passGraph.outputs) {\n\t\t\t\tlines.push(` - ${output}`);\n\t\t\t}\n\t\t}\n\t}\n\tlines.push('activeRenderTargets:');\n\tif (context.activeRenderTargets.length === 0) {\n\t\tlines.push(' - <none>');\n\t} else {\n\t\tfor (const target of context.activeRenderTargets) {\n\t\t\tlines.push(` - ${target}`);\n\t\t}\n\t}\n\treturn lines.join('\\n');\n}\n\nexport function MotionGPUErrorOverlay({ report }: MotionGPUErrorOverlayProps) {\n\tconst detailsSummary = report.source ? 'Additional diagnostics' : 'Technical details';\n\n\treturn (\n\t\t<Portal>\n\t\t\t<style>{MOTIONGPU_ERROR_OVERLAY_STYLES}</style>\n\t\t\t<div className=\"motiongpu-error-overlay\" role=\"presentation\">\n\t\t\t\t<section\n\t\t\t\t\tclassName=\"motiongpu-error-dialog\"\n\t\t\t\t\trole=\"alertdialog\"\n\t\t\t\t\taria-live=\"assertive\"\n\t\t\t\t\taria-modal=\"true\"\n\t\t\t\t\tdata-testid=\"motiongpu-error\"\n\t\t\t\t>\n\t\t\t\t\t<header className=\"motiongpu-error-header\">\n\t\t\t\t\t\t<div className=\"motiongpu-error-header-top\">\n\t\t\t\t\t\t\t<div className=\"motiongpu-error-badges\">\n\t\t\t\t\t\t\t\t<div className=\"motiongpu-error-badge-wrap\">\n\t\t\t\t\t\t\t\t\t<p className=\"motiongpu-error-badge motiongpu-error-badge-phase\">\n\t\t\t\t\t\t\t\t\t\t{report.phase}\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<div className=\"motiongpu-error-badge-wrap\">\n\t\t\t\t\t\t\t\t\t<p className=\"motiongpu-error-badge motiongpu-error-badge-severity\">\n\t\t\t\t\t\t\t\t\t\t{report.severity}\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t<h2 className=\"motiongpu-error-title\">{report.title}</h2>\n\t\t\t\t\t\t<p className=\"motiongpu-error-recoverable\">\n\t\t\t\t\t\t\tRecoverable: <span>{report.recoverable ? 'yes' : 'no'}</span>\n\t\t\t\t\t\t</p>\n\t\t\t\t\t</header>\n\t\t\t\t\t<div className=\"motiongpu-error-body\">\n\t\t\t\t\t\t{shouldShowErrorMessage(report) ? (\n\t\t\t\t\t\t\t<p className=\"motiongpu-error-message\">{resolveDisplayMessage(report)}</p>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t<p className=\"motiongpu-error-hint\">{report.hint}</p>\n\t\t\t\t\t</div>\n\n\t\t\t\t\t{report.source ? (\n\t\t\t\t\t\t<section className=\"motiongpu-error-source\" aria-label=\"Source\">\n\t\t\t\t\t\t\t<h3 className=\"motiongpu-error-source-title\">Source</h3>\n\t\t\t\t\t\t\t<div className=\"motiongpu-error-source-frame\" role=\"presentation\">\n\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\tclassName=\"motiongpu-error-source-tabs\"\n\t\t\t\t\t\t\t\t\trole=\"tablist\"\n\t\t\t\t\t\t\t\t\taria-label=\"Source files\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclassName=\"motiongpu-error-source-tab motiongpu-error-source-tab-active\"\n\t\t\t\t\t\t\t\t\t\trole=\"tab\"\n\t\t\t\t\t\t\t\t\t\taria-selected=\"true\"\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t{report.source.location}\n\t\t\t\t\t\t\t\t\t\t{report.source.column ? `, col ${report.source.column}` : ''}\n\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t<span className=\"motiongpu-error-source-tab-spacer\" aria-hidden=\"true\"></span>\n\t\t\t\t\t\t\t\t</div>\n\n\t\t\t\t\t\t\t\t<div className=\"motiongpu-error-source-snippet\">\n\t\t\t\t\t\t\t\t\t{report.source.snippet.map((snippetLine) => (\n\t\t\t\t\t\t\t\t\t\t<div\n\t\t\t\t\t\t\t\t\t\t\tkey={`snippet-${snippetLine.number}`}\n\t\t\t\t\t\t\t\t\t\t\tclassName={\n\t\t\t\t\t\t\t\t\t\t\t\tsnippetLine.highlight\n\t\t\t\t\t\t\t\t\t\t\t\t\t? 'motiongpu-error-source-row motiongpu-error-source-row-active'\n\t\t\t\t\t\t\t\t\t\t\t\t\t: 'motiongpu-error-source-row'\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"motiongpu-error-source-line\">{snippetLine.number}</span>\n\t\t\t\t\t\t\t\t\t\t\t<span className=\"motiongpu-error-source-code\">{snippetLine.code || ' '}</span>\n\t\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t))}\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</section>\n\t\t\t\t\t) : null}\n\n\t\t\t\t\t<div className=\"motiongpu-error-sections\">\n\t\t\t\t\t\t{report.details.length > 0 ? (\n\t\t\t\t\t\t\t<details className=\"motiongpu-error-details\" open>\n\t\t\t\t\t\t\t\t<summary>{detailsSummary}</summary>\n\t\t\t\t\t\t\t\t<pre>{report.details.join('\\n')}</pre>\n\t\t\t\t\t\t\t</details>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t{report.stack.length > 0 ? (\n\t\t\t\t\t\t\t<details className=\"motiongpu-error-details\">\n\t\t\t\t\t\t\t\t<summary>Stack trace</summary>\n\t\t\t\t\t\t\t\t<pre>{report.stack.join('\\n')}</pre>\n\t\t\t\t\t\t\t</details>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t\t{report.context ? (\n\t\t\t\t\t\t\t<details className=\"motiongpu-error-details\">\n\t\t\t\t\t\t\t\t<summary>Runtime context</summary>\n\t\t\t\t\t\t\t\t<pre>{formatRuntimeContext(report.context)}</pre>\n\t\t\t\t\t\t\t</details>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</div>\n\t\t\t\t</section>\n\t\t\t</div>\n\t\t</Portal>\n\t);\n}\n"],"mappings":"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"}
@@ -4,3 +4,4 @@ export interface PortalProps {
4
4
  children?: ReactNode;
5
5
  }
6
6
  export declare function Portal({ target, children }: PortalProps): import("react").ReactPortal | null;
7
+ //# sourceMappingURL=Portal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Portal.d.ts","sourceRoot":"","sources":["../../src/lib/react/Portal.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG5D,MAAM,WAAW,WAAW;IAC3B,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACrB;AAYD,wBAAgB,MAAM,CAAC,EAAE,MAAe,EAAE,QAAQ,EAAE,EAAE,WAAW,sCAehE"}
@@ -1,24 +1,21 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useEffect, useState } from 'react';
3
- import { createPortal } from 'react-dom';
1
+ import { useEffect, useState } from "react";
2
+ import { createPortal } from "react-dom";
3
+ import { jsx } from "react/jsx-runtime";
4
+ //#region src/lib/react/Portal.tsx
4
5
  function resolveTargetElement(input) {
5
- if (typeof document === 'undefined') {
6
- throw new Error('Portal target resolution requires a browser environment');
7
- }
8
- return typeof input === 'string'
9
- ? (document.querySelector(input) ?? document.body)
10
- : (input ?? document.body);
6
+ if (typeof document === "undefined") throw new Error("Portal target resolution requires a browser environment");
7
+ return typeof input === "string" ? document.querySelector(input) ?? document.body : input ?? document.body;
11
8
  }
12
- export function Portal({ target = 'body', children }) {
13
- const [targetElement, setTargetElement] = useState(null);
14
- useEffect(() => {
15
- if (typeof document === 'undefined') {
16
- return;
17
- }
18
- setTargetElement(resolveTargetElement(target));
19
- }, [target]);
20
- if (!targetElement) {
21
- return null;
22
- }
23
- return createPortal(_jsx("div", { children: children ?? null }), targetElement);
9
+ function Portal({ target = "body", children }) {
10
+ const [targetElement, setTargetElement] = useState(null);
11
+ useEffect(() => {
12
+ if (typeof document === "undefined") return;
13
+ setTargetElement(resolveTargetElement(target));
14
+ }, [target]);
15
+ if (!targetElement) return null;
16
+ return createPortal(/* @__PURE__ */ jsx("div", { children: children ?? null }), targetElement);
24
17
  }
18
+ //#endregion
19
+ export { Portal };
20
+
21
+ //# sourceMappingURL=Portal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Portal.js","names":[],"sources":["../../src/lib/react/Portal.tsx"],"sourcesContent":["import { useEffect, useState, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\n\nexport interface PortalProps {\n\ttarget?: string | HTMLElement | null;\n\tchildren?: ReactNode;\n}\n\nfunction resolveTargetElement(input: string | HTMLElement | null | undefined): HTMLElement {\n\tif (typeof document === 'undefined') {\n\t\tthrow new Error('Portal target resolution requires a browser environment');\n\t}\n\n\treturn typeof input === 'string'\n\t\t? (document.querySelector<HTMLElement>(input) ?? document.body)\n\t\t: (input ?? document.body);\n}\n\nexport function Portal({ target = 'body', children }: PortalProps) {\n\tconst [targetElement, setTargetElement] = useState<HTMLElement | null>(null);\n\n\tuseEffect(() => {\n\t\tif (typeof document === 'undefined') {\n\t\t\treturn;\n\t\t}\n\t\tsetTargetElement(resolveTargetElement(target));\n\t}, [target]);\n\n\tif (!targetElement) {\n\t\treturn null;\n\t}\n\n\treturn createPortal(<div>{children ?? null}</div>, targetElement);\n}\n"],"mappings":";;;;AAQA,SAAS,qBAAqB,OAA6D;AAC1F,KAAI,OAAO,aAAa,YACvB,OAAM,IAAI,MAAM,0DAA0D;AAG3E,QAAO,OAAO,UAAU,WACpB,SAAS,cAA2B,MAAM,IAAI,SAAS,OACvD,SAAS,SAAS;;AAGvB,SAAgB,OAAO,EAAE,SAAS,QAAQ,YAAyB;CAClE,MAAM,CAAC,eAAe,oBAAoB,SAA6B,KAAK;AAE5E,iBAAgB;AACf,MAAI,OAAO,aAAa,YACvB;AAED,mBAAiB,qBAAqB,OAAO,CAAC;IAC5C,CAAC,OAAO,CAAC;AAEZ,KAAI,CAAC,cACJ,QAAO;AAGR,QAAO,aAAa,oBAAC,OAAD,EAAA,UAAM,YAAY,MAAW,CAAA,EAAE,cAAc"}
@@ -9,3 +9,4 @@ export type { MotionGPUUserContext, MotionGPUUserNamespace } from './motiongpu-c
9
9
  export type { FrameProfilingSnapshot, FrameKey, FrameTaskInvalidation, FrameTaskInvalidationToken, FrameRunTimings, FrameScheduleSnapshot, FrameStage, FrameStageCallback, FrameTimingStats, FrameTask } from '../core/frame-registry.js';
10
10
  export type { SetMotionGPUUserContextOptions } from './use-motiongpu-user-context.js';
11
11
  export type { RenderPassContext, RenderTarget, UniformLayout, UniformLayoutEntry } from '../core/types.js';
12
+ //# sourceMappingURL=advanced.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"advanced.d.ts","sourceRoot":"","sources":["../../src/lib/react/advanced.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,oBAAoB,EAAE,6BAA6B,EAAE,MAAM,8BAA8B,CAAC;AACnG,OAAO,EACN,uBAAuB,EACvB,uBAAuB,EACvB,0BAA0B,EAC1B,MAAM,iCAAiC,CAAC;AACzC,YAAY,EACX,2BAA2B,EAC3B,sBAAsB,EACtB,eAAe,EACf,qBAAqB,EACrB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,oBAAoB,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAC3F,YAAY,EACX,sBAAsB,EACtB,QAAQ,EACR,qBAAqB,EACrB,0BAA0B,EAC1B,eAAe,EACf,qBAAqB,EACrB,UAAU,EACV,kBAAkB,EAClB,gBAAgB,EAChB,SAAS,EACT,MAAM,2BAA2B,CAAC;AACnC,YAAY,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AACtF,YAAY,EACX,iBAAiB,EACjB,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,MAAM,kBAAkB,CAAC"}
@@ -1,6 +1,14 @@
1
- /**
2
- * React adapter advanced entrypoint for MotionGPU.
3
- */
4
- export * from './index.js';
5
- export { applySchedulerPreset, captureSchedulerDebugSnapshot } from '../core/scheduler-helpers.js';
6
- export { setMotionGPUUserContext, useMotionGPUUserContext, useSetMotionGPUUserContext } from './use-motiongpu-user-context.js';
1
+ import { defineMaterial } from "../core/material.js";
2
+ import { BlitPass } from "../passes/BlitPass.js";
3
+ import { CopyPass } from "../passes/CopyPass.js";
4
+ import { ShaderPass } from "../passes/ShaderPass.js";
5
+ import { ComputePass } from "../passes/ComputePass.js";
6
+ import { PingPongComputePass } from "../passes/PingPongComputePass.js";
7
+ import { applySchedulerPreset, captureSchedulerDebugSnapshot } from "../core/scheduler-helpers.js";
8
+ import { useMotionGPU } from "./motiongpu-context.js";
9
+ import { useFrame } from "./frame-context.js";
10
+ import { FragCanvas } from "./FragCanvas.js";
11
+ import { useTexture } from "./use-texture.js";
12
+ import "./index.js";
13
+ import { setMotionGPUUserContext, useMotionGPUUserContext, useSetMotionGPUUserContext } from "./use-motiongpu-user-context.js";
14
+ export { BlitPass, ComputePass, CopyPass, FragCanvas, PingPongComputePass, ShaderPass, applySchedulerPreset, captureSchedulerDebugSnapshot, defineMaterial, setMotionGPUUserContext, useFrame, useMotionGPU, useMotionGPUUserContext, useSetMotionGPUUserContext, useTexture };
@@ -12,3 +12,4 @@ export declare function useFrame(callback: FrameCallback, options?: UseFrameOpti
12
12
  * Registers a frame callback with an explicit task key.
13
13
  */
14
14
  export declare function useFrame(key: FrameKey, callback: FrameCallback, options?: UseFrameOptions): UseFrameResult;
15
+ //# sourceMappingURL=frame-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-context.d.ts","sourceRoot":"","sources":["../../src/lib/react/frame-context.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,aAAa,EACb,QAAQ,EACR,sBAAsB,EACtB,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,UAAU,EACV,kBAAkB,EAClB,SAAS,EACT,qBAAqB,EACrB,0BAA0B,EAC1B,eAAe,EACf,cAAc,EACd,MAAM,2BAA2B,CAAC;AAOnC;;GAEG;AACH,eAAO,MAAM,yBAAyB,+CAA4C,CAAC;AAEnF,YAAY,EACX,aAAa,EACb,QAAQ,EACR,sBAAsB,EACtB,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,UAAU,EACV,kBAAkB,EAClB,SAAS,EACT,qBAAqB,EACrB,0BAA0B,EAC1B,eAAe,EACf,cAAc,EACd,CAAC;AAEF;;GAEG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,cAAc,CAAC;AAE7F;;GAEG;AACH,wBAAgB,QAAQ,CACvB,GAAG,EAAE,QAAQ,EACb,QAAQ,EAAE,aAAa,EACvB,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC"}
@@ -1,98 +1,92 @@
1
- import { createContext, useContext, useEffect, useRef } from 'react';
2
- import { createCurrentWritable } from '../core/current-value.js';
3
- import { useMotionGPU } from './motiongpu-context.js';
1
+ import { createCurrentWritable } from "../core/current-value.js";
2
+ import { useMotionGPU } from "./motiongpu-context.js";
3
+ import { createContext, useContext, useEffect, useRef } from "react";
4
+ //#region src/lib/react/frame-context.ts
4
5
  /**
5
- * Placeholder stage used before a frame task registration becomes available.
6
- */
7
- const PENDING_STAGE_KEY = Symbol('motiongpu-react-pending-stage');
6
+ * Placeholder stage used before a frame task registration becomes available.
7
+ */
8
+ var PENDING_STAGE_KEY = Symbol("motiongpu-react-pending-stage");
8
9
  /**
9
- * React context container for the active frame registry.
10
- */
11
- export const FrameRegistryReactContext = createContext(null);
10
+ * React context container for the active frame registry.
11
+ */
12
+ var FrameRegistryReactContext = createContext(null);
12
13
  /**
13
- * Registers a callback in the active frame registry and auto-unsubscribes on unmount.
14
- *
15
- * @param keyOrCallback - Task key or callback for auto-key registration.
16
- * @param callbackOrOptions - Callback (keyed overload) or options (auto-key overload).
17
- * @param maybeOptions - Optional registration options for keyed overload.
18
- * Registration key/options are frozen on first render; subsequent renders do not re-register.
19
- * @returns Registration control API with task, start/stop controls and started state.
20
- * @throws {Error} When called outside `<FragCanvas>`.
21
- * @throws {Error} When callback is missing in keyed overload.
22
- */
23
- export function useFrame(keyOrCallback, callbackOrOptions, maybeOptions) {
24
- const registry = useContext(FrameRegistryReactContext);
25
- if (!registry) {
26
- throw new Error('useFrame must be used inside <FragCanvas>');
27
- }
28
- const motiongpu = useMotionGPU();
29
- const resolved = typeof keyOrCallback === 'function'
30
- ? {
31
- key: undefined,
32
- callback: keyOrCallback,
33
- options: callbackOrOptions
34
- }
35
- : {
36
- key: keyOrCallback,
37
- callback: callbackOrOptions,
38
- options: maybeOptions
39
- };
40
- if (typeof resolved.callback !== 'function') {
41
- throw new Error('useFrame requires a callback');
42
- }
43
- const callbackRef = useRef(resolved.callback);
44
- callbackRef.current = resolved.callback;
45
- const registrationConfigRef = useRef(null);
46
- if (!registrationConfigRef.current) {
47
- registrationConfigRef.current = {
48
- key: resolved.key,
49
- options: resolved.options
50
- };
51
- }
52
- const registrationConfig = registrationConfigRef.current;
53
- const registrationRef = useRef(null);
54
- const taskRef = useRef({
55
- key: registrationConfig.key !== undefined
56
- ? registrationConfig.key
57
- : Symbol('motiongpu-react-pending-task-key'),
58
- stage: PENDING_STAGE_KEY
59
- });
60
- const startedStoreRef = useRef(createCurrentWritable(false));
61
- const startedStore = startedStoreRef.current;
62
- useEffect(() => {
63
- const wrappedCallback = (state) => {
64
- callbackRef.current(state);
65
- };
66
- const registration = registrationConfig.key === undefined
67
- ? registry.register(wrappedCallback, registrationConfig.options)
68
- : registry.register(registrationConfig.key, wrappedCallback, registrationConfig.options);
69
- registrationRef.current = registration;
70
- taskRef.current = registration.task;
71
- const unsubscribeStarted = registration.started.subscribe((value) => {
72
- startedStore.set(value);
73
- });
74
- return () => {
75
- unsubscribeStarted();
76
- registration.unsubscribe();
77
- if (registrationRef.current === registration) {
78
- registrationRef.current = null;
79
- }
80
- startedStore.set(false);
81
- };
82
- }, [registrationConfig, registry, startedStore]);
83
- useEffect(() => {
84
- motiongpu.invalidate();
85
- }, [motiongpu, resolved.callback]);
86
- return {
87
- get task() {
88
- return taskRef.current;
89
- },
90
- start: () => {
91
- registrationRef.current?.start();
92
- },
93
- stop: () => {
94
- registrationRef.current?.stop();
95
- },
96
- started: startedStore
97
- };
14
+ * Registers a callback in the active frame registry and auto-unsubscribes on unmount.
15
+ *
16
+ * @param keyOrCallback - Task key or callback for auto-key registration.
17
+ * @param callbackOrOptions - Callback (keyed overload) or options (auto-key overload).
18
+ * @param maybeOptions - Optional registration options for keyed overload.
19
+ * Registration key/options are frozen on first render; subsequent renders do not re-register.
20
+ * @returns Registration control API with task, start/stop controls and started state.
21
+ * @throws {Error} When called outside `<FragCanvas>`.
22
+ * @throws {Error} When callback is missing in keyed overload.
23
+ */
24
+ function useFrame(keyOrCallback, callbackOrOptions, maybeOptions) {
25
+ const registry = useContext(FrameRegistryReactContext);
26
+ if (!registry) throw new Error("useFrame must be used inside <FragCanvas>");
27
+ const motiongpu = useMotionGPU();
28
+ const resolved = typeof keyOrCallback === "function" ? {
29
+ key: void 0,
30
+ callback: keyOrCallback,
31
+ options: callbackOrOptions
32
+ } : {
33
+ key: keyOrCallback,
34
+ callback: callbackOrOptions,
35
+ options: maybeOptions
36
+ };
37
+ if (typeof resolved.callback !== "function") throw new Error("useFrame requires a callback");
38
+ const callbackRef = useRef(resolved.callback);
39
+ callbackRef.current = resolved.callback;
40
+ const registrationConfigRef = useRef(null);
41
+ if (!registrationConfigRef.current) registrationConfigRef.current = {
42
+ key: resolved.key,
43
+ options: resolved.options
44
+ };
45
+ const registrationConfig = registrationConfigRef.current;
46
+ const registrationRef = useRef(null);
47
+ const taskRef = useRef({
48
+ key: registrationConfig.key !== void 0 ? registrationConfig.key : Symbol("motiongpu-react-pending-task-key"),
49
+ stage: PENDING_STAGE_KEY
50
+ });
51
+ const startedStore = useRef(createCurrentWritable(false)).current;
52
+ useEffect(() => {
53
+ const wrappedCallback = (state) => {
54
+ callbackRef.current(state);
55
+ };
56
+ const registration = registrationConfig.key === void 0 ? registry.register(wrappedCallback, registrationConfig.options) : registry.register(registrationConfig.key, wrappedCallback, registrationConfig.options);
57
+ registrationRef.current = registration;
58
+ taskRef.current = registration.task;
59
+ const unsubscribeStarted = registration.started.subscribe((value) => {
60
+ startedStore.set(value);
61
+ });
62
+ return () => {
63
+ unsubscribeStarted();
64
+ registration.unsubscribe();
65
+ if (registrationRef.current === registration) registrationRef.current = null;
66
+ startedStore.set(false);
67
+ };
68
+ }, [
69
+ registrationConfig,
70
+ registry,
71
+ startedStore
72
+ ]);
73
+ useEffect(() => {
74
+ motiongpu.invalidate();
75
+ }, [motiongpu, resolved.callback]);
76
+ return {
77
+ get task() {
78
+ return taskRef.current;
79
+ },
80
+ start: () => {
81
+ registrationRef.current?.start();
82
+ },
83
+ stop: () => {
84
+ registrationRef.current?.stop();
85
+ },
86
+ started: startedStore
87
+ };
98
88
  }
89
+ //#endregion
90
+ export { FrameRegistryReactContext, useFrame };
91
+
92
+ //# sourceMappingURL=frame-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-context.js","names":[],"sources":["../../src/lib/react/frame-context.ts"],"sourcesContent":["import { createContext, useContext, useEffect, useRef } from 'react';\nimport { createCurrentWritable } from '../core/current-value.js';\nimport { useMotionGPU } from './motiongpu-context.js';\nimport type {\n\tFrameCallback,\n\tFrameKey,\n\tFrameProfilingSnapshot,\n\tFrameRegistry,\n\tFrameRunTimings,\n\tFrameScheduleSnapshot,\n\tFrameStage,\n\tFrameStageCallback,\n\tFrameTask,\n\tFrameTaskInvalidation,\n\tFrameTaskInvalidationToken,\n\tUseFrameOptions,\n\tUseFrameResult\n} from '../core/frame-registry.js';\n\n/**\n * Placeholder stage used before a frame task registration becomes available.\n */\nconst PENDING_STAGE_KEY = Symbol('motiongpu-react-pending-stage');\n\n/**\n * React context container for the active frame registry.\n */\nexport const FrameRegistryReactContext = createContext<FrameRegistry | null>(null);\n\nexport type {\n\tFrameCallback,\n\tFrameKey,\n\tFrameProfilingSnapshot,\n\tFrameRegistry,\n\tFrameRunTimings,\n\tFrameScheduleSnapshot,\n\tFrameStage,\n\tFrameStageCallback,\n\tFrameTask,\n\tFrameTaskInvalidation,\n\tFrameTaskInvalidationToken,\n\tUseFrameOptions,\n\tUseFrameResult\n};\n\n/**\n * Registers a frame callback using an auto-generated task key.\n */\nexport function useFrame(callback: FrameCallback, options?: UseFrameOptions): UseFrameResult;\n\n/**\n * Registers a frame callback with an explicit task key.\n */\nexport function useFrame(\n\tkey: FrameKey,\n\tcallback: FrameCallback,\n\toptions?: UseFrameOptions\n): UseFrameResult;\n\n/**\n * Registers a callback in the active frame registry and auto-unsubscribes on unmount.\n *\n * @param keyOrCallback - Task key or callback for auto-key registration.\n * @param callbackOrOptions - Callback (keyed overload) or options (auto-key overload).\n * @param maybeOptions - Optional registration options for keyed overload.\n * Registration key/options are frozen on first render; subsequent renders do not re-register.\n * @returns Registration control API with task, start/stop controls and started state.\n * @throws {Error} When called outside `<FragCanvas>`.\n * @throws {Error} When callback is missing in keyed overload.\n */\nexport function useFrame(\n\tkeyOrCallback: FrameKey | FrameCallback,\n\tcallbackOrOptions?: FrameCallback | UseFrameOptions,\n\tmaybeOptions?: UseFrameOptions\n): UseFrameResult {\n\tconst registry = useContext(FrameRegistryReactContext);\n\tif (!registry) {\n\t\tthrow new Error('useFrame must be used inside <FragCanvas>');\n\t}\n\tconst motiongpu = useMotionGPU();\n\n\tconst resolved =\n\t\ttypeof keyOrCallback === 'function'\n\t\t\t? {\n\t\t\t\t\tkey: undefined,\n\t\t\t\t\tcallback: keyOrCallback,\n\t\t\t\t\toptions: callbackOrOptions as UseFrameOptions | undefined\n\t\t\t\t}\n\t\t\t: {\n\t\t\t\t\tkey: keyOrCallback,\n\t\t\t\t\tcallback: callbackOrOptions as FrameCallback,\n\t\t\t\t\toptions: maybeOptions\n\t\t\t\t};\n\tif (typeof resolved.callback !== 'function') {\n\t\tthrow new Error('useFrame requires a callback');\n\t}\n\n\tconst callbackRef = useRef(resolved.callback);\n\tcallbackRef.current = resolved.callback;\n\tconst registrationConfigRef = useRef<{\n\t\tkey: FrameKey | undefined;\n\t\toptions: UseFrameOptions | undefined;\n\t} | null>(null);\n\tif (!registrationConfigRef.current) {\n\t\tregistrationConfigRef.current = {\n\t\t\tkey: resolved.key,\n\t\t\toptions: resolved.options\n\t\t};\n\t}\n\tconst registrationConfig = registrationConfigRef.current;\n\n\tconst registrationRef = useRef<{\n\t\ttask: FrameTask;\n\t\tstart: () => void;\n\t\tstop: () => void;\n\t\tstarted: UseFrameResult['started'];\n\t\tunsubscribe: () => void;\n\t} | null>(null);\n\tconst taskRef = useRef<FrameTask>({\n\t\tkey:\n\t\t\tregistrationConfig.key !== undefined\n\t\t\t\t? registrationConfig.key\n\t\t\t\t: Symbol('motiongpu-react-pending-task-key'),\n\t\tstage: PENDING_STAGE_KEY\n\t});\n\tconst startedStoreRef = useRef(createCurrentWritable(false));\n\tconst startedStore = startedStoreRef.current;\n\n\tuseEffect(() => {\n\t\tconst wrappedCallback: FrameCallback = (state) => {\n\t\t\tcallbackRef.current(state);\n\t\t};\n\t\tconst registration =\n\t\t\tregistrationConfig.key === undefined\n\t\t\t\t? registry.register(wrappedCallback, registrationConfig.options)\n\t\t\t\t: registry.register(registrationConfig.key, wrappedCallback, registrationConfig.options);\n\t\tregistrationRef.current = registration;\n\t\ttaskRef.current = registration.task;\n\t\tconst unsubscribeStarted = registration.started.subscribe((value) => {\n\t\t\tstartedStore.set(value);\n\t\t});\n\n\t\treturn () => {\n\t\t\tunsubscribeStarted();\n\t\t\tregistration.unsubscribe();\n\t\t\tif (registrationRef.current === registration) {\n\t\t\t\tregistrationRef.current = null;\n\t\t\t}\n\t\t\tstartedStore.set(false);\n\t\t};\n\t}, [registrationConfig, registry, startedStore]);\n\n\tuseEffect(() => {\n\t\tmotiongpu.invalidate();\n\t}, [motiongpu, resolved.callback]);\n\n\treturn {\n\t\tget task() {\n\t\t\treturn taskRef.current;\n\t\t},\n\t\tstart: () => {\n\t\t\tregistrationRef.current?.start();\n\t\t},\n\t\tstop: () => {\n\t\t\tregistrationRef.current?.stop();\n\t\t},\n\t\tstarted: startedStore\n\t};\n}\n"],"mappings":";;;;;;;AAsBA,IAAM,oBAAoB,OAAO,gCAAgC;;;;AAKjE,IAAa,4BAA4B,cAAoC,KAAK;;;;;;;;;;;;AA2ClF,SAAgB,SACf,eACA,mBACA,cACiB;CACjB,MAAM,WAAW,WAAW,0BAA0B;AACtD,KAAI,CAAC,SACJ,OAAM,IAAI,MAAM,4CAA4C;CAE7D,MAAM,YAAY,cAAc;CAEhC,MAAM,WACL,OAAO,kBAAkB,aACtB;EACA,KAAK;EACL,UAAU;EACV,SAAS;EACT,GACA;EACA,KAAK;EACL,UAAU;EACV,SAAS;EACT;AACJ,KAAI,OAAO,SAAS,aAAa,WAChC,OAAM,IAAI,MAAM,+BAA+B;CAGhD,MAAM,cAAc,OAAO,SAAS,SAAS;AAC7C,aAAY,UAAU,SAAS;CAC/B,MAAM,wBAAwB,OAGpB,KAAK;AACf,KAAI,CAAC,sBAAsB,QAC1B,uBAAsB,UAAU;EAC/B,KAAK,SAAS;EACd,SAAS,SAAS;EAClB;CAEF,MAAM,qBAAqB,sBAAsB;CAEjD,MAAM,kBAAkB,OAMd,KAAK;CACf,MAAM,UAAU,OAAkB;EACjC,KACC,mBAAmB,QAAQ,SACxB,mBAAmB,MACnB,OAAO,mCAAmC;EAC9C,OAAO;EACP,CAAC;CAEF,MAAM,eADkB,OAAO,sBAAsB,MAAM,CAAC,CACvB;AAErC,iBAAgB;EACf,MAAM,mBAAkC,UAAU;AACjD,eAAY,QAAQ,MAAM;;EAE3B,MAAM,eACL,mBAAmB,QAAQ,SACxB,SAAS,SAAS,iBAAiB,mBAAmB,QAAQ,GAC9D,SAAS,SAAS,mBAAmB,KAAK,iBAAiB,mBAAmB,QAAQ;AAC1F,kBAAgB,UAAU;AAC1B,UAAQ,UAAU,aAAa;EAC/B,MAAM,qBAAqB,aAAa,QAAQ,WAAW,UAAU;AACpE,gBAAa,IAAI,MAAM;IACtB;AAEF,eAAa;AACZ,uBAAoB;AACpB,gBAAa,aAAa;AAC1B,OAAI,gBAAgB,YAAY,aAC/B,iBAAgB,UAAU;AAE3B,gBAAa,IAAI,MAAM;;IAEtB;EAAC;EAAoB;EAAU;EAAa,CAAC;AAEhD,iBAAgB;AACf,YAAU,YAAY;IACpB,CAAC,WAAW,SAAS,SAAS,CAAC;AAElC,QAAO;EACN,IAAI,OAAO;AACV,UAAO,QAAQ;;EAEhB,aAAa;AACZ,mBAAgB,SAAS,OAAO;;EAEjC,YAAY;AACX,mBAAgB,SAAS,MAAM;;EAEhC,SAAS;EACT"}