@lovo/matter-react 0.3.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/CHANGELOG.md +12 -0
- package/README.md +9 -5
- package/dist/index.cjs +183 -174
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +91 -83
- package/dist/index.d.ts +91 -83
- package/dist/index.js +184 -175
- package/dist/index.js.map +1 -1
- package/package.json +29 -29
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @lovo/matter-react
|
|
2
2
|
|
|
3
|
+
## 0.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 1c69220: Rename public API symbols to domain-accurate names.
|
|
8
|
+
|
|
9
|
+
New primary names: `FrameScheduler`, `GpuRenderer`, `GpuBackend` (`@lovo/matter`); `ShaderScene`, `ShaderSceneProps`, `ShaderContext`, `ShaderContextValue`, `useShaderContext`, `ShaderMonitor`, `ShaderMonitorProps`, `AnimatableSignal` (`@lovo/matter-react`).
|
|
10
|
+
|
|
11
|
+
Old names (`MatterScheduler`, `MatterRenderer`, `MatterBackend`, `MatterScene`, `MatterSceneProps`, `MatterContext`, `MatterContextValue`, `useMatterContext`, `MatterMonitor`, `MatterMonitorProps`, `MatterSignal`, `MatterBackend`) are deprecated with `@deprecated` JSDoc and continue to work. They will be removed no earlier than 0.5.0.
|
|
12
|
+
|
|
13
|
+
**Migration:** Replace old names with new in your imports and JSX. A one-pass find-and-replace is sufficient — no behavioral changes.
|
|
14
|
+
|
|
3
15
|
## 0.3.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
React binding for **Matter** — shader components on WebGPU + Three.js TSL.
|
|
4
4
|
|
|
5
|
-
This package wraps the engine ([`@lovo/matter`](https://www.npmjs.com/package/@lovo/matter)) with React-friendly primitives: a shared `<
|
|
5
|
+
This package wraps the engine ([`@lovo/matter`](https://www.npmjs.com/package/@lovo/matter)) with React-friendly primitives: a shared `<ShaderScene>` canvas, a `useShaderMaterial` hook for `@react-three/fiber` integration, and input hooks (`useCursor`, `useScroll`).
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -17,21 +17,21 @@ npm install @lovo/matter @lovo/matter-react react three
|
|
|
17
17
|
Matter components work in three configurations:
|
|
18
18
|
|
|
19
19
|
1. **Drop-in** — each component manages its own canvas. Simplest path; one canvas per effect.
|
|
20
|
-
2. **Shared scene** — wrap multiple Matter components in a single `<
|
|
20
|
+
2. **Shared scene** — wrap multiple Matter components in a single `<ShaderScene>` to share one canvas (faster, layered effects).
|
|
21
21
|
3. **Inside `@react-three/fiber`** — use `useShaderMaterial` directly inside a r3f `<Canvas>` you already own.
|
|
22
22
|
|
|
23
23
|
## Minimal usage (Mode 2: shared scene)
|
|
24
24
|
|
|
25
25
|
```tsx
|
|
26
|
-
import {
|
|
26
|
+
import { ShaderScene } from '@lovo/matter-react'
|
|
27
27
|
// LinearGradient is copy-pasted into your project via @lovo/matter-cli
|
|
28
28
|
import { LinearGradient } from '@/components/matter/linear-gradient'
|
|
29
29
|
|
|
30
30
|
export default function Hero() {
|
|
31
31
|
return (
|
|
32
|
-
<
|
|
32
|
+
<ShaderScene>
|
|
33
33
|
<LinearGradient colors={['#0b0c2a', '#1d1f57', '#7d2dff']} angle={120} />
|
|
34
|
-
</
|
|
34
|
+
</ShaderScene>
|
|
35
35
|
)
|
|
36
36
|
}
|
|
37
37
|
```
|
|
@@ -52,6 +52,10 @@ The component lands in `src/components/matter/linear-gradient.tsx` and is yours
|
|
|
52
52
|
|
|
53
53
|
<https://github.com/lovo-hq/matter>
|
|
54
54
|
|
|
55
|
+
## Migration from 0.3.x
|
|
56
|
+
|
|
57
|
+
`MatterScene`, `MatterMonitor`, `useMatterContext`, and related types have been renamed to `ShaderScene`, `ShaderMonitor`, `useShaderContext`, `ShaderContextValue`, etc. The old names are deprecated and still work — remove them at your leisure before 0.5.0.
|
|
58
|
+
|
|
55
59
|
## License
|
|
56
60
|
|
|
57
61
|
MIT — see [LICENSE](./LICENSE).
|
package/dist/index.cjs
CHANGED
|
@@ -21,32 +21,103 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
FallbackBoundary: () => FallbackBoundary,
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
ShaderMonitor: () => ShaderMonitor,
|
|
25
|
+
ShaderScene: () => ShaderScene,
|
|
26
26
|
useAnimatableUniform: () => useAnimatableUniform,
|
|
27
27
|
useCursor: () => useCursor,
|
|
28
|
-
useMatterContext: () => useMatterContext,
|
|
29
28
|
useOverlayPass: () => useOverlayPass,
|
|
30
29
|
useResize: () => useResize,
|
|
31
30
|
useScroll: () => useScroll,
|
|
31
|
+
useShaderContext: () => useShaderContext,
|
|
32
32
|
useShaderMaterial: () => useShaderMaterial,
|
|
33
33
|
useStaticHint: () => useStaticHint
|
|
34
34
|
});
|
|
35
35
|
module.exports = __toCommonJS(index_exports);
|
|
36
36
|
|
|
37
|
-
// src/
|
|
37
|
+
// src/components/fallback-boundary/fallback-boundary.tsx
|
|
38
|
+
var import_react = require("react");
|
|
39
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
40
|
+
function FallbackBoundary({ fallback, children }) {
|
|
41
|
+
const [mounted, setMounted] = (0, import_react.useState)(false);
|
|
42
|
+
(0, import_react.useEffect)(() => {
|
|
43
|
+
setMounted(true);
|
|
44
|
+
}, []);
|
|
45
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: mounted ? children : fallback ?? null });
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/components/shader-monitor/shader-monitor.tsx
|
|
49
|
+
var import_react3 = require("react");
|
|
50
|
+
|
|
51
|
+
// src/context/shader-context.ts
|
|
38
52
|
var import_react2 = require("react");
|
|
39
|
-
var
|
|
40
|
-
var import_webgpu = require("three/webgpu");
|
|
41
|
-
var import_tsl = require("three/tsl");
|
|
42
|
-
var import_matter = require("@lovo/matter");
|
|
53
|
+
var ShaderContext = (0, import_react2.createContext)(null);
|
|
43
54
|
|
|
44
|
-
// src/
|
|
45
|
-
var
|
|
46
|
-
var
|
|
55
|
+
// src/components/shader-monitor/shader-monitor.tsx
|
|
56
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
57
|
+
var anchorStyle = {
|
|
58
|
+
"top-left": { top: 8, left: 8 },
|
|
59
|
+
"top-right": { top: 8, right: 8 },
|
|
60
|
+
"bottom-left": { bottom: 8, left: 8 },
|
|
61
|
+
"bottom-right": { bottom: 8, right: 8 }
|
|
62
|
+
};
|
|
63
|
+
var baseStyle = {
|
|
64
|
+
position: "absolute",
|
|
65
|
+
zIndex: 10,
|
|
66
|
+
padding: "6px 8px",
|
|
67
|
+
borderRadius: 6,
|
|
68
|
+
background: "rgba(0, 0, 0, 0.6)",
|
|
69
|
+
color: "#fff",
|
|
70
|
+
font: "11px ui-monospace, monospace",
|
|
71
|
+
lineHeight: 1.4,
|
|
72
|
+
pointerEvents: "none",
|
|
73
|
+
whiteSpace: "pre"
|
|
74
|
+
};
|
|
75
|
+
function ShaderMonitor({ anchor = "top-right" }) {
|
|
76
|
+
const ctx = (0, import_react3.useContext)(ShaderContext);
|
|
77
|
+
const [stats, setStats] = (0, import_react3.useState)({ fps: 0, ticks: 0, frames: 0 });
|
|
78
|
+
const ticksRef = (0, import_react3.useRef)(0);
|
|
79
|
+
const fpsAccumRef = (0, import_react3.useRef)({ frames: 0, lastSampleAt: 0, fps: 0 });
|
|
80
|
+
(0, import_react3.useEffect)(() => {
|
|
81
|
+
if (!ctx) return;
|
|
82
|
+
const client = (tick) => {
|
|
83
|
+
ticksRef.current += 1;
|
|
84
|
+
const acc = fpsAccumRef.current;
|
|
85
|
+
acc.frames += 1;
|
|
86
|
+
if (acc.lastSampleAt === 0) acc.lastSampleAt = tick.now;
|
|
87
|
+
const dt = tick.now - acc.lastSampleAt;
|
|
88
|
+
if (dt >= 500) {
|
|
89
|
+
acc.fps = Math.round(acc.frames * 1e3 / dt);
|
|
90
|
+
acc.frames = 0;
|
|
91
|
+
acc.lastSampleAt = tick.now;
|
|
92
|
+
}
|
|
93
|
+
setStats({ fps: acc.fps, ticks: ticksRef.current, frames: acc.frames });
|
|
94
|
+
};
|
|
95
|
+
ctx.scheduler.add(client);
|
|
96
|
+
return () => ctx.scheduler.remove(client);
|
|
97
|
+
}, [ctx]);
|
|
98
|
+
if (!ctx) {
|
|
99
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { "data-testid": "matter-monitor", style: { ...baseStyle, ...anchorStyle[anchor] }, children: "no scene" });
|
|
100
|
+
}
|
|
101
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { "data-testid": "matter-monitor", style: { ...baseStyle, ...anchorStyle[anchor] }, children: [
|
|
102
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { "data-testid": "matter-monitor-fps", children: [
|
|
103
|
+
"fps: ",
|
|
104
|
+
stats.fps || "\u2014"
|
|
105
|
+
] }),
|
|
106
|
+
"\n",
|
|
107
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { "data-testid": "matter-monitor-ticks", children: [
|
|
108
|
+
"ticks: ",
|
|
109
|
+
stats.ticks
|
|
110
|
+
] })
|
|
111
|
+
] });
|
|
112
|
+
}
|
|
47
113
|
|
|
48
|
-
// src/
|
|
49
|
-
var
|
|
114
|
+
// src/components/shader-scene/shader-scene.tsx
|
|
115
|
+
var import_matter = require("@lovo/matter");
|
|
116
|
+
var import_react4 = require("react");
|
|
117
|
+
var import_three = require("three");
|
|
118
|
+
var import_tsl = require("three/tsl");
|
|
119
|
+
var import_webgpu = require("three/webgpu");
|
|
120
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
50
121
|
var defaultStyle = {
|
|
51
122
|
position: "absolute",
|
|
52
123
|
inset: 0,
|
|
@@ -54,12 +125,12 @@ var defaultStyle = {
|
|
|
54
125
|
width: "100%",
|
|
55
126
|
height: "100%"
|
|
56
127
|
};
|
|
57
|
-
function
|
|
128
|
+
function ShaderScene(props) {
|
|
58
129
|
const { children, fallback, className, style, maxDPR } = props;
|
|
59
|
-
const canvasRef = (0,
|
|
60
|
-
const [ctx, setCtx] = (0,
|
|
61
|
-
const [error, setError] = (0,
|
|
62
|
-
(0,
|
|
130
|
+
const canvasRef = (0, import_react4.useRef)(null);
|
|
131
|
+
const [ctx, setCtx] = (0, import_react4.useState)(null);
|
|
132
|
+
const [error, setError] = (0, import_react4.useState)(null);
|
|
133
|
+
(0, import_react4.useEffect)(() => {
|
|
63
134
|
const canvas = canvasRef.current;
|
|
64
135
|
if (!canvas) return;
|
|
65
136
|
let cancelled = false;
|
|
@@ -75,14 +146,14 @@ function MatterScene(props) {
|
|
|
75
146
|
const camera = new import_three.OrthographicCamera(-1, 1, 1, -1, 0.1, 10);
|
|
76
147
|
camera.position.z = 1;
|
|
77
148
|
const postProcessing = new import_webgpu.PostProcessing(renderer.three);
|
|
78
|
-
const scheduler = new import_matter.
|
|
149
|
+
const scheduler = new import_matter.FrameScheduler();
|
|
79
150
|
const overlays = /* @__PURE__ */ new Map();
|
|
80
151
|
const basePass = (0, import_tsl.pass)(scene, camera);
|
|
81
152
|
const rebuildOutputNode = () => {
|
|
82
|
-
const
|
|
83
|
-
postProcessing.outputNode =
|
|
153
|
+
const seed = basePass;
|
|
154
|
+
postProcessing.outputNode = Array.from(overlays.values()).reduce(
|
|
84
155
|
(node, transform) => transform(node),
|
|
85
|
-
|
|
156
|
+
seed
|
|
86
157
|
);
|
|
87
158
|
postProcessing.needsUpdate = true;
|
|
88
159
|
};
|
|
@@ -123,7 +194,7 @@ function MatterScene(props) {
|
|
|
123
194
|
} catch (err) {
|
|
124
195
|
if (cancelled) return;
|
|
125
196
|
const e = err instanceof Error ? err : new Error(String(err));
|
|
126
|
-
console.error("[
|
|
197
|
+
console.error("[ShaderScene] renderer init failed:", e);
|
|
127
198
|
setError(e);
|
|
128
199
|
}
|
|
129
200
|
};
|
|
@@ -135,9 +206,9 @@ function MatterScene(props) {
|
|
|
135
206
|
setCtx(null);
|
|
136
207
|
};
|
|
137
208
|
}, [maxDPR]);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
209
|
+
let content;
|
|
210
|
+
if (error) {
|
|
211
|
+
content = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
141
212
|
"div",
|
|
142
213
|
{
|
|
143
214
|
style: {
|
|
@@ -154,47 +225,67 @@ function MatterScene(props) {
|
|
|
154
225
|
textAlign: "center"
|
|
155
226
|
},
|
|
156
227
|
children: [
|
|
157
|
-
"
|
|
228
|
+
"ShaderScene init failed:",
|
|
158
229
|
"\n",
|
|
159
230
|
error.message
|
|
160
231
|
]
|
|
161
232
|
}
|
|
162
|
-
)
|
|
233
|
+
);
|
|
234
|
+
} else if (ctx) {
|
|
235
|
+
content = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ShaderContext.Provider, { value: ctx, children });
|
|
236
|
+
} else {
|
|
237
|
+
content = fallback ?? null;
|
|
238
|
+
}
|
|
239
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className, style: { ...defaultStyle, ...style }, children: [
|
|
240
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("canvas", { ref: canvasRef, style: { width: "100%", height: "100%", display: "block" } }),
|
|
241
|
+
content
|
|
163
242
|
] });
|
|
164
243
|
}
|
|
165
244
|
|
|
166
|
-
// src/
|
|
167
|
-
var
|
|
168
|
-
|
|
169
|
-
|
|
245
|
+
// src/hooks/use-animatable-uniform/use-animatable-uniform.ts
|
|
246
|
+
var import_react5 = require("react");
|
|
247
|
+
var import_tsl2 = require("three/tsl");
|
|
248
|
+
var isSignal = (value) => {
|
|
249
|
+
if (typeof value !== "object" || value === null) return false;
|
|
250
|
+
return "get" in value && typeof value.get === "function" && "on" in value && typeof value.on === "function";
|
|
251
|
+
};
|
|
252
|
+
function useAnimatableUniform(value) {
|
|
253
|
+
const uniformNode = (0, import_react5.useMemo)(() => {
|
|
254
|
+
const initial = isSignal(value) ? value.get() : value;
|
|
255
|
+
return (0, import_tsl2.uniform)(initial);
|
|
256
|
+
}, []);
|
|
257
|
+
(0, import_react5.useEffect)(() => {
|
|
258
|
+
if (isSignal(value)) {
|
|
259
|
+
const unsub = value.on("change", (next) => {
|
|
260
|
+
uniformNode.value = next;
|
|
261
|
+
});
|
|
262
|
+
return unsub;
|
|
263
|
+
}
|
|
264
|
+
uniformNode.value = value;
|
|
265
|
+
return void 0;
|
|
266
|
+
}, [value, uniformNode]);
|
|
267
|
+
return uniformNode;
|
|
170
268
|
}
|
|
171
269
|
|
|
172
|
-
// src/
|
|
173
|
-
var
|
|
174
|
-
var
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}, [build]);
|
|
181
|
-
(0, import_react4.useEffect)(() => {
|
|
182
|
-
return () => material.dispose();
|
|
183
|
-
}, [material]);
|
|
184
|
-
return material;
|
|
270
|
+
// src/hooks/use-cursor/use-cursor.ts
|
|
271
|
+
var import_matter2 = require("@lovo/matter");
|
|
272
|
+
var import_react7 = require("react");
|
|
273
|
+
|
|
274
|
+
// src/hooks/use-shader-context/use-shader-context.ts
|
|
275
|
+
var import_react6 = require("react");
|
|
276
|
+
function useShaderContext() {
|
|
277
|
+
return (0, import_react6.useContext)(ShaderContext);
|
|
185
278
|
}
|
|
186
279
|
|
|
187
|
-
// src/
|
|
188
|
-
var import_react5 = require("react");
|
|
189
|
-
var import_matter2 = require("@lovo/matter");
|
|
280
|
+
// src/hooks/use-cursor/use-cursor.ts
|
|
190
281
|
var STUB_SIGNAL = {
|
|
191
282
|
get: () => [0.5, 0.5],
|
|
192
283
|
on: () => () => void 0
|
|
193
284
|
};
|
|
194
285
|
function useCursor(opts = {}) {
|
|
195
|
-
const ctx =
|
|
196
|
-
const [input, setInput] = (0,
|
|
197
|
-
(0,
|
|
286
|
+
const ctx = useShaderContext();
|
|
287
|
+
const [input, setInput] = (0, import_react7.useState)(null);
|
|
288
|
+
(0, import_react7.useEffect)(() => {
|
|
198
289
|
const canvas = ctx?.renderer.three.domElement;
|
|
199
290
|
const elementOpt = opts.element ?? (canvas instanceof HTMLElement ? canvas : void 0);
|
|
200
291
|
const fresh = new import_matter2.CursorInput({ ...opts, element: elementOpt });
|
|
@@ -219,7 +310,7 @@ function useCursor(opts = {}) {
|
|
|
219
310
|
};
|
|
220
311
|
}
|
|
221
312
|
return () => {
|
|
222
|
-
detach
|
|
313
|
+
detach();
|
|
223
314
|
fresh.dispose();
|
|
224
315
|
setInput(null);
|
|
225
316
|
};
|
|
@@ -227,16 +318,27 @@ function useCursor(opts = {}) {
|
|
|
227
318
|
return input ?? STUB_SIGNAL;
|
|
228
319
|
}
|
|
229
320
|
|
|
230
|
-
// src/
|
|
231
|
-
var
|
|
321
|
+
// src/hooks/use-overlay-pass/use-overlay-pass.ts
|
|
322
|
+
var import_react8 = require("react");
|
|
323
|
+
function useOverlayPass(transform, deps) {
|
|
324
|
+
const ctx = useShaderContext();
|
|
325
|
+
(0, import_react8.useEffect)(() => {
|
|
326
|
+
if (!ctx) return;
|
|
327
|
+
const unregister = ctx.registerOverlay(transform);
|
|
328
|
+
return unregister;
|
|
329
|
+
}, [ctx, ...deps]);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// src/hooks/use-resize/use-resize.ts
|
|
333
|
+
var import_react9 = require("react");
|
|
232
334
|
var STUB_SIGNAL2 = {
|
|
233
335
|
get: () => [0, 0, 1],
|
|
234
336
|
on: () => () => void 0
|
|
235
337
|
};
|
|
236
338
|
function useResize() {
|
|
237
|
-
const ctx =
|
|
238
|
-
const [signal, setSignal] = (0,
|
|
239
|
-
(0,
|
|
339
|
+
const ctx = useShaderContext();
|
|
340
|
+
const [signal, setSignal] = (0, import_react9.useState)(null);
|
|
341
|
+
(0, import_react9.useEffect)(() => {
|
|
240
342
|
if (!ctx) return void 0;
|
|
241
343
|
const canvas = ctx.renderer.three.domElement;
|
|
242
344
|
if (!(canvas instanceof HTMLCanvasElement)) return void 0;
|
|
@@ -296,15 +398,15 @@ function useResize() {
|
|
|
296
398
|
return signal ?? STUB_SIGNAL2;
|
|
297
399
|
}
|
|
298
400
|
|
|
299
|
-
// src/
|
|
300
|
-
var
|
|
401
|
+
// src/hooks/use-scroll/use-scroll.ts
|
|
402
|
+
var import_react10 = require("react");
|
|
301
403
|
var STUB_SIGNAL3 = {
|
|
302
404
|
get: () => [0, 0],
|
|
303
405
|
on: () => () => void 0
|
|
304
406
|
};
|
|
305
407
|
function useScroll() {
|
|
306
|
-
const [signal, setSignal] = (0,
|
|
307
|
-
(0,
|
|
408
|
+
const [signal, setSignal] = (0, import_react10.useState)(null);
|
|
409
|
+
(0, import_react10.useEffect)(() => {
|
|
308
410
|
if (typeof window === "undefined") return void 0;
|
|
309
411
|
const compute = () => {
|
|
310
412
|
const y = window.scrollY;
|
|
@@ -346,135 +448,42 @@ function useScroll() {
|
|
|
346
448
|
return signal ?? STUB_SIGNAL3;
|
|
347
449
|
}
|
|
348
450
|
|
|
349
|
-
// src/
|
|
350
|
-
var import_react8 = require("react");
|
|
351
|
-
var import_tsl2 = require("three/tsl");
|
|
352
|
-
var isSignal = (value) => {
|
|
353
|
-
return typeof value === "object" && value !== null && typeof value.get === "function" && typeof value.on === "function";
|
|
354
|
-
};
|
|
355
|
-
function useAnimatableUniform(value) {
|
|
356
|
-
const uniformNode = (0, import_react8.useMemo)(() => {
|
|
357
|
-
const initial = isSignal(value) ? value.get() : value;
|
|
358
|
-
return (0, import_tsl2.uniform)(initial);
|
|
359
|
-
}, []);
|
|
360
|
-
(0, import_react8.useEffect)(() => {
|
|
361
|
-
if (isSignal(value)) {
|
|
362
|
-
const unsub = value.on("change", (next) => {
|
|
363
|
-
;
|
|
364
|
-
uniformNode.value = next;
|
|
365
|
-
});
|
|
366
|
-
return unsub;
|
|
367
|
-
}
|
|
368
|
-
;
|
|
369
|
-
uniformNode.value = value;
|
|
370
|
-
return void 0;
|
|
371
|
-
}, [value, uniformNode]);
|
|
372
|
-
return uniformNode;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// src/useOverlayPass.ts
|
|
376
|
-
var import_react9 = require("react");
|
|
377
|
-
function useOverlayPass(transform, deps) {
|
|
378
|
-
const ctx = useMatterContext();
|
|
379
|
-
(0, import_react9.useEffect)(() => {
|
|
380
|
-
if (!ctx) return;
|
|
381
|
-
const unregister = ctx.registerOverlay(transform);
|
|
382
|
-
return unregister;
|
|
383
|
-
}, [ctx, ...deps]);
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
// src/FallbackBoundary.tsx
|
|
387
|
-
var import_react10 = require("react");
|
|
388
|
-
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
389
|
-
function FallbackBoundary({ fallback, children }) {
|
|
390
|
-
const [mounted, setMounted] = (0, import_react10.useState)(false);
|
|
391
|
-
(0, import_react10.useEffect)(() => {
|
|
392
|
-
setMounted(true);
|
|
393
|
-
}, []);
|
|
394
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: mounted ? children : fallback ?? null });
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// src/useStaticHint.ts
|
|
451
|
+
// src/hooks/use-shader-material/use-shader-material.ts
|
|
398
452
|
var import_react11 = require("react");
|
|
399
|
-
|
|
400
|
-
|
|
453
|
+
var import_webgpu2 = require("three/webgpu");
|
|
454
|
+
function useShaderMaterial(build) {
|
|
455
|
+
const material = (0, import_react11.useMemo)(() => {
|
|
456
|
+
const m = new import_webgpu2.MeshBasicNodeMaterial();
|
|
457
|
+
m.colorNode = build();
|
|
458
|
+
return m;
|
|
459
|
+
}, [build]);
|
|
401
460
|
(0, import_react11.useEffect)(() => {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
}, [ctx, hint]);
|
|
461
|
+
return () => material.dispose();
|
|
462
|
+
}, [material]);
|
|
463
|
+
return material;
|
|
406
464
|
}
|
|
407
465
|
|
|
408
|
-
// src/
|
|
466
|
+
// src/hooks/use-static-hint/use-static-hint.ts
|
|
409
467
|
var import_react12 = require("react");
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
"top-left": { top: 8, left: 8 },
|
|
413
|
-
"top-right": { top: 8, right: 8 },
|
|
414
|
-
"bottom-left": { bottom: 8, left: 8 },
|
|
415
|
-
"bottom-right": { bottom: 8, right: 8 }
|
|
416
|
-
};
|
|
417
|
-
var baseStyle = {
|
|
418
|
-
position: "absolute",
|
|
419
|
-
zIndex: 10,
|
|
420
|
-
padding: "6px 8px",
|
|
421
|
-
borderRadius: 6,
|
|
422
|
-
background: "rgba(0, 0, 0, 0.6)",
|
|
423
|
-
color: "#fff",
|
|
424
|
-
font: "11px ui-monospace, monospace",
|
|
425
|
-
lineHeight: 1.4,
|
|
426
|
-
pointerEvents: "none",
|
|
427
|
-
whiteSpace: "pre"
|
|
428
|
-
};
|
|
429
|
-
function MatterMonitor({ anchor = "top-right" }) {
|
|
430
|
-
const ctx = (0, import_react12.useContext)(MatterContext);
|
|
431
|
-
const [stats, setStats] = (0, import_react12.useState)({ fps: 0, ticks: 0, frames: 0 });
|
|
432
|
-
const ticksRef = (0, import_react12.useRef)(0);
|
|
433
|
-
const fpsAccumRef = (0, import_react12.useRef)({ frames: 0, lastSampleAt: 0, fps: 0 });
|
|
468
|
+
function useStaticHint(hint) {
|
|
469
|
+
const ctx = useShaderContext();
|
|
434
470
|
(0, import_react12.useEffect)(() => {
|
|
435
471
|
if (!ctx) return;
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
acc.frames += 1;
|
|
440
|
-
if (acc.lastSampleAt === 0) acc.lastSampleAt = tick.now;
|
|
441
|
-
const dt = tick.now - acc.lastSampleAt;
|
|
442
|
-
if (dt >= 500) {
|
|
443
|
-
acc.fps = Math.round(acc.frames * 1e3 / dt);
|
|
444
|
-
acc.frames = 0;
|
|
445
|
-
acc.lastSampleAt = tick.now;
|
|
446
|
-
}
|
|
447
|
-
setStats({ fps: acc.fps, ticks: ticksRef.current, frames: acc.frames });
|
|
448
|
-
};
|
|
449
|
-
ctx.scheduler.add(client);
|
|
450
|
-
return () => ctx.scheduler.remove(client);
|
|
451
|
-
}, [ctx]);
|
|
452
|
-
if (!ctx) {
|
|
453
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { "data-testid": "matter-monitor", style: { ...baseStyle, ...anchorStyle[anchor] }, children: "no scene" });
|
|
454
|
-
}
|
|
455
|
-
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { "data-testid": "matter-monitor", style: { ...baseStyle, ...anchorStyle[anchor] }, children: [
|
|
456
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { "data-testid": "matter-monitor-fps", children: [
|
|
457
|
-
"fps: ",
|
|
458
|
-
stats.fps || "\u2014"
|
|
459
|
-
] }),
|
|
460
|
-
"\n",
|
|
461
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { "data-testid": "matter-monitor-ticks", children: [
|
|
462
|
-
"ticks: ",
|
|
463
|
-
stats.ticks
|
|
464
|
-
] })
|
|
465
|
-
] });
|
|
472
|
+
ctx.scheduler.setIdle(hint);
|
|
473
|
+
return () => ctx.scheduler.setIdle(false);
|
|
474
|
+
}, [ctx, hint]);
|
|
466
475
|
}
|
|
467
476
|
// Annotate the CommonJS export names for ESM import in node:
|
|
468
477
|
0 && (module.exports = {
|
|
469
478
|
FallbackBoundary,
|
|
470
|
-
|
|
471
|
-
|
|
479
|
+
ShaderMonitor,
|
|
480
|
+
ShaderScene,
|
|
472
481
|
useAnimatableUniform,
|
|
473
482
|
useCursor,
|
|
474
|
-
useMatterContext,
|
|
475
483
|
useOverlayPass,
|
|
476
484
|
useResize,
|
|
477
485
|
useScroll,
|
|
486
|
+
useShaderContext,
|
|
478
487
|
useShaderMaterial,
|
|
479
488
|
useStaticHint
|
|
480
489
|
});
|