@motion-core/motion-gpu 0.7.0 → 0.8.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/README.md +40 -34
  2. package/dist/motion-gpu.css +295 -0
  3. package/dist/vue/FragCanvas.js +8 -0
  4. package/dist/vue/FragCanvas.js.map +1 -0
  5. package/dist/vue/FragCanvas.vue.d.ts +49 -0
  6. package/dist/vue/FragCanvas.vue.d.ts.map +1 -0
  7. package/dist/vue/FragCanvas.vue_vue_type_script_setup_true_lang.js +228 -0
  8. package/dist/vue/FragCanvas.vue_vue_type_script_setup_true_lang.js.map +1 -0
  9. package/dist/vue/MotionGPUErrorOverlay.js +8 -0
  10. package/dist/vue/MotionGPUErrorOverlay.js.map +1 -0
  11. package/dist/vue/MotionGPUErrorOverlay.vue.d.ts +8 -0
  12. package/dist/vue/MotionGPUErrorOverlay.vue.d.ts.map +1 -0
  13. package/dist/vue/MotionGPUErrorOverlay.vue_vue_type_script_setup_true_lang.js +166 -0
  14. package/dist/vue/MotionGPUErrorOverlay.vue_vue_type_script_setup_true_lang.js.map +1 -0
  15. package/dist/vue/Portal.js +7 -0
  16. package/dist/vue/Portal.js.map +1 -0
  17. package/dist/vue/Portal.vue.d.ts +18 -0
  18. package/dist/vue/Portal.vue.d.ts.map +1 -0
  19. package/dist/vue/Portal.vue_vue_type_script_setup_true_lang.js +29 -0
  20. package/dist/vue/Portal.vue_vue_type_script_setup_true_lang.js.map +1 -0
  21. package/dist/vue/advanced.d.ts +12 -0
  22. package/dist/vue/advanced.d.ts.map +1 -0
  23. package/dist/vue/advanced.js +15 -0
  24. package/dist/vue/frame-context.d.ts +22 -0
  25. package/dist/vue/frame-context.d.ts.map +1 -0
  26. package/dist/vue/frame-context.js +38 -0
  27. package/dist/vue/frame-context.js.map +1 -0
  28. package/dist/vue/index.d.ts +21 -0
  29. package/dist/vue/index.d.ts.map +1 -0
  30. package/dist/vue/index.js +14 -0
  31. package/dist/vue/motiongpu-context.d.ts +81 -0
  32. package/dist/vue/motiongpu-context.d.ts.map +1 -0
  33. package/dist/vue/motiongpu-context.js +29 -0
  34. package/dist/vue/motiongpu-context.js.map +1 -0
  35. package/dist/vue/shims-vue.d.js +0 -0
  36. package/dist/vue/use-motiongpu-user-context.d.ts +44 -0
  37. package/dist/vue/use-motiongpu-user-context.d.ts.map +1 -0
  38. package/dist/vue/use-motiongpu-user-context.js +76 -0
  39. package/dist/vue/use-motiongpu-user-context.js.map +1 -0
  40. package/dist/vue/use-pointer.d.ts +94 -0
  41. package/dist/vue/use-pointer.d.ts.map +1 -0
  42. package/dist/vue/use-pointer.js +298 -0
  43. package/dist/vue/use-pointer.js.map +1 -0
  44. package/dist/vue/use-texture.d.ts +45 -0
  45. package/dist/vue/use-texture.d.ts.map +1 -0
  46. package/dist/vue/use-texture.js +135 -0
  47. package/dist/vue/use-texture.js.map +1 -0
  48. package/package.json +25 -7
  49. package/src/lib/vue/FragCanvas.vue +294 -0
  50. package/src/lib/vue/MotionGPUErrorOverlay.vue +518 -0
  51. package/src/lib/vue/Portal.vue +46 -0
  52. package/src/lib/vue/advanced.ts +32 -0
  53. package/src/lib/vue/frame-context.ts +96 -0
  54. package/src/lib/vue/index.ts +78 -0
  55. package/src/lib/vue/motiongpu-context.ts +97 -0
  56. package/src/lib/vue/shims-vue.d.ts +6 -0
  57. package/src/lib/vue/use-motiongpu-user-context.ts +145 -0
  58. package/src/lib/vue/use-pointer.ts +514 -0
  59. package/src/lib/vue/use-texture.ts +232 -0
