@motion-core/motion-gpu 0.4.1 → 0.5.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 (228) hide show
  1. package/README.md +99 -0
  2. package/dist/advanced.d.ts +1 -0
  3. package/dist/advanced.d.ts.map +1 -0
  4. package/dist/advanced.js +14 -6
  5. package/dist/core/advanced.d.ts +1 -0
  6. package/dist/core/advanced.d.ts.map +1 -0
  7. package/dist/core/advanced.js +14 -5
  8. package/dist/core/compute-shader.d.ts +87 -0
  9. package/dist/core/compute-shader.d.ts.map +1 -0
  10. package/dist/core/compute-shader.js +205 -0
  11. package/dist/core/compute-shader.js.map +1 -0
  12. package/dist/core/current-value.d.ts +1 -0
  13. package/dist/core/current-value.d.ts.map +1 -0
  14. package/dist/core/current-value.js +35 -34
  15. package/dist/core/current-value.js.map +1 -0
  16. package/dist/core/error-diagnostics.d.ts +1 -0
  17. package/dist/core/error-diagnostics.d.ts.map +1 -0
  18. package/dist/core/error-diagnostics.js +70 -137
  19. package/dist/core/error-diagnostics.js.map +1 -0
  20. package/dist/core/error-report.d.ts +2 -1
  21. package/dist/core/error-report.d.ts.map +1 -0
  22. package/dist/core/error-report.js +247 -233
  23. package/dist/core/error-report.js.map +1 -0
  24. package/dist/core/frame-registry.d.ts +1 -0
  25. package/dist/core/frame-registry.d.ts.map +1 -0
  26. package/dist/core/frame-registry.js +546 -662
  27. package/dist/core/frame-registry.js.map +1 -0
  28. package/dist/core/index.d.ts +6 -2
  29. package/dist/core/index.d.ts.map +1 -0
  30. package/dist/core/index.js +13 -12
  31. package/dist/core/material-preprocess.d.ts +1 -0
  32. package/dist/core/material-preprocess.d.ts.map +1 -0
  33. package/dist/core/material-preprocess.js +131 -152
  34. package/dist/core/material-preprocess.js.map +1 -0
  35. package/dist/core/material.d.ts +23 -6
  36. package/dist/core/material.d.ts.map +1 -0
  37. package/dist/core/material.js +290 -317
  38. package/dist/core/material.js.map +1 -0
  39. package/dist/core/recompile-policy.d.ts +1 -0
  40. package/dist/core/recompile-policy.d.ts.map +1 -0
  41. package/dist/core/recompile-policy.js +18 -13
  42. package/dist/core/recompile-policy.js.map +1 -0
  43. package/dist/core/render-graph.d.ts +8 -3
  44. package/dist/core/render-graph.d.ts.map +1 -0
  45. package/dist/core/render-graph.js +77 -68
  46. package/dist/core/render-graph.js.map +1 -0
  47. package/dist/core/render-targets.d.ts +1 -0
  48. package/dist/core/render-targets.d.ts.map +1 -0
  49. package/dist/core/render-targets.js +52 -53
  50. package/dist/core/render-targets.js.map +1 -0
  51. package/dist/core/renderer.d.ts +1 -0
  52. package/dist/core/renderer.d.ts.map +1 -0
  53. package/dist/core/renderer.js +1337 -1081
  54. package/dist/core/renderer.js.map +1 -0
  55. package/dist/core/runtime-loop.d.ts +3 -2
  56. package/dist/core/runtime-loop.d.ts.map +1 -0
  57. package/dist/core/runtime-loop.js +353 -362
  58. package/dist/core/runtime-loop.js.map +1 -0
  59. package/dist/core/scheduler-helpers.d.ts +1 -0
  60. package/dist/core/scheduler-helpers.d.ts.map +1 -0
  61. package/dist/core/scheduler-helpers.js +52 -51
  62. package/dist/core/scheduler-helpers.js.map +1 -0
  63. package/dist/core/shader.d.ts +10 -1
  64. package/dist/core/shader.d.ts.map +1 -0
  65. package/dist/core/shader.js +109 -115
  66. package/dist/core/shader.js.map +1 -0
  67. package/dist/core/storage-buffers.d.ts +37 -0
  68. package/dist/core/storage-buffers.d.ts.map +1 -0
  69. package/dist/core/storage-buffers.js +95 -0
  70. package/dist/core/storage-buffers.js.map +1 -0
  71. package/dist/core/texture-loader.d.ts +1 -0
  72. package/dist/core/texture-loader.d.ts.map +1 -0
  73. package/dist/core/texture-loader.js +209 -273
  74. package/dist/core/texture-loader.js.map +1 -0
  75. package/dist/core/textures.d.ts +13 -0
  76. package/dist/core/textures.d.ts.map +1 -0
  77. package/dist/core/textures.js +111 -116
  78. package/dist/core/textures.js.map +1 -0
  79. package/dist/core/types.d.ts +147 -4
  80. package/dist/core/types.d.ts.map +1 -0
  81. package/dist/core/types.js +0 -4
  82. package/dist/core/uniforms.d.ts +1 -0
  83. package/dist/core/uniforms.d.ts.map +1 -0
  84. package/dist/core/uniforms.js +170 -191
  85. package/dist/core/uniforms.js.map +1 -0
  86. package/dist/index.d.ts +1 -0
  87. package/dist/index.d.ts.map +1 -0
  88. package/dist/index.js +13 -6
  89. package/dist/passes/BlitPass.d.ts +1 -0
  90. package/dist/passes/BlitPass.d.ts.map +1 -0
  91. package/dist/passes/BlitPass.js +23 -18
  92. package/dist/passes/BlitPass.js.map +1 -0
  93. package/dist/passes/ComputePass.d.ts +83 -0
  94. package/dist/passes/ComputePass.d.ts.map +1 -0
  95. package/dist/passes/ComputePass.js +92 -0
  96. package/dist/passes/ComputePass.js.map +1 -0
  97. package/dist/passes/CopyPass.d.ts +1 -0
  98. package/dist/passes/CopyPass.d.ts.map +1 -0
  99. package/dist/passes/CopyPass.js +58 -52
  100. package/dist/passes/CopyPass.js.map +1 -0
  101. package/dist/passes/FullscreenPass.d.ts +1 -0
  102. package/dist/passes/FullscreenPass.d.ts.map +1 -0
  103. package/dist/passes/FullscreenPass.js +127 -130
  104. package/dist/passes/FullscreenPass.js.map +1 -0
  105. package/dist/passes/PingPongComputePass.d.ts +104 -0
  106. package/dist/passes/PingPongComputePass.d.ts.map +1 -0
  107. package/dist/passes/PingPongComputePass.js +132 -0
  108. package/dist/passes/PingPongComputePass.js.map +1 -0
  109. package/dist/passes/ShaderPass.d.ts +1 -0
  110. package/dist/passes/ShaderPass.d.ts.map +1 -0
  111. package/dist/passes/ShaderPass.js +41 -37
  112. package/dist/passes/ShaderPass.js.map +1 -0
  113. package/dist/passes/index.d.ts +3 -0
  114. package/dist/passes/index.d.ts.map +1 -0
  115. package/dist/passes/index.js +6 -3
  116. package/dist/react/FragCanvas.d.ts +3 -2
  117. package/dist/react/FragCanvas.d.ts.map +1 -0
  118. package/dist/react/FragCanvas.js +234 -211
  119. package/dist/react/FragCanvas.js.map +1 -0
  120. package/dist/react/MotionGPUErrorOverlay.d.ts +1 -0
  121. package/dist/react/MotionGPUErrorOverlay.d.ts.map +1 -0
  122. package/dist/react/MotionGPUErrorOverlay.js +200 -14
  123. package/dist/react/MotionGPUErrorOverlay.js.map +1 -0
  124. package/dist/react/Portal.d.ts +1 -0
  125. package/dist/react/Portal.d.ts.map +1 -0
  126. package/dist/react/Portal.js +18 -21
  127. package/dist/react/Portal.js.map +1 -0
  128. package/dist/react/advanced.d.ts +1 -0
  129. package/dist/react/advanced.d.ts.map +1 -0
  130. package/dist/react/advanced.js +14 -6
  131. package/dist/react/frame-context.d.ts +1 -0
  132. package/dist/react/frame-context.d.ts.map +1 -0
  133. package/dist/react/frame-context.js +88 -94
  134. package/dist/react/frame-context.js.map +1 -0
  135. package/dist/react/index.d.ts +6 -2
  136. package/dist/react/index.d.ts.map +1 -0
  137. package/dist/react/index.js +12 -9
  138. package/dist/react/motiongpu-context.d.ts +1 -0
  139. package/dist/react/motiongpu-context.d.ts.map +1 -0
  140. package/dist/react/motiongpu-context.js +18 -15
  141. package/dist/react/motiongpu-context.js.map +1 -0
  142. package/dist/react/use-motiongpu-user-context.d.ts +1 -0
  143. package/dist/react/use-motiongpu-user-context.d.ts.map +1 -0
  144. package/dist/react/use-motiongpu-user-context.js +83 -82
  145. package/dist/react/use-motiongpu-user-context.js.map +1 -0
  146. package/dist/react/use-texture.d.ts +1 -0
  147. package/dist/react/use-texture.d.ts.map +1 -0
  148. package/dist/react/use-texture.js +132 -152
  149. package/dist/react/use-texture.js.map +1 -0
  150. package/dist/svelte/FragCanvas.svelte +2 -2
  151. package/dist/svelte/FragCanvas.svelte.d.ts +3 -2
  152. package/dist/svelte/FragCanvas.svelte.d.ts.map +1 -0
  153. package/dist/svelte/MotionGPUErrorOverlay.svelte +137 -7
  154. package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts +1 -0
  155. package/dist/svelte/MotionGPUErrorOverlay.svelte.d.ts.map +1 -0
  156. package/dist/svelte/Portal.svelte.d.ts +1 -0
  157. package/dist/svelte/Portal.svelte.d.ts.map +1 -0
  158. package/dist/svelte/advanced.d.ts +1 -0
  159. package/dist/svelte/advanced.d.ts.map +1 -0
  160. package/dist/svelte/advanced.js +13 -6
  161. package/dist/svelte/frame-context.d.ts +1 -0
  162. package/dist/svelte/frame-context.d.ts.map +1 -0
  163. package/dist/svelte/frame-context.js +27 -27
  164. package/dist/svelte/frame-context.js.map +1 -0
  165. package/dist/svelte/index.d.ts +6 -2
  166. package/dist/svelte/index.d.ts.map +1 -0
  167. package/dist/svelte/index.js +12 -9
  168. package/dist/svelte/motiongpu-context.d.ts +1 -0
  169. package/dist/svelte/motiongpu-context.d.ts.map +1 -0
  170. package/dist/svelte/motiongpu-context.js +24 -21
  171. package/dist/svelte/motiongpu-context.js.map +1 -0
  172. package/dist/svelte/use-motiongpu-user-context.d.ts +1 -0
  173. package/dist/svelte/use-motiongpu-user-context.d.ts.map +1 -0
  174. package/dist/svelte/use-motiongpu-user-context.js +69 -70
  175. package/dist/svelte/use-motiongpu-user-context.js.map +1 -0
  176. package/dist/svelte/use-texture.d.ts +1 -0
  177. package/dist/svelte/use-texture.d.ts.map +1 -0
  178. package/dist/svelte/use-texture.js +125 -147
  179. package/dist/svelte/use-texture.js.map +1 -0
  180. package/package.json +12 -7
  181. package/src/lib/advanced.ts +6 -0
  182. package/src/lib/core/advanced.ts +12 -0
  183. package/src/lib/core/compute-shader.ts +326 -0
  184. package/src/lib/core/current-value.ts +64 -0
  185. package/src/lib/core/error-diagnostics.ts +236 -0
  186. package/src/lib/core/error-report.ts +535 -0
  187. package/src/lib/core/frame-registry.ts +1190 -0
  188. package/src/lib/core/index.ts +94 -0
  189. package/src/lib/core/material-preprocess.ts +295 -0
  190. package/src/lib/core/material.ts +748 -0
  191. package/src/lib/core/recompile-policy.ts +31 -0
  192. package/src/lib/core/render-graph.ts +173 -0
  193. package/src/lib/core/render-targets.ts +107 -0
  194. package/src/lib/core/renderer.ts +2161 -0
  195. package/src/lib/core/runtime-loop.ts +537 -0
  196. package/src/lib/core/scheduler-helpers.ts +136 -0
  197. package/src/lib/core/shader.ts +301 -0
  198. package/src/lib/core/storage-buffers.ts +142 -0
  199. package/src/lib/core/texture-loader.ts +482 -0
  200. package/src/lib/core/textures.ts +257 -0
  201. package/src/lib/core/types.ts +743 -0
  202. package/src/lib/core/uniforms.ts +282 -0
  203. package/src/lib/index.ts +6 -0
  204. package/src/lib/passes/BlitPass.ts +54 -0
  205. package/src/lib/passes/ComputePass.ts +136 -0
  206. package/src/lib/passes/CopyPass.ts +80 -0
  207. package/src/lib/passes/FullscreenPass.ts +173 -0
  208. package/src/lib/passes/PingPongComputePass.ts +180 -0
  209. package/src/lib/passes/ShaderPass.ts +89 -0
  210. package/src/lib/passes/index.ts +9 -0
  211. package/src/lib/react/FragCanvas.tsx +345 -0
  212. package/src/lib/react/MotionGPUErrorOverlay.tsx +524 -0
  213. package/src/lib/react/Portal.tsx +34 -0
  214. package/src/lib/react/advanced.ts +36 -0
  215. package/src/lib/react/frame-context.ts +169 -0
  216. package/src/lib/react/index.ts +68 -0
  217. package/src/lib/react/motiongpu-context.ts +88 -0
  218. package/src/lib/react/use-motiongpu-user-context.ts +186 -0
  219. package/src/lib/react/use-texture.ts +233 -0
  220. package/src/lib/svelte/FragCanvas.svelte +249 -0
  221. package/src/lib/svelte/MotionGPUErrorOverlay.svelte +512 -0
  222. package/src/lib/svelte/Portal.svelte +31 -0
  223. package/src/lib/svelte/advanced.ts +32 -0
  224. package/src/lib/svelte/frame-context.ts +87 -0
  225. package/src/lib/svelte/index.ts +68 -0
  226. package/src/lib/svelte/motiongpu-context.ts +97 -0
  227. package/src/lib/svelte/use-motiongpu-user-context.ts +145 -0
  228. package/src/lib/svelte/use-texture.ts +232 -0
