@motion-core/motion-gpu 0.4.0 → 0.4.2

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 (207) hide show
  1. package/dist/advanced.d.ts +1 -0
  2. package/dist/advanced.d.ts.map +1 -0
  3. package/dist/advanced.js +12 -6
  4. package/dist/core/advanced.d.ts +1 -0
  5. package/dist/core/advanced.d.ts.map +1 -0
  6. package/dist/core/advanced.js +12 -5
  7. package/dist/core/current-value.d.ts +1 -0
  8. package/dist/core/current-value.d.ts.map +1 -0
  9. package/dist/core/current-value.js +35 -34
  10. package/dist/core/current-value.js.map +1 -0
  11. package/dist/core/error-diagnostics.d.ts +1 -0
  12. package/dist/core/error-diagnostics.d.ts.map +1 -0
  13. package/dist/core/error-diagnostics.js +70 -137
  14. package/dist/core/error-diagnostics.js.map +1 -0
  15. package/dist/core/error-report.d.ts +1 -0
  16. package/dist/core/error-report.d.ts.map +1 -0
  17. package/dist/core/error-report.js +184 -233
  18. package/dist/core/error-report.js.map +1 -0
  19. package/dist/core/frame-registry.d.ts +1 -0
  20. package/dist/core/frame-registry.d.ts.map +1 -0
  21. package/dist/core/frame-registry.js +546 -662
  22. package/dist/core/frame-registry.js.map +1 -0
  23. package/dist/core/index.d.ts +1 -0
  24. package/dist/core/index.d.ts.map +1 -0
  25. package/dist/core/index.js +11 -12
  26. package/dist/core/material-preprocess.d.ts +1 -0
  27. package/dist/core/material-preprocess.d.ts.map +1 -0
  28. package/dist/core/material-preprocess.js +128 -151
  29. package/dist/core/material-preprocess.js.map +1 -0
  30. package/dist/core/material.d.ts +1 -0
  31. package/dist/core/material.d.ts.map +1 -0
  32. package/dist/core/material.js +263 -317
  33. package/dist/core/material.js.map +1 -0
  34. package/dist/core/recompile-policy.d.ts +1 -0
  35. package/dist/core/recompile-policy.d.ts.map +1 -0
  36. package/dist/core/recompile-policy.js +18 -13
  37. package/dist/core/recompile-policy.js.map +1 -0
  38. package/dist/core/render-graph.d.ts +1 -0
  39. package/dist/core/render-graph.d.ts.map +1 -0
  40. package/dist/core/render-graph.js +61 -68
  41. package/dist/core/render-graph.js.map +1 -0
  42. package/dist/core/render-targets.d.ts +2 -0
  43. package/dist/core/render-targets.d.ts.map +1 -0
  44. package/dist/core/render-targets.js +52 -53
  45. package/dist/core/render-targets.js.map +1 -0
  46. package/dist/core/renderer.d.ts +1 -0
  47. package/dist/core/renderer.d.ts.map +1 -0
  48. package/dist/core/renderer.js +942 -1081
  49. package/dist/core/renderer.js.map +1 -0
  50. package/dist/core/runtime-loop.d.ts +2 -0
  51. package/dist/core/runtime-loop.d.ts.map +1 -0
  52. package/dist/core/runtime-loop.js +305 -362
  53. package/dist/core/runtime-loop.js.map +1 -0
  54. package/dist/core/scheduler-helpers.d.ts +1 -0
  55. package/dist/core/scheduler-helpers.d.ts.map +1 -0
  56. package/dist/core/scheduler-helpers.js +52 -51
  57. package/dist/core/scheduler-helpers.js.map +1 -0
  58. package/dist/core/shader.d.ts +1 -0
  59. package/dist/core/shader.d.ts.map +1 -0
  60. package/dist/core/shader.js +92 -117
  61. package/dist/core/shader.js.map +1 -0
  62. package/dist/core/texture-loader.d.ts +1 -0
  63. package/dist/core/texture-loader.d.ts.map +1 -0
  64. package/dist/core/texture-loader.js +205 -273
  65. package/dist/core/texture-loader.js.map +1 -0
  66. package/dist/core/textures.d.ts +2 -0
  67. package/dist/core/textures.d.ts.map +1 -0
  68. package/dist/core/textures.js +106 -116
  69. package/dist/core/textures.js.map +1 -0
  70. package/dist/core/types.d.ts +2 -0
  71. package/dist/core/types.d.ts.map +1 -0
  72. package/dist/core/types.js +0 -4
  73. package/dist/core/uniforms.d.ts +1 -0
  74. package/dist/core/uniforms.d.ts.map +1 -0
  75. package/dist/core/uniforms.js +170 -191
  76. package/dist/core/uniforms.js.map +1 -0
  77. package/dist/index.d.ts +1 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +11 -6
  80. package/dist/passes/BlitPass.d.ts +1 -0
  81. package/dist/passes/BlitPass.d.ts.map +1 -0
  82. package/dist/passes/BlitPass.js +23 -18
  83. package/dist/passes/BlitPass.js.map +1 -0
  84. package/dist/passes/CopyPass.d.ts +2 -0
  85. package/dist/passes/CopyPass.d.ts.map +1 -0
  86. package/dist/passes/CopyPass.js +58 -52
  87. package/dist/passes/CopyPass.js.map +1 -0
  88. package/dist/passes/FullscreenPass.d.ts +2 -0
  89. package/dist/passes/FullscreenPass.d.ts.map +1 -0
  90. package/dist/passes/FullscreenPass.js +127 -130
  91. package/dist/passes/FullscreenPass.js.map +1 -0
  92. package/dist/passes/ShaderPass.d.ts +1 -0
  93. package/dist/passes/ShaderPass.d.ts.map +1 -0
  94. package/dist/passes/ShaderPass.js +40 -37
  95. package/dist/passes/ShaderPass.js.map +1 -0
  96. package/dist/passes/index.d.ts +1 -0
  97. package/dist/passes/index.d.ts.map +1 -0
  98. package/dist/passes/index.js +4 -3
  99. package/dist/react/FragCanvas.d.ts +2 -0
  100. package/dist/react/FragCanvas.d.ts.map +1 -0
  101. package/dist/react/FragCanvas.js +234 -211
  102. package/dist/react/FragCanvas.js.map +1 -0
  103. package/dist/react/MotionGPUErrorOverlay.d.ts +1 -0
  104. package/dist/react/MotionGPUErrorOverlay.d.ts.map +1 -0
  105. package/dist/react/MotionGPUErrorOverlay.js +384 -48
  106. package/dist/react/MotionGPUErrorOverlay.js.map +1 -0
  107. package/dist/react/Portal.d.ts +1 -0
  108. package/dist/react/Portal.d.ts.map +1 -0
  109. package/dist/react/Portal.js +18 -21
  110. package/dist/react/Portal.js.map +1 -0
  111. package/dist/react/advanced.d.ts +1 -0
  112. package/dist/react/advanced.d.ts.map +1 -0
  113. package/dist/react/advanced.js +12 -6
  114. package/dist/react/frame-context.d.ts +1 -0
  115. package/dist/react/frame-context.d.ts.map +1 -0
  116. package/dist/react/frame-context.js +88 -94
  117. package/dist/react/frame-context.js.map +1 -0
  118. package/dist/react/index.d.ts +1 -0
  119. package/dist/react/index.d.ts.map +1 -0
  120. package/dist/react/index.js +10 -9
  121. package/dist/react/motiongpu-context.d.ts +1 -0
  122. package/dist/react/motiongpu-context.d.ts.map +1 -0
  123. package/dist/react/motiongpu-context.js +18 -15
  124. package/dist/react/motiongpu-context.js.map +1 -0
  125. package/dist/react/use-motiongpu-user-context.d.ts +1 -0
  126. package/dist/react/use-motiongpu-user-context.d.ts.map +1 -0
  127. package/dist/react/use-motiongpu-user-context.js +83 -82
  128. package/dist/react/use-motiongpu-user-context.js.map +1 -0
  129. package/dist/react/use-texture.d.ts +1 -0
  130. package/dist/react/use-texture.d.ts.map +1 -0
  131. package/dist/react/use-texture.js +132 -152
  132. package/dist/react/use-texture.js.map +1 -0
  133. package/dist/svelte/FragCanvas.svelte.d.ts +2 -0
  134. package/dist/svelte/FragCanvas.svelte.d.ts.map +1 -0
  135. package/dist/svelte/MotionGPUErrorOverlay.svelte +17 -20
  136. package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts +1 -0
  137. package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts.map +1 -0
  138. package/dist/svelte/Portal.svelte.d.ts +1 -0
  139. package/dist/svelte/Portal.svelte.d.ts.map +1 -0
  140. package/dist/svelte/advanced.d.ts +1 -0
  141. package/dist/svelte/advanced.d.ts.map +1 -0
  142. package/dist/svelte/advanced.js +11 -6
  143. package/dist/svelte/frame-context.d.ts +1 -0
  144. package/dist/svelte/frame-context.d.ts.map +1 -0
  145. package/dist/svelte/frame-context.js +27 -27
  146. package/dist/svelte/frame-context.js.map +1 -0
  147. package/dist/svelte/index.d.ts +1 -0
  148. package/dist/svelte/index.d.ts.map +1 -0
  149. package/dist/svelte/index.js +10 -9
  150. package/dist/svelte/motiongpu-context.d.ts +1 -0
  151. package/dist/svelte/motiongpu-context.d.ts.map +1 -0
  152. package/dist/svelte/motiongpu-context.js +24 -21
  153. package/dist/svelte/motiongpu-context.js.map +1 -0
  154. package/dist/svelte/use-motiongpu-user-context.d.ts +1 -0
  155. package/dist/svelte/use-motiongpu-user-context.d.ts.map +1 -0
  156. package/dist/svelte/use-motiongpu-user-context.js +69 -70
  157. package/dist/svelte/use-motiongpu-user-context.js.map +1 -0
  158. package/dist/svelte/use-texture.d.ts +1 -0
  159. package/dist/svelte/use-texture.d.ts.map +1 -0
  160. package/dist/svelte/use-texture.js +125 -147
  161. package/dist/svelte/use-texture.js.map +1 -0
  162. package/package.json +15 -7
  163. package/src/lib/advanced.ts +6 -0
  164. package/src/lib/core/advanced.ts +12 -0
  165. package/src/lib/core/current-value.ts +64 -0
  166. package/src/lib/core/error-diagnostics.ts +236 -0
  167. package/src/lib/core/error-report.ts +406 -0
  168. package/src/lib/core/frame-registry.ts +1189 -0
  169. package/src/lib/core/index.ts +77 -0
  170. package/src/lib/core/material-preprocess.ts +284 -0
  171. package/src/lib/core/material.ts +667 -0
  172. package/src/lib/core/recompile-policy.ts +31 -0
  173. package/src/lib/core/render-graph.ts +143 -0
  174. package/src/lib/core/render-targets.ts +107 -0
  175. package/src/lib/core/renderer.ts +1547 -0
  176. package/src/lib/core/runtime-loop.ts +458 -0
  177. package/src/lib/core/scheduler-helpers.ts +136 -0
  178. package/src/lib/core/shader.ts +258 -0
  179. package/src/lib/core/texture-loader.ts +476 -0
  180. package/src/lib/core/textures.ts +235 -0
  181. package/src/lib/core/types.ts +582 -0
  182. package/src/lib/core/uniforms.ts +282 -0
  183. package/src/lib/index.ts +6 -0
  184. package/src/lib/passes/BlitPass.ts +54 -0
  185. package/src/lib/passes/CopyPass.ts +80 -0
  186. package/src/lib/passes/FullscreenPass.ts +173 -0
  187. package/src/lib/passes/ShaderPass.ts +88 -0
  188. package/src/lib/passes/index.ts +3 -0
  189. package/src/lib/react/MotionGPUErrorOverlay.tsx +392 -0
  190. package/src/lib/react/advanced.ts +36 -0
  191. package/src/lib/react/frame-context.ts +169 -0
  192. package/src/lib/react/index.ts +51 -0
  193. package/src/lib/react/motiongpu-context.ts +88 -0
  194. package/src/lib/react/use-motiongpu-user-context.ts +186 -0
  195. package/src/lib/react/use-texture.ts +233 -0
  196. package/src/lib/svelte/FragCanvas.svelte +249 -0
  197. package/src/lib/svelte/MotionGPUErrorOverlay.svelte +382 -0
  198. package/src/lib/svelte/Portal.svelte +31 -0
  199. package/src/lib/svelte/advanced.ts +32 -0
  200. package/src/lib/svelte/frame-context.ts +87 -0
  201. package/src/lib/svelte/index.ts +51 -0
  202. package/src/lib/svelte/motiongpu-context.ts +97 -0
  203. package/src/lib/svelte/use-motiongpu-user-context.ts +145 -0
  204. package/src/lib/svelte/use-texture.ts +232 -0
  205. package/dist/react/MotionGPUErrorOverlay.tsx +0 -129
  206. /package/{dist → src/lib}/react/FragCanvas.tsx +0 -0
  207. /package/{dist → src/lib}/react/Portal.tsx +0 -0