@@ -0,0 +1,294 @@
1
+ <script lang="ts">
2
+ import type { MotionGPUErrorReport } from '../core/error-report.js';
3
+ import type { FragMaterial } from '../core/material.js';
4
+ import type {
5
+ AnyPass,
6
+ OutputColorSpace,
7
+ RenderMode,
8
+ RenderTargetDefinitionMap
9
+ } from '../core/types.js';
10
+
11
+ export interface FragCanvasProps {
12
+ material: FragMaterial;
13
+ renderTargets?: RenderTargetDefinitionMap;
14
+ passes?: AnyPass[];
15
+ clearColor?: [number, number, number, number];
16
+ outputColorSpace?: OutputColorSpace;
17
+ renderMode?: RenderMode;
18
+ autoRender?: boolean;
19
+ maxDelta?: number;
20
+ adapterOptions?: GPURequestAdapterOptions;
21
+ deviceDescriptor?: GPUDeviceDescriptor;
22
+ dpr?: number;
23
+ showErrorOverlay?: boolean;
24
+ onError?: (report: MotionGPUErrorReport) => void;
25
+ errorHistoryLimit?: number;
26
+ onErrorHistory?: (history: MotionGPUErrorReport[]) => void;
27
+ canvasClass?: string;
28
+ canvasStyle?: string | Record<string, string | number>;
29
+ }
30
+
31
+ const initialDpr = typeof window === 'undefined' ? 1 : (window.devicePixelRatio ?? 1);
32
+ </script>
33
+
34
+ <script setup lang="ts">
35
+ import { computed, onBeforeUnmount, onMounted, shallowRef, useTemplateRef, watch } from 'vue';
36
+ import { createCurrentWritable as currentWritable } from '../core/current-value.js';
37
+ import { toMotionGPUErrorReport } from '../core/error-report.js';
38
+ import { createFrameRegistry } from '../core/frame-registry.js';
39
+ import { createMotionGPURuntimeLoop } from '../core/runtime-loop.js';
40
+ import { provideFrameRegistry } from './frame-context.js';
41
+ import { provideMotionGPUContext } from './motiongpu-context.js';
42
+ import MotionGPUErrorOverlay from './MotionGPUErrorOverlay.vue';
43
+
44
+ const props = withDefaults(defineProps<FragCanvasProps>(), {
45
+ renderTargets: () => ({}),
46
+ passes: () => [],
47
+ clearColor: () => [0, 0, 0, 1] as [number, number, number, number],
48
+ outputColorSpace: 'srgb',
49
+ renderMode: 'always',
50
+ autoRender: true,
51
+ maxDelta: 0.1,
52
+ dpr: () => initialDpr,
53
+ showErrorOverlay: true,
54
+ errorHistoryLimit: 0,
55
+ canvasClass: ''
56
+ });
57
+
58
+ const wrapperStyle = Object.freeze({
59
+ position: 'relative',
60
+ width: '100%',
61
+ height: '100%',
62
+ minWidth: '0',
63
+ minHeight: '0',
64
+ overflow: 'hidden'
65
+ });
66
+
67
+ const baseCanvasStyle = Object.freeze({
68
+ position: 'absolute',
69
+ inset: '0',
70
+ display: 'block',
71
+ width: '100%',
72
+ height: '100%'
73
+ });
74
+
75
+ const resolvedCanvasStyle = computed(() => [baseCanvasStyle, props.canvasStyle]);
76
+
77
+ defineSlots<{
78
+ default(): unknown;
79
+ errorRenderer(props: { report: MotionGPUErrorReport }): unknown;
80
+ }>();
81
+
82
+ const canvasRef = useTemplateRef<HTMLCanvasElement>('canvasEl');
83
+ const errorReport = shallowRef<MotionGPUErrorReport | null>(null);
84
+ const errorHistory = shallowRef<MotionGPUErrorReport[]>([]);
85
+
86
+ const registry = createFrameRegistry({ maxDelta: 0.1 });
87
+ provideFrameRegistry(registry);
88
+
89
+ let requestFrameSignal: (() => void) | null = null;
90
+ let runtimeLoopHandle: ReturnType<typeof createMotionGPURuntimeLoop> | null = null;
91
+ const requestFrame = (): void => {
92
+ requestFrameSignal?.();
93
+ };
94
+ const invalidateFrame = (): void => {
95
+ registry.invalidate();
96
+ requestFrame();
97
+ };
98
+ const advanceFrame = (): void => {
99
+ registry.advance();
100
+ requestFrame();
101
+ };
102
+
103
+ const size = currentWritable({ width: 0, height: 0 });
104
+ const dprState = currentWritable<number>(initialDpr, requestFrame);
105
+ const maxDeltaState = currentWritable<number>(0.1, (value) => {
106
+ registry.setMaxDelta(value);
107
+ requestFrame();
108
+ });
109
+ const renderModeState = currentWritable<RenderMode>('always', (value) => {
110
+ registry.setRenderMode(value);
111
+ requestFrame();
112
+ });
113
+ const autoRenderState = currentWritable<boolean>(true, (value) => {
114
+ registry.setAutoRender(value);
115
+ requestFrame();
116
+ });
117
+ const userState = currentWritable<Record<string | symbol, unknown>>({});
118
+
119
+ provideMotionGPUContext({
120
+ get canvas() {
121
+ return canvasRef.value ?? undefined;
122
+ },
123
+ size,
124
+ dpr: dprState,
125
+ maxDelta: maxDeltaState,
126
+ renderMode: renderModeState,
127
+ autoRender: autoRenderState,
128
+ user: userState,
129
+ invalidate: invalidateFrame,
130
+ advance: advanceFrame,
131
+ scheduler: {
132
+ createStage: registry.createStage,
133
+ getStage: registry.getStage,
134
+ setDiagnosticsEnabled: registry.setDiagnosticsEnabled,
135
+ getDiagnosticsEnabled: registry.getDiagnosticsEnabled,
136
+ getLastRunTimings: registry.getLastRunTimings,
137
+ getSchedule: registry.getSchedule,
138
+ setProfilingEnabled: registry.setProfilingEnabled,
139
+ setProfilingWindow: registry.setProfilingWindow,
140
+ resetProfiling: registry.resetProfiling,
141
+ getProfilingEnabled: registry.getProfilingEnabled,
142
+ getProfilingWindow: registry.getProfilingWindow,
143
+ getProfilingSnapshot: registry.getProfilingSnapshot
144
+ }
145
+ });
146
+
147
+ /**
148
+ * Normalizes the user-supplied error history limit to a non-negative integer.
149
+ */
150
+ function getNormalizedErrorHistoryLimit(value: number): number {
151
+ if (!Number.isFinite(value) || value <= 0) {
152
+ return 0;
153
+ }
154
+
155
+ return Math.floor(value);
156
+ }
157
+
158
+ watch(
159
+ () => props.renderMode,
160
+ (value) => {
161
+ renderModeState.set(value);
162
+ }
163
+ );
164
+
165
+ watch(
166
+ () => props.autoRender,
167
+ (value) => {
168
+ autoRenderState.set(value);
169
+ }
170
+ );
171
+
172
+ watch(
173
+ () => props.maxDelta,
174
+ (value) => {
175
+ maxDeltaState.set(value);
176
+ }
177
+ );
178
+
179
+ watch(
180
+ () => props.dpr,
181
+ (value) => {
182
+ dprState.set(value);
183
+ }
184
+ );
185
+
186
+ watch([() => errorHistory.value, () => props.errorHistoryLimit], ([history, rawLimit]) => {
187
+ const limit = getNormalizedErrorHistoryLimit(rawLimit);
188
+ if (limit <= 0) {
189
+ if (history.length === 0) {
190
+ return;
191
+ }
192
+ errorHistory.value = [];
193
+ props.onErrorHistory?.([]);
194
+ return;
195
+ }
196
+
197
+ if (history.length <= limit) {
198
+ return;
199
+ }
200
+
201
+ const trimmed = history.slice(history.length - limit);
202
+ errorHistory.value = trimmed;
203
+ props.onErrorHistory?.(trimmed);
204
+ });
205
+
206
+ onMounted(() => {
207
+ renderModeState.set(props.renderMode);
208
+ autoRenderState.set(props.autoRender);
209
+ maxDeltaState.set(props.maxDelta);
210
+ dprState.set(props.dpr);
211
+ requestFrame();
212
+
213
+ const canvas = canvasRef.value;
214
+ if (!canvas) {
215
+ const report = toMotionGPUErrorReport(
216
+ new Error('Canvas element is not available'),
217
+ 'initialization'
218
+ );
219
+ errorReport.value = report;
220
+ const historyLimit = getNormalizedErrorHistoryLimit(props.errorHistoryLimit);
221
+ if (historyLimit > 0) {
222
+ const nextHistory = [report].slice(-historyLimit);
223
+ errorHistory.value = nextHistory;
224
+ props.onErrorHistory?.(nextHistory);
225
+ }
226
+ props.onError?.(report);
227
+ return;
228
+ }
229
+
230
+ const runtimeLoop = createMotionGPURuntimeLoop({
231
+ canvas,
232
+ registry,
233
+ size,
234
+ dpr: dprState,
235
+ maxDelta: maxDeltaState,
236
+ getMaterial: () => props.material,
237
+ getRenderTargets: () => props.renderTargets,
238
+ getPasses: () => props.passes,
239
+ getClearColor: () => props.clearColor,
240
+ getOutputColorSpace: () => props.outputColorSpace,
241
+ getAdapterOptions: () => props.adapterOptions,
242
+ getDeviceDescriptor: () => props.deviceDescriptor,
243
+ getOnError: () => props.onError,
244
+ getErrorHistoryLimit: () => props.errorHistoryLimit,
245
+ getOnErrorHistory: () => props.onErrorHistory,
246
+ reportErrorHistory: (history) => {
247
+ errorHistory.value = history;
248
+ },
249
+ reportError: (report) => {
250
+ errorReport.value = report;
251
+ }
252
+ });
253
+ runtimeLoopHandle = runtimeLoop;
254
+ requestFrameSignal = runtimeLoop.requestFrame;
255
+ });
256
+
257
+ onBeforeUnmount(() => {
258
+ requestFrameSignal = null;
259
+ runtimeLoopHandle?.destroy();
260
+ runtimeLoopHandle = null;
261
+ registry.clear();
262
+ });
263
+ </script>
264
+
265
+ <template>
266
+ <div class="motiongpu-canvas-wrap" :style="wrapperStyle">
267
+ <canvas ref="canvasEl" :class="canvasClass" :style="resolvedCanvasStyle"></canvas>
268
+ <template v-if="showErrorOverlay && errorReport">
269
+ <slot name="errorRenderer" :report="errorReport">
270
+ <MotionGPUErrorOverlay :report="errorReport" />
271
+ </slot>
272
+ </template>
273
+ <slot />
274
+ </div>
275
+ </template>
276
+
277
+ <style>
278
+ .motiongpu-canvas-wrap {
279
+ position: relative;
280
+ width: 100%;
281
+ height: 100%;
282
+ min-width: 0;
283
+ min-height: 0;
284
+ overflow: hidden;
285
+ }
286
+
287
+ .motiongpu-canvas-wrap > canvas {
288
+ position: absolute;
289
+ inset: 0;
290
+ display: block;
291
+ width: 100%;
292
+ height: 100%;
293
+ }
294
+ </style>