@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
@@ -0,0 +1,512 @@
1
+ <script lang="ts">
2
+ import type { MotionGPUErrorReport } from '../core/error-report';
3
+ import Portal from './Portal.svelte';
4
+
5
+ interface Props {
6
+ report: MotionGPUErrorReport;
7
+ }
8
+
9
+ let { report }: Props = $props();
10
+
11
+ const normalizeErrorText = (value: string): string => {
12
+ return value
13
+ .trim()
14
+ .replace(/[.:!]+$/g, '')
15
+ .toLowerCase();
16
+ };
17
+
18
+ const shouldShowErrorMessage = (value: MotionGPUErrorReport): boolean => {
19
+ return resolveDisplayMessage(value).length > 0;
20
+ };
21
+
22
+ const resolveDisplayMessage = (value: MotionGPUErrorReport): string => {
23
+ const rawMessage = value.message.trim();
24
+ if (rawMessage.length === 0) {
25
+ return '';
26
+ }
27
+
28
+ const normalizedMessage = normalizeErrorText(rawMessage);
29
+ const normalizedTitle = normalizeErrorText(value.title);
30
+ if (normalizedMessage === normalizedTitle) {
31
+ return '';
32
+ }
33
+
34
+ const escapedTitle = value.title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
35
+ const prefixPattern = new RegExp(`^${escapedTitle}\\s*[:\\-|]\\s*`, 'i');
36
+ const stripped = rawMessage.replace(prefixPattern, '').trim();
37
+ return stripped.length > 0 ? stripped : rawMessage;
38
+ };
39
+
40
+ const formatRuntimeContext = (context: MotionGPUErrorReport['context']): string => {
41
+ if (!context) {
42
+ return '';
43
+ }
44
+
45
+ const indentBlock = (value: string, spaces = 2): string => {
46
+ const prefix = ' '.repeat(spaces);
47
+ return value
48
+ .split('\n')
49
+ .map((line) => `${prefix}${line}`)
50
+ .join('\n');
51
+ };
52
+
53
+ const formatMaterialSignature = (value: string): string => {
54
+ const trimmed = value.trim();
55
+ if (trimmed.length === 0) {
56
+ return '<empty>';
57
+ }
58
+ try {
59
+ return JSON.stringify(JSON.parse(trimmed), null, 2);
60
+ } catch {
61
+ return trimmed;
62
+ }
63
+ };
64
+
65
+ const lines: string[] = [];
66
+ if (context.materialSignature) {
67
+ lines.push('materialSignature:');
68
+ lines.push(indentBlock(formatMaterialSignature(context.materialSignature)));
69
+ }
70
+ if (context.passGraph) {
71
+ lines.push('passGraph:');
72
+ lines.push(` passCount: ${context.passGraph.passCount}`);
73
+ lines.push(` enabledPassCount: ${context.passGraph.enabledPassCount}`);
74
+ lines.push(' inputs:');
75
+ if (context.passGraph.inputs.length === 0) {
76
+ lines.push(' - <none>');
77
+ } else {
78
+ for (const input of context.passGraph.inputs) {
79
+ lines.push(` - ${input}`);
80
+ }
81
+ }
82
+ lines.push(' outputs:');
83
+ if (context.passGraph.outputs.length === 0) {
84
+ lines.push(' - <none>');
85
+ } else {
86
+ for (const output of context.passGraph.outputs) {
87
+ lines.push(` - ${output}`);
88
+ }
89
+ }
90
+ }
91
+ lines.push('activeRenderTargets:');
92
+ if (context.activeRenderTargets.length === 0) {
93
+ lines.push(' - <none>');
94
+ } else {
95
+ for (const target of context.activeRenderTargets) {
96
+ lines.push(` - ${target}`);
97
+ }
98
+ }
99
+ return lines.join('\n');
100
+ };
101
+ </script>
102
+
103
+ <Portal>
104
+ <div class="motiongpu-error-overlay" role="presentation">
105
+ <section
106
+ class="motiongpu-error-dialog"
107
+ role="alertdialog"
108
+ aria-live="assertive"
109
+ aria-modal="true"
110
+ data-testid="motiongpu-error"
111
+ >
112
+ <header class="motiongpu-error-header">
113
+ <div class="motiongpu-error-header-top">
114
+ <div class="motiongpu-error-badges">
115
+ <div class="motiongpu-error-badge-wrap">
116
+ <p class="motiongpu-error-badge motiongpu-error-badge-phase">
117
+ {report.phase}
118
+ </p>
119
+ </div>
120
+ <div class="motiongpu-error-badge-wrap">
121
+ <p class="motiongpu-error-badge motiongpu-error-badge-severity">
122
+ {report.severity}
123
+ </p>
124
+ </div>
125
+ </div>
126
+ </div>
127
+ <h2 class="motiongpu-error-title">{report.title}</h2>
128
+ <p class="motiongpu-error-recoverable">
129
+ Recoverable: <span>{report.recoverable ? 'yes' : 'no'}</span>
130
+ </p>
131
+ </header>
132
+ <div class="motiongpu-error-body">
133
+ {#if shouldShowErrorMessage(report)}
134
+ <p class="motiongpu-error-message">{resolveDisplayMessage(report)}</p>
135
+ {/if}
136
+ <p class="motiongpu-error-hint">{report.hint}</p>
137
+ </div>
138
+
139
+ {#if report.source}
140
+ <section class="motiongpu-error-source" aria-label="Source">
141
+ <h3 class="motiongpu-error-source-title">Source</h3>
142
+ <div class="motiongpu-error-source-frame" role="presentation">
143
+ <div class="motiongpu-error-source-tabs" role="tablist" aria-label="Source files">
144
+ <span
145
+ class="motiongpu-error-source-tab motiongpu-error-source-tab-active"
146
+ role="tab"
147
+ aria-selected="true"
148
+ >{report.source.location}{#if report.source.column}, col {report.source
149
+ .column}{/if}</span
150
+ >
151
+ <span class="motiongpu-error-source-tab-spacer" aria-hidden="true"></span>
152
+ </div>
153
+
154
+ <div class="motiongpu-error-source-snippet">
155
+ {#each report.source.snippet as snippetLine (`snippet-${snippetLine.number}`)}
156
+ <div
157
+ class="motiongpu-error-source-row"
158
+ class:motiongpu-error-source-row-active={snippetLine.highlight}
159
+ >
160
+ <span class="motiongpu-error-source-line">{snippetLine.number}</span>
161
+ <span class="motiongpu-error-source-code">{snippetLine.code || ' '}</span>
162
+ </div>
163
+ {/each}
164
+ </div>
165
+ </div>
166
+ </section>
167
+ {/if}
168
+
169
+ <div class="motiongpu-error-sections">
170
+ {#if report.details.length > 0}
171
+ <details class="motiongpu-error-details" open>
172
+ <summary>{report.source ? 'Additional diagnostics' : 'Technical details'}</summary>
173
+ <pre>{report.details.join('\n')}</pre>
174
+ </details>
175
+ {/if}
176
+ {#if report.stack.length > 0}
177
+ <details class="motiongpu-error-details">
178
+ <summary>Stack trace</summary>
179
+ <pre>{report.stack.join('\n')}</pre>
180
+ </details>
181
+ {/if}
182
+ {#if report.context}
183
+ <details class="motiongpu-error-details">
184
+ <summary>Runtime context</summary>
185
+ <pre>{formatRuntimeContext(report.context)}</pre>
186
+ </details>
187
+ {/if}
188
+ </div>
189
+ </section>
190
+ </div>
191
+ </Portal>
192
+
193
+ <style>
194
+ .motiongpu-error-overlay {
195
+ --motiongpu-base-hue: var(--base-hue, 265);
196
+ --motiongpu-color-background: oklch(0.2178 0.0056 var(--motiongpu-base-hue));
197
+ --motiongpu-color-background-muted: oklch(0.261 0.007 var(--motiongpu-base-hue));
198
+ --motiongpu-color-foreground: oklch(1 0 0);
199
+ --motiongpu-color-foreground-muted: oklch(0.6699 0.0081 var(--motiongpu-base-hue));
200
+ --motiongpu-color-card: var(--motiongpu-color-background);
201
+ --motiongpu-color-accent: oklch(0.6996 0.181959 44.4414);
202
+ --motiongpu-color-accent-secondary: oklch(0.5096 0.131959 44.4414);
203
+ --motiongpu-color-border: oklch(0.928 0.013 var(--motiongpu-base-hue) / 0.05);
204
+ --motiongpu-color-white-fixed: oklch(1 0 0);
205
+ --motiongpu-shadow-card: var(
206
+ --shadow-2xl,
207
+ 0px 1px 1px -0.5px rgba(0, 0, 0, 0.06),
208
+ 0px 3px 3px -1.5px rgba(0, 0, 0, 0.06),
209
+ 0px 6px 6px -3px rgba(0, 0, 0, 0.06),
210
+ 0px 12px 12px -6px rgba(0, 0, 0, 0.06),
211
+ 0px 24px 24px -12px rgba(0, 0, 0, 0.05),
212
+ 0px 48px 48px -24px rgba(0, 0, 0, 0.06)
213
+ );
214
+ --motiongpu-radius-md: var(--radius-md, 0.5rem);
215
+ --motiongpu-radius-lg: var(--radius-lg, 0.75rem);
216
+ --motiongpu-radius-xl: var(--radius-xl, 1rem);
217
+ --motiongpu-font-sans: var(
218
+ --font-sans,
219
+ 'Inter',
220
+ 'Segoe UI',
221
+ 'Helvetica Neue',
222
+ Arial,
223
+ sans-serif
224
+ );
225
+ --motiongpu-font-mono: var(--font-mono, 'SFMono-Regular', 'Menlo', 'Consolas', monospace);
226
+ position: fixed;
227
+ inset: 0;
228
+ display: grid;
229
+ place-items: center;
230
+ padding: clamp(0.75rem, 1.4vw, 1.5rem);
231
+ background: rgba(0, 0, 0, 0.8);
232
+ backdrop-filter: blur(10px);
233
+ z-index: 2147483647;
234
+ font-family: var(--motiongpu-font-sans);
235
+ color-scheme: dark;
236
+ }
237
+
238
+ .motiongpu-error-dialog {
239
+ width: min(52rem, calc(100vw - 1.5rem));
240
+ max-height: min(84vh, 44rem);
241
+ overflow: auto;
242
+ margin: 0;
243
+ padding: 1.1rem;
244
+ border: 1px solid var(--motiongpu-color-border);
245
+ border-radius: var(--motiongpu-radius-xl);
246
+ max-width: calc(100vw - 1.5rem);
247
+ box-sizing: border-box;
248
+ font-size: 0.875rem;
249
+ font-weight: 400;
250
+ line-height: 1.45;
251
+ background: var(--motiongpu-color-card);
252
+ color: var(--motiongpu-color-foreground);
253
+ box-shadow: var(--motiongpu-shadow-card);
254
+ }
255
+
256
+ .motiongpu-error-header {
257
+ display: grid;
258
+ gap: 0.55rem;
259
+ padding-bottom: 0.9rem;
260
+ border-bottom: 1px solid var(--motiongpu-color-border);
261
+ }
262
+
263
+ .motiongpu-error-header-top {
264
+ display: flex;
265
+ align-items: flex-start;
266
+ gap: 0.75rem;
267
+ }
268
+
269
+ .motiongpu-error-badges {
270
+ display: inline-flex;
271
+ align-items: center;
272
+ gap: 0.4rem;
273
+ flex-wrap: wrap;
274
+ }
275
+
276
+ .motiongpu-error-badge-wrap {
277
+ display: inline-flex;
278
+ align-items: center;
279
+ gap: 0.4rem;
280
+ width: fit-content;
281
+ padding: 0.18rem;
282
+ border-radius: 999px;
283
+ border: 1px solid var(--motiongpu-color-border);
284
+ background: var(--motiongpu-color-background-muted);
285
+ }
286
+
287
+ .motiongpu-error-badge {
288
+ display: inline-flex;
289
+ align-items: center;
290
+ margin: 0;
291
+ padding: 0.22rem 0.56rem;
292
+ border-radius: 999px;
293
+ font-size: 0.66rem;
294
+ letter-spacing: 0.08em;
295
+ line-height: 1;
296
+ font-weight: 500;
297
+ text-transform: uppercase;
298
+ color: var(--motiongpu-color-white-fixed);
299
+ background: linear-gradient(
300
+ 180deg,
301
+ var(--motiongpu-color-accent) 0%,
302
+ var(--motiongpu-color-accent-secondary) 100%
303
+ );
304
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.24);
305
+ }
306
+
307
+ .motiongpu-error-recoverable {
308
+ margin: 0;
309
+ font-size: 0.67rem;
310
+ line-height: 1.2;
311
+ letter-spacing: 0.06em;
312
+ text-transform: uppercase;
313
+ color: var(--motiongpu-color-foreground-muted);
314
+ }
315
+
316
+ .motiongpu-error-recoverable span {
317
+ font-family: var(--motiongpu-font-mono);
318
+ color: var(--motiongpu-color-foreground);
319
+ }
320
+
321
+ .motiongpu-error-title {
322
+ margin: 0;
323
+ font-size: clamp(1.02rem, 1vw + 0.72rem, 1.32rem);
324
+ font-weight: 500;
325
+ line-height: 1.18;
326
+ letter-spacing: -0.02em;
327
+ text-wrap: balance;
328
+ color: var(--motiongpu-color-foreground);
329
+ }
330
+
331
+ .motiongpu-error-body {
332
+ display: grid;
333
+ gap: 0.62rem;
334
+ margin-top: 0.92rem;
335
+ }
336
+
337
+ .motiongpu-error-message {
338
+ margin: 0;
339
+ padding: 0.72rem 0.78rem;
340
+ border: 1px solid color-mix(in oklch, var(--motiongpu-color-accent) 28%, transparent);
341
+ border-radius: var(--motiongpu-radius-md);
342
+ background: color-mix(in oklch, var(--motiongpu-color-accent) 10%, transparent);
343
+ font-size: 0.82rem;
344
+ line-height: 1.4;
345
+ font-weight: 400;
346
+ color: var(--motiongpu-color-foreground);
347
+ }
348
+
349
+ .motiongpu-error-hint {
350
+ margin: 0;
351
+ font-size: 0.82rem;
352
+ line-height: 1.45;
353
+ font-weight: 400;
354
+ color: var(--motiongpu-color-foreground-muted);
355
+ }
356
+
357
+ .motiongpu-error-sections {
358
+ display: grid;
359
+ gap: 0.62rem;
360
+ margin-top: 0.95rem;
361
+ }
362
+
363
+ .motiongpu-error-source {
364
+ display: grid;
365
+ gap: 0.48rem;
366
+ margin-top: 0.96rem;
367
+ }
368
+
369
+ .motiongpu-error-source-title {
370
+ margin: 0;
371
+ font-size: 0.8rem;
372
+ font-weight: 500;
373
+ line-height: 1.3;
374
+ letter-spacing: 0.045em;
375
+ text-transform: uppercase;
376
+ color: var(--motiongpu-color-foreground);
377
+ }
378
+
379
+ .motiongpu-error-source-frame {
380
+ border: 1px solid var(--motiongpu-color-border);
381
+ border-radius: var(--motiongpu-radius-lg);
382
+ overflow: hidden;
383
+ background: var(--motiongpu-color-background-muted);
384
+ }
385
+
386
+ .motiongpu-error-source-tabs {
387
+ display: flex;
388
+ align-items: stretch;
389
+ border-bottom: 1px solid var(--motiongpu-color-border);
390
+ background: var(--motiongpu-color-background);
391
+ }
392
+
393
+ .motiongpu-error-source-tab {
394
+ display: inline-flex;
395
+ align-items: center;
396
+ padding: 0.5rem 0.68rem;
397
+ font-size: 0.76rem;
398
+ font-weight: 400;
399
+ line-height: 1.2;
400
+ color: var(--motiongpu-color-foreground-muted);
401
+ border-right: 1px solid var(--motiongpu-color-border);
402
+ }
403
+
404
+ .motiongpu-error-source-tab-active {
405
+ color: var(--motiongpu-color-foreground);
406
+ background: var(--motiongpu-color-background-muted);
407
+ }
408
+
409
+ .motiongpu-error-source-tab-spacer {
410
+ flex: 1 1 auto;
411
+ }
412
+
413
+ .motiongpu-error-source-snippet {
414
+ display: grid;
415
+ background: var(--motiongpu-color-background-muted);
416
+ }
417
+
418
+ .motiongpu-error-source-row {
419
+ display: grid;
420
+ grid-template-columns: 2rem minmax(0, 1fr);
421
+ align-items: start;
422
+ gap: 0.42rem;
423
+ padding: 0.2rem 0.68rem;
424
+ }
425
+
426
+ .motiongpu-error-source-row-active {
427
+ background: color-mix(in oklch, var(--motiongpu-color-accent) 10%, transparent);
428
+ }
429
+
430
+ .motiongpu-error-source-line {
431
+ font-family: var(--motiongpu-font-mono);
432
+ font-size: 0.77rem;
433
+ font-weight: 400;
434
+ line-height: 1.3;
435
+ font-variant-numeric: tabular-nums;
436
+ font-feature-settings: 'tnum' 1;
437
+ border-right: 1px solid var(--motiongpu-color-border);
438
+ color: var(--motiongpu-color-foreground-muted);
439
+ text-align: left;
440
+ }
441
+
442
+ .motiongpu-error-source-code {
443
+ font-family: var(--motiongpu-font-mono);
444
+ font-size: 0.77rem;
445
+ font-weight: 400;
446
+ line-height: 1.3;
447
+ color: var(--motiongpu-color-foreground);
448
+ white-space: pre-wrap;
449
+ word-break: break-word;
450
+ }
451
+
452
+ .motiongpu-error-details {
453
+ border: 1px solid var(--motiongpu-color-border);
454
+ border-radius: var(--motiongpu-radius-lg);
455
+ overflow: hidden;
456
+ background: var(--motiongpu-color-background);
457
+ }
458
+
459
+ .motiongpu-error-details summary {
460
+ cursor: pointer;
461
+ padding: 0.56rem 0.68rem;
462
+ font-size: 0.7rem;
463
+ letter-spacing: 0.07em;
464
+ line-height: 1.2;
465
+ font-weight: 500;
466
+ text-transform: uppercase;
467
+ color: var(--motiongpu-color-foreground);
468
+ }
469
+
470
+ .motiongpu-error-details[open] summary {
471
+ border-bottom: 1px solid var(--motiongpu-color-border);
472
+ }
473
+
474
+ .motiongpu-error-details pre {
475
+ margin: 0;
476
+ padding: 0.62rem 0.68rem;
477
+ white-space: pre-wrap;
478
+ word-break: break-word;
479
+ overflow: auto;
480
+ background: var(--motiongpu-color-background-muted);
481
+ font-size: 0.74rem;
482
+ line-height: 1.4;
483
+ font-weight: 400;
484
+ color: var(--motiongpu-color-foreground);
485
+ font-family: var(--motiongpu-font-mono);
486
+ }
487
+
488
+ @media (max-width: 42rem) {
489
+ .motiongpu-error-overlay {
490
+ padding: 0.62rem;
491
+ }
492
+
493
+ .motiongpu-error-dialog {
494
+ padding: 0.85rem;
495
+ }
496
+
497
+ .motiongpu-error-title {
498
+ font-size: 1.02rem;
499
+ }
500
+
501
+ .motiongpu-error-header-top {
502
+ flex-direction: column;
503
+ align-items: flex-start;
504
+ }
505
+ }
506
+
507
+ @media (prefers-reduced-motion: reduce) {
508
+ .motiongpu-error-overlay {
509
+ backdrop-filter: none;
510
+ }
511
+ }
512
+ </style>
@@ -0,0 +1,31 @@
1
+ <script lang="ts">
2
+ import type { Snippet } from 'svelte';
3
+
4
+ interface Props {
5
+ target?: string | HTMLElement | null;
6
+ children?: Snippet;
7
+ }
8
+
9
+ let { target = 'body', children }: Props = $props();
10
+
11
+ function resolveTargetElement(input: string | HTMLElement | null | undefined): HTMLElement {
12
+ return typeof input === 'string'
13
+ ? (document.querySelector<HTMLElement>(input) ?? document.body)
14
+ : (input ?? document.body);
15
+ }
16
+
17
+ const portal = (node: HTMLDivElement) => {
18
+ const targetElement = resolveTargetElement(target);
19
+ targetElement.appendChild(node);
20
+
21
+ return () => {
22
+ if (node.parentNode === targetElement) {
23
+ targetElement.removeChild(node);
24
+ }
25
+ };
26
+ };
27
+ </script>
28
+
29
+ <div {@attach portal}>
30
+ {@render children?.()}
31
+ </div>
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Svelte adapter advanced entrypoint for MotionGPU.
3
+ */
4
+ export * from './index.js';
5
+ export { applySchedulerPreset, captureSchedulerDebugSnapshot } from '../core/scheduler-helpers.js';
6
+ export { setMotionGPUUserContext, useMotionGPUUserContext } from './use-motiongpu-user-context.js';
7
+ export type {
8
+ ApplySchedulerPresetOptions,
9
+ SchedulerDebugSnapshot,
10
+ SchedulerPreset,
11
+ SchedulerPresetConfig
12
+ } from '../core/scheduler-helpers.js';
13
+ export type { MotionGPUUserContext, MotionGPUUserNamespace } from './motiongpu-context.js';
14
+ export type {
15
+ FrameProfilingSnapshot,
16
+ FrameKey,
17
+ FrameTaskInvalidation,
18
+ FrameTaskInvalidationToken,
19
+ FrameRunTimings,
20
+ FrameScheduleSnapshot,
21
+ FrameStage,
22
+ FrameStageCallback,
23
+ FrameTimingStats,
24
+ FrameTask
25
+ } from '../core/frame-registry.js';
26
+ export type { SetMotionGPUUserContextOptions } from './use-motiongpu-user-context.js';
27
+ export type {
28
+ RenderPassContext,
29
+ RenderTarget,
30
+ UniformLayout,
31
+ UniformLayoutEntry
32
+ } from '../core/types.js';
@@ -0,0 +1,87 @@
1
+ import { getContext, onDestroy, setContext } from 'svelte';
2
+ import {
3
+ createFrameRegistry,
4
+ type FrameCallback,
5
+ type FrameKey,
6
+ type FrameProfilingSnapshot,
7
+ type FrameRegistry,
8
+ type FrameRunTimings,
9
+ type FrameScheduleSnapshot,
10
+ type FrameStage,
11
+ type FrameStageCallback,
12
+ type FrameTask,
13
+ type FrameTaskInvalidation,
14
+ type FrameTaskInvalidationToken,
15
+ type UseFrameOptions,
16
+ type UseFrameResult
17
+ } from '../core/frame-registry.js';
18
+
19
+ /**
20
+ * Svelte context key for the active frame registry.
21
+ */
22
+ const FRAME_CONTEXT_KEY = Symbol('motiongpu.frame-context');
23
+
24
+ export {
25
+ createFrameRegistry,
26
+ type FrameCallback,
27
+ type FrameKey,
28
+ type FrameProfilingSnapshot,
29
+ type FrameRegistry,
30
+ type FrameRunTimings,
31
+ type FrameScheduleSnapshot,
32
+ type FrameStage,
33
+ type FrameStageCallback,
34
+ type FrameTask,
35
+ type FrameTaskInvalidation,
36
+ type FrameTaskInvalidationToken,
37
+ type UseFrameOptions,
38
+ type UseFrameResult
39
+ };
40
+
41
+ /**
42
+ * Provides a frame registry through Svelte context.
43
+ */
44
+ export function provideFrameRegistry(registry: FrameRegistry): void {
45
+ setContext(FRAME_CONTEXT_KEY, registry);
46
+ }
47
+
48
+ /**
49
+ * Registers a frame callback using an auto-generated task key.
50
+ */
51
+ export function useFrame(callback: FrameCallback, options?: UseFrameOptions): UseFrameResult;
52
+
53
+ /**
54
+ * Registers a frame callback with an explicit task key.
55
+ */
56
+ export function useFrame(
57
+ key: FrameKey,
58
+ callback: FrameCallback,
59
+ options?: UseFrameOptions
60
+ ): UseFrameResult;
61
+
62
+ /**
63
+ * Registers a callback in the active frame registry and auto-unsubscribes on destroy.
64
+ */
65
+ export function useFrame(
66
+ keyOrCallback: FrameKey | FrameCallback,
67
+ callbackOrOptions?: FrameCallback | UseFrameOptions,
68
+ maybeOptions?: UseFrameOptions
69
+ ): UseFrameResult {
70
+ const registry = getContext<FrameRegistry>(FRAME_CONTEXT_KEY);
71
+ if (!registry) {
72
+ throw new Error('useFrame must be used inside <FragCanvas>');
73
+ }
74
+
75
+ const registration =
76
+ typeof keyOrCallback === 'function'
77
+ ? registry.register(keyOrCallback, callbackOrOptions as UseFrameOptions | undefined)
78
+ : registry.register(keyOrCallback, callbackOrOptions as FrameCallback, maybeOptions);
79
+ onDestroy(registration.unsubscribe);
80
+
81
+ return {
82
+ task: registration.task,
83
+ start: registration.start,
84
+ stop: registration.stop,
85
+ started: registration.started
86
+ };
87
+ }