@@ -0,0 +1,249 @@
1
+ <script lang="ts">
2
+ import { onMount } from 'svelte';
3
+ import type { Snippet } from 'svelte';
4
+ import type { FragMaterial } from '../core/material';
5
+ import { createCurrentWritable as currentWritable } from '../core/current-value';
6
+ import { toMotionGPUErrorReport, type MotionGPUErrorReport } from '../core/error-report';
7
+ import MotionGPUErrorOverlay from './MotionGPUErrorOverlay.svelte';
8
+ import { createMotionGPURuntimeLoop } from '../core/runtime-loop';
9
+ import type {
10
+ FrameInvalidationToken,
11
+ OutputColorSpace,
12
+ RenderPass,
13
+ RenderMode,
14
+ RenderTargetDefinitionMap
15
+ } from '../core/types';
16
+ import { provideMotionGPUContext } from './motiongpu-context';
17
+ import { createFrameRegistry, provideFrameRegistry } from './frame-context';
18
+
19
+ interface Props {
20
+ material: FragMaterial;
21
+ renderTargets?: RenderTargetDefinitionMap;
22
+ passes?: RenderPass[];
23
+ clearColor?: [number, number, number, number];
24
+ outputColorSpace?: OutputColorSpace;
25
+ renderMode?: RenderMode;
26
+ autoRender?: boolean;
27
+ maxDelta?: number;
28
+ adapterOptions?: GPURequestAdapterOptions;
29
+ deviceDescriptor?: GPUDeviceDescriptor;
30
+ dpr?: number;
31
+ showErrorOverlay?: boolean;
32
+ errorRenderer?: Snippet<[MotionGPUErrorReport]>;
33
+ onError?: (report: MotionGPUErrorReport) => void;
34
+ errorHistoryLimit?: number;
35
+ onErrorHistory?: (history: MotionGPUErrorReport[]) => void;
36
+ class?: string;
37
+ style?: string;
38
+ children?: Snippet;
39
+ }
40
+
41
+ const initialDpr = typeof window === 'undefined' ? 1 : (window.devicePixelRatio ?? 1);
42
+
43
+ let {
44
+ material,
45
+ renderTargets = {},
46
+ passes = [],
47
+ clearColor = [0, 0, 0, 1],
48
+ outputColorSpace = 'srgb',
49
+ renderMode = 'always',
50
+ autoRender = true,
51
+ maxDelta = 0.1,
52
+ adapterOptions = undefined,
53
+ deviceDescriptor = undefined,
54
+ dpr = initialDpr,
55
+ showErrorOverlay = true,
56
+ errorRenderer = undefined,
57
+ onError = undefined,
58
+ errorHistoryLimit = 0,
59
+ onErrorHistory = undefined,
60
+ class: className = '',
61
+ style = '',
62
+ children
63
+ }: Props = $props();
64
+
65
+ let canvas: HTMLCanvasElement | undefined;
66
+ let errorReport = $state<MotionGPUErrorReport | null>(null);
67
+ let errorHistory = $state<MotionGPUErrorReport[]>([]);
68
+
69
+ let normalizedErrorHistoryLimit = $derived.by(() => {
70
+ if (!Number.isFinite(errorHistoryLimit) || errorHistoryLimit <= 0) {
71
+ return 0;
72
+ }
73
+ return Math.floor(errorHistoryLimit);
74
+ });
75
+
76
+ const bindCanvas = (node: HTMLCanvasElement) => {
77
+ canvas = node;
78
+ return () => {
79
+ if (canvas === node) {
80
+ canvas = undefined;
81
+ }
82
+ };
83
+ };
84
+
85
+ const registry = createFrameRegistry({ maxDelta: 0.1 });
86
+ provideFrameRegistry(registry);
87
+ let requestFrameSignal: (() => void) | null = null;
88
+ const requestFrame = (): void => {
89
+ requestFrameSignal?.();
90
+ };
91
+ const invalidateFrame = (token?: FrameInvalidationToken): void => {
92
+ registry.invalidate(token);
93
+ requestFrame();
94
+ };
95
+ const advanceFrame = (): void => {
96
+ registry.advance();
97
+ requestFrame();
98
+ };
99
+ const size = currentWritable({ width: 0, height: 0 });
100
+ const dprState = currentWritable(initialDpr, requestFrame);
101
+ const maxDeltaState = currentWritable<number>(0.1, (value) => {
102
+ registry.setMaxDelta(value);
103
+ requestFrame();
104
+ });
105
+ const renderModeState = currentWritable<RenderMode>('always', (value) => {
106
+ registry.setRenderMode(value);
107
+ requestFrame();
108
+ });
109
+ const autoRenderState = currentWritable<boolean>(true, (value) => {
110
+ registry.setAutoRender(value);
111
+ requestFrame();
112
+ });
113
+ const userState = currentWritable<Record<string | symbol, unknown>>({});
114
+
115
+ provideMotionGPUContext({
116
+ get canvas() {
117
+ return canvas;
118
+ },
119
+ size,
120
+ dpr: dprState,
121
+ maxDelta: maxDeltaState,
122
+ renderMode: renderModeState,
123
+ autoRender: autoRenderState,
124
+ user: userState,
125
+ invalidate: () => invalidateFrame(),
126
+ advance: advanceFrame,
127
+ scheduler: {
128
+ createStage: registry.createStage,
129
+ getStage: registry.getStage,
130
+ setDiagnosticsEnabled: registry.setDiagnosticsEnabled,
131
+ getDiagnosticsEnabled: registry.getDiagnosticsEnabled,
132
+ getLastRunTimings: registry.getLastRunTimings,
133
+ getSchedule: registry.getSchedule,
134
+ setProfilingEnabled: registry.setProfilingEnabled,
135
+ setProfilingWindow: registry.setProfilingWindow,
136
+ resetProfiling: registry.resetProfiling,
137
+ getProfilingEnabled: registry.getProfilingEnabled,
138
+ getProfilingWindow: registry.getProfilingWindow,
139
+ getProfilingSnapshot: registry.getProfilingSnapshot
140
+ }
141
+ });
142
+
143
+ $effect(() => {
144
+ renderModeState.set(renderMode);
145
+ autoRenderState.set(autoRender);
146
+ maxDeltaState.set(maxDelta);
147
+ dprState.set(dpr);
148
+ requestFrame();
149
+ });
150
+
151
+ $effect(() => {
152
+ const limit = normalizedErrorHistoryLimit;
153
+ if (limit <= 0) {
154
+ if (errorHistory.length === 0) {
155
+ return;
156
+ }
157
+ errorHistory = [];
158
+ onErrorHistory?.([]);
159
+ return;
160
+ }
161
+
162
+ if (errorHistory.length <= limit) {
163
+ return;
164
+ }
165
+
166
+ const trimmed = errorHistory.slice(errorHistory.length - limit);
167
+ errorHistory = trimmed;
168
+ onErrorHistory?.(trimmed);
169
+ });
170
+
171
+ onMount(() => {
172
+ if (!canvas) {
173
+ const report = toMotionGPUErrorReport(
174
+ new Error('Canvas element is not available'),
175
+ 'initialization'
176
+ );
177
+ errorReport = report;
178
+ const historyLimit = normalizedErrorHistoryLimit;
179
+ if (historyLimit > 0) {
180
+ const nextHistory = [report].slice(-historyLimit);
181
+ errorHistory = nextHistory;
182
+ onErrorHistory?.(nextHistory);
183
+ }
184
+ onError?.(report);
185
+ return () => registry.clear();
186
+ }
187
+
188
+ const runtimeLoop = createMotionGPURuntimeLoop({
189
+ canvas,
190
+ registry,
191
+ size,
192
+ dpr: dprState,
193
+ maxDelta: maxDeltaState,
194
+ getMaterial: () => material,
195
+ getRenderTargets: () => renderTargets,
196
+ getPasses: () => passes,
197
+ getClearColor: () => clearColor,
198
+ getOutputColorSpace: () => outputColorSpace,
199
+ getAdapterOptions: () => adapterOptions,
200
+ getDeviceDescriptor: () => deviceDescriptor,
201
+ getOnError: () => onError,
202
+ getErrorHistoryLimit: () => errorHistoryLimit,
203
+ getOnErrorHistory: () => onErrorHistory,
204
+ reportErrorHistory: (history) => {
205
+ errorHistory = history;
206
+ },
207
+ reportError: (report) => {
208
+ errorReport = report;
209
+ }
210
+ });
211
+ requestFrameSignal = runtimeLoop.requestFrame;
212
+
213
+ return () => {
214
+ requestFrameSignal = null;
215
+ runtimeLoop.destroy();
216
+ };
217
+ });
218
+ </script>
219
+
220
+ <div class="motiongpu-canvas-wrap">
221
+ <canvas {@attach bindCanvas} class={className} {style}></canvas>
222
+ {#if showErrorOverlay && errorReport}
223
+ {#if errorRenderer}
224
+ {@render errorRenderer(errorReport)}
225
+ {:else}
226
+ <MotionGPUErrorOverlay report={errorReport} />
227
+ {/if}
228
+ {/if}
229
+ {@render children?.()}
230
+ </div>
231
+
232
+ <style>
233
+ .motiongpu-canvas-wrap {
234
+ position: relative;
235
+ width: 100%;
236
+ height: 100%;
237
+ min-width: 0;
238
+ min-height: 0;
239
+ overflow: hidden;
240
+ }
241
+
242
+ canvas {
243
+ position: absolute;
244
+ inset: 0;
245
+ display: block;
246
+ width: 100%;
247
+ height: 100%;
248
+ }
249
+ </style>
@@ -0,0 +1,382 @@
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 normalizeErrorText(value.message) !== normalizeErrorText(value.title);
20
+ };
21
+ </script>
22
+
23
+ <Portal>
24
+ <div class="motiongpu-error-overlay" role="presentation">
25
+ <section
26
+ class="motiongpu-error-dialog"
27
+ role="alertdialog"
28
+ aria-live="assertive"
29
+ aria-modal="true"
30
+ data-testid="motiongpu-error"
31
+ >
32
+ <header class="motiongpu-error-header">
33
+ <div class="motiongpu-error-badge-wrap">
34
+ <p class="motiongpu-error-phase">
35
+ {report.phase}
36
+ </p>
37
+ </div>
38
+ <h2 class="motiongpu-error-title">{report.title}</h2>
39
+ </header>
40
+ <div class="motiongpu-error-body">
41
+ {#if shouldShowErrorMessage(report)}
42
+ <p class="motiongpu-error-message">{report.message}</p>
43
+ {/if}
44
+ <p class="motiongpu-error-hint">{report.hint}</p>
45
+ </div>
46
+
47
+ {#if report.source}
48
+ <section class="motiongpu-error-source" aria-label="Source">
49
+ <h3 class="motiongpu-error-source-title">Source</h3>
50
+ <div class="motiongpu-error-source-frame" role="presentation">
51
+ <div class="motiongpu-error-source-tabs" role="tablist" aria-label="Source files">
52
+ <span
53
+ class="motiongpu-error-source-tab motiongpu-error-source-tab-active"
54
+ role="tab"
55
+ aria-selected="true"
56
+ >{report.source.location}{#if report.source.column}, col {report.source
57
+ .column}{/if}</span
58
+ >
59
+ <span class="motiongpu-error-source-tab-spacer" aria-hidden="true"></span>
60
+ </div>
61
+
62
+ <div class="motiongpu-error-source-snippet">
63
+ {#each report.source.snippet as snippetLine (`snippet-${snippetLine.number}`)}
64
+ <div
65
+ class="motiongpu-error-source-row"
66
+ class:motiongpu-error-source-row-active={snippetLine.highlight}
67
+ >
68
+ <span class="motiongpu-error-source-line">{snippetLine.number}</span>
69
+ <span class="motiongpu-error-source-code">{snippetLine.code || ' '}</span>
70
+ </div>
71
+ {/each}
72
+ </div>
73
+ </div>
74
+ </section>
75
+ {/if}
76
+
77
+ <div class="motiongpu-error-sections">
78
+ {#if report.details.length > 0}
79
+ <details class="motiongpu-error-details" open>
80
+ <summary>{report.source ? 'Additional diagnostics' : 'Technical details'}</summary>
81
+ <pre>{report.details.join('\n')}</pre>
82
+ </details>
83
+ {/if}
84
+ {#if report.stack.length > 0}
85
+ <details class="motiongpu-error-details">
86
+ <summary>Stack trace</summary>
87
+ <pre>{report.stack.join('\n')}</pre>
88
+ </details>
89
+ {/if}
90
+ </div>
91
+ </section>
92
+ </div>
93
+ </Portal>
94
+
95
+ <style>
96
+ .motiongpu-error-overlay {
97
+ --motiongpu-base-hue: var(--base-hue, 265);
98
+ --motiongpu-color-background: oklch(0.2178 0.0056 var(--motiongpu-base-hue));
99
+ --motiongpu-color-background-muted: oklch(0.261 0.007 var(--motiongpu-base-hue));
100
+ --motiongpu-color-foreground: oklch(1 0 0);
101
+ --motiongpu-color-foreground-muted: oklch(0.6699 0.0081 var(--motiongpu-base-hue));
102
+ --motiongpu-color-card: var(--motiongpu-color-background);
103
+ --motiongpu-color-accent: oklch(0.6996 0.181959 44.4414);
104
+ --motiongpu-color-accent-secondary: oklch(0.5096 0.131959 44.4414);
105
+ --motiongpu-color-border: oklch(0.928 0.013 var(--motiongpu-base-hue) / 0.05);
106
+ --motiongpu-color-white-fixed: oklch(1 0 0);
107
+ --motiongpu-shadow-card: var(
108
+ --shadow-2xl,
109
+ 0px 1px 1px -0.5px rgba(0, 0, 0, 0.06),
110
+ 0px 3px 3px -1.5px rgba(0, 0, 0, 0.06),
111
+ 0px 6px 6px -3px rgba(0, 0, 0, 0.06),
112
+ 0px 12px 12px -6px rgba(0, 0, 0, 0.06),
113
+ 0px 24px 24px -12px rgba(0, 0, 0, 0.05),
114
+ 0px 48px 48px -24px rgba(0, 0, 0, 0.06)
115
+ );
116
+ --motiongpu-radius-md: var(--radius-md, 0.5rem);
117
+ --motiongpu-radius-lg: var(--radius-lg, 0.75rem);
118
+ --motiongpu-radius-xl: var(--radius-xl, 1rem);
119
+ --motiongpu-font-sans: var(
120
+ --font-sans,
121
+ 'Inter',
122
+ 'Segoe UI',
123
+ 'Helvetica Neue',
124
+ Arial,
125
+ sans-serif
126
+ );
127
+ --motiongpu-font-mono: var(--font-mono, 'SFMono-Regular', 'Menlo', 'Consolas', monospace);
128
+ position: fixed;
129
+ inset: 0;
130
+ display: grid;
131
+ place-items: center;
132
+ padding: clamp(0.75rem, 1.4vw, 1.5rem);
133
+ background: rgba(0, 0, 0, 0.8);
134
+ backdrop-filter: blur(10px);
135
+ z-index: 2147483647;
136
+ font-family: var(--motiongpu-font-sans);
137
+ color-scheme: dark;
138
+ }
139
+
140
+ .motiongpu-error-dialog {
141
+ width: min(52rem, calc(100vw - 1.5rem));
142
+ max-height: min(84vh, 44rem);
143
+ overflow: auto;
144
+ margin: 0;
145
+ padding: 1.1rem;
146
+ border: 1px solid var(--motiongpu-color-border);
147
+ border-radius: var(--motiongpu-radius-xl);
148
+ max-width: calc(100vw - 1.5rem);
149
+ box-sizing: border-box;
150
+ font-size: 0.875rem;
151
+ font-weight: 400;
152
+ line-height: 1.45;
153
+ background: var(--motiongpu-color-card);
154
+ color: var(--motiongpu-color-foreground);
155
+ box-shadow: var(--motiongpu-shadow-card);
156
+ }
157
+
158
+ .motiongpu-error-header {
159
+ display: grid;
160
+ gap: 0.55rem;
161
+ padding-bottom: 0.9rem;
162
+ border-bottom: 1px solid var(--motiongpu-color-border);
163
+ }
164
+
165
+ .motiongpu-error-badge-wrap {
166
+ display: inline-flex;
167
+ align-items: center;
168
+ gap: 0.4rem;
169
+ width: fit-content;
170
+ padding: 0.18rem;
171
+ border-radius: 999px;
172
+ border: 1px solid var(--motiongpu-color-border);
173
+ background: var(--motiongpu-color-background-muted);
174
+ }
175
+
176
+ .motiongpu-error-phase {
177
+ display: inline-flex;
178
+ align-items: center;
179
+ margin: 0;
180
+ padding: 0.22rem 0.56rem;
181
+ border-radius: 999px;
182
+ font-size: 0.66rem;
183
+ letter-spacing: 0.08em;
184
+ line-height: 1;
185
+ font-weight: 500;
186
+ text-transform: uppercase;
187
+ color: var(--motiongpu-color-white-fixed);
188
+ background: linear-gradient(
189
+ 180deg,
190
+ var(--motiongpu-color-accent) 0%,
191
+ var(--motiongpu-color-accent-secondary) 100%
192
+ );
193
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.24);
194
+ }
195
+
196
+ .motiongpu-error-title {
197
+ margin: 0;
198
+ font-size: clamp(1.02rem, 1vw + 0.72rem, 1.32rem);
199
+ font-weight: 500;
200
+ line-height: 1.18;
201
+ letter-spacing: -0.02em;
202
+ text-wrap: balance;
203
+ color: var(--motiongpu-color-foreground);
204
+ }
205
+
206
+ .motiongpu-error-body {
207
+ display: grid;
208
+ gap: 0.62rem;
209
+ margin-top: 0.92rem;
210
+ }
211
+
212
+ .motiongpu-error-message {
213
+ margin: 0;
214
+ padding: 0.72rem 0.78rem;
215
+ border: 1px solid color-mix(in oklch, var(--motiongpu-color-accent) 28%, transparent);
216
+ border-radius: var(--motiongpu-radius-md);
217
+ background: color-mix(in oklch, var(--motiongpu-color-accent) 10%, transparent);
218
+ font-size: 0.82rem;
219
+ line-height: 1.4;
220
+ font-weight: 400;
221
+ color: var(--motiongpu-color-foreground);
222
+ }
223
+
224
+ .motiongpu-error-hint {
225
+ margin: 0;
226
+ font-size: 0.82rem;
227
+ line-height: 1.45;
228
+ font-weight: 400;
229
+ color: var(--motiongpu-color-foreground-muted);
230
+ }
231
+
232
+ .motiongpu-error-sections {
233
+ display: grid;
234
+ gap: 0.62rem;
235
+ margin-top: 0.95rem;
236
+ }
237
+
238
+ .motiongpu-error-source {
239
+ display: grid;
240
+ gap: 0.48rem;
241
+ margin-top: 0.96rem;
242
+ }
243
+
244
+ .motiongpu-error-source-title {
245
+ margin: 0;
246
+ font-size: 0.8rem;
247
+ font-weight: 500;
248
+ line-height: 1.3;
249
+ letter-spacing: 0.045em;
250
+ text-transform: uppercase;
251
+ color: var(--motiongpu-color-foreground);
252
+ }
253
+
254
+ .motiongpu-error-source-frame {
255
+ border: 1px solid var(--motiongpu-color-border);
256
+ border-radius: var(--motiongpu-radius-lg);
257
+ overflow: hidden;
258
+ background: var(--motiongpu-color-background-muted);
259
+ }
260
+
261
+ .motiongpu-error-source-tabs {
262
+ display: flex;
263
+ align-items: stretch;
264
+ border-bottom: 1px solid var(--motiongpu-color-border);
265
+ background: var(--motiongpu-color-background);
266
+ }
267
+
268
+ .motiongpu-error-source-tab {
269
+ display: inline-flex;
270
+ align-items: center;
271
+ padding: 0.5rem 0.68rem;
272
+ font-size: 0.76rem;
273
+ font-weight: 400;
274
+ line-height: 1.2;
275
+ color: var(--motiongpu-color-foreground-muted);
276
+ border-right: 1px solid var(--motiongpu-color-border);
277
+ }
278
+
279
+ .motiongpu-error-source-tab-active {
280
+ color: var(--motiongpu-color-foreground);
281
+ background: var(--motiongpu-color-background-muted);
282
+ }
283
+
284
+ .motiongpu-error-source-tab-spacer {
285
+ flex: 1 1 auto;
286
+ }
287
+
288
+ .motiongpu-error-source-snippet {
289
+ display: grid;
290
+ background: var(--motiongpu-color-background-muted);
291
+ }
292
+
293
+ .motiongpu-error-source-row {
294
+ display: grid;
295
+ grid-template-columns: 2rem minmax(0, 1fr);
296
+ align-items: start;
297
+ gap: 0.42rem;
298
+ padding: 0.2rem 0.68rem;
299
+ }
300
+
301
+ .motiongpu-error-source-row-active {
302
+ background: color-mix(in oklch, var(--motiongpu-color-accent) 10%, transparent);
303
+ }
304
+
305
+ .motiongpu-error-source-line {
306
+ font-family: var(--motiongpu-font-mono);
307
+ font-size: 0.77rem;
308
+ font-weight: 400;
309
+ line-height: 1.3;
310
+ font-variant-numeric: tabular-nums;
311
+ font-feature-settings: 'tnum' 1;
312
+ border-right: 1px solid var(--motiongpu-color-border);
313
+ color: var(--motiongpu-color-foreground-muted);
314
+ text-align: left;
315
+ }
316
+
317
+ .motiongpu-error-source-code {
318
+ font-family: var(--motiongpu-font-mono);
319
+ font-size: 0.77rem;
320
+ font-weight: 400;
321
+ line-height: 1.3;
322
+ color: var(--motiongpu-color-foreground);
323
+ white-space: pre-wrap;
324
+ word-break: break-word;
325
+ }
326
+
327
+ .motiongpu-error-details {
328
+ border: 1px solid var(--motiongpu-color-border);
329
+ border-radius: var(--motiongpu-radius-lg);
330
+ overflow: hidden;
331
+ background: var(--motiongpu-color-background);
332
+ }
333
+
334
+ .motiongpu-error-details summary {
335
+ cursor: pointer;
336
+ padding: 0.56rem 0.68rem;
337
+ font-size: 0.7rem;
338
+ letter-spacing: 0.07em;
339
+ line-height: 1.2;
340
+ font-weight: 500;
341
+ text-transform: uppercase;
342
+ color: var(--motiongpu-color-foreground);
343
+ }
344
+
345
+ .motiongpu-error-details[open] summary {
346
+ border-bottom: 1px solid var(--motiongpu-color-border);
347
+ }
348
+
349
+ .motiongpu-error-details pre {
350
+ margin: 0;
351
+ padding: 0.62rem 0.68rem;
352
+ white-space: pre-wrap;
353
+ word-break: break-word;
354
+ overflow: auto;
355
+ background: var(--motiongpu-color-background-muted);
356
+ font-size: 0.74rem;
357
+ line-height: 1.4;
358
+ font-weight: 400;
359
+ color: var(--motiongpu-color-foreground);
360
+ font-family: var(--motiongpu-font-mono);
361
+ }
362
+
363
+ @media (max-width: 42rem) {
364
+ .motiongpu-error-overlay {
365
+ padding: 0.62rem;
366
+ }
367
+
368
+ .motiongpu-error-dialog {
369
+ padding: 0.85rem;
370
+ }
371
+
372
+ .motiongpu-error-title {
373
+ font-size: 1.02rem;
374
+ }
375
+ }
376
+
377
+ @media (prefers-reduced-motion: reduce) {
378
+ .motiongpu-error-overlay {
379
+ backdrop-filter: none;
380
+ }
381
+ }
382
+ </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';