@motion-core/motion-gpu 0.2.0 → 0.4.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.
- package/README.md +78 -1
- package/dist/core/current-value.js +3 -0
- package/dist/core/error-diagnostics.d.ts +14 -0
- package/dist/core/error-diagnostics.js +41 -1
- package/dist/core/error-report.d.ts +37 -0
- package/dist/core/error-report.js +60 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/material-preprocess.d.ts +5 -5
- package/dist/core/material-preprocess.js +1 -4
- package/dist/core/material.d.ts +32 -23
- package/dist/core/material.js +14 -7
- package/dist/core/renderer.d.ts +10 -0
- package/dist/core/renderer.js +66 -4
- package/dist/core/runtime-loop.d.ts +3 -0
- package/dist/core/runtime-loop.js +72 -1
- package/dist/core/types.d.ts +24 -10
- package/dist/passes/BlitPass.d.ts +6 -27
- package/dist/passes/BlitPass.js +10 -121
- package/dist/passes/FullscreenPass.d.ts +37 -0
- package/dist/passes/FullscreenPass.js +131 -0
- package/dist/passes/ShaderPass.d.ts +6 -26
- package/dist/passes/ShaderPass.js +10 -121
- package/dist/react/FragCanvas.d.ts +26 -0
- package/dist/react/FragCanvas.js +218 -0
- package/dist/react/FragCanvas.tsx +345 -0
- package/dist/react/MotionGPUErrorOverlay.d.ts +6 -0
- package/dist/react/MotionGPUErrorOverlay.js +52 -0
- package/dist/react/MotionGPUErrorOverlay.tsx +129 -0
- package/dist/react/Portal.d.ts +6 -0
- package/dist/react/Portal.js +24 -0
- package/dist/react/Portal.tsx +34 -0
- package/dist/react/advanced.d.ts +11 -0
- package/dist/react/advanced.js +6 -0
- package/dist/react/frame-context.d.ts +14 -0
- package/dist/react/frame-context.js +98 -0
- package/dist/react/index.d.ts +15 -0
- package/dist/react/index.js +9 -0
- package/dist/react/motiongpu-context.d.ts +73 -0
- package/dist/react/motiongpu-context.js +18 -0
- package/dist/react/use-motiongpu-user-context.d.ts +49 -0
- package/dist/react/use-motiongpu-user-context.js +94 -0
- package/dist/react/use-texture.d.ts +40 -0
- package/dist/react/use-texture.js +162 -0
- package/dist/svelte/FragCanvas.svelte +45 -16
- package/dist/svelte/FragCanvas.svelte.d.ts +2 -0
- package/dist/svelte/MotionGPUErrorOverlay.svelte +10 -19
- package/dist/svelte/Portal.svelte +6 -21
- package/dist/svelte/use-motiongpu-user-context.d.ts +9 -1
- package/dist/svelte/use-motiongpu-user-context.js +4 -1
- package/dist/svelte/use-texture.d.ts +11 -2
- package/dist/svelte/use-texture.js +13 -3
- package/package.json +28 -3
|
@@ -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.
|
|
57
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
361
|
+
font-weight: 400;
|
|
371
362
|
color: var(--motiongpu-color-foreground);
|
|
372
363
|
font-family: var(--motiongpu-font-mono);
|
|
373
364
|
}
|
|
@@ -14,33 +14,18 @@
|
|
|
14
14
|
: (input ?? document.body);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
const portal = (node: HTMLDivElement
|
|
18
|
-
|
|
17
|
+
const portal = (node: HTMLDivElement) => {
|
|
18
|
+
const targetElement = resolveTargetElement(target);
|
|
19
19
|
targetElement.appendChild(node);
|
|
20
20
|
|
|
21
|
-
return {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (nextTargetElement === targetElement) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (node.parentNode === targetElement) {
|
|
29
|
-
targetElement.removeChild(node);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
nextTargetElement.appendChild(node);
|
|
33
|
-
targetElement = nextTargetElement;
|
|
34
|
-
},
|
|
35
|
-
destroy() {
|
|
36
|
-
if (node.parentNode === targetElement) {
|
|
37
|
-
targetElement.removeChild(node);
|
|
38
|
-
}
|
|
21
|
+
return () => {
|
|
22
|
+
if (node.parentNode === targetElement) {
|
|
23
|
+
targetElement.removeChild(node);
|
|
39
24
|
}
|
|
40
25
|
};
|
|
41
26
|
};
|
|
42
27
|
</script>
|
|
43
28
|
|
|
44
|
-
<div
|
|
29
|
+
<div {@attach portal}>
|
|
45
30
|
{@render children?.()}
|
|
46
31
|
</div>
|
|
@@ -17,6 +17,14 @@ export interface SetMotionGPUUserContextOptions {
|
|
|
17
17
|
* @default 'skip'
|
|
18
18
|
*/
|
|
19
19
|
existing?: 'merge' | 'replace' | 'skip';
|
|
20
|
+
/**
|
|
21
|
+
* How function inputs should be interpreted:
|
|
22
|
+
* - `factory`: call function and store its return value
|
|
23
|
+
* - `value`: store function itself
|
|
24
|
+
*
|
|
25
|
+
* @default 'factory'
|
|
26
|
+
*/
|
|
27
|
+
functionValue?: 'factory' | 'value';
|
|
20
28
|
}
|
|
21
29
|
/**
|
|
22
30
|
* Returns a read-only view of the entire motiongpu user context store.
|
|
@@ -25,7 +33,7 @@ export declare function useMotionGPUUserContext<UC extends UserContextStore = Us
|
|
|
25
33
|
/**
|
|
26
34
|
* Reads a namespaced user context value as a reactive readable store.
|
|
27
35
|
*/
|
|
28
|
-
export declare function useMotionGPUUserContext<
|
|
36
|
+
export declare function useMotionGPUUserContext<UC extends UserContextStore = UserContextStore, K extends keyof UC & MotionGPUUserNamespace = keyof UC & MotionGPUUserNamespace>(namespace: K): CurrentReadable<UC[K] | undefined>;
|
|
29
37
|
/**
|
|
30
38
|
* Sets a namespaced user context value with explicit write semantics.
|
|
31
39
|
*
|
|
@@ -43,6 +43,7 @@ export function useMotionGPUUserContext(namespace) {
|
|
|
43
43
|
export function setMotionGPUUserContext(namespace, value, options) {
|
|
44
44
|
const userStore = useMotionGPU().user;
|
|
45
45
|
const mode = options?.existing ?? 'skip';
|
|
46
|
+
const functionValueMode = options?.functionValue ?? 'factory';
|
|
46
47
|
let resolvedValue;
|
|
47
48
|
userStore.update((context) => {
|
|
48
49
|
const hasExisting = namespace in context;
|
|
@@ -50,7 +51,9 @@ export function setMotionGPUUserContext(namespace, value, options) {
|
|
|
50
51
|
resolvedValue = context[namespace];
|
|
51
52
|
return context;
|
|
52
53
|
}
|
|
53
|
-
const nextValue = typeof value === 'function'
|
|
54
|
+
const nextValue = typeof value === 'function' && functionValueMode === 'factory'
|
|
55
|
+
? value()
|
|
56
|
+
: value;
|
|
54
57
|
if (hasExisting && mode === 'merge') {
|
|
55
58
|
const currentValue = context[namespace];
|
|
56
59
|
if (isObjectEntry(currentValue) && isObjectEntry(nextValue)) {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type CurrentReadable } from '../core/current-value.js';
|
|
2
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
|
*/
|
|
@@ -25,11 +30,15 @@ export interface UseTextureResult {
|
|
|
25
30
|
* Supported URL input variants for `useTexture`.
|
|
26
31
|
*/
|
|
27
32
|
export type TextureUrlInput = string[] | (() => string[]);
|
|
33
|
+
/**
|
|
34
|
+
* Supported options input variants for `useTexture`.
|
|
35
|
+
*/
|
|
36
|
+
export type TextureOptionsInput = TextureLoadOptions | (() => TextureLoadOptions);
|
|
28
37
|
/**
|
|
29
38
|
* Loads textures from URLs and exposes reactive loading/error state.
|
|
30
39
|
*
|
|
31
40
|
* @param urlInput - URLs array or lazy URL provider.
|
|
32
|
-
* @param
|
|
41
|
+
* @param optionsInput - Loader options object or lazy options provider.
|
|
33
42
|
* @returns Reactive texture loading state with reload support.
|
|
34
43
|
*/
|
|
35
|
-
export declare function useTexture(urlInput: TextureUrlInput,
|
|
44
|
+
export declare function useTexture(urlInput: TextureUrlInput, optionsInput?: TextureOptionsInput): UseTextureResult;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { onDestroy } from 'svelte';
|
|
2
2
|
import { createCurrentWritable as currentWritable } from '../core/current-value.js';
|
|
3
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
|
*/
|
|
@@ -53,19 +54,23 @@ function mergeAbortSignals(primary, secondary) {
|
|
|
53
54
|
* Loads textures from URLs and exposes reactive loading/error state.
|
|
54
55
|
*
|
|
55
56
|
* @param urlInput - URLs array or lazy URL provider.
|
|
56
|
-
* @param
|
|
57
|
+
* @param optionsInput - Loader options object or lazy options provider.
|
|
57
58
|
* @returns Reactive texture loading state with reload support.
|
|
58
59
|
*/
|
|
59
|
-
export function useTexture(urlInput,
|
|
60
|
+
export function useTexture(urlInput, optionsInput = {}) {
|
|
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;
|
|
66
68
|
let runningLoad = null;
|
|
67
69
|
let reloadQueued = false;
|
|
68
70
|
const getUrls = typeof urlInput === 'function' ? urlInput : () => urlInput;
|
|
71
|
+
const getOptions = typeof optionsInput === 'function'
|
|
72
|
+
? optionsInput
|
|
73
|
+
: () => optionsInput;
|
|
69
74
|
const executeLoad = async () => {
|
|
70
75
|
if (disposed) {
|
|
71
76
|
return;
|
|
@@ -75,7 +80,9 @@ export function useTexture(urlInput, options = {}) {
|
|
|
75
80
|
activeController = controller;
|
|
76
81
|
loading.set(true);
|
|
77
82
|
error.set(null);
|
|
83
|
+
errorReport.set(null);
|
|
78
84
|
const previous = textures.current;
|
|
85
|
+
const options = getOptions() ?? {};
|
|
79
86
|
const mergedSignal = mergeAbortSignals(controller.signal, options.signal);
|
|
80
87
|
try {
|
|
81
88
|
const loaded = await loadTexturesFromUrls(getUrls(), {
|
|
@@ -98,7 +105,9 @@ export function useTexture(urlInput, options = {}) {
|
|
|
98
105
|
}
|
|
99
106
|
disposeTextures(previous);
|
|
100
107
|
textures.set(null);
|
|
101
|
-
|
|
108
|
+
const normalizedError = toError(nextError);
|
|
109
|
+
error.set(normalizedError);
|
|
110
|
+
errorReport.set(toMotionGPUErrorReport(normalizedError, 'initialization'));
|
|
102
111
|
}
|
|
103
112
|
finally {
|
|
104
113
|
if (!disposed && version === requestVersion) {
|
|
@@ -142,6 +151,7 @@ export function useTexture(urlInput, options = {}) {
|
|
|
142
151
|
textures,
|
|
143
152
|
loading,
|
|
144
153
|
error,
|
|
154
|
+
errorReport,
|
|
145
155
|
reload: load
|
|
146
156
|
};
|
|
147
157
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@motion-core/motion-gpu",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Framework-agnostic WebGPU runtime for fullscreen WGSL shaders with explicit Svelte adapter entrypoints.",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Framework-agnostic WebGPU runtime for fullscreen WGSL shaders with explicit Svelte and React adapter entrypoints.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"svelte",
|
|
7
7
|
"svelte5",
|
|
8
|
+
"react",
|
|
9
|
+
"react18",
|
|
8
10
|
"webgpu",
|
|
9
11
|
"wgsl",
|
|
10
12
|
"shader",
|
|
@@ -46,6 +48,14 @@
|
|
|
46
48
|
"svelte": "./dist/svelte/advanced.js",
|
|
47
49
|
"default": "./dist/svelte/advanced.js"
|
|
48
50
|
},
|
|
51
|
+
"./react": {
|
|
52
|
+
"types": "./dist/react/index.d.ts",
|
|
53
|
+
"default": "./dist/react/index.js"
|
|
54
|
+
},
|
|
55
|
+
"./react/advanced": {
|
|
56
|
+
"types": "./dist/react/advanced.d.ts",
|
|
57
|
+
"default": "./dist/react/advanced.js"
|
|
58
|
+
},
|
|
49
59
|
"./core": {
|
|
50
60
|
"types": "./dist/core/index.d.ts",
|
|
51
61
|
"default": "./dist/core/index.js"
|
|
@@ -59,7 +69,7 @@
|
|
|
59
69
|
"dist"
|
|
60
70
|
],
|
|
61
71
|
"scripts": {
|
|
62
|
-
"build": "svelte-package -i src/lib -o dist",
|
|
72
|
+
"build": "svelte-package -i src/lib -o dist && node ./scripts/build/transpile-react-tsx.mjs",
|
|
63
73
|
"prepack": "bun run build",
|
|
64
74
|
"check": "svelte-check --tsconfig ./tsconfig.json && publint",
|
|
65
75
|
"test": "vitest run",
|
|
@@ -68,6 +78,8 @@
|
|
|
68
78
|
"test:e2e": "playwright test",
|
|
69
79
|
"test:e2e:headed": "playwright test --headed",
|
|
70
80
|
"e2e:serve": "vite --config e2e/vite.config.ts",
|
|
81
|
+
"e2e:serve:svelte": "MOTION_GPU_E2E_FRAMEWORK=svelte vite --config e2e/vite.config.ts",
|
|
82
|
+
"e2e:serve:react": "MOTION_GPU_E2E_FRAMEWORK=react vite --config e2e/vite.config.ts",
|
|
71
83
|
"perf:core": "bun run ./scripts/perf/core-benchmark.ts",
|
|
72
84
|
"perf:core:check": "bun run ./scripts/perf/core-benchmark.ts --strict",
|
|
73
85
|
"perf:core:baseline": "bun run ./scripts/perf/core-benchmark.ts --update-baseline",
|
|
@@ -78,9 +90,17 @@
|
|
|
78
90
|
"format": "prettier --write ."
|
|
79
91
|
},
|
|
80
92
|
"peerDependencies": {
|
|
93
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
94
|
+
"react-dom": "^18.0.0 || ^19.0.0",
|
|
81
95
|
"svelte": "^5.0.0"
|
|
82
96
|
},
|
|
83
97
|
"peerDependenciesMeta": {
|
|
98
|
+
"react": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
101
|
+
"react-dom": {
|
|
102
|
+
"optional": true
|
|
103
|
+
},
|
|
84
104
|
"svelte": {
|
|
85
105
|
"optional": true
|
|
86
106
|
}
|
|
@@ -91,7 +111,10 @@
|
|
|
91
111
|
"@playwright/test": "^1.58.2",
|
|
92
112
|
"@sveltejs/package": "^2.5.0",
|
|
93
113
|
"@sveltejs/vite-plugin-svelte": "^6.2.4",
|
|
114
|
+
"@testing-library/react": "^16.3.0",
|
|
94
115
|
"@testing-library/svelte": "^5.2.8",
|
|
116
|
+
"@types/react": "^19.2.2",
|
|
117
|
+
"@types/react-dom": "^19.2.2",
|
|
95
118
|
"@vitest/coverage-v8": "^4.0.18",
|
|
96
119
|
"@types/node": "^25.3.3",
|
|
97
120
|
"@webgpu/types": "^0.1.66",
|
|
@@ -104,6 +127,8 @@
|
|
|
104
127
|
"prettier-plugin-svelte": "^3.4.1",
|
|
105
128
|
"prettier-plugin-tailwindcss": "^0.7.2",
|
|
106
129
|
"publint": "^0.3.15",
|
|
130
|
+
"react": "^19.2.0",
|
|
131
|
+
"react-dom": "^19.2.0",
|
|
107
132
|
"svelte": "^5.51.0",
|
|
108
133
|
"svelte-check": "^4.3.6",
|
|
109
134
|
"typescript": "^5.9.3",
|