@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,392 @@
1
+ import type { MotionGPUErrorReport } from '../core/error-report.js';
2
+ import { Portal } from './Portal.js';
3
+
4
+ interface MotionGPUErrorOverlayProps {
5
+ report: MotionGPUErrorReport;
6
+ }
7
+
8
+ const MOTIONGPU_ERROR_OVERLAY_STYLES = `
9
+ .motiongpu-error-overlay {
10
+ --motiongpu-base-hue: var(--base-hue, 265);
11
+ --motiongpu-color-background: oklch(0.2178 0.0056 var(--motiongpu-base-hue));
12
+ --motiongpu-color-background-muted: oklch(0.261 0.007 var(--motiongpu-base-hue));
13
+ --motiongpu-color-foreground: oklch(1 0 0);
14
+ --motiongpu-color-foreground-muted: oklch(0.6699 0.0081 var(--motiongpu-base-hue));
15
+ --motiongpu-color-card: var(--motiongpu-color-background);
16
+ --motiongpu-color-accent: oklch(0.6996 0.181959 44.4414);
17
+ --motiongpu-color-accent-secondary: oklch(0.5096 0.131959 44.4414);
18
+ --motiongpu-color-border: oklch(0.928 0.013 var(--motiongpu-base-hue) / 0.05);
19
+ --motiongpu-color-white-fixed: oklch(1 0 0);
20
+ --motiongpu-shadow-card: var(
21
+ --shadow-2xl,
22
+ 0px 1px 1px -0.5px rgba(0, 0, 0, 0.06),
23
+ 0px 3px 3px -1.5px rgba(0, 0, 0, 0.06),
24
+ 0px 6px 6px -3px rgba(0, 0, 0, 0.06),
25
+ 0px 12px 12px -6px rgba(0, 0, 0, 0.06),
26
+ 0px 24px 24px -12px rgba(0, 0, 0, 0.05),
27
+ 0px 48px 48px -24px rgba(0, 0, 0, 0.06)
28
+ );
29
+ --motiongpu-radius-md: var(--radius-md, 0.5rem);
30
+ --motiongpu-radius-lg: var(--radius-lg, 0.75rem);
31
+ --motiongpu-radius-xl: var(--radius-xl, 1rem);
32
+ --motiongpu-font-sans: var(
33
+ --font-sans,
34
+ 'Inter',
35
+ 'Segoe UI',
36
+ 'Helvetica Neue',
37
+ Arial,
38
+ sans-serif
39
+ );
40
+ --motiongpu-font-mono: var(--font-mono, 'SFMono-Regular', 'Menlo', 'Consolas', monospace);
41
+ position: fixed;
42
+ inset: 0;
43
+ display: grid;
44
+ place-items: center;
45
+ padding: clamp(0.75rem, 1.4vw, 1.5rem);
46
+ background: rgba(0, 0, 0, 0.8);
47
+ backdrop-filter: blur(10px);
48
+ z-index: 2147483647;
49
+ font-family: var(--motiongpu-font-sans);
50
+ color-scheme: dark;
51
+ }
52
+
53
+ .motiongpu-error-dialog {
54
+ width: min(52rem, calc(100vw - 1.5rem));
55
+ max-height: min(84vh, 44rem);
56
+ overflow: auto;
57
+ margin: 0;
58
+ padding: 1.1rem;
59
+ border: 1px solid var(--motiongpu-color-border);
60
+ border-radius: var(--motiongpu-radius-xl);
61
+ max-width: calc(100vw - 1.5rem);
62
+ box-sizing: border-box;
63
+ font-size: 0.875rem;
64
+ font-weight: 400;
65
+ line-height: 1.45;
66
+ background: var(--motiongpu-color-card);
67
+ color: var(--motiongpu-color-foreground);
68
+ box-shadow: var(--motiongpu-shadow-card);
69
+ }
70
+
71
+ .motiongpu-error-header {
72
+ display: grid;
73
+ gap: 0.55rem;
74
+ padding-bottom: 0.9rem;
75
+ border-bottom: 1px solid var(--motiongpu-color-border);
76
+ }
77
+
78
+ .motiongpu-error-badge-wrap {
79
+ display: inline-flex;
80
+ align-items: center;
81
+ gap: 0.4rem;
82
+ width: fit-content;
83
+ padding: 0.18rem;
84
+ border-radius: 999px;
85
+ border: 1px solid var(--motiongpu-color-border);
86
+ background: var(--motiongpu-color-background-muted);
87
+ }
88
+
89
+ .motiongpu-error-phase {
90
+ display: inline-flex;
91
+ align-items: center;
92
+ margin: 0;
93
+ padding: 0.22rem 0.56rem;
94
+ border-radius: 999px;
95
+ font-size: 0.66rem;
96
+ letter-spacing: 0.08em;
97
+ line-height: 1;
98
+ font-weight: 500;
99
+ text-transform: uppercase;
100
+ color: var(--motiongpu-color-white-fixed);
101
+ background: linear-gradient(
102
+ 180deg,
103
+ var(--motiongpu-color-accent) 0%,
104
+ var(--motiongpu-color-accent-secondary) 100%
105
+ );
106
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.24);
107
+ }
108
+
109
+ .motiongpu-error-title {
110
+ margin: 0;
111
+ font-size: clamp(1.02rem, 1vw + 0.72rem, 1.32rem);
112
+ font-weight: 500;
113
+ line-height: 1.18;
114
+ letter-spacing: -0.02em;
115
+ text-wrap: balance;
116
+ color: var(--motiongpu-color-foreground);
117
+ }
118
+
119
+ .motiongpu-error-body {
120
+ display: grid;
121
+ gap: 0.62rem;
122
+ margin-top: 0.92rem;
123
+ }
124
+
125
+ .motiongpu-error-message {
126
+ margin: 0;
127
+ padding: 0.72rem 0.78rem;
128
+ border: 1px solid color-mix(in oklch, var(--motiongpu-color-accent) 28%, transparent);
129
+ border-radius: var(--motiongpu-radius-md);
130
+ background: color-mix(in oklch, var(--motiongpu-color-accent) 10%, transparent);
131
+ font-size: 0.82rem;
132
+ line-height: 1.4;
133
+ font-weight: 400;
134
+ color: var(--motiongpu-color-foreground);
135
+ }
136
+
137
+ .motiongpu-error-hint {
138
+ margin: 0;
139
+ font-size: 0.82rem;
140
+ line-height: 1.45;
141
+ font-weight: 400;
142
+ color: var(--motiongpu-color-foreground-muted);
143
+ }
144
+
145
+ .motiongpu-error-sections {
146
+ display: grid;
147
+ gap: 0.62rem;
148
+ margin-top: 0.95rem;
149
+ }
150
+
151
+ .motiongpu-error-source {
152
+ display: grid;
153
+ gap: 0.48rem;
154
+ margin-top: 0.96rem;
155
+ }
156
+
157
+ .motiongpu-error-source-title {
158
+ margin: 0;
159
+ font-size: 0.8rem;
160
+ font-weight: 500;
161
+ line-height: 1.3;
162
+ letter-spacing: 0.045em;
163
+ text-transform: uppercase;
164
+ color: var(--motiongpu-color-foreground);
165
+ }
166
+
167
+ .motiongpu-error-source-frame {
168
+ border: 1px solid var(--motiongpu-color-border);
169
+ border-radius: var(--motiongpu-radius-lg);
170
+ overflow: hidden;
171
+ background: var(--motiongpu-color-background-muted);
172
+ }
173
+
174
+ .motiongpu-error-source-tabs {
175
+ display: flex;
176
+ align-items: stretch;
177
+ border-bottom: 1px solid var(--motiongpu-color-border);
178
+ background: var(--motiongpu-color-background);
179
+ }
180
+
181
+ .motiongpu-error-source-tab {
182
+ display: inline-flex;
183
+ align-items: center;
184
+ padding: 0.5rem 0.68rem;
185
+ font-size: 0.76rem;
186
+ font-weight: 400;
187
+ line-height: 1.2;
188
+ color: var(--motiongpu-color-foreground-muted);
189
+ border-right: 1px solid var(--motiongpu-color-border);
190
+ }
191
+
192
+ .motiongpu-error-source-tab-active {
193
+ color: var(--motiongpu-color-foreground);
194
+ background: var(--motiongpu-color-background-muted);
195
+ }
196
+
197
+ .motiongpu-error-source-tab-spacer {
198
+ flex: 1 1 auto;
199
+ }
200
+
201
+ .motiongpu-error-source-snippet {
202
+ display: grid;
203
+ background: var(--motiongpu-color-background-muted);
204
+ }
205
+
206
+ .motiongpu-error-source-row {
207
+ display: grid;
208
+ grid-template-columns: 2rem minmax(0, 1fr);
209
+ align-items: start;
210
+ gap: 0.42rem;
211
+ padding: 0.2rem 0.68rem;
212
+ }
213
+
214
+ .motiongpu-error-source-row-active {
215
+ background: color-mix(in oklch, var(--motiongpu-color-accent) 10%, transparent);
216
+ }
217
+
218
+ .motiongpu-error-source-line {
219
+ font-family: var(--motiongpu-font-mono);
220
+ font-size: 0.77rem;
221
+ font-weight: 400;
222
+ line-height: 1.3;
223
+ font-variant-numeric: tabular-nums;
224
+ font-feature-settings: 'tnum' 1;
225
+ border-right: 1px solid var(--motiongpu-color-border);
226
+ color: var(--motiongpu-color-foreground-muted);
227
+ text-align: left;
228
+ }
229
+
230
+ .motiongpu-error-source-code {
231
+ font-family: var(--motiongpu-font-mono);
232
+ font-size: 0.77rem;
233
+ font-weight: 400;
234
+ line-height: 1.3;
235
+ color: var(--motiongpu-color-foreground);
236
+ white-space: pre-wrap;
237
+ word-break: break-word;
238
+ }
239
+
240
+ .motiongpu-error-details {
241
+ border: 1px solid var(--motiongpu-color-border);
242
+ border-radius: var(--motiongpu-radius-lg);
243
+ overflow: hidden;
244
+ background: var(--motiongpu-color-background);
245
+ }
246
+
247
+ .motiongpu-error-details summary {
248
+ cursor: pointer;
249
+ padding: 0.56rem 0.68rem;
250
+ font-size: 0.7rem;
251
+ letter-spacing: 0.07em;
252
+ line-height: 1.2;
253
+ font-weight: 500;
254
+ text-transform: uppercase;
255
+ color: var(--motiongpu-color-foreground);
256
+ }
257
+
258
+ .motiongpu-error-details[open] summary {
259
+ border-bottom: 1px solid var(--motiongpu-color-border);
260
+ }
261
+
262
+ .motiongpu-error-details pre {
263
+ margin: 0;
264
+ padding: 0.62rem 0.68rem;
265
+ white-space: pre-wrap;
266
+ word-break: break-word;
267
+ overflow: auto;
268
+ background: var(--motiongpu-color-background-muted);
269
+ font-size: 0.74rem;
270
+ line-height: 1.4;
271
+ font-weight: 400;
272
+ color: var(--motiongpu-color-foreground);
273
+ font-family: var(--motiongpu-font-mono);
274
+ }
275
+
276
+ @media (max-width: 42rem) {
277
+ .motiongpu-error-overlay {
278
+ padding: 0.62rem;
279
+ }
280
+
281
+ .motiongpu-error-dialog {
282
+ padding: 0.85rem;
283
+ }
284
+
285
+ .motiongpu-error-title {
286
+ font-size: 1.02rem;
287
+ }
288
+ }
289
+
290
+ @media (prefers-reduced-motion: reduce) {
291
+ .motiongpu-error-overlay {
292
+ backdrop-filter: none;
293
+ }
294
+ }
295
+ `;
296
+
297
+ function normalizeErrorText(value: string): string {
298
+ return value
299
+ .trim()
300
+ .replace(/[.:!]+$/g, '')
301
+ .toLowerCase();
302
+ }
303
+
304
+ function shouldShowErrorMessage(value: MotionGPUErrorReport): boolean {
305
+ return normalizeErrorText(value.message) !== normalizeErrorText(value.title);
306
+ }
307
+
308
+ export function MotionGPUErrorOverlay({ report }: MotionGPUErrorOverlayProps) {
309
+ const detailsSummary = report.source ? 'Additional diagnostics' : 'Technical details';
310
+
311
+ return (
312
+ <Portal>
313
+ <style>{MOTIONGPU_ERROR_OVERLAY_STYLES}</style>
314
+ <div className="motiongpu-error-overlay" role="presentation">
315
+ <section
316
+ className="motiongpu-error-dialog"
317
+ role="alertdialog"
318
+ aria-live="assertive"
319
+ aria-modal="true"
320
+ data-testid="motiongpu-error"
321
+ >
322
+ <header className="motiongpu-error-header">
323
+ <div className="motiongpu-error-badge-wrap">
324
+ <p className="motiongpu-error-phase">{report.phase}</p>
325
+ </div>
326
+ <h2 className="motiongpu-error-title">{report.title}</h2>
327
+ </header>
328
+ <div className="motiongpu-error-body">
329
+ {shouldShowErrorMessage(report) ? (
330
+ <p className="motiongpu-error-message">{report.message}</p>
331
+ ) : null}
332
+ <p className="motiongpu-error-hint">{report.hint}</p>
333
+ </div>
334
+
335
+ {report.source ? (
336
+ <section className="motiongpu-error-source" aria-label="Source">
337
+ <h3 className="motiongpu-error-source-title">Source</h3>
338
+ <div className="motiongpu-error-source-frame" role="presentation">
339
+ <div
340
+ className="motiongpu-error-source-tabs"
341
+ role="tablist"
342
+ aria-label="Source files"
343
+ >
344
+ <span
345
+ className="motiongpu-error-source-tab motiongpu-error-source-tab-active"
346
+ role="tab"
347
+ aria-selected="true"
348
+ >
349
+ {report.source.location}
350
+ {report.source.column ? `, col ${report.source.column}` : ''}
351
+ </span>
352
+ <span className="motiongpu-error-source-tab-spacer" aria-hidden="true"></span>
353
+ </div>
354
+
355
+ <div className="motiongpu-error-source-snippet">
356
+ {report.source.snippet.map((snippetLine) => (
357
+ <div
358
+ key={`snippet-${snippetLine.number}`}
359
+ className={
360
+ snippetLine.highlight
361
+ ? 'motiongpu-error-source-row motiongpu-error-source-row-active'
362
+ : 'motiongpu-error-source-row'
363
+ }
364
+ >
365
+ <span className="motiongpu-error-source-line">{snippetLine.number}</span>
366
+ <span className="motiongpu-error-source-code">{snippetLine.code || ' '}</span>
367
+ </div>
368
+ ))}
369
+ </div>
370
+ </div>
371
+ </section>
372
+ ) : null}
373
+
374
+ <div className="motiongpu-error-sections">
375
+ {report.details.length > 0 ? (
376
+ <details className="motiongpu-error-details" open>
377
+ <summary>{detailsSummary}</summary>
378
+ <pre>{report.details.join('\n')}</pre>
379
+ </details>
380
+ ) : null}
381
+ {report.stack.length > 0 ? (
382
+ <details className="motiongpu-error-details">
383
+ <summary>Stack trace</summary>
384
+ <pre>{report.stack.join('\n')}</pre>
385
+ </details>
386
+ ) : null}
387
+ </div>
388
+ </section>
389
+ </div>
390
+ </Portal>
391
+ );
392
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * React adapter advanced entrypoint for MotionGPU.
3
+ */
4
+ export * from './index.js';
5
+ export { applySchedulerPreset, captureSchedulerDebugSnapshot } from '../core/scheduler-helpers.js';
6
+ export {
7
+ setMotionGPUUserContext,
8
+ useMotionGPUUserContext,
9
+ useSetMotionGPUUserContext
10
+ } from './use-motiongpu-user-context.js';
11
+ export type {
12
+ ApplySchedulerPresetOptions,
13
+ SchedulerDebugSnapshot,
14
+ SchedulerPreset,
15
+ SchedulerPresetConfig
16
+ } from '../core/scheduler-helpers.js';
17
+ export type { MotionGPUUserContext, MotionGPUUserNamespace } from './motiongpu-context.js';
18
+ export type {
19
+ FrameProfilingSnapshot,
20
+ FrameKey,
21
+ FrameTaskInvalidation,
22
+ FrameTaskInvalidationToken,
23
+ FrameRunTimings,
24
+ FrameScheduleSnapshot,
25
+ FrameStage,
26
+ FrameStageCallback,
27
+ FrameTimingStats,
28
+ FrameTask
29
+ } from '../core/frame-registry.js';
30
+ export type { SetMotionGPUUserContextOptions } from './use-motiongpu-user-context.js';
31
+ export type {
32
+ RenderPassContext,
33
+ RenderTarget,
34
+ UniformLayout,
35
+ UniformLayoutEntry
36
+ } from '../core/types.js';
@@ -0,0 +1,169 @@
1
+ import { createContext, useContext, useEffect, useRef } from 'react';
2
+ import { createCurrentWritable } from '../core/current-value.js';
3
+ import { useMotionGPU } from './motiongpu-context.js';
4
+ import type {
5
+ FrameCallback,
6
+ FrameKey,
7
+ FrameProfilingSnapshot,
8
+ FrameRegistry,
9
+ FrameRunTimings,
10
+ FrameScheduleSnapshot,
11
+ FrameStage,
12
+ FrameStageCallback,
13
+ FrameTask,
14
+ FrameTaskInvalidation,
15
+ FrameTaskInvalidationToken,
16
+ UseFrameOptions,
17
+ UseFrameResult
18
+ } from '../core/frame-registry.js';
19
+
20
+ /**
21
+ * Placeholder stage used before a frame task registration becomes available.
22
+ */
23
+ const PENDING_STAGE_KEY = Symbol('motiongpu-react-pending-stage');
24
+
25
+ /**
26
+ * React context container for the active frame registry.
27
+ */
28
+ export const FrameRegistryReactContext = createContext<FrameRegistry | null>(null);
29
+
30
+ export type {
31
+ FrameCallback,
32
+ FrameKey,
33
+ FrameProfilingSnapshot,
34
+ FrameRegistry,
35
+ FrameRunTimings,
36
+ FrameScheduleSnapshot,
37
+ FrameStage,
38
+ FrameStageCallback,
39
+ FrameTask,
40
+ FrameTaskInvalidation,
41
+ FrameTaskInvalidationToken,
42
+ UseFrameOptions,
43
+ UseFrameResult
44
+ };
45
+
46
+ /**
47
+ * Registers a frame callback using an auto-generated task key.
48
+ */
49
+ export function useFrame(callback: FrameCallback, options?: UseFrameOptions): UseFrameResult;
50
+
51
+ /**
52
+ * Registers a frame callback with an explicit task key.
53
+ */
54
+ export function useFrame(
55
+ key: FrameKey,
56
+ callback: FrameCallback,
57
+ options?: UseFrameOptions
58
+ ): UseFrameResult;
59
+
60
+ /**
61
+ * Registers a callback in the active frame registry and auto-unsubscribes on unmount.
62
+ *
63
+ * @param keyOrCallback - Task key or callback for auto-key registration.
64
+ * @param callbackOrOptions - Callback (keyed overload) or options (auto-key overload).
65
+ * @param maybeOptions - Optional registration options for keyed overload.
66
+ * Registration key/options are frozen on first render; subsequent renders do not re-register.
67
+ * @returns Registration control API with task, start/stop controls and started state.
68
+ * @throws {Error} When called outside `<FragCanvas>`.
69
+ * @throws {Error} When callback is missing in keyed overload.
70
+ */
71
+ export function useFrame(
72
+ keyOrCallback: FrameKey | FrameCallback,
73
+ callbackOrOptions?: FrameCallback | UseFrameOptions,
74
+ maybeOptions?: UseFrameOptions
75
+ ): UseFrameResult {
76
+ const registry = useContext(FrameRegistryReactContext);
77
+ if (!registry) {
78
+ throw new Error('useFrame must be used inside <FragCanvas>');
79
+ }
80
+ const motiongpu = useMotionGPU();
81
+
82
+ const resolved =
83
+ typeof keyOrCallback === 'function'
84
+ ? {
85
+ key: undefined,
86
+ callback: keyOrCallback,
87
+ options: callbackOrOptions as UseFrameOptions | undefined
88
+ }
89
+ : {
90
+ key: keyOrCallback,
91
+ callback: callbackOrOptions as FrameCallback,
92
+ options: maybeOptions
93
+ };
94
+ if (typeof resolved.callback !== 'function') {
95
+ throw new Error('useFrame requires a callback');
96
+ }
97
+
98
+ const callbackRef = useRef(resolved.callback);
99
+ callbackRef.current = resolved.callback;
100
+ const registrationConfigRef = useRef<{
101
+ key: FrameKey | undefined;
102
+ options: UseFrameOptions | undefined;
103
+ } | null>(null);
104
+ if (!registrationConfigRef.current) {
105
+ registrationConfigRef.current = {
106
+ key: resolved.key,
107
+ options: resolved.options
108
+ };
109
+ }
110
+ const registrationConfig = registrationConfigRef.current;
111
+
112
+ const registrationRef = useRef<{
113
+ task: FrameTask;
114
+ start: () => void;
115
+ stop: () => void;
116
+ started: UseFrameResult['started'];
117
+ unsubscribe: () => void;
118
+ } | null>(null);
119
+ const taskRef = useRef<FrameTask>({
120
+ key:
121
+ registrationConfig.key !== undefined
122
+ ? registrationConfig.key
123
+ : Symbol('motiongpu-react-pending-task-key'),
124
+ stage: PENDING_STAGE_KEY
125
+ });
126
+ const startedStoreRef = useRef(createCurrentWritable(false));
127
+ const startedStore = startedStoreRef.current;
128
+
129
+ useEffect(() => {
130
+ const wrappedCallback: FrameCallback = (state) => {
131
+ callbackRef.current(state);
132
+ };
133
+ const registration =
134
+ registrationConfig.key === undefined
135
+ ? registry.register(wrappedCallback, registrationConfig.options)
136
+ : registry.register(registrationConfig.key, wrappedCallback, registrationConfig.options);
137
+ registrationRef.current = registration;
138
+ taskRef.current = registration.task;
139
+ const unsubscribeStarted = registration.started.subscribe((value) => {
140
+ startedStore.set(value);
141
+ });
142
+
143
+ return () => {
144
+ unsubscribeStarted();
145
+ registration.unsubscribe();
146
+ if (registrationRef.current === registration) {
147
+ registrationRef.current = null;
148
+ }
149
+ startedStore.set(false);
150
+ };
151
+ }, [registrationConfig, registry, startedStore]);
152
+
153
+ useEffect(() => {
154
+ motiongpu.invalidate();
155
+ }, [motiongpu, resolved.callback]);
156
+
157
+ return {
158
+ get task() {
159
+ return taskRef.current;
160
+ },
161
+ start: () => {
162
+ registrationRef.current?.start();
163
+ },
164
+ stop: () => {
165
+ registrationRef.current?.stop();
166
+ },
167
+ started: startedStore
168
+ };
169
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * React adapter entrypoint for MotionGPU.
3
+ */
4
+ export { FragCanvas } from './FragCanvas.js';
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 {
11
+ FrameInvalidationToken,
12
+ FrameState,
13
+ OutputColorSpace,
14
+ RenderPass,
15
+ RenderPassContext,
16
+ RenderPassFlags,
17
+ RenderPassInputSlot,
18
+ RenderPassOutputSlot,
19
+ RenderMode,
20
+ RenderTarget,
21
+ RenderTargetDefinition,
22
+ RenderTargetDefinitionMap,
23
+ TextureData,
24
+ TextureDefinition,
25
+ TextureDefinitionMap,
26
+ TextureUpdateMode,
27
+ TextureMap,
28
+ TextureSource,
29
+ TextureValue,
30
+ TypedUniform,
31
+ UniformMat4Value,
32
+ UniformMap,
33
+ UniformType,
34
+ UniformValue
35
+ } from '../core/types.js';
36
+ export type {
37
+ LoadedTexture,
38
+ TextureDecodeOptions,
39
+ TextureLoadOptions
40
+ } from '../core/texture-loader.js';
41
+ export type {
42
+ FragMaterial,
43
+ FragMaterialInput,
44
+ MaterialIncludes,
45
+ MaterialDefineValue,
46
+ MaterialDefines,
47
+ TypedMaterialDefineValue
48
+ } from '../core/material.js';
49
+ export type { MotionGPUContext } from './motiongpu-context.js';
50
+ export type { UseFrameOptions, UseFrameResult } from './frame-context.js';
51
+ export type { TextureUrlInput, UseTextureResult } from './use-texture.js';