@lovo/matter-react 0.4.1 → 0.6.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 +16 -2
- package/README.md +1 -1
- package/dist/index.cjs +194 -138
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -129
- package/dist/index.d.ts +23 -129
- package/dist/index.js +188 -133
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @lovo/matter-react
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
## 0.5.0
|
|
6
|
+
|
|
7
|
+
### Minor Changes
|
|
8
|
+
|
|
9
|
+
- 35274c3: Rename ambiguous `@lovo/matter-react` public exports to clearer names (BREAKING, pre-1.0):
|
|
10
|
+
|
|
11
|
+
- `useOverlayPass` → `usePostProcessPass` (and the paired type `OverlayTransform` → `PostProcessTransform`)
|
|
12
|
+
- `useStaticHint` → `useStaticSceneHint`
|
|
13
|
+
- `MonitorAnchor` (type) → `ShaderMonitorAnchor`
|
|
14
|
+
|
|
15
|
+
Migration: update imports and call sites to the new names. Behavior is unchanged.
|
|
16
|
+
|
|
3
17
|
## 0.4.1
|
|
4
18
|
|
|
5
19
|
## 0.4.0
|
|
@@ -23,13 +37,13 @@
|
|
|
23
37
|
**New: `useOverlayPass(transform, deps)` hook**
|
|
24
38
|
|
|
25
39
|
```ts
|
|
26
|
-
import {
|
|
40
|
+
import { useAnimatableUniform, useOverlayPass } from '@lovo/matter-react';
|
|
27
41
|
|
|
28
42
|
export function MyOverlay({ intensity }) {
|
|
29
43
|
const intensityU = useAnimatableUniform(intensity);
|
|
30
44
|
useOverlayPass(
|
|
31
45
|
(input) => input.mul(intensityU), // takes upstream pixel, returns modified pixel
|
|
32
|
-
[intensityU]
|
|
46
|
+
[intensityU],
|
|
33
47
|
);
|
|
34
48
|
return null;
|
|
35
49
|
}
|
package/README.md
CHANGED
|
@@ -38,7 +38,7 @@ export default function Hero() {
|
|
|
38
38
|
|
|
39
39
|
## Getting components
|
|
40
40
|
|
|
41
|
-
Polished drop-in components (`<LinearGradient>`, `<Aurora>`, `<DotField>`, `<
|
|
41
|
+
Polished drop-in components (`<LinearGradient>`, `<Aurora>`, `<DotField>`, `<SimplexNoise>`, `<MeshGradient>`, `<Waves>`) ship via the shadcn-style copy-paste CLI. Install it once:
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
44
|
npm install -D @lovo/matter-cli
|
package/dist/index.cjs
CHANGED
|
@@ -25,12 +25,13 @@ __export(index_exports, {
|
|
|
25
25
|
ShaderScene: () => ShaderScene,
|
|
26
26
|
useAnimatableUniform: () => useAnimatableUniform,
|
|
27
27
|
useCursor: () => useCursor,
|
|
28
|
-
|
|
28
|
+
useDisplayGamut: () => useDisplayGamut,
|
|
29
|
+
usePostProcessPass: () => usePostProcessPass,
|
|
29
30
|
useResize: () => useResize,
|
|
30
31
|
useScroll: () => useScroll,
|
|
31
32
|
useShaderContext: () => useShaderContext,
|
|
32
33
|
useShaderMaterial: () => useShaderMaterial,
|
|
33
|
-
|
|
34
|
+
useStaticSceneHint: () => useStaticSceneHint
|
|
34
35
|
});
|
|
35
36
|
module.exports = __toCommonJS(index_exports);
|
|
36
37
|
|
|
@@ -73,29 +74,29 @@ var baseStyle = {
|
|
|
73
74
|
whiteSpace: "pre"
|
|
74
75
|
};
|
|
75
76
|
function ShaderMonitor({ anchor = "top-right" }) {
|
|
76
|
-
const
|
|
77
|
+
const shaderContext = (0, import_react3.useContext)(ShaderContext);
|
|
77
78
|
const [stats, setStats] = (0, import_react3.useState)({ fps: 0, ticks: 0, frames: 0 });
|
|
78
79
|
const ticksRef = (0, import_react3.useRef)(0);
|
|
79
80
|
const fpsAccumRef = (0, import_react3.useRef)({ frames: 0, lastSampleAt: 0, fps: 0 });
|
|
80
81
|
(0, import_react3.useEffect)(() => {
|
|
81
|
-
if (!
|
|
82
|
-
const
|
|
82
|
+
if (!shaderContext) return;
|
|
83
|
+
const schedulerTickHandler = (tick) => {
|
|
83
84
|
ticksRef.current += 1;
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
if (
|
|
87
|
-
const
|
|
88
|
-
if (
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
85
|
+
const fpsAccumulator = fpsAccumRef.current;
|
|
86
|
+
fpsAccumulator.frames += 1;
|
|
87
|
+
if (fpsAccumulator.lastSampleAt === 0) fpsAccumulator.lastSampleAt = tick.now;
|
|
88
|
+
const deltaTimeSinceLastSample = tick.now - fpsAccumulator.lastSampleAt;
|
|
89
|
+
if (deltaTimeSinceLastSample >= 500) {
|
|
90
|
+
fpsAccumulator.fps = Math.round(fpsAccumulator.frames * 1e3 / deltaTimeSinceLastSample);
|
|
91
|
+
fpsAccumulator.frames = 0;
|
|
92
|
+
fpsAccumulator.lastSampleAt = tick.now;
|
|
92
93
|
}
|
|
93
|
-
setStats({ fps:
|
|
94
|
+
setStats({ fps: fpsAccumulator.fps, ticks: ticksRef.current, frames: fpsAccumulator.frames });
|
|
94
95
|
};
|
|
95
|
-
|
|
96
|
-
return () =>
|
|
97
|
-
}, [
|
|
98
|
-
if (!
|
|
96
|
+
shaderContext.scheduler.add(schedulerTickHandler);
|
|
97
|
+
return () => shaderContext.scheduler.remove(schedulerTickHandler);
|
|
98
|
+
}, [shaderContext]);
|
|
99
|
+
if (!shaderContext) {
|
|
99
100
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { "data-testid": "matter-monitor", style: { ...baseStyle, ...anchorStyle[anchor] }, children: "no scene" });
|
|
100
101
|
}
|
|
101
102
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { "data-testid": "matter-monitor", style: { ...baseStyle, ...anchorStyle[anchor] }, children: [
|
|
@@ -112,11 +113,44 @@ function ShaderMonitor({ anchor = "top-right" }) {
|
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
// src/components/shader-scene/shader-scene.tsx
|
|
116
|
+
var import_react5 = require("react");
|
|
115
117
|
var import_matter = require("@lovo/matter");
|
|
116
|
-
var import_react4 = require("react");
|
|
117
118
|
var import_three = require("three");
|
|
118
119
|
var import_tsl = require("three/tsl");
|
|
119
120
|
var import_webgpu = require("three/webgpu");
|
|
121
|
+
|
|
122
|
+
// src/hooks/use-display-gamut/use-display-gamut.ts
|
|
123
|
+
var import_react4 = require("react");
|
|
124
|
+
var P3_QUERY = "(color-gamut: p3)";
|
|
125
|
+
function detectGamut() {
|
|
126
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
127
|
+
return "srgb";
|
|
128
|
+
}
|
|
129
|
+
return window.matchMedia(P3_QUERY).matches ? "p3" : "srgb";
|
|
130
|
+
}
|
|
131
|
+
function useDisplayGamut(preference) {
|
|
132
|
+
const [resolved, setResolved] = (0, import_react4.useState)(
|
|
133
|
+
() => preference === "auto" ? detectGamut() : preference
|
|
134
|
+
);
|
|
135
|
+
(0, import_react4.useEffect)(() => {
|
|
136
|
+
if (preference !== "auto") {
|
|
137
|
+
setResolved(preference);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
141
|
+
setResolved("srgb");
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const mediaQuery = window.matchMedia(P3_QUERY);
|
|
145
|
+
const update = () => setResolved(mediaQuery.matches ? "p3" : "srgb");
|
|
146
|
+
update();
|
|
147
|
+
mediaQuery.addEventListener("change", update);
|
|
148
|
+
return () => mediaQuery.removeEventListener("change", update);
|
|
149
|
+
}, [preference]);
|
|
150
|
+
return resolved;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/components/shader-scene/shader-scene.tsx
|
|
120
154
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
121
155
|
var defaultStyle = {
|
|
122
156
|
position: "absolute",
|
|
@@ -126,18 +160,21 @@ var defaultStyle = {
|
|
|
126
160
|
height: "100%"
|
|
127
161
|
};
|
|
128
162
|
function ShaderScene(props) {
|
|
129
|
-
const { children, fallback, className, style, maxDPR } = props;
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
const [
|
|
133
|
-
(0,
|
|
163
|
+
const { children, fallback, className, style, maxDPR, gamut = "auto" } = props;
|
|
164
|
+
const resolvedGamut = useDisplayGamut(gamut);
|
|
165
|
+
const canvasRef = (0, import_react5.useRef)(null);
|
|
166
|
+
const [shaderContext, setShaderContext] = (0, import_react5.useState)(null);
|
|
167
|
+
const [error, setError] = (0, import_react5.useState)(null);
|
|
168
|
+
const [firstFramePainted, setFirstFramePainted] = (0, import_react5.useState)(false);
|
|
169
|
+
(0, import_react5.useEffect)(() => {
|
|
134
170
|
const canvas = canvasRef.current;
|
|
135
171
|
if (!canvas) return;
|
|
136
172
|
let cancelled = false;
|
|
137
173
|
let cleanup = null;
|
|
174
|
+
let firstPaintRaf = null;
|
|
138
175
|
const setup = async () => {
|
|
139
176
|
try {
|
|
140
|
-
const renderer = await (0, import_matter.createRenderer)(canvas, { maxDPR });
|
|
177
|
+
const renderer = await (0, import_matter.createRenderer)(canvas, { maxDPR, gamut: resolvedGamut });
|
|
141
178
|
if (cancelled) {
|
|
142
179
|
renderer.dispose();
|
|
143
180
|
return;
|
|
@@ -148,12 +185,11 @@ function ShaderScene(props) {
|
|
|
148
185
|
const postProcessing = new import_webgpu.PostProcessing(renderer.three);
|
|
149
186
|
const scheduler = new import_matter.FrameScheduler();
|
|
150
187
|
const overlays = /* @__PURE__ */ new Map();
|
|
151
|
-
const
|
|
188
|
+
const basePassNode = (0, import_tsl.vec4)((0, import_tsl.pass)(scene, camera));
|
|
152
189
|
const rebuildOutputNode = () => {
|
|
153
|
-
const seed = basePass;
|
|
154
190
|
postProcessing.outputNode = Array.from(overlays.values()).reduce(
|
|
155
|
-
(
|
|
156
|
-
|
|
191
|
+
(currentPipeline, transform) => transform(currentPipeline),
|
|
192
|
+
basePassNode
|
|
157
193
|
);
|
|
158
194
|
postProcessing.needsUpdate = true;
|
|
159
195
|
};
|
|
@@ -167,7 +203,18 @@ function ShaderScene(props) {
|
|
|
167
203
|
rebuildOutputNode();
|
|
168
204
|
};
|
|
169
205
|
};
|
|
170
|
-
|
|
206
|
+
let firstPaintSignaled = false;
|
|
207
|
+
const renderFrame = () => {
|
|
208
|
+
postProcessing.render();
|
|
209
|
+
if (!firstPaintSignaled && (scene.children.length > 0 || overlays.size > 0)) {
|
|
210
|
+
firstPaintSignaled = true;
|
|
211
|
+
firstPaintRaf = requestAnimationFrame(() => {
|
|
212
|
+
firstPaintRaf = null;
|
|
213
|
+
if (!cancelled) setFirstFramePainted(true);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
scheduler.add(renderFrame);
|
|
171
218
|
scheduler.start();
|
|
172
219
|
const visibility = (0, import_matter.createVisibilityWatcher)();
|
|
173
220
|
const intersection = (0, import_matter.createIntersectionWatcher)(canvas);
|
|
@@ -179,33 +226,38 @@ function ShaderScene(props) {
|
|
|
179
226
|
updatePauseState();
|
|
180
227
|
const unsubVisibility = visibility.subscribe(updatePauseState);
|
|
181
228
|
const unsubIntersection = intersection.subscribe(updatePauseState);
|
|
182
|
-
const
|
|
183
|
-
|
|
229
|
+
const resizeObserver = new ResizeObserver(() => renderer.resize());
|
|
230
|
+
resizeObserver.observe(canvas);
|
|
184
231
|
cleanup = () => {
|
|
185
232
|
unsubVisibility();
|
|
186
233
|
unsubIntersection();
|
|
187
234
|
visibility.dispose();
|
|
188
235
|
intersection.dispose();
|
|
189
|
-
|
|
236
|
+
resizeObserver.disconnect();
|
|
190
237
|
scheduler.dispose();
|
|
191
238
|
renderer.dispose();
|
|
192
239
|
};
|
|
193
|
-
|
|
194
|
-
} catch (
|
|
240
|
+
setShaderContext({ renderer, scene, camera, scheduler, registerOverlay });
|
|
241
|
+
} catch (caughtError) {
|
|
195
242
|
if (cancelled) return;
|
|
196
|
-
const
|
|
197
|
-
console.error("[ShaderScene] renderer init failed:",
|
|
198
|
-
setError(
|
|
243
|
+
const normalizedError = caughtError instanceof Error ? caughtError : new Error(String(caughtError));
|
|
244
|
+
console.error("[ShaderScene] renderer init failed:", normalizedError);
|
|
245
|
+
setError(normalizedError);
|
|
199
246
|
}
|
|
200
247
|
};
|
|
201
248
|
void setup();
|
|
202
249
|
return () => {
|
|
203
250
|
cancelled = true;
|
|
251
|
+
if (firstPaintRaf !== null) {
|
|
252
|
+
cancelAnimationFrame(firstPaintRaf);
|
|
253
|
+
firstPaintRaf = null;
|
|
254
|
+
}
|
|
204
255
|
cleanup?.();
|
|
205
256
|
cleanup = null;
|
|
206
|
-
|
|
257
|
+
setShaderContext(null);
|
|
258
|
+
setFirstFramePainted(false);
|
|
207
259
|
};
|
|
208
|
-
}, [maxDPR]);
|
|
260
|
+
}, [maxDPR, resolvedGamut]);
|
|
209
261
|
let content;
|
|
210
262
|
if (error) {
|
|
211
263
|
content = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
@@ -231,10 +283,11 @@ function ShaderScene(props) {
|
|
|
231
283
|
]
|
|
232
284
|
}
|
|
233
285
|
);
|
|
234
|
-
} else if (ctx) {
|
|
235
|
-
content = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ShaderContext.Provider, { value: ctx, children });
|
|
236
286
|
} else {
|
|
237
|
-
content =
|
|
287
|
+
content = /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
288
|
+
shaderContext && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ShaderContext.Provider, { value: shaderContext, children }),
|
|
289
|
+
!firstFramePainted && (fallback ?? null)
|
|
290
|
+
] });
|
|
238
291
|
}
|
|
239
292
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className, style: { ...defaultStyle, ...style }, children: [
|
|
240
293
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("canvas", { ref: canvasRef, style: { width: "100%", height: "100%", display: "block" } }),
|
|
@@ -243,18 +296,18 @@ function ShaderScene(props) {
|
|
|
243
296
|
}
|
|
244
297
|
|
|
245
298
|
// src/hooks/use-animatable-uniform/use-animatable-uniform.ts
|
|
246
|
-
var
|
|
299
|
+
var import_react6 = require("react");
|
|
247
300
|
var import_tsl2 = require("three/tsl");
|
|
248
301
|
var isSignal = (value) => {
|
|
249
302
|
if (typeof value !== "object" || value === null) return false;
|
|
250
303
|
return "get" in value && typeof value.get === "function" && "on" in value && typeof value.on === "function";
|
|
251
304
|
};
|
|
252
305
|
function useAnimatableUniform(value) {
|
|
253
|
-
const uniformNode = (0,
|
|
306
|
+
const uniformNode = (0, import_react6.useMemo)(() => {
|
|
254
307
|
const initial = isSignal(value) ? value.get() : value;
|
|
255
308
|
return (0, import_tsl2.uniform)(initial);
|
|
256
309
|
}, []);
|
|
257
|
-
(0,
|
|
310
|
+
(0, import_react6.useEffect)(() => {
|
|
258
311
|
if (isSignal(value)) {
|
|
259
312
|
const unsub = value.on("change", (next) => {
|
|
260
313
|
uniformNode.value = next;
|
|
@@ -268,13 +321,13 @@ function useAnimatableUniform(value) {
|
|
|
268
321
|
}
|
|
269
322
|
|
|
270
323
|
// src/hooks/use-cursor/use-cursor.ts
|
|
324
|
+
var import_react8 = require("react");
|
|
271
325
|
var import_matter2 = require("@lovo/matter");
|
|
272
|
-
var import_react7 = require("react");
|
|
273
326
|
|
|
274
327
|
// src/hooks/use-shader-context/use-shader-context.ts
|
|
275
|
-
var
|
|
328
|
+
var import_react7 = require("react");
|
|
276
329
|
function useShaderContext() {
|
|
277
|
-
return (0,
|
|
330
|
+
return (0, import_react7.useContext)(ShaderContext);
|
|
278
331
|
}
|
|
279
332
|
|
|
280
333
|
// src/hooks/use-cursor/use-cursor.ts
|
|
@@ -283,81 +336,91 @@ var STUB_SIGNAL = {
|
|
|
283
336
|
on: () => () => void 0
|
|
284
337
|
};
|
|
285
338
|
function useCursor(opts = {}) {
|
|
286
|
-
const
|
|
287
|
-
const [input, setInput] = (0,
|
|
288
|
-
(0,
|
|
289
|
-
const canvas =
|
|
290
|
-
const
|
|
291
|
-
const
|
|
292
|
-
setInput(
|
|
339
|
+
const shaderContext = useShaderContext();
|
|
340
|
+
const [input, setInput] = (0, import_react8.useState)(null);
|
|
341
|
+
(0, import_react8.useEffect)(() => {
|
|
342
|
+
const canvas = shaderContext?.renderer.three.domElement;
|
|
343
|
+
const resolvedElement = opts.element ?? (canvas instanceof HTMLElement ? canvas : void 0);
|
|
344
|
+
const newCursorInput = new import_matter2.CursorInput({ ...opts, element: resolvedElement });
|
|
345
|
+
setInput(newCursorInput);
|
|
293
346
|
let detach = null;
|
|
294
|
-
if (
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
detach = () =>
|
|
347
|
+
if (shaderContext?.scheduler) {
|
|
348
|
+
const schedulerTickHandler = ({ delta }) => newCursorInput.tick(delta);
|
|
349
|
+
shaderContext.scheduler.add(schedulerTickHandler);
|
|
350
|
+
detach = () => shaderContext.scheduler.remove(schedulerTickHandler);
|
|
298
351
|
} else {
|
|
299
|
-
let
|
|
352
|
+
let animationFrameId = null;
|
|
300
353
|
let lastNow = performance.now();
|
|
301
354
|
const loop = (now) => {
|
|
302
355
|
const delta = (now - lastNow) / 1e3;
|
|
303
356
|
lastNow = now;
|
|
304
|
-
|
|
305
|
-
|
|
357
|
+
newCursorInput.tick(delta);
|
|
358
|
+
animationFrameId = requestAnimationFrame(loop);
|
|
306
359
|
};
|
|
307
|
-
|
|
360
|
+
animationFrameId = requestAnimationFrame(loop);
|
|
308
361
|
detach = () => {
|
|
309
|
-
if (
|
|
362
|
+
if (animationFrameId !== null) cancelAnimationFrame(animationFrameId);
|
|
310
363
|
};
|
|
311
364
|
}
|
|
312
365
|
return () => {
|
|
313
366
|
detach();
|
|
314
|
-
|
|
367
|
+
newCursorInput.dispose();
|
|
315
368
|
setInput(null);
|
|
316
369
|
};
|
|
317
|
-
}, [
|
|
370
|
+
}, [shaderContext]);
|
|
318
371
|
return input ?? STUB_SIGNAL;
|
|
319
372
|
}
|
|
320
373
|
|
|
321
374
|
// src/hooks/use-overlay-pass/use-overlay-pass.ts
|
|
322
|
-
var
|
|
323
|
-
function
|
|
324
|
-
const
|
|
325
|
-
(0,
|
|
326
|
-
if (!
|
|
327
|
-
const unregister =
|
|
375
|
+
var import_react9 = require("react");
|
|
376
|
+
function usePostProcessPass(transform, deps) {
|
|
377
|
+
const shaderContext = useShaderContext();
|
|
378
|
+
(0, import_react9.useEffect)(() => {
|
|
379
|
+
if (!shaderContext) return;
|
|
380
|
+
const unregister = shaderContext.registerOverlay(transform);
|
|
328
381
|
return unregister;
|
|
329
|
-
}, [
|
|
382
|
+
}, [shaderContext, ...deps]);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// src/hooks/use-resize/use-resize.ts
|
|
386
|
+
var import_react10 = require("react");
|
|
387
|
+
|
|
388
|
+
// src/internal/create-signal.ts
|
|
389
|
+
function createSignal(getValue) {
|
|
390
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
391
|
+
return {
|
|
392
|
+
listeners,
|
|
393
|
+
signal: {
|
|
394
|
+
get: getValue,
|
|
395
|
+
on: (_event, listener) => {
|
|
396
|
+
listeners.add(listener);
|
|
397
|
+
return () => {
|
|
398
|
+
listeners.delete(listener);
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
};
|
|
330
403
|
}
|
|
331
404
|
|
|
332
405
|
// src/hooks/use-resize/use-resize.ts
|
|
333
|
-
var import_react9 = require("react");
|
|
334
406
|
var STUB_SIGNAL2 = {
|
|
335
407
|
get: () => [0, 0, 1],
|
|
336
408
|
on: () => () => void 0
|
|
337
409
|
};
|
|
338
410
|
function useResize() {
|
|
339
|
-
const
|
|
340
|
-
const [signal, setSignal] = (0,
|
|
341
|
-
(0,
|
|
342
|
-
if (!
|
|
343
|
-
const canvas =
|
|
411
|
+
const shaderContext = useShaderContext();
|
|
412
|
+
const [signal, setSignal] = (0, import_react10.useState)(null);
|
|
413
|
+
(0, import_react10.useEffect)(() => {
|
|
414
|
+
if (!shaderContext) return void 0;
|
|
415
|
+
const canvas = shaderContext.renderer.three.domElement;
|
|
344
416
|
if (!(canvas instanceof HTMLCanvasElement)) return void 0;
|
|
345
417
|
let value = [
|
|
346
418
|
canvas.clientWidth,
|
|
347
419
|
canvas.clientHeight,
|
|
348
420
|
typeof window !== "undefined" ? window.devicePixelRatio : 1
|
|
349
421
|
];
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
get: () => value,
|
|
353
|
-
on: (_event, cb) => {
|
|
354
|
-
listeners.add(cb);
|
|
355
|
-
return () => {
|
|
356
|
-
listeners.delete(cb);
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
};
|
|
360
|
-
setSignal(fresh);
|
|
422
|
+
const { signal: newSignal, listeners } = createSignal(() => value);
|
|
423
|
+
setSignal(newSignal);
|
|
361
424
|
const emit = () => {
|
|
362
425
|
const next = [
|
|
363
426
|
canvas.clientWidth,
|
|
@@ -366,66 +429,59 @@ function useResize() {
|
|
|
366
429
|
];
|
|
367
430
|
if (next[0] === value[0] && next[1] === value[1] && next[2] === value[2]) return;
|
|
368
431
|
value = next;
|
|
369
|
-
for (const
|
|
432
|
+
for (const listener of listeners) listener(next);
|
|
370
433
|
};
|
|
371
434
|
const observer = new ResizeObserver(emit);
|
|
372
435
|
observer.observe(canvas);
|
|
373
|
-
let
|
|
374
|
-
let
|
|
436
|
+
let mediaQueryList = null;
|
|
437
|
+
let mediaQueryListener = null;
|
|
375
438
|
const setupDprWatch = () => {
|
|
376
439
|
if (typeof window === "undefined") return;
|
|
377
440
|
const dpr = window.devicePixelRatio;
|
|
378
|
-
const
|
|
379
|
-
const
|
|
441
|
+
const nextMediaQueryList = window.matchMedia(`(resolution: ${dpr}dppx)`);
|
|
442
|
+
const nextMediaQueryListener = () => {
|
|
380
443
|
emit();
|
|
381
|
-
if (
|
|
444
|
+
if (mediaQueryList && mediaQueryListener)
|
|
445
|
+
mediaQueryList.removeEventListener("change", mediaQueryListener);
|
|
382
446
|
setupDprWatch();
|
|
383
447
|
};
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
448
|
+
nextMediaQueryList.addEventListener("change", nextMediaQueryListener);
|
|
449
|
+
mediaQueryList = nextMediaQueryList;
|
|
450
|
+
mediaQueryListener = nextMediaQueryListener;
|
|
387
451
|
};
|
|
388
452
|
setupDprWatch();
|
|
389
453
|
return () => {
|
|
390
454
|
observer.disconnect();
|
|
391
|
-
if (
|
|
392
|
-
|
|
393
|
-
|
|
455
|
+
if (mediaQueryList && mediaQueryListener)
|
|
456
|
+
mediaQueryList.removeEventListener("change", mediaQueryListener);
|
|
457
|
+
mediaQueryList = null;
|
|
458
|
+
mediaQueryListener = null;
|
|
394
459
|
listeners.clear();
|
|
395
460
|
setSignal(null);
|
|
396
461
|
};
|
|
397
|
-
}, [
|
|
462
|
+
}, [shaderContext]);
|
|
398
463
|
return signal ?? STUB_SIGNAL2;
|
|
399
464
|
}
|
|
400
465
|
|
|
401
466
|
// src/hooks/use-scroll/use-scroll.ts
|
|
402
|
-
var
|
|
467
|
+
var import_react11 = require("react");
|
|
403
468
|
var STUB_SIGNAL3 = {
|
|
404
469
|
get: () => [0, 0],
|
|
405
470
|
on: () => () => void 0
|
|
406
471
|
};
|
|
407
472
|
function useScroll() {
|
|
408
|
-
const [signal, setSignal] = (0,
|
|
409
|
-
(0,
|
|
473
|
+
const [signal, setSignal] = (0, import_react11.useState)(null);
|
|
474
|
+
(0, import_react11.useEffect)(() => {
|
|
410
475
|
if (typeof window === "undefined") return void 0;
|
|
411
476
|
const compute = () => {
|
|
412
|
-
const
|
|
477
|
+
const scrollYPosition = window.scrollY;
|
|
413
478
|
const max = Math.max(document.documentElement.scrollHeight - window.innerHeight, 1);
|
|
414
|
-
const progress = Math.max(0, Math.min(1,
|
|
415
|
-
return [
|
|
479
|
+
const progress = Math.max(0, Math.min(1, scrollYPosition / max));
|
|
480
|
+
return [scrollYPosition, progress];
|
|
416
481
|
};
|
|
417
482
|
let value = compute();
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
get: () => value,
|
|
421
|
-
on: (_event, cb) => {
|
|
422
|
-
listeners.add(cb);
|
|
423
|
-
return () => {
|
|
424
|
-
listeners.delete(cb);
|
|
425
|
-
};
|
|
426
|
-
}
|
|
427
|
-
};
|
|
428
|
-
setSignal(fresh);
|
|
483
|
+
const { signal: newSignal, listeners } = createSignal(() => value);
|
|
484
|
+
setSignal(newSignal);
|
|
429
485
|
let rafPending = false;
|
|
430
486
|
const onScroll = () => {
|
|
431
487
|
if (rafPending) return;
|
|
@@ -435,7 +491,7 @@ function useScroll() {
|
|
|
435
491
|
const next = compute();
|
|
436
492
|
if (next[0] === value[0] && next[1] === value[1]) return;
|
|
437
493
|
value = next;
|
|
438
|
-
for (const
|
|
494
|
+
for (const listener of listeners) listener(next);
|
|
439
495
|
});
|
|
440
496
|
};
|
|
441
497
|
window.addEventListener("scroll", onScroll, { passive: true });
|
|
@@ -449,29 +505,28 @@ function useScroll() {
|
|
|
449
505
|
}
|
|
450
506
|
|
|
451
507
|
// src/hooks/use-shader-material/use-shader-material.ts
|
|
452
|
-
var
|
|
508
|
+
var import_react12 = require("react");
|
|
453
509
|
var import_webgpu2 = require("three/webgpu");
|
|
454
510
|
function useShaderMaterial(build) {
|
|
455
|
-
const material = (0,
|
|
456
|
-
const
|
|
457
|
-
|
|
458
|
-
return
|
|
511
|
+
const material = (0, import_react12.useMemo)(() => {
|
|
512
|
+
const nodeMaterial = new import_webgpu2.MeshBasicNodeMaterial();
|
|
513
|
+
nodeMaterial.colorNode = build();
|
|
514
|
+
return nodeMaterial;
|
|
459
515
|
}, [build]);
|
|
460
|
-
(0,
|
|
516
|
+
(0, import_react12.useEffect)(() => {
|
|
461
517
|
return () => material.dispose();
|
|
462
518
|
}, [material]);
|
|
463
519
|
return material;
|
|
464
520
|
}
|
|
465
521
|
|
|
466
522
|
// src/hooks/use-static-hint/use-static-hint.ts
|
|
467
|
-
var
|
|
468
|
-
function
|
|
469
|
-
const
|
|
470
|
-
(0,
|
|
471
|
-
if (!
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
}, [ctx, hint]);
|
|
523
|
+
var import_react13 = require("react");
|
|
524
|
+
function useStaticSceneHint(isStatic) {
|
|
525
|
+
const shaderContext = useShaderContext();
|
|
526
|
+
(0, import_react13.useEffect)(() => {
|
|
527
|
+
if (!shaderContext) return;
|
|
528
|
+
return shaderContext.scheduler.setIdle(isStatic);
|
|
529
|
+
}, [shaderContext, isStatic]);
|
|
475
530
|
}
|
|
476
531
|
// Annotate the CommonJS export names for ESM import in node:
|
|
477
532
|
0 && (module.exports = {
|
|
@@ -480,11 +535,12 @@ function useStaticHint(hint) {
|
|
|
480
535
|
ShaderScene,
|
|
481
536
|
useAnimatableUniform,
|
|
482
537
|
useCursor,
|
|
483
|
-
|
|
538
|
+
useDisplayGamut,
|
|
539
|
+
usePostProcessPass,
|
|
484
540
|
useResize,
|
|
485
541
|
useScroll,
|
|
486
542
|
useShaderContext,
|
|
487
543
|
useShaderMaterial,
|
|
488
|
-
|
|
544
|
+
useStaticSceneHint
|
|
489
545
|
});
|
|
490
546
|
//# sourceMappingURL=index.cjs.map
|