@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 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 `<MatterScene>` canvas, a `useShaderMaterial` hook for `@react-three/fiber` integration, and input hooks (`useCursor`, `useScroll`).
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 `<MatterScene>` to share one canvas (faster, layered effects).
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 { MatterScene } from '@lovo/matter-react'
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
- <MatterScene>
32
+ <ShaderScene>
33
33
  <LinearGradient colors={['#0b0c2a', '#1d1f57', '#7d2dff']} angle={120} />
34
- </MatterScene>
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
- MatterMonitor: () => MatterMonitor,
25
- MatterScene: () => MatterScene,
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/MatterScene.tsx
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 import_three = require("three");
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/matter-context.ts
45
- var import_react = require("react");
46
- var MatterContext = (0, import_react.createContext)(null);
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/MatterScene.tsx
49
- var import_jsx_runtime = require("react/jsx-runtime");
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 MatterScene(props) {
128
+ function ShaderScene(props) {
58
129
  const { children, fallback, className, style, maxDPR } = props;
59
- const canvasRef = (0, import_react2.useRef)(null);
60
- const [ctx, setCtx] = (0, import_react2.useState)(null);
61
- const [error, setError] = (0, import_react2.useState)(null);
62
- (0, import_react2.useEffect)(() => {
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.MatterScheduler();
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 transforms = Array.from(overlays.values());
83
- postProcessing.outputNode = transforms.reduce(
153
+ const seed = basePass;
154
+ postProcessing.outputNode = Array.from(overlays.values()).reduce(
84
155
  (node, transform) => transform(node),
85
- basePass
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("[MatterScene] renderer init failed:", e);
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
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className, style: { ...defaultStyle, ...style }, children: [
139
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("canvas", { ref: canvasRef, style: { width: "100%", height: "100%", display: "block" } }),
140
- error ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
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
- "MatterScene init failed:",
228
+ "ShaderScene init failed:",
158
229
  "\n",
159
230
  error.message
160
231
  ]
161
232
  }
162
- ) : ctx ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MatterContext.Provider, { value: ctx, children }) : fallback ?? null
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/useMatterContext.ts
167
- var import_react3 = require("react");
168
- function useMatterContext() {
169
- return (0, import_react3.useContext)(MatterContext);
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/useShaderMaterial.ts
173
- var import_react4 = require("react");
174
- var import_webgpu2 = require("three/webgpu");
175
- function useShaderMaterial(build) {
176
- const material = (0, import_react4.useMemo)(() => {
177
- const m = new import_webgpu2.MeshBasicNodeMaterial();
178
- m.colorNode = build();
179
- return m;
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/useCursor.ts
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 = useMatterContext();
196
- const [input, setInput] = (0, import_react5.useState)(null);
197
- (0, import_react5.useEffect)(() => {
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/useResize.ts
231
- var import_react6 = require("react");
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 = useMatterContext();
238
- const [signal, setSignal] = (0, import_react6.useState)(null);
239
- (0, import_react6.useEffect)(() => {
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/useScroll.ts
300
- var import_react7 = require("react");
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, import_react7.useState)(null);
307
- (0, import_react7.useEffect)(() => {
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/useAnimatableUniform.ts
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
- function useStaticHint(hint) {
400
- const ctx = useMatterContext();
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
- if (!ctx) return;
403
- ctx.scheduler.setIdle(hint);
404
- return () => ctx.scheduler.setIdle(false);
405
- }, [ctx, hint]);
461
+ return () => material.dispose();
462
+ }, [material]);
463
+ return material;
406
464
  }
407
465
 
408
- // src/MatterMonitor.tsx
466
+ // src/hooks/use-static-hint/use-static-hint.ts
409
467
  var import_react12 = require("react");
410
- var import_jsx_runtime3 = require("react/jsx-runtime");
411
- var anchorStyle = {
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
- const client = (tick) => {
437
- ticksRef.current += 1;
438
- const acc = fpsAccumRef.current;
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
- MatterMonitor,
471
- MatterScene,
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
  });