@motion-core/motion-gpu 0.1.0 → 0.3.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 (70) hide show
  1. package/README.md +37 -11
  2. package/dist/advanced.d.ts +3 -11
  3. package/dist/advanced.js +3 -6
  4. package/dist/core/advanced.d.ts +6 -0
  5. package/dist/core/advanced.js +5 -0
  6. package/dist/core/current-value.d.ts +23 -0
  7. package/dist/core/current-value.js +36 -0
  8. package/dist/core/error-diagnostics.d.ts +15 -1
  9. package/dist/core/error-diagnostics.js +41 -1
  10. package/dist/core/error-report.d.ts +37 -0
  11. package/dist/core/error-report.js +62 -3
  12. package/dist/{frame-context.d.ts → core/frame-registry.d.ts} +3 -17
  13. package/dist/{frame-context.js → core/frame-registry.js} +2 -37
  14. package/dist/core/index.d.ts +19 -0
  15. package/dist/core/index.js +12 -0
  16. package/dist/core/material-preprocess.d.ts +1 -1
  17. package/dist/core/material-preprocess.js +1 -1
  18. package/dist/core/material.d.ts +4 -4
  19. package/dist/core/material.js +3 -3
  20. package/dist/core/recompile-policy.d.ts +1 -1
  21. package/dist/core/render-graph.d.ts +1 -1
  22. package/dist/core/render-targets.d.ts +1 -1
  23. package/dist/core/render-targets.js +1 -1
  24. package/dist/core/renderer.d.ts +11 -1
  25. package/dist/core/renderer.js +72 -10
  26. package/dist/core/runtime-loop.d.ts +34 -0
  27. package/dist/core/runtime-loop.js +365 -0
  28. package/dist/{advanced-scheduler.d.ts → core/scheduler-helpers.d.ts} +6 -2
  29. package/dist/core/shader.d.ts +2 -2
  30. package/dist/core/shader.js +1 -1
  31. package/dist/core/texture-loader.d.ts +1 -1
  32. package/dist/core/textures.d.ts +1 -1
  33. package/dist/core/textures.js +1 -1
  34. package/dist/core/types.d.ts +4 -0
  35. package/dist/core/uniforms.d.ts +1 -1
  36. package/dist/index.d.ts +3 -14
  37. package/dist/index.js +3 -8
  38. package/dist/passes/BlitPass.d.ts +6 -27
  39. package/dist/passes/BlitPass.js +10 -121
  40. package/dist/passes/CopyPass.d.ts +1 -1
  41. package/dist/passes/CopyPass.js +1 -1
  42. package/dist/passes/FullscreenPass.d.ts +37 -0
  43. package/dist/passes/FullscreenPass.js +131 -0
  44. package/dist/passes/ShaderPass.d.ts +6 -26
  45. package/dist/passes/ShaderPass.js +10 -121
  46. package/dist/passes/index.d.ts +3 -3
  47. package/dist/passes/index.js +3 -3
  48. package/dist/svelte/FragCanvas.svelte +263 -0
  49. package/dist/{FragCanvas.svelte.d.ts → svelte/FragCanvas.svelte.d.ts} +5 -3
  50. package/dist/{MotionGPUErrorOverlay.svelte → svelte/MotionGPUErrorOverlay.svelte} +11 -20
  51. package/dist/{MotionGPUErrorOverlay.svelte.d.ts → svelte/MotionGPUErrorOverlay.svelte.d.ts} +1 -1
  52. package/dist/svelte/advanced.d.ts +11 -0
  53. package/dist/svelte/advanced.js +6 -0
  54. package/dist/svelte/frame-context.d.ts +14 -0
  55. package/dist/svelte/frame-context.js +32 -0
  56. package/dist/svelte/index.d.ts +15 -0
  57. package/dist/svelte/index.js +9 -0
  58. package/dist/{motiongpu-context.d.ts → svelte/motiongpu-context.d.ts} +5 -7
  59. package/dist/{use-motiongpu-user-context.d.ts → svelte/use-motiongpu-user-context.d.ts} +2 -2
  60. package/dist/{use-motiongpu-user-context.js → svelte/use-motiongpu-user-context.js} +1 -1
  61. package/dist/{use-texture.d.ts → svelte/use-texture.d.ts} +7 -2
  62. package/dist/{use-texture.js → svelte/use-texture.js} +9 -3
  63. package/package.json +25 -5
  64. package/dist/FragCanvas.svelte +0 -511
  65. package/dist/current-writable.d.ts +0 -31
  66. package/dist/current-writable.js +0 -27
  67. /package/dist/{advanced-scheduler.js → core/scheduler-helpers.js} +0 -0
  68. /package/dist/{Portal.svelte → svelte/Portal.svelte} +0 -0
  69. /package/dist/{Portal.svelte.d.ts → svelte/Portal.svelte.d.ts} +0 -0
  70. /package/dist/{motiongpu-context.js → svelte/motiongpu-context.js} +0 -0
