@motion-core/motion-gpu 0.1.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 (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +325 -0
  3. package/dist/FragCanvas.svelte +511 -0
  4. package/dist/FragCanvas.svelte.d.ts +26 -0
  5. package/dist/MotionGPUErrorOverlay.svelte +394 -0
  6. package/dist/MotionGPUErrorOverlay.svelte.d.ts +7 -0
  7. package/dist/Portal.svelte +46 -0
  8. package/dist/Portal.svelte.d.ts +8 -0
  9. package/dist/advanced-scheduler.d.ts +44 -0
  10. package/dist/advanced-scheduler.js +58 -0
  11. package/dist/advanced.d.ts +14 -0
  12. package/dist/advanced.js +9 -0
  13. package/dist/core/error-diagnostics.d.ts +40 -0
  14. package/dist/core/error-diagnostics.js +111 -0
  15. package/dist/core/error-report.d.ts +67 -0
  16. package/dist/core/error-report.js +190 -0
  17. package/dist/core/material-preprocess.d.ts +63 -0
  18. package/dist/core/material-preprocess.js +166 -0
  19. package/dist/core/material.d.ts +157 -0
  20. package/dist/core/material.js +358 -0
  21. package/dist/core/recompile-policy.d.ts +27 -0
  22. package/dist/core/recompile-policy.js +15 -0
  23. package/dist/core/render-graph.d.ts +55 -0
  24. package/dist/core/render-graph.js +73 -0
  25. package/dist/core/render-targets.d.ts +39 -0
  26. package/dist/core/render-targets.js +63 -0
  27. package/dist/core/renderer.d.ts +9 -0
  28. package/dist/core/renderer.js +1097 -0
  29. package/dist/core/shader.d.ts +42 -0
  30. package/dist/core/shader.js +196 -0
  31. package/dist/core/texture-loader.d.ts +129 -0
  32. package/dist/core/texture-loader.js +295 -0
  33. package/dist/core/textures.d.ts +114 -0
  34. package/dist/core/textures.js +136 -0
  35. package/dist/core/types.d.ts +523 -0
  36. package/dist/core/types.js +4 -0
  37. package/dist/core/uniforms.d.ts +48 -0
  38. package/dist/core/uniforms.js +222 -0
  39. package/dist/current-writable.d.ts +31 -0
  40. package/dist/current-writable.js +27 -0
  41. package/dist/frame-context.d.ts +287 -0
  42. package/dist/frame-context.js +731 -0
  43. package/dist/index.d.ts +17 -0
  44. package/dist/index.js +11 -0
  45. package/dist/motiongpu-context.d.ts +77 -0
  46. package/dist/motiongpu-context.js +26 -0
  47. package/dist/passes/BlitPass.d.ts +32 -0
  48. package/dist/passes/BlitPass.js +158 -0
  49. package/dist/passes/CopyPass.d.ts +25 -0
  50. package/dist/passes/CopyPass.js +53 -0
  51. package/dist/passes/ShaderPass.d.ts +40 -0
  52. package/dist/passes/ShaderPass.js +182 -0
  53. package/dist/passes/index.d.ts +3 -0
  54. package/dist/passes/index.js +3 -0
  55. package/dist/use-motiongpu-user-context.d.ts +35 -0
  56. package/dist/use-motiongpu-user-context.js +74 -0
  57. package/dist/use-texture.d.ts +35 -0
  58. package/dist/use-texture.js +147 -0
  59. package/package.json +94 -0
@@ -0,0 +1,74 @@
1
+ import { useMotionGPU } from './motiongpu-context';
2
+ /**
3
+ * Checks whether a value is a non-array object suitable for shallow merge.
4
+ */
5
+ function isObjectEntry(value) {
6
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
7
+ }
8
+ /**
9
+ * Read-only user context hook:
10
+ * - no args: returns full user context store
11
+ * - namespace: returns namespaced store view
12
+ *
13
+ * @param namespace - Optional namespace key.
14
+ */
15
+ export function useMotionGPUUserContext(namespace) {
16
+ const userStore = useMotionGPU().user;
17
+ if (namespace === undefined) {
18
+ const allStore = {
19
+ get current() {
20
+ return userStore.current;
21
+ },
22
+ subscribe(run) {
23
+ return userStore.subscribe((context) => run(context));
24
+ }
25
+ };
26
+ return allStore;
27
+ }
28
+ const scopedStore = {
29
+ get current() {
30
+ return userStore.current[namespace];
31
+ },
32
+ subscribe(run) {
33
+ return userStore.subscribe((context) => run(context[namespace]));
34
+ }
35
+ };
36
+ return scopedStore;
37
+ }
38
+ /**
39
+ * Sets a namespaced user context value with explicit write semantics.
40
+ *
41
+ * Returns the effective value stored under the namespace.
42
+ */
43
+ export function setMotionGPUUserContext(namespace, value, options) {
44
+ const userStore = useMotionGPU().user;
45
+ const mode = options?.existing ?? 'skip';
46
+ let resolvedValue;
47
+ userStore.update((context) => {
48
+ const hasExisting = namespace in context;
49
+ if (hasExisting && mode === 'skip') {
50
+ resolvedValue = context[namespace];
51
+ return context;
52
+ }
53
+ const nextValue = typeof value === 'function' ? value() : value;
54
+ if (hasExisting && mode === 'merge') {
55
+ const currentValue = context[namespace];
56
+ if (isObjectEntry(currentValue) && isObjectEntry(nextValue)) {
57
+ resolvedValue = {
58
+ ...currentValue,
59
+ ...nextValue
60
+ };
61
+ return {
62
+ ...context,
63
+ [namespace]: resolvedValue
64
+ };
65
+ }
66
+ }
67
+ resolvedValue = nextValue;
68
+ return {
69
+ ...context,
70
+ [namespace]: nextValue
71
+ };
72
+ });
73
+ return resolvedValue;
74
+ }
@@ -0,0 +1,35 @@
1
+ import type { CurrentReadable } from './current-writable';
2
+ import { type LoadedTexture, type TextureLoadOptions } from './core/texture-loader';
3
+ /**
4
+ * Reactive state returned by {@link useTexture}.
5
+ */
6
+ export interface UseTextureResult {
7
+ /**
8
+ * Loaded textures or `null` when unavailable/failed.
9
+ */
10
+ textures: CurrentReadable<LoadedTexture[] | null>;
11
+ /**
12
+ * `true` while an active load request is running.
13
+ */
14
+ loading: CurrentReadable<boolean>;
15
+ /**
16
+ * Last loading error.
17
+ */
18
+ error: CurrentReadable<Error | null>;
19
+ /**
20
+ * Reloads all textures using current URL input.
21
+ */
22
+ reload: () => Promise<void>;
23
+ }
24
+ /**
25
+ * Supported URL input variants for `useTexture`.
26
+ */
27
+ export type TextureUrlInput = string[] | (() => string[]);
28
+ /**
29
+ * Loads textures from URLs and exposes reactive loading/error state.
30
+ *
31
+ * @param urlInput - URLs array or lazy URL provider.
32
+ * @param options - Loader options passed to URL fetch/decode pipeline.
33
+ * @returns Reactive texture loading state with reload support.
34
+ */
35
+ export declare function useTexture(urlInput: TextureUrlInput, options?: TextureLoadOptions): UseTextureResult;
@@ -0,0 +1,147 @@
1
+ import { onDestroy } from 'svelte';
2
+ import { currentWritable } from './current-writable';
3
+ import { isAbortError, loadTexturesFromUrls } from './core/texture-loader';
4
+ /**
5
+ * Normalizes unknown thrown values to an `Error` instance.
6
+ */
7
+ function toError(error) {
8
+ if (error instanceof Error) {
9
+ return error;
10
+ }
11
+ return new Error('Unknown texture loading error');
12
+ }
13
+ /**
14
+ * Releases GPU-side resources for a list of loaded textures.
15
+ */
16
+ function disposeTextures(list) {
17
+ for (const texture of list ?? []) {
18
+ texture.dispose();
19
+ }
20
+ }
21
+ function mergeAbortSignals(primary, secondary) {
22
+ if (!secondary) {
23
+ return {
24
+ signal: primary,
25
+ dispose: () => { }
26
+ };
27
+ }
28
+ if (typeof AbortSignal.any === 'function') {
29
+ return {
30
+ signal: AbortSignal.any([primary, secondary]),
31
+ dispose: () => { }
32
+ };
33
+ }
34
+ const fallback = new AbortController();
35
+ let disposed = false;
36
+ const cleanup = () => {
37
+ if (disposed) {
38
+ return;
39
+ }
40
+ disposed = true;
41
+ primary.removeEventListener('abort', abort);
42
+ secondary.removeEventListener('abort', abort);
43
+ };
44
+ const abort = () => fallback.abort();
45
+ primary.addEventListener('abort', abort, { once: true });
46
+ secondary.addEventListener('abort', abort, { once: true });
47
+ return {
48
+ signal: fallback.signal,
49
+ dispose: cleanup
50
+ };
51
+ }
52
+ /**
53
+ * Loads textures from URLs and exposes reactive loading/error state.
54
+ *
55
+ * @param urlInput - URLs array or lazy URL provider.
56
+ * @param options - Loader options passed to URL fetch/decode pipeline.
57
+ * @returns Reactive texture loading state with reload support.
58
+ */
59
+ export function useTexture(urlInput, options = {}) {
60
+ const textures = currentWritable(null);
61
+ const loading = currentWritable(true);
62
+ const error = currentWritable(null);
63
+ let disposed = false;
64
+ let requestVersion = 0;
65
+ let activeController = null;
66
+ let runningLoad = null;
67
+ let reloadQueued = false;
68
+ const getUrls = typeof urlInput === 'function' ? urlInput : () => urlInput;
69
+ const executeLoad = async () => {
70
+ if (disposed) {
71
+ return;
72
+ }
73
+ const version = ++requestVersion;
74
+ const controller = new AbortController();
75
+ activeController = controller;
76
+ loading.set(true);
77
+ error.set(null);
78
+ const previous = textures.current;
79
+ const mergedSignal = mergeAbortSignals(controller.signal, options.signal);
80
+ try {
81
+ const loaded = await loadTexturesFromUrls(getUrls(), {
82
+ ...options,
83
+ signal: mergedSignal.signal
84
+ });
85
+ if (disposed || version !== requestVersion) {
86
+ disposeTextures(loaded);
87
+ return;
88
+ }
89
+ textures.set(loaded);
90
+ disposeTextures(previous);
91
+ }
92
+ catch (nextError) {
93
+ if (disposed || version !== requestVersion) {
94
+ return;
95
+ }
96
+ if (isAbortError(nextError)) {
97
+ return;
98
+ }
99
+ disposeTextures(previous);
100
+ textures.set(null);
101
+ error.set(toError(nextError));
102
+ }
103
+ finally {
104
+ if (!disposed && version === requestVersion) {
105
+ loading.set(false);
106
+ }
107
+ if (activeController === controller) {
108
+ activeController = null;
109
+ }
110
+ mergedSignal.dispose();
111
+ }
112
+ };
113
+ const runLoadLoop = async () => {
114
+ do {
115
+ reloadQueued = false;
116
+ await executeLoad();
117
+ } while (reloadQueued && !disposed);
118
+ };
119
+ const load = () => {
120
+ activeController?.abort();
121
+ if (runningLoad) {
122
+ reloadQueued = true;
123
+ return runningLoad;
124
+ }
125
+ const pending = runLoadLoop();
126
+ const trackedPending = pending.finally(() => {
127
+ if (runningLoad === trackedPending) {
128
+ runningLoad = null;
129
+ }
130
+ });
131
+ runningLoad = trackedPending;
132
+ return trackedPending;
133
+ };
134
+ void load();
135
+ onDestroy(() => {
136
+ disposed = true;
137
+ requestVersion += 1;
138
+ activeController?.abort();
139
+ disposeTextures(textures.current);
140
+ });
141
+ return {
142
+ textures,
143
+ loading,
144
+ error,
145
+ reload: load
146
+ };
147
+ }
package/package.json ADDED
@@ -0,0 +1,94 @@
1
+ {
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.",
5
+ "keywords": [
6
+ "svelte",
7
+ "svelte5",
8
+ "webgpu",
9
+ "wgsl",
10
+ "shader",
11
+ "graphics",
12
+ "gpu",
13
+ "postprocessing"
14
+ ],
15
+ "homepage": "https://github.com/Motion-Core/motion-gpu/tree/master/packages/motion-gpu#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/Motion-Core/motion-gpu/issues"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/Motion-Core/motion-gpu.git",
22
+ "directory": "packages/motion-gpu"
23
+ },
24
+ "license": "MIT",
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "type": "module",
29
+ "svelte": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "svelte": "./dist/index.js",
35
+ "default": "./dist/index.js"
36
+ },
37
+ "./advanced": {
38
+ "types": "./dist/advanced.d.ts",
39
+ "svelte": "./dist/advanced.js",
40
+ "default": "./dist/advanced.js"
41
+ }
42
+ },
43
+ "files": [
44
+ "dist"
45
+ ],
46
+ "scripts": {
47
+ "build": "svelte-package -i src/lib -o dist",
48
+ "prepack": "bun run build",
49
+ "check": "svelte-check --tsconfig ./tsconfig.json && publint",
50
+ "test": "vitest run",
51
+ "test:coverage": "vitest run --coverage",
52
+ "test:watch": "vitest",
53
+ "test:e2e": "playwright test",
54
+ "test:e2e:headed": "playwright test --headed",
55
+ "e2e:serve": "vite --config e2e/vite.config.ts",
56
+ "perf:core": "bun run ./scripts/perf/core-benchmark.ts",
57
+ "perf:core:check": "bun run ./scripts/perf/core-benchmark.ts --strict",
58
+ "perf:core:baseline": "bun run ./scripts/perf/core-benchmark.ts --update-baseline",
59
+ "perf:runtime": "bun run ./scripts/perf/runtime-benchmark.ts",
60
+ "perf:runtime:check": "bun run ./scripts/perf/runtime-benchmark.ts --strict",
61
+ "perf:runtime:baseline": "bun run ./scripts/perf/runtime-benchmark.ts --update-baseline",
62
+ "lint": "prettier --check . && eslint .",
63
+ "format": "prettier --write ."
64
+ },
65
+ "peerDependencies": {
66
+ "svelte": "^5.0.0"
67
+ },
68
+ "devDependencies": {
69
+ "@eslint/compat": "^2.0.2",
70
+ "@eslint/js": "^10.0.1",
71
+ "@playwright/test": "^1.58.2",
72
+ "@sveltejs/package": "^2.5.0",
73
+ "@sveltejs/vite-plugin-svelte": "^6.2.4",
74
+ "@testing-library/svelte": "^5.2.8",
75
+ "@vitest/coverage-v8": "^4.0.18",
76
+ "@types/node": "^25.3.3",
77
+ "@webgpu/types": "^0.1.66",
78
+ "eslint": "^10.0.2",
79
+ "eslint-config-prettier": "^10.1.8",
80
+ "eslint-plugin-svelte": "^3.14.0",
81
+ "globals": "^17.3.0",
82
+ "happy-dom": "^20.0.10",
83
+ "prettier": "^3.8.1",
84
+ "prettier-plugin-svelte": "^3.4.1",
85
+ "prettier-plugin-tailwindcss": "^0.7.2",
86
+ "publint": "^0.3.15",
87
+ "svelte": "^5.51.0",
88
+ "svelte-check": "^4.3.6",
89
+ "typescript": "^5.9.3",
90
+ "typescript-eslint": "^8.54.0",
91
+ "vite": "^7.3.1",
92
+ "vitest": "^4.0.18"
93
+ }
94
+ }