@@ -0,0 +1,524 @@
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-header-top {
79
+ display: flex;
80
+ align-items: flex-start;
81
+ gap: 0.75rem;
82
+ }
83
+
84
+ .motiongpu-error-badges {
85
+ display: inline-flex;
86
+ align-items: center;
87
+ gap: 0.4rem;
88
+ flex-wrap: wrap;
89
+ }
90
+
91
+ .motiongpu-error-badge-wrap {
92
+ display: inline-flex;
93
+ align-items: center;
94
+ gap: 0.4rem;
95
+ width: fit-content;
96
+ padding: 0.18rem;
97
+ border-radius: 999px;
98
+ border: 1px solid var(--motiongpu-color-border);
99
+ background: var(--motiongpu-color-background-muted);
100
+ }
101
+
102
+ .motiongpu-error-badge {
103
+ display: inline-flex;
104
+ align-items: center;
105
+ margin: 0;
106
+ padding: 0.22rem 0.56rem;
107
+ border-radius: 999px;
108
+ font-size: 0.66rem;
109
+ letter-spacing: 0.08em;
110
+ line-height: 1;
111
+ font-weight: 500;
112
+ text-transform: uppercase;
113
+ color: var(--motiongpu-color-white-fixed);
114
+ background: linear-gradient(
115
+ 180deg,
116
+ var(--motiongpu-color-accent) 0%,
117
+ var(--motiongpu-color-accent-secondary) 100%
118
+ );
119
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.24);
120
+ }
121
+
122
+ .motiongpu-error-recoverable {
123
+ margin: 0;
124
+ font-size: 0.67rem;
125
+ line-height: 1.2;
126
+ letter-spacing: 0.06em;
127
+ text-transform: uppercase;
128
+ color: var(--motiongpu-color-foreground-muted);
129
+ }
130
+
131
+ .motiongpu-error-recoverable span {
132
+ font-family: var(--motiongpu-font-mono);
133
+ color: var(--motiongpu-color-foreground);
134
+ }
135
+
136
+ .motiongpu-error-title {
137
+ margin: 0;
138
+ font-size: clamp(1.02rem, 1vw + 0.72rem, 1.32rem);
139
+ font-weight: 500;
140
+ line-height: 1.18;
141
+ letter-spacing: -0.02em;
142
+ text-wrap: balance;
143
+ color: var(--motiongpu-color-foreground);
144
+ }
145
+
146
+ .motiongpu-error-body {
147
+ display: grid;
148
+ gap: 0.62rem;
149
+ margin-top: 0.92rem;
150
+ }
151
+
152
+ .motiongpu-error-message {
153
+ margin: 0;
154
+ padding: 0.72rem 0.78rem;
155
+ border: 1px solid color-mix(in oklch, var(--motiongpu-color-accent) 28%, transparent);
156
+ border-radius: var(--motiongpu-radius-md);
157
+ background: color-mix(in oklch, var(--motiongpu-color-accent) 10%, transparent);
158
+ font-size: 0.82rem;
159
+ line-height: 1.4;
160
+ font-weight: 400;
161
+ color: var(--motiongpu-color-foreground);
162
+ }
163
+
164
+ .motiongpu-error-hint {
165
+ margin: 0;
166
+ font-size: 0.82rem;
167
+ line-height: 1.45;
168
+ font-weight: 400;
169
+ color: var(--motiongpu-color-foreground-muted);
170
+ }
171
+
172
+ .motiongpu-error-sections {
173
+ display: grid;
174
+ gap: 0.62rem;
175
+ margin-top: 0.95rem;
176
+ }
177
+
178
+ .motiongpu-error-source {
179
+ display: grid;
180
+ gap: 0.48rem;
181
+ margin-top: 0.96rem;
182
+ }
183
+
184
+ .motiongpu-error-source-title {
185
+ margin: 0;
186
+ font-size: 0.8rem;
187
+ font-weight: 500;
188
+ line-height: 1.3;
189
+ letter-spacing: 0.045em;
190
+ text-transform: uppercase;
191
+ color: var(--motiongpu-color-foreground);
192
+ }
193
+
194
+ .motiongpu-error-source-frame {
195
+ border: 1px solid var(--motiongpu-color-border);
196
+ border-radius: var(--motiongpu-radius-lg);
197
+ overflow: hidden;
198
+ background: var(--motiongpu-color-background-muted);
199
+ }
200
+
201
+ .motiongpu-error-source-tabs {
202
+ display: flex;
203
+ align-items: stretch;
204
+ border-bottom: 1px solid var(--motiongpu-color-border);
205
+ background: var(--motiongpu-color-background);
206
+ }
207
+
208
+ .motiongpu-error-source-tab {
209
+ display: inline-flex;
210
+ align-items: center;
211
+ padding: 0.5rem 0.68rem;
212
+ font-size: 0.76rem;
213
+ font-weight: 400;
214
+ line-height: 1.2;
215
+ color: var(--motiongpu-color-foreground-muted);
216
+ border-right: 1px solid var(--motiongpu-color-border);
217
+ }
218
+
219
+ .motiongpu-error-source-tab-active {
220
+ color: var(--motiongpu-color-foreground);
221
+ background: var(--motiongpu-color-background-muted);
222
+ }
223
+
224
+ .motiongpu-error-source-tab-spacer {
225
+ flex: 1 1 auto;
226
+ }
227
+
228
+ .motiongpu-error-source-snippet {
229
+ display: grid;
230
+ background: var(--motiongpu-color-background-muted);
231
+ }
232
+
233
+ .motiongpu-error-source-row {
234
+ display: grid;
235
+ grid-template-columns: 2rem minmax(0, 1fr);
236
+ align-items: start;
237
+ gap: 0.42rem;
238
+ padding: 0.2rem 0.68rem;
239
+ }
240
+
241
+ .motiongpu-error-source-row-active {
242
+ background: color-mix(in oklch, var(--motiongpu-color-accent) 10%, transparent);
243
+ }
244
+
245
+ .motiongpu-error-source-line {
246
+ font-family: var(--motiongpu-font-mono);
247
+ font-size: 0.77rem;
248
+ font-weight: 400;
249
+ line-height: 1.3;
250
+ font-variant-numeric: tabular-nums;
251
+ font-feature-settings: 'tnum' 1;
252
+ border-right: 1px solid var(--motiongpu-color-border);
253
+ color: var(--motiongpu-color-foreground-muted);
254
+ text-align: left;
255
+ }
256
+
257
+ .motiongpu-error-source-code {
258
+ font-family: var(--motiongpu-font-mono);
259
+ font-size: 0.77rem;
260
+ font-weight: 400;
261
+ line-height: 1.3;
262
+ color: var(--motiongpu-color-foreground);
263
+ white-space: pre-wrap;
264
+ word-break: break-word;
265
+ }
266
+
267
+ .motiongpu-error-details {
268
+ border: 1px solid var(--motiongpu-color-border);
269
+ border-radius: var(--motiongpu-radius-lg);
270
+ overflow: hidden;
271
+ background: var(--motiongpu-color-background);
272
+ }
273
+
274
+ .motiongpu-error-details summary {
275
+ cursor: pointer;
276
+ padding: 0.56rem 0.68rem;
277
+ font-size: 0.7rem;
278
+ letter-spacing: 0.07em;
279
+ line-height: 1.2;
280
+ font-weight: 500;
281
+ text-transform: uppercase;
282
+ color: var(--motiongpu-color-foreground);
283
+ }
284
+
285
+ .motiongpu-error-details[open] summary {
286
+ border-bottom: 1px solid var(--motiongpu-color-border);
287
+ }
288
+
289
+ .motiongpu-error-details pre {
290
+ margin: 0;
291
+ padding: 0.62rem 0.68rem;
292
+ white-space: pre-wrap;
293
+ word-break: break-word;
294
+ overflow: auto;
295
+ background: var(--motiongpu-color-background-muted);
296
+ font-size: 0.74rem;
297
+ line-height: 1.4;
298
+ font-weight: 400;
299
+ color: var(--motiongpu-color-foreground);
300
+ font-family: var(--motiongpu-font-mono);
301
+ }
302
+
303
+ @media (max-width: 42rem) {
304
+ .motiongpu-error-overlay {
305
+ padding: 0.62rem;
306
+ }
307
+
308
+ .motiongpu-error-dialog {
309
+ padding: 0.85rem;
310
+ }
311
+
312
+ .motiongpu-error-title {
313
+ font-size: 1.02rem;
314
+ }
315
+
316
+ .motiongpu-error-header-top {
317
+ flex-direction: column;
318
+ align-items: flex-start;
319
+ }
320
+ }
321
+
322
+ @media (prefers-reduced-motion: reduce) {
323
+ .motiongpu-error-overlay {
324
+ backdrop-filter: none;
325
+ }
326
+ }
327
+ `;
328
+
329
+ function normalizeErrorText(value: string): string {
330
+ return value
331
+ .trim()
332
+ .replace(/[.:!]+$/g, '')
333
+ .toLowerCase();
334
+ }
335
+
336
+ function shouldShowErrorMessage(value: MotionGPUErrorReport): boolean {
337
+ return resolveDisplayMessage(value).length > 0;
338
+ }
339
+
340
+ function resolveDisplayMessage(value: MotionGPUErrorReport): string {
341
+ const rawMessage = value.message.trim();
342
+ if (rawMessage.length === 0) {
343
+ return '';
344
+ }
345
+
346
+ const normalizedMessage = normalizeErrorText(rawMessage);
347
+ const normalizedTitle = normalizeErrorText(value.title);
348
+ if (normalizedMessage === normalizedTitle) {
349
+ return '';
350
+ }
351
+
352
+ const escapedTitle = value.title.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
353
+ const prefixPattern = new RegExp(`^${escapedTitle}\\s*[:\\-|]\\s*`, 'i');
354
+ const stripped = rawMessage.replace(prefixPattern, '').trim();
355
+ return stripped.length > 0 ? stripped : rawMessage;
356
+ }
357
+
358
+ function formatRuntimeContext(context: MotionGPUErrorReport['context']): string {
359
+ if (!context) {
360
+ return '';
361
+ }
362
+
363
+ const indentBlock = (value: string, spaces = 2): string => {
364
+ const prefix = ' '.repeat(spaces);
365
+ return value
366
+ .split('\n')
367
+ .map((line) => `${prefix}${line}`)
368
+ .join('\n');
369
+ };
370
+
371
+ const formatMaterialSignature = (value: string): string => {
372
+ const trimmed = value.trim();
373
+ if (trimmed.length === 0) {
374
+ return '<empty>';
375
+ }
376
+ try {
377
+ return JSON.stringify(JSON.parse(trimmed), null, 2);
378
+ } catch {
379
+ return trimmed;
380
+ }
381
+ };
382
+
383
+ const lines: string[] = [];
384
+ if (context.materialSignature) {
385
+ lines.push('materialSignature:');
386
+ lines.push(indentBlock(formatMaterialSignature(context.materialSignature)));
387
+ }
388
+ if (context.passGraph) {
389
+ lines.push('passGraph:');
390
+ lines.push(` passCount: ${context.passGraph.passCount}`);
391
+ lines.push(` enabledPassCount: ${context.passGraph.enabledPassCount}`);
392
+ lines.push(' inputs:');
393
+ if (context.passGraph.inputs.length === 0) {
394
+ lines.push(' - <none>');
395
+ } else {
396
+ for (const input of context.passGraph.inputs) {
397
+ lines.push(` - ${input}`);
398
+ }
399
+ }
400
+ lines.push(' outputs:');
401
+ if (context.passGraph.outputs.length === 0) {
402
+ lines.push(' - <none>');
403
+ } else {
404
+ for (const output of context.passGraph.outputs) {
405
+ lines.push(` - ${output}`);
406
+ }
407
+ }
408
+ }
409
+ lines.push('activeRenderTargets:');
410
+ if (context.activeRenderTargets.length === 0) {
411
+ lines.push(' - <none>');
412
+ } else {
413
+ for (const target of context.activeRenderTargets) {
414
+ lines.push(` - ${target}`);
415
+ }
416
+ }
417
+ return lines.join('\n');
418
+ }
419
+
420
+ export function MotionGPUErrorOverlay({ report }: MotionGPUErrorOverlayProps) {
421
+ const detailsSummary = report.source ? 'Additional diagnostics' : 'Technical details';
422
+
423
+ return (
424
+ <Portal>
425
+ <style>{MOTIONGPU_ERROR_OVERLAY_STYLES}</style>
426
+ <div className="motiongpu-error-overlay" role="presentation">
427
+ <section
428
+ className="motiongpu-error-dialog"
429
+ role="alertdialog"
430
+ aria-live="assertive"
431
+ aria-modal="true"
432
+ data-testid="motiongpu-error"
433
+ >
434
+ <header className="motiongpu-error-header">
435
+ <div className="motiongpu-error-header-top">
436
+ <div className="motiongpu-error-badges">
437
+ <div className="motiongpu-error-badge-wrap">
438
+ <p className="motiongpu-error-badge motiongpu-error-badge-phase">
439
+ {report.phase}
440
+ </p>
441
+ </div>
442
+ <div className="motiongpu-error-badge-wrap">
443
+ <p className="motiongpu-error-badge motiongpu-error-badge-severity">
444
+ {report.severity}
445
+ </p>
446
+ </div>
447
+ </div>
448
+ </div>
449
+ <h2 className="motiongpu-error-title">{report.title}</h2>
450
+ <p className="motiongpu-error-recoverable">
451
+ Recoverable: <span>{report.recoverable ? 'yes' : 'no'}</span>
452
+ </p>
453
+ </header>
454
+ <div className="motiongpu-error-body">
455
+ {shouldShowErrorMessage(report) ? (
456
+ <p className="motiongpu-error-message">{resolveDisplayMessage(report)}</p>
457
+ ) : null}
458
+ <p className="motiongpu-error-hint">{report.hint}</p>
459
+ </div>
460
+
461
+ {report.source ? (
462
+ <section className="motiongpu-error-source" aria-label="Source">
463
+ <h3 className="motiongpu-error-source-title">Source</h3>
464
+ <div className="motiongpu-error-source-frame" role="presentation">
465
+ <div
466
+ className="motiongpu-error-source-tabs"
467
+ role="tablist"
468
+ aria-label="Source files"
469
+ >
470
+ <span
471
+ className="motiongpu-error-source-tab motiongpu-error-source-tab-active"
472
+ role="tab"
473
+ aria-selected="true"
474
+ >
475
+ {report.source.location}
476
+ {report.source.column ? `, col ${report.source.column}` : ''}
477
+ </span>
478
+ <span className="motiongpu-error-source-tab-spacer" aria-hidden="true"></span>
479
+ </div>
480
+
481
+ <div className="motiongpu-error-source-snippet">
482
+ {report.source.snippet.map((snippetLine) => (
483
+ <div
484
+ key={`snippet-${snippetLine.number}`}
485
+ className={
486
+ snippetLine.highlight
487
+ ? 'motiongpu-error-source-row motiongpu-error-source-row-active'
488
+ : 'motiongpu-error-source-row'
489
+ }
490
+ >
491
+ <span className="motiongpu-error-source-line">{snippetLine.number}</span>
492
+ <span className="motiongpu-error-source-code">{snippetLine.code || ' '}</span>
493
+ </div>
494
+ ))}
495
+ </div>
496
+ </div>
497
+ </section>
498
+ ) : null}
499
+
500
+ <div className="motiongpu-error-sections">
501
+ {report.details.length > 0 ? (
502
+ <details className="motiongpu-error-details" open>
503
+ <summary>{detailsSummary}</summary>
504
+ <pre>{report.details.join('\n')}</pre>
505
+ </details>
506
+ ) : null}
507
+ {report.stack.length > 0 ? (
508
+ <details className="motiongpu-error-details">
509
+ <summary>Stack trace</summary>
510
+ <pre>{report.stack.join('\n')}</pre>
511
+ </details>
512
+ ) : null}
513
+ {report.context ? (
514
+ <details className="motiongpu-error-details">
515
+ <summary>Runtime context</summary>
516
+ <pre>{formatRuntimeContext(report.context)}</pre>
517
+ </details>
518
+ ) : null}
519
+ </div>
520
+ </section>
521
+ </div>
522
+ </Portal>
523
+ );
524
+ }
@@ -0,0 +1,34 @@
1
+ import { useEffect, useState, type ReactNode } from 'react';
2
+ import { createPortal } from 'react-dom';
3
+
4
+ export interface PortalProps {
5
+ target?: string | HTMLElement | null;
6
+ children?: ReactNode;
7
+ }
8
+
9
+ function resolveTargetElement(input: string | HTMLElement | null | undefined): HTMLElement {
10
+ if (typeof document === 'undefined') {
11
+ throw new Error('Portal target resolution requires a browser environment');
12
+ }
13
+
14
+ return typeof input === 'string'
15
+ ? (document.querySelector<HTMLElement>(input) ?? document.body)
16
+ : (input ?? document.body);
17
+ }
18
+
19
+ export function Portal({ target = 'body', children }: PortalProps) {
20
+ const [targetElement, setTargetElement] = useState<HTMLElement | null>(null);
21
+
22
+ useEffect(() => {
23
+ if (typeof document === 'undefined') {
24
+ return;
25
+ }
26
+ setTargetElement(resolveTargetElement(target));
27
+ }, [target]);
28
+
29
+ if (!targetElement) {
30
+ return null;
31
+ }
32
+
33
+ return createPortal(<div>{children ?? null}</div>, targetElement);
34
+ }
@@ -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';