@@ -0,0 +1,263 @@
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
+ const getNormalizedErrorHistoryLimit = (): number => {
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
+ destroy: () => {
80
+ if (canvas === node) {
81
+ canvas = undefined;
82
+ }
83
+ }
84
+ };
85
+ };
86
+
87
+ const registry = createFrameRegistry({ maxDelta: 0.1 });
88
+ provideFrameRegistry(registry);
89
+ let requestFrameSignal: (() => void) | null = null;
90
+ const requestFrame = (): void => {
91
+ requestFrameSignal?.();
92
+ };
93
+ const invalidateFrame = (token?: FrameInvalidationToken): void => {
94
+ registry.invalidate(token);
95
+ requestFrame();
96
+ };
97
+ const advanceFrame = (): void => {
98
+ registry.advance();
99
+ requestFrame();
100
+ };
101
+ const size = currentWritable({ width: 0, height: 0 });
102
+ const dprState = currentWritable(initialDpr, requestFrame);
103
+ const maxDeltaState = currentWritable<number>(0.1, (value) => {
104
+ registry.setMaxDelta(value);
105
+ requestFrame();
106
+ });
107
+ const renderModeState = currentWritable<RenderMode>('always', (value) => {
108
+ registry.setRenderMode(value);
109
+ requestFrame();
110
+ });
111
+ const autoRenderState = currentWritable<boolean>(true, (value) => {
112
+ registry.setAutoRender(value);
113
+ requestFrame();
114
+ });
115
+ const userState = currentWritable<Record<string | symbol, unknown>>({});
116
+
117
+ provideMotionGPUContext({
118
+ get canvas() {
119
+ return canvas;
120
+ },
121
+ size,
122
+ dpr: dprState,
123
+ maxDelta: maxDeltaState,
124
+ renderMode: renderModeState,
125
+ autoRender: autoRenderState,
126
+ user: userState,
127
+ invalidate: () => invalidateFrame(),
128
+ advance: advanceFrame,
129
+ scheduler: {
130
+ createStage: registry.createStage,
131
+ getStage: registry.getStage,
132
+ setDiagnosticsEnabled: registry.setDiagnosticsEnabled,
133
+ getDiagnosticsEnabled: registry.getDiagnosticsEnabled,
134
+ getLastRunTimings: registry.getLastRunTimings,
135
+ getSchedule: registry.getSchedule,
136
+ setProfilingEnabled: registry.setProfilingEnabled,
137
+ setProfilingWindow: registry.setProfilingWindow,
138
+ resetProfiling: registry.resetProfiling,
139
+ getProfilingEnabled: registry.getProfilingEnabled,
140
+ getProfilingWindow: registry.getProfilingWindow,
141
+ getProfilingSnapshot: registry.getProfilingSnapshot
142
+ }
143
+ });
144
+
145
+ $effect(() => {
146
+ renderModeState.set(renderMode);
147
+ requestFrame();
148
+ });
149
+
150
+ $effect(() => {
151
+ autoRenderState.set(autoRender);
152
+ requestFrame();
153
+ });
154
+
155
+ $effect(() => {
156
+ maxDeltaState.set(maxDelta);
157
+ requestFrame();
158
+ });
159
+
160
+ $effect(() => {
161
+ dprState.set(dpr);
162
+ requestFrame();
163
+ });
164
+
165
+ $effect(() => {
166
+ const limit = getNormalizedErrorHistoryLimit();
167
+ if (limit <= 0) {
168
+ if (errorHistory.length === 0) {
169
+ return;
170
+ }
171
+ errorHistory = [];
172
+ onErrorHistory?.([]);
173
+ return;
174
+ }
175
+
176
+ if (errorHistory.length <= limit) {
177
+ return;
178
+ }
179
+
180
+ const trimmed = errorHistory.slice(errorHistory.length - limit);
181
+ errorHistory = trimmed;
182
+ onErrorHistory?.(trimmed);
183
+ });
184
+
185
+ onMount(() => {
186
+ if (!canvas) {
187
+ const report = toMotionGPUErrorReport(
188
+ new Error('Canvas element is not available'),
189
+ 'initialization'
190
+ );
191
+ errorReport = report;
192
+ const historyLimit = getNormalizedErrorHistoryLimit();
193
+ if (historyLimit > 0) {
194
+ const nextHistory = [report].slice(-historyLimit);
195
+ errorHistory = nextHistory;
196
+ onErrorHistory?.(nextHistory);
197
+ }
198
+ onError?.(report);
199
+ return () => registry.clear();
200
+ }
201
+
202
+ const runtimeLoop = createMotionGPURuntimeLoop({
203
+ canvas,
204
+ registry,
205
+ size,
206
+ dpr: dprState,
207
+ maxDelta: maxDeltaState,
208
+ getMaterial: () => material,
209
+ getRenderTargets: () => renderTargets,
210
+ getPasses: () => passes,
211
+ getClearColor: () => clearColor,
212
+ getOutputColorSpace: () => outputColorSpace,
213
+ getAdapterOptions: () => adapterOptions,
214
+ getDeviceDescriptor: () => deviceDescriptor,
215
+ getOnError: () => onError,
216
+ getErrorHistoryLimit: () => errorHistoryLimit,
217
+ getOnErrorHistory: () => onErrorHistory,
218
+ reportErrorHistory: (history) => {
219
+ errorHistory = history;
220
+ },
221
+ reportError: (report) => {
222
+ errorReport = report;
223
+ }
224
+ });
225
+ requestFrameSignal = runtimeLoop.requestFrame;
226
+
227
+ return () => {
228
+ requestFrameSignal = null;
229
+ runtimeLoop.destroy();
230
+ };
231
+ });
232
+ </script>
233
+
234
+ <div class="motiongpu-canvas-wrap">
235
+ <canvas use:bindCanvas class={className} {style}></canvas>
236
+ {#if showErrorOverlay && errorReport}
237
+ {#if errorRenderer}
238
+ {@render errorRenderer(errorReport)}
239
+ {:else}
240
+ <MotionGPUErrorOverlay report={errorReport} />
241
+ {/if}
242
+ {/if}
243
+ {@render children?.()}
244
+ </div>
245
+
246
+ <style>
247
+ .motiongpu-canvas-wrap {
248
+ position: relative;
249
+ width: 100%;
250
+ height: 100%;
251
+ min-width: 0;
252
+ min-height: 0;
253
+ overflow: hidden;
254
+ }
255
+
256
+ canvas {
257
+ position: absolute;
258
+ inset: 0;
259
+ display: block;
260
+ width: 100%;
261
+ height: 100%;
262
+ }
263
+ </style>
@@ -1,7 +1,7 @@
1
1
  import type { Snippet } from 'svelte';
2
- import { type FragMaterial } from './core/material';
3
- import { type MotionGPUErrorReport } from './core/error-report';
4
- import type { OutputColorSpace, RenderPass, RenderMode, RenderTargetDefinitionMap } from './core/types';
2
+ import type { FragMaterial } from '../core/material';
3
+ import { type MotionGPUErrorReport } from '../core/error-report';
4
+ import type { OutputColorSpace, RenderPass, RenderMode, RenderTargetDefinitionMap } from '../core/types';
5
5
  interface Props {
6
6
  material: FragMaterial;
7
7
  renderTargets?: RenderTargetDefinitionMap;
@@ -17,6 +17,8 @@ interface Props {
17
17
  showErrorOverlay?: boolean;
18
18
  errorRenderer?: Snippet<[MotionGPUErrorReport]>;
19
19
  onError?: (report: MotionGPUErrorReport) => void;
20
+ errorHistoryLimit?: number;
21
+ onErrorHistory?: (history: MotionGPUErrorReport[]) => void;
20
22
  class?: string;
21
23
  style?: string;
22
24
  children?: Snippet;
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import type { MotionGPUErrorReport } from './core/error-report';
2
+ import type { MotionGPUErrorReport } from '../core/error-report';
3
3
  import Portal from './Portal.svelte';
4
4
 
5
5
  interface Props {
@@ -53,9 +53,8 @@
53
53
  class="motiongpu-error-source-tab motiongpu-error-source-tab-active"
54
54
  role="tab"
55
55
  aria-selected="true"
56
- >{report.source.component} (fragment line {report.source
57
- .line}{#if report.source.column}, col
58
- {report.source.column}{/if})</span
56
+ >{report.source.location}{#if report.source.column}, col {report.source
57
+ .column}{/if}</span
59
58
  >
60
59
  <span class="motiongpu-error-source-tab-spacer" aria-hidden="true"></span>
61
60
  </div>
@@ -117,21 +116,13 @@
117
116
  --motiongpu-radius-xl: var(--radius-xl, 1rem);
118
117
  --motiongpu-font-sans: var(
119
118
  --font-sans,
120
- 'Aeonik Pro',
121
119
  'Inter',
122
120
  'Segoe UI',
123
121
  'Helvetica Neue',
124
122
  Arial,
125
123
  sans-serif
126
124
  );
127
- --motiongpu-font-mono: var(
128
- --font-mono,
129
- 'Aeonik font-mono',
130
- 'SFMono-Regular',
131
- 'Menlo',
132
- 'Consolas',
133
- monospace
134
- );
125
+ --motiongpu-font-mono: var(--font-mono, 'SFMono-Regular', 'Menlo', 'Consolas', monospace);
135
126
  position: fixed;
136
127
  inset: 0;
137
128
  display: grid;
@@ -156,7 +147,7 @@
156
147
  max-width: calc(100vw - 1.5rem);
157
148
  box-sizing: border-box;
158
149
  font-size: 0.875rem;
159
- font-weight: 300;
150
+ font-weight: 400;
160
151
  line-height: 1.45;
161
152
  background: linear-gradient(
162
153
  180deg,
@@ -229,7 +220,7 @@
229
220
  background: color-mix(in srgb, var(--motiongpu-color-accent) 9%, var(--motiongpu-color-card));
230
221
  font-size: 0.82rem;
231
222
  line-height: 1.4;
232
- font-weight: 300;
223
+ font-weight: 400;
233
224
  color: var(--motiongpu-color-foreground);
234
225
  }
235
226
 
@@ -237,7 +228,7 @@
237
228
  margin: 0;
238
229
  font-size: 0.82rem;
239
230
  line-height: 1.45;
240
- font-weight: 300;
231
+ font-weight: 400;
241
232
  color: var(--motiongpu-color-foreground-muted);
242
233
  }
243
234
 
@@ -282,7 +273,7 @@
282
273
  align-items: center;
283
274
  padding: 0.5rem 0.68rem;
284
275
  font-size: 0.76rem;
285
- font-weight: 300;
276
+ font-weight: 400;
286
277
  line-height: 1.2;
287
278
  color: var(--motiongpu-color-foreground-muted);
288
279
  border-right: 1px solid var(--motiongpu-color-border);
@@ -317,7 +308,7 @@
317
308
  .motiongpu-error-source-line {
318
309
  font-family: var(--motiongpu-font-mono);
319
310
  font-size: 0.77rem;
320
- font-weight: 300;
311
+ font-weight: 400;
321
312
  line-height: 1.3;
322
313
  font-variant-numeric: tabular-nums;
323
314
  font-feature-settings: 'tnum' 1;
@@ -329,7 +320,7 @@
329
320
  .motiongpu-error-source-code {
330
321
  font-family: var(--motiongpu-font-mono);
331
322
  font-size: 0.77rem;
332
- font-weight: 350;
323
+ font-weight: 400;
333
324
  line-height: 1.3;
334
325
  color: var(--motiongpu-color-foreground);
335
326
  white-space: pre-wrap;
@@ -367,7 +358,7 @@
367
358
  background: var(--motiongpu-color-background-muted);
368
359
  font-size: 0.74rem;
369
360
  line-height: 1.4;
370
- font-weight: 300;
361
+ font-weight: 400;
371
362
  color: var(--motiongpu-color-foreground);
372
363
  font-family: var(--motiongpu-font-mono);
373
364
  }
@@ -1,4 +1,4 @@
1
- import type { MotionGPUErrorReport } from './core/error-report';
1
+ import type { MotionGPUErrorReport } from '../core/error-report';
2
2
  interface Props {
3
3
  report: MotionGPUErrorReport;
4
4
  }
@@ -0,0 +1,11 @@
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 { ApplySchedulerPresetOptions, SchedulerDebugSnapshot, SchedulerPreset, SchedulerPresetConfig } from '../core/scheduler-helpers.js';
8
+ export type { MotionGPUUserContext, MotionGPUUserNamespace } from './motiongpu-context.js';
9
+ export type { FrameProfilingSnapshot, FrameKey, FrameTaskInvalidation, FrameTaskInvalidationToken, FrameRunTimings, FrameScheduleSnapshot, FrameStage, FrameStageCallback, FrameTimingStats, FrameTask } from '../core/frame-registry.js';
10
+ export type { SetMotionGPUUserContextOptions } from './use-motiongpu-user-context.js';
11
+ export type { RenderPassContext, RenderTarget, UniformLayout, UniformLayoutEntry } from '../core/types.js';
@@ -0,0 +1,6 @@
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';
@@ -0,0 +1,14 @@
1
+ import { createFrameRegistry, type FrameCallback, type FrameKey, type FrameProfilingSnapshot, type FrameRegistry, type FrameRunTimings, type FrameScheduleSnapshot, type FrameStage, type FrameStageCallback, type FrameTask, type FrameTaskInvalidation, type FrameTaskInvalidationToken, type UseFrameOptions, type UseFrameResult } from '../core/frame-registry.js';
2
+ export { createFrameRegistry, type FrameCallback, type FrameKey, type FrameProfilingSnapshot, type FrameRegistry, type FrameRunTimings, type FrameScheduleSnapshot, type FrameStage, type FrameStageCallback, type FrameTask, type FrameTaskInvalidation, type FrameTaskInvalidationToken, type UseFrameOptions, type UseFrameResult };
3
+ /**
4
+ * Provides a frame registry through Svelte context.
5
+ */
6
+ export declare function provideFrameRegistry(registry: FrameRegistry): void;
7
+ /**
8
+ * Registers a frame callback using an auto-generated task key.
9
+ */
10
+ export declare function useFrame(callback: FrameCallback, options?: UseFrameOptions): UseFrameResult;
11
+ /**
12
+ * Registers a frame callback with an explicit task key.
13
+ */
14
+ export declare function useFrame(key: FrameKey, callback: FrameCallback, options?: UseFrameOptions): UseFrameResult;
@@ -0,0 +1,32 @@
1
+ import { getContext, onDestroy, setContext } from 'svelte';
2
+ import { createFrameRegistry } from '../core/frame-registry.js';
3
+ /**
4
+ * Svelte context key for the active frame registry.
5
+ */
6
+ const FRAME_CONTEXT_KEY = Symbol('motiongpu.frame-context');
7
+ export { createFrameRegistry };
8
+ /**
9
+ * Provides a frame registry through Svelte context.
10
+ */
11
+ export function provideFrameRegistry(registry) {
12
+ setContext(FRAME_CONTEXT_KEY, registry);
13
+ }
14
+ /**
15
+ * Registers a callback in the active frame registry and auto-unsubscribes on destroy.
16
+ */
17
+ export function useFrame(keyOrCallback, callbackOrOptions, maybeOptions) {
18
+ const registry = getContext(FRAME_CONTEXT_KEY);
19
+ if (!registry) {
20
+ throw new Error('useFrame must be used inside <FragCanvas>');
21
+ }
22
+ const registration = typeof keyOrCallback === 'function'
23
+ ? registry.register(keyOrCallback, callbackOrOptions)
24
+ : registry.register(keyOrCallback, callbackOrOptions, maybeOptions);
25
+ onDestroy(registration.unsubscribe);
26
+ return {
27
+ task: registration.task,
28
+ start: registration.start,
29
+ stop: registration.stop,
30
+ started: registration.started
31
+ };
32
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Svelte adapter entrypoint for MotionGPU.
3
+ */
4
+ export { default as FragCanvas } from './FragCanvas.svelte';
5
+ export { defineMaterial } from '../core/material.js';
6
+ export { BlitPass, CopyPass, ShaderPass } from '../passes/index.js';
7
+ export { useMotionGPU } from './motiongpu-context.js';
8
+ export { useFrame } from './frame-context.js';
9
+ export { useTexture } from './use-texture.js';
10
+ export type { FrameInvalidationToken, FrameState, OutputColorSpace, RenderPass, RenderPassContext, RenderPassFlags, RenderPassInputSlot, RenderPassOutputSlot, RenderMode, RenderTarget, RenderTargetDefinition, RenderTargetDefinitionMap, TextureData, TextureDefinition, TextureDefinitionMap, TextureUpdateMode, TextureMap, TextureSource, TextureValue, TypedUniform, UniformMat4Value, UniformMap, UniformType, UniformValue } from '../core/types.js';
11
+ export type { LoadedTexture, TextureDecodeOptions, TextureLoadOptions } from '../core/texture-loader.js';
12
+ export type { FragMaterial, FragMaterialInput, MaterialIncludes, MaterialDefineValue, MaterialDefines, TypedMaterialDefineValue } from '../core/material.js';
13
+ export type { MotionGPUContext } from './motiongpu-context.js';
14
+ export type { UseFrameOptions, UseFrameResult } from './frame-context.js';
15
+ export type { TextureUrlInput, UseTextureResult } from './use-texture.js';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Svelte adapter entrypoint for MotionGPU.
3
+ */
4
+ export { default as FragCanvas } from './FragCanvas.svelte';
5
+ export { defineMaterial } from '../core/material.js';
6
+ export { BlitPass, CopyPass, ShaderPass } from '../passes/index.js';
7
+ export { useMotionGPU } from './motiongpu-context.js';
8
+ export { useFrame } from './frame-context.js';
9
+ export { useTexture } from './use-texture.js';
@@ -1,10 +1,8 @@
1
- import type { RenderMode } from './core/types';
2
- import type { CurrentReadable, CurrentWritable } from './current-writable';
3
- import type { FrameProfilingSnapshot, FrameRegistry, FrameRunTimings, FrameScheduleSnapshot } from './frame-context';
4
- /**
5
- * Exposed subset of frame scheduler controls intended for public consumption.
6
- */
7
- export type MotionGPUScheduler = Pick<FrameRegistry, 'createStage' | 'getStage' | 'setDiagnosticsEnabled' | 'getDiagnosticsEnabled' | 'getLastRunTimings' | 'getSchedule' | 'setProfilingEnabled' | 'setProfilingWindow' | 'resetProfiling' | 'getProfilingEnabled' | 'getProfilingWindow' | 'getProfilingSnapshot'>;
1
+ import type { RenderMode } from '../core/types.js';
2
+ import type { CurrentReadable, CurrentWritable } from '../core/current-value.js';
3
+ import type { FrameProfilingSnapshot, FrameRunTimings, FrameScheduleSnapshot } from '../core/frame-registry.js';
4
+ import type { MotionGPUScheduler as CoreMotionGPUScheduler } from '../core/scheduler-helpers.js';
5
+ export type MotionGPUScheduler = CoreMotionGPUScheduler;
8
6
  export type { FrameProfilingSnapshot, FrameRunTimings, FrameScheduleSnapshot };
9
7
  /**
10
8
  * Namespace identifier for user-owned context entries.
@@ -1,5 +1,5 @@
1
- import type { CurrentReadable } from './current-writable';
2
- import { type MotionGPUUserNamespace } from './motiongpu-context';
1
+ import type { CurrentReadable } from '../core/current-value.js';
2
+ import { type MotionGPUUserNamespace } from './motiongpu-context.js';
3
3
  /**
4
4
  * Internal shape of the user context store.
5
5
  */
@@ -1,4 +1,4 @@
1
- import { useMotionGPU } from './motiongpu-context';
1
+ import { useMotionGPU } from './motiongpu-context.js';
2
2
  /**
3
3
  * Checks whether a value is a non-array object suitable for shallow merge.
4
4
  */
@@ -1,5 +1,6 @@
1
- import type { CurrentReadable } from './current-writable';
2
- import { type LoadedTexture, type TextureLoadOptions } from './core/texture-loader';
1
+ import { type CurrentReadable } from '../core/current-value.js';
2
+ import { type LoadedTexture, type TextureLoadOptions } from '../core/texture-loader.js';
3
+ import { type MotionGPUErrorReport } from '../core/error-report.js';
3
4
  /**
4
5
  * Reactive state returned by {@link useTexture}.
5
6
  */
@@ -16,6 +17,10 @@ export interface UseTextureResult {
16
17
  * Last loading error.
17
18
  */
18
19
  error: CurrentReadable<Error | null>;
20
+ /**
21
+ * Last loading error normalized to MotionGPU diagnostics report shape.
22
+ */
23
+ errorReport: CurrentReadable<MotionGPUErrorReport | null>;
19
24
  /**
20
25
  * Reloads all textures using current URL input.
21
26
  */
@@ -1,6 +1,7 @@
1
1
  import { onDestroy } from 'svelte';
2
- import { currentWritable } from './current-writable';
3
- import { isAbortError, loadTexturesFromUrls } from './core/texture-loader';
2
+ import { createCurrentWritable as currentWritable } from '../core/current-value.js';
3
+ import { isAbortError, loadTexturesFromUrls } from '../core/texture-loader.js';
4
+ import { toMotionGPUErrorReport } from '../core/error-report.js';
4
5
  /**
5
6
  * Normalizes unknown thrown values to an `Error` instance.
6
7
  */
@@ -60,6 +61,7 @@ export function useTexture(urlInput, options = {}) {
60
61
  const textures = currentWritable(null);
61
62
  const loading = currentWritable(true);
62
63
  const error = currentWritable(null);
64
+ const errorReport = currentWritable(null);
63
65
  let disposed = false;
64
66
  let requestVersion = 0;
65
67
  let activeController = null;
@@ -75,6 +77,7 @@ export function useTexture(urlInput, options = {}) {
75
77
  activeController = controller;
76
78
  loading.set(true);
77
79
  error.set(null);
80
+ errorReport.set(null);
78
81
  const previous = textures.current;
79
82
  const mergedSignal = mergeAbortSignals(controller.signal, options.signal);
80
83
  try {
@@ -98,7 +101,9 @@ export function useTexture(urlInput, options = {}) {
98
101
  }
99
102
  disposeTextures(previous);
100
103
  textures.set(null);
101
- error.set(toError(nextError));
104
+ const normalizedError = toError(nextError);
105
+ error.set(normalizedError);
106
+ errorReport.set(toMotionGPUErrorReport(normalizedError, 'initialization'));
102
107
  }
103
108
  finally {
104
109
  if (!disposed && version === requestVersion) {
@@ -142,6 +147,7 @@ export function useTexture(urlInput, options = {}) {
142
147
  textures,
143
148
  loading,
144
149
  error,
150
+ errorReport,
145
151
  reload: load
146
152
  };
147
153
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@motion-core/motion-gpu",
3
- "version": "0.1.0",
4
- "description": "Svelte 5 package for fullscreen WGSL shaders with a WebGPU runtime, scheduler, and render graph.",
3
+ "version": "0.3.0",
4
+ "description": "Framework-agnostic WebGPU runtime for fullscreen WGSL shaders with explicit Svelte adapter entrypoints.",
5
5
  "keywords": [
6
6
  "svelte",
7
7
  "svelte5",
@@ -26,18 +26,33 @@
26
26
  "access": "public"
27
27
  },
28
28
  "type": "module",
29
- "svelte": "./dist/index.js",
30
29
  "types": "./dist/index.d.ts",
31
30
  "exports": {
32
31
  ".": {
33
32
  "types": "./dist/index.d.ts",
34
- "svelte": "./dist/index.js",
35
33
  "default": "./dist/index.js"
36
34
  },
37
35
  "./advanced": {
38
36
  "types": "./dist/advanced.d.ts",
39
- "svelte": "./dist/advanced.js",
40
37
  "default": "./dist/advanced.js"
38
+ },
39
+ "./svelte": {
40
+ "types": "./dist/svelte/index.d.ts",
41
+ "svelte": "./dist/svelte/index.js",
42
+ "default": "./dist/svelte/index.js"
43
+ },
44
+ "./svelte/advanced": {
45
+ "types": "./dist/svelte/advanced.d.ts",
46
+ "svelte": "./dist/svelte/advanced.js",
47
+ "default": "./dist/svelte/advanced.js"
48
+ },
49
+ "./core": {
50
+ "types": "./dist/core/index.d.ts",
51
+ "default": "./dist/core/index.js"
52
+ },
53
+ "./core/advanced": {
54
+ "types": "./dist/core/advanced.d.ts",
55
+ "default": "./dist/core/advanced.js"
41
56
  }
42
57
  },
43
58
  "files": [
@@ -65,6 +80,11 @@
65
80
  "peerDependencies": {
66
81
  "svelte": "^5.0.0"
67
82
  },
83
+ "peerDependenciesMeta": {
84
+ "svelte": {
85
+ "optional": true
86
+ }
87
+ },
68
88
  "devDependencies": {
69
89
  "@eslint/compat": "^2.0.2",
70
90
  "@eslint/js": "^10.0.1",