paperlab 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/{chunk-6IADJZX5.js → chunk-HRXQTJFS.js} +45 -28
- package/dist/chunk-HRXQTJFS.js.map +1 -0
- package/dist/index.cjs +107 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/stage.cjs +258 -234
- package/dist/stage.cjs.map +1 -1
- package/dist/stage.js +17 -8
- package/dist/stage.js.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-6IADJZX5.js.map +0 -1
package/dist/stage.cjs
CHANGED
|
@@ -52,8 +52,8 @@ module.exports = __toCommonJS(stage_exports);
|
|
|
52
52
|
|
|
53
53
|
// src/stage/PaperStage.tsx
|
|
54
54
|
var THREE22 = __toESM(require("three"), 1);
|
|
55
|
-
var
|
|
56
|
-
var
|
|
55
|
+
var import_fiber11 = require("@react-three/fiber");
|
|
56
|
+
var import_react24 = require("react");
|
|
57
57
|
var import_zod29 = require("zod");
|
|
58
58
|
|
|
59
59
|
// src/a11y/index.tsx
|
|
@@ -275,8 +275,8 @@ function contentText(config) {
|
|
|
275
275
|
// src/PaperField.tsx
|
|
276
276
|
var THREE16 = __toESM(require("three"), 1);
|
|
277
277
|
var import_gsap5 = require("gsap");
|
|
278
|
-
var
|
|
279
|
-
var
|
|
278
|
+
var import_fiber7 = require("@react-three/fiber");
|
|
279
|
+
var import_react17 = require("react");
|
|
280
280
|
|
|
281
281
|
// src/config/schema.ts
|
|
282
282
|
var import_zod14 = require("zod");
|
|
@@ -2110,9 +2110,24 @@ function paintBackdrop(backdrop, width, height, image) {
|
|
|
2110
2110
|
return texture;
|
|
2111
2111
|
}
|
|
2112
2112
|
|
|
2113
|
+
// src/scene/release.tsx
|
|
2114
|
+
var import_fiber3 = require("@react-three/fiber");
|
|
2115
|
+
var import_react4 = require("react");
|
|
2116
|
+
function ReleaseContextOnUnmount() {
|
|
2117
|
+
const gl = (0, import_fiber3.useThree)((s) => s.gl);
|
|
2118
|
+
(0, import_react4.useEffect)(
|
|
2119
|
+
() => () => {
|
|
2120
|
+
gl.forceContextLoss();
|
|
2121
|
+
gl.dispose();
|
|
2122
|
+
},
|
|
2123
|
+
[gl]
|
|
2124
|
+
);
|
|
2125
|
+
return null;
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2113
2128
|
// src/field/dropZones.tsx
|
|
2114
2129
|
var THREE4 = __toESM(require("three"), 1);
|
|
2115
|
-
var
|
|
2130
|
+
var import_react5 = require("react");
|
|
2116
2131
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
2117
2132
|
var DropZoneRegistry = class {
|
|
2118
2133
|
zones = /* @__PURE__ */ new Map();
|
|
@@ -2151,7 +2166,7 @@ var DropZoneRegistry = class {
|
|
|
2151
2166
|
for (const fn of this.listeners) fn();
|
|
2152
2167
|
}
|
|
2153
2168
|
};
|
|
2154
|
-
var DropZoneContext = (0,
|
|
2169
|
+
var DropZoneContext = (0, import_react5.createContext)(null);
|
|
2155
2170
|
var globCache = /* @__PURE__ */ new Map();
|
|
2156
2171
|
var globRegExp = (glob) => {
|
|
2157
2172
|
let re = globCache.get(glob);
|
|
@@ -2167,17 +2182,17 @@ function zoneAccepts(zone, name) {
|
|
|
2167
2182
|
}
|
|
2168
2183
|
var zoneContains = (zone, x, y) => Math.abs(x - zone.bounds.position[0]) <= zone.bounds.size[0] / 2 && Math.abs(y - zone.bounds.position[1]) <= zone.bounds.size[1] / 2;
|
|
2169
2184
|
function DropZoneVisual({ registry: registry4, config }) {
|
|
2170
|
-
(0,
|
|
2185
|
+
(0, import_react5.useSyncExternalStore)(registry4.subscribe, registry4.getVersion, registry4.getVersion);
|
|
2171
2186
|
const hovered = registry4.hovered === config.id;
|
|
2172
2187
|
const style = config.highlight ?? "glow";
|
|
2173
2188
|
const [w, h] = config.bounds.size;
|
|
2174
|
-
const edges = (0,
|
|
2189
|
+
const edges = (0, import_react5.useMemo)(() => {
|
|
2175
2190
|
const plane = new THREE4.PlaneGeometry(w, h);
|
|
2176
2191
|
const geo = new THREE4.EdgesGeometry(plane);
|
|
2177
2192
|
plane.dispose();
|
|
2178
2193
|
return geo;
|
|
2179
2194
|
}, [w, h]);
|
|
2180
|
-
(0,
|
|
2195
|
+
(0, import_react5.useEffect)(() => () => edges.dispose(), [edges]);
|
|
2181
2196
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("group", { position: config.bounds.position, children: [
|
|
2182
2197
|
style !== "outline" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("mesh", { children: [
|
|
2183
2198
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("planeGeometry", { args: [w, h] }),
|
|
@@ -2198,8 +2213,8 @@ function DropZoneVisual({ registry: registry4, config }) {
|
|
|
2198
2213
|
// src/PaperMesh.tsx
|
|
2199
2214
|
var THREE11 = __toESM(require("three"), 1);
|
|
2200
2215
|
var import_gsap2 = require("gsap");
|
|
2201
|
-
var
|
|
2202
|
-
var
|
|
2216
|
+
var import_fiber4 = require("@react-three/fiber");
|
|
2217
|
+
var import_react11 = require("react");
|
|
2203
2218
|
|
|
2204
2219
|
// src/config/serialize.ts
|
|
2205
2220
|
function parsePreset(input) {
|
|
@@ -2262,9 +2277,9 @@ function computeSheetNormals(geometry) {
|
|
|
2262
2277
|
}
|
|
2263
2278
|
|
|
2264
2279
|
// src/core/stable.ts
|
|
2265
|
-
var
|
|
2280
|
+
var import_react6 = require("react");
|
|
2266
2281
|
function useStable(value) {
|
|
2267
|
-
const held = (0,
|
|
2282
|
+
const held = (0, import_react6.useRef)(value);
|
|
2268
2283
|
if (!deepEqual(held.current, value)) held.current = value;
|
|
2269
2284
|
return held.current;
|
|
2270
2285
|
}
|
|
@@ -2580,7 +2595,7 @@ function listPresets() {
|
|
|
2580
2595
|
|
|
2581
2596
|
// src/content/texture.ts
|
|
2582
2597
|
var THREE6 = __toESM(require("three"), 1);
|
|
2583
|
-
var
|
|
2598
|
+
var import_react7 = require("react");
|
|
2584
2599
|
|
|
2585
2600
|
// src/content/type.ts
|
|
2586
2601
|
function wrapLines(ctx, text, maxWidth, font) {
|
|
@@ -2869,9 +2884,9 @@ function makeTexture(canvas) {
|
|
|
2869
2884
|
return tex;
|
|
2870
2885
|
}
|
|
2871
2886
|
function useContentTexture(content, sheet2, stock) {
|
|
2872
|
-
const [texture, setTexture] = (0,
|
|
2887
|
+
const [texture, setTexture] = (0, import_react7.useState)(null);
|
|
2873
2888
|
const key = JSON.stringify({ content: content ?? null, w: sheet2.width, h: sheet2.height, stock: stock.id });
|
|
2874
|
-
(0,
|
|
2889
|
+
(0, import_react7.useEffect)(() => {
|
|
2875
2890
|
let disposed = false;
|
|
2876
2891
|
let tex = null;
|
|
2877
2892
|
if (!content) {
|
|
@@ -3840,7 +3855,7 @@ var ClothSim = class {
|
|
|
3840
3855
|
|
|
3841
3856
|
// src/surface/PaperMaterial.tsx
|
|
3842
3857
|
var THREE10 = __toESM(require("three"), 1);
|
|
3843
|
-
var
|
|
3858
|
+
var import_react9 = require("react");
|
|
3844
3859
|
var import_three_custom_shader_material = __toESM(require("three-custom-shader-material"), 1);
|
|
3845
3860
|
|
|
3846
3861
|
// src/surface/compose.ts
|
|
@@ -4213,14 +4228,14 @@ function padPositions(positions) {
|
|
|
4213
4228
|
}
|
|
4214
4229
|
|
|
4215
4230
|
// src/scene/rig.tsx
|
|
4216
|
-
var
|
|
4231
|
+
var import_react8 = require("react");
|
|
4217
4232
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
4218
|
-
var LightRigContext = (0,
|
|
4233
|
+
var LightRigContext = (0, import_react8.createContext)(null);
|
|
4219
4234
|
function LightRig({ rig, children }) {
|
|
4220
4235
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LightRigContext.Provider, { value: rig, children });
|
|
4221
4236
|
}
|
|
4222
4237
|
function useLightRig(own) {
|
|
4223
|
-
return (0,
|
|
4238
|
+
return (0, import_react8.useContext)(LightRigContext) ?? getLightingPreset(own);
|
|
4224
4239
|
}
|
|
4225
4240
|
|
|
4226
4241
|
// src/surface/PaperMaterial.tsx
|
|
@@ -4246,8 +4261,8 @@ function PaperMaterial({
|
|
|
4246
4261
|
sheet2,
|
|
4247
4262
|
rig
|
|
4248
4263
|
);
|
|
4249
|
-
const bound = (0,
|
|
4250
|
-
(0,
|
|
4264
|
+
const bound = (0, import_react9.useMemo)(() => composed.uniforms, [composed.structureKey]);
|
|
4265
|
+
(0, import_react9.useEffect)(() => {
|
|
4251
4266
|
for (const [key, uniform] of Object.entries(composed.uniforms)) {
|
|
4252
4267
|
if (!bound[key] || key === "uFrontMap" || key === "uBackMap") continue;
|
|
4253
4268
|
if (bound[key].value instanceof THREE10.Color && uniform.value instanceof THREE10.Color) {
|
|
@@ -4258,7 +4273,7 @@ function PaperMaterial({
|
|
|
4258
4273
|
}
|
|
4259
4274
|
}
|
|
4260
4275
|
});
|
|
4261
|
-
(0,
|
|
4276
|
+
(0, import_react9.useEffect)(() => {
|
|
4262
4277
|
if (bound.uFrontMap) bound.uFrontMap.value = texture;
|
|
4263
4278
|
if (bound.uBackMap) bound.uBackMap.value = backTexture ?? null;
|
|
4264
4279
|
}, [bound, texture, backTexture]);
|
|
@@ -4292,7 +4307,7 @@ function quantizeProgress(p, duration, fps = ON_TWOS_FPS) {
|
|
|
4292
4307
|
}
|
|
4293
4308
|
|
|
4294
4309
|
// src/states/usePaperStates.ts
|
|
4295
|
-
var
|
|
4310
|
+
var import_react10 = require("react");
|
|
4296
4311
|
|
|
4297
4312
|
// src/states/machine.ts
|
|
4298
4313
|
var import_gsap = require("gsap");
|
|
@@ -4519,15 +4534,15 @@ var PaperStateMachine = class {
|
|
|
4519
4534
|
// src/states/usePaperStates.ts
|
|
4520
4535
|
function usePaperStates(config, enabled, instant, onAction, onStateChange) {
|
|
4521
4536
|
const live = enabled && Boolean(config.states);
|
|
4522
|
-
const key = (0,
|
|
4523
|
-
const onActionRef = (0,
|
|
4537
|
+
const key = (0, import_react10.useMemo)(() => JSON.stringify(config), [config]);
|
|
4538
|
+
const onActionRef = (0, import_react10.useRef)(onAction);
|
|
4524
4539
|
onActionRef.current = onAction;
|
|
4525
|
-
const onStateChangeRef = (0,
|
|
4540
|
+
const onStateChangeRef = (0, import_react10.useRef)(onStateChange);
|
|
4526
4541
|
onStateChangeRef.current = onStateChange;
|
|
4527
|
-
const machineRef = (0,
|
|
4528
|
-
const lastStateRef = (0,
|
|
4529
|
-
const [animated, setAnimated] = (0,
|
|
4530
|
-
(0,
|
|
4542
|
+
const machineRef = (0, import_react10.useRef)(null);
|
|
4543
|
+
const lastStateRef = (0, import_react10.useRef)("rest");
|
|
4544
|
+
const [animated, setAnimated] = (0, import_react10.useState)(null);
|
|
4545
|
+
(0, import_react10.useEffect)(() => {
|
|
4531
4546
|
if (!live) {
|
|
4532
4547
|
machineRef.current?.dispose();
|
|
4533
4548
|
machineRef.current = null;
|
|
@@ -4554,7 +4569,7 @@ function usePaperStates(config, enabled, instant, onAction, onStateChange) {
|
|
|
4554
4569
|
lastStateRef.current = machine.state;
|
|
4555
4570
|
setAnimated({ config: machine.structuralConfig(), state: machine.state });
|
|
4556
4571
|
}, [key, live, instant]);
|
|
4557
|
-
(0,
|
|
4572
|
+
(0, import_react10.useEffect)(
|
|
4558
4573
|
() => () => {
|
|
4559
4574
|
machineRef.current?.dispose();
|
|
4560
4575
|
machineRef.current = null;
|
|
@@ -4586,7 +4601,7 @@ function configInputs(props) {
|
|
|
4586
4601
|
}
|
|
4587
4602
|
function useResolvedConfig(props) {
|
|
4588
4603
|
const inputs = useStable(configInputs(props));
|
|
4589
|
-
return (0,
|
|
4604
|
+
return (0, import_react11.useMemo)(() => resolveConfig(props), [inputs]);
|
|
4590
4605
|
}
|
|
4591
4606
|
function resolveConfig(props) {
|
|
4592
4607
|
const base = props.preset ? typeof props.preset === "string" ? getPreset(props.preset) : parsePreset(props.preset) : paperConfigSchema.parse({});
|
|
@@ -4610,7 +4625,7 @@ var planeNormal = new THREE11.Vector3();
|
|
|
4610
4625
|
var anchorScratch = new THREE11.Vector3();
|
|
4611
4626
|
var worldScratch = new THREE11.Vector3();
|
|
4612
4627
|
var quatScratch = new THREE11.Quaternion();
|
|
4613
|
-
var PaperMesh = (0,
|
|
4628
|
+
var PaperMesh = (0, import_react11.forwardRef)(function PaperMesh2(props, ref) {
|
|
4614
4629
|
const resolved = useResolvedConfig(props);
|
|
4615
4630
|
const reduced = usePrefersReducedMotion(props.reducedMotion);
|
|
4616
4631
|
const statesLive = Boolean(resolved.states) && props.stateTriggers !== false;
|
|
@@ -4620,33 +4635,33 @@ var PaperMesh = (0, import_react10.forwardRef)(function PaperMesh2(props, ref) {
|
|
|
4620
4635
|
state: machineState
|
|
4621
4636
|
} = usePaperStates(resolved, statesLive, reduced, props.onStateAction, props.onStateChange);
|
|
4622
4637
|
const behavior = config.behavior ? getBehavior(config.behavior.type) : null;
|
|
4623
|
-
const machineRef = (0,
|
|
4638
|
+
const machineRef = (0, import_react11.useRef)(null);
|
|
4624
4639
|
machineRef.current = machine;
|
|
4625
|
-
const resolvedRef = (0,
|
|
4640
|
+
const resolvedRef = (0, import_react11.useRef)(resolved);
|
|
4626
4641
|
resolvedRef.current = resolved;
|
|
4627
4642
|
const isCloth = !reduced && typeof config.physics === "object";
|
|
4628
4643
|
const idle = !reduced && typeof config.physics === "string" && config.physics !== "none" ? getIdlePreset(config.physics) : null;
|
|
4629
|
-
const meshRef = (0,
|
|
4630
|
-
const groupRef = (0,
|
|
4631
|
-
const handleRefs = (0,
|
|
4632
|
-
const overridesRef = (0,
|
|
4633
|
-
const dirtyRef = (0,
|
|
4634
|
-
const playingRef = (0,
|
|
4635
|
-
const tweenRef = (0,
|
|
4636
|
-
const draggingRef = (0,
|
|
4637
|
-
const configRef = (0,
|
|
4644
|
+
const meshRef = (0, import_react11.useRef)(null);
|
|
4645
|
+
const groupRef = (0, import_react11.useRef)(null);
|
|
4646
|
+
const handleRefs = (0, import_react11.useRef)([]);
|
|
4647
|
+
const overridesRef = (0, import_react11.useRef)({});
|
|
4648
|
+
const dirtyRef = (0, import_react11.useRef)(true);
|
|
4649
|
+
const playingRef = (0, import_react11.useRef)(false);
|
|
4650
|
+
const tweenRef = (0, import_react11.useRef)(null);
|
|
4651
|
+
const draggingRef = (0, import_react11.useRef)(null);
|
|
4652
|
+
const configRef = (0, import_react11.useRef)(config);
|
|
4638
4653
|
configRef.current = config;
|
|
4639
|
-
const controls = (0,
|
|
4640
|
-
const camera = (0,
|
|
4654
|
+
const controls = (0, import_fiber4.useThree)((s) => s.controls);
|
|
4655
|
+
const camera = (0, import_fiber4.useThree)((s) => s.camera);
|
|
4641
4656
|
const behaviorKey = JSON.stringify(config.behavior ?? null);
|
|
4642
4657
|
const deformersKey = JSON.stringify(config.deformers ?? null);
|
|
4643
4658
|
const sheetKey = JSON.stringify(config.sheet);
|
|
4644
4659
|
const physicsKey = JSON.stringify(config.physics);
|
|
4645
|
-
(0,
|
|
4660
|
+
(0, import_react11.useEffect)(() => {
|
|
4646
4661
|
if (!draggingRef.current && !playingRef.current) overridesRef.current = {};
|
|
4647
4662
|
dirtyRef.current = true;
|
|
4648
4663
|
}, [behaviorKey, deformersKey, sheetKey, physicsKey]);
|
|
4649
|
-
const { minSegments, autoSegments, animatedStack } = (0,
|
|
4664
|
+
const { minSegments, autoSegments, animatedStack } = (0, import_react11.useMemo)(() => {
|
|
4650
4665
|
const cfg = configRef.current;
|
|
4651
4666
|
const probe2 = buildStack(cfg, {});
|
|
4652
4667
|
if (!probe2) {
|
|
@@ -4675,18 +4690,18 @@ var PaperMesh = (0, import_react10.forwardRef)(function PaperMesh2(props, ref) {
|
|
|
4675
4690
|
animatedStack: animated
|
|
4676
4691
|
};
|
|
4677
4692
|
}, [behaviorKey, deformersKey, physicsKey]);
|
|
4678
|
-
const geometry = (0,
|
|
4693
|
+
const geometry = (0, import_react11.useMemo)(() => {
|
|
4679
4694
|
if (!isCloth) return createSheetGeometry(config.sheet, minSegments, autoSegments);
|
|
4680
4695
|
const [sx, sy] = resolveSegments(config.sheet, 2);
|
|
4681
4696
|
const capped = Math.min(Math.max(sx, sy), CLOTH_MAX_SEGMENTS);
|
|
4682
4697
|
return new THREE11.PlaneGeometry(config.sheet.width, config.sheet.height, capped, capped);
|
|
4683
4698
|
}, [sheetKey, minSegments, autoSegments, isCloth]);
|
|
4684
|
-
(0,
|
|
4685
|
-
const basePositions = (0,
|
|
4699
|
+
(0, import_react11.useEffect)(() => () => geometry.dispose(), [geometry]);
|
|
4700
|
+
const basePositions = (0, import_react11.useMemo)(
|
|
4686
4701
|
() => Float32Array.from(geometry.attributes.position.array),
|
|
4687
4702
|
[geometry]
|
|
4688
4703
|
);
|
|
4689
|
-
const sim = (0,
|
|
4704
|
+
const sim = (0, import_react11.useMemo)(() => {
|
|
4690
4705
|
if (!isCloth) return null;
|
|
4691
4706
|
const cloth = configRef.current.physics;
|
|
4692
4707
|
const cols = geometry.parameters.widthSegments + 1;
|
|
@@ -4739,7 +4754,7 @@ var PaperMesh = (0, import_react10.forwardRef)(function PaperMesh2(props, ref) {
|
|
|
4739
4754
|
playingRef.current = false;
|
|
4740
4755
|
tweenRef.current?.pause();
|
|
4741
4756
|
};
|
|
4742
|
-
(0,
|
|
4757
|
+
(0, import_react11.useEffect)(() => {
|
|
4743
4758
|
if (props.autoplay && !reduced) play();
|
|
4744
4759
|
return () => {
|
|
4745
4760
|
tweenRef.current?.kill();
|
|
@@ -4755,7 +4770,7 @@ var PaperMesh = (0, import_react10.forwardRef)(function PaperMesh2(props, ref) {
|
|
|
4755
4770
|
behavior: { ...cfg.behavior, ...overridesRef.current }
|
|
4756
4771
|
});
|
|
4757
4772
|
};
|
|
4758
|
-
(0,
|
|
4773
|
+
(0, import_react11.useImperativeHandle)(ref, () => ({
|
|
4759
4774
|
play,
|
|
4760
4775
|
pause,
|
|
4761
4776
|
get playing() {
|
|
@@ -4792,8 +4807,8 @@ var PaperMesh = (0, import_react10.forwardRef)(function PaperMesh2(props, ref) {
|
|
|
4792
4807
|
placeProgrammatic: () => machineRef.current?.placeProgrammatic() ?? false,
|
|
4793
4808
|
returnProgrammatic: () => machineRef.current?.returnProgrammatic() ?? false
|
|
4794
4809
|
}));
|
|
4795
|
-
const idlePose = (0,
|
|
4796
|
-
(0,
|
|
4810
|
+
const idlePose = (0, import_react11.useRef)({ position: [0, 0, 0], rotation: [0, 0, 0] });
|
|
4811
|
+
(0, import_fiber4.useFrame)(({ clock }, delta) => {
|
|
4797
4812
|
const cfg = liveConfig();
|
|
4798
4813
|
const now = reduced ? 0 : cfg.onTwos ? quantizeTime(clock.elapsedTime) : clock.elapsedTime;
|
|
4799
4814
|
const hasBehaviorTransform = Boolean(behavior?.transform && cfg.behavior);
|
|
@@ -4878,7 +4893,7 @@ var PaperMesh = (0, import_react10.forwardRef)(function PaperMesh2(props, ref) {
|
|
|
4878
4893
|
const p = overridesRef.current[behavior.progressParam];
|
|
4879
4894
|
if (typeof p === "number") props.onProgress?.(p);
|
|
4880
4895
|
};
|
|
4881
|
-
const grabAnchor = (0,
|
|
4896
|
+
const grabAnchor = (0, import_react11.useRef)(new THREE11.Vector3());
|
|
4882
4897
|
const clothDown = (e) => {
|
|
4883
4898
|
if (!isCloth || !sim || !props.interactive || !groupRef.current) return;
|
|
4884
4899
|
e.stopPropagation();
|
|
@@ -5094,22 +5109,22 @@ function resolveFieldSlotConfig(slot, fallback, index, layoutId, layoutOptions)
|
|
|
5094
5109
|
// src/field/fieldGroup.tsx
|
|
5095
5110
|
var THREE13 = __toESM(require("three"), 1);
|
|
5096
5111
|
var import_gsap3 = require("gsap");
|
|
5097
|
-
var
|
|
5098
|
-
var
|
|
5112
|
+
var import_fiber5 = require("@react-three/fiber");
|
|
5113
|
+
var import_react13 = require("react");
|
|
5099
5114
|
var import_three_custom_shader_material2 = __toESM(require("three-custom-shader-material"), 1);
|
|
5100
5115
|
|
|
5101
5116
|
// src/content/atlas.ts
|
|
5102
5117
|
var THREE12 = __toESM(require("three"), 1);
|
|
5103
|
-
var
|
|
5118
|
+
var import_react12 = require("react");
|
|
5104
5119
|
var MAX_ATLAS = 4096;
|
|
5105
5120
|
function atlasGrid(count, aspect = 1) {
|
|
5106
5121
|
const cols = Math.max(1, Math.min(count, Math.ceil(Math.sqrt(count * Math.max(aspect, 0.01)))));
|
|
5107
5122
|
return { cols, rows: Math.max(1, Math.ceil(count / cols)) };
|
|
5108
5123
|
}
|
|
5109
5124
|
function useContentAtlas(contents, sheet2, stock) {
|
|
5110
|
-
const [atlas, setAtlas] = (0,
|
|
5125
|
+
const [atlas, setAtlas] = (0, import_react12.useState)(null);
|
|
5111
5126
|
const stableContents = useStable(contents);
|
|
5112
|
-
(0,
|
|
5127
|
+
(0, import_react12.useEffect)(() => {
|
|
5113
5128
|
let disposed = false;
|
|
5114
5129
|
const aspect = sheet2.height / sheet2.width;
|
|
5115
5130
|
const { cols, rows } = atlasGrid(contents.length, aspect);
|
|
@@ -5839,11 +5854,11 @@ function FieldGroup({
|
|
|
5839
5854
|
const stock = getStock(config.stock);
|
|
5840
5855
|
const rig = useLightRig(config.scene.lighting);
|
|
5841
5856
|
const behavior = config.behavior && !config.deformers ? getBehavior(config.behavior.type) : null;
|
|
5842
|
-
const progressRef = (0,
|
|
5857
|
+
const progressRef = (0, import_react13.useRef)(
|
|
5843
5858
|
behavior ? config.behavior[behavior.progressParam] : 0
|
|
5844
5859
|
);
|
|
5845
5860
|
const buildStackAt = (progress) => fieldShapeStack(config, progress);
|
|
5846
|
-
const initialStack = (0,
|
|
5861
|
+
const initialStack = (0, import_react13.useMemo)(
|
|
5847
5862
|
() => buildStackAt(progressRef.current),
|
|
5848
5863
|
[
|
|
5849
5864
|
JSON.stringify(config.behavior ?? null),
|
|
@@ -5852,7 +5867,7 @@ function FieldGroup({
|
|
|
5852
5867
|
]
|
|
5853
5868
|
);
|
|
5854
5869
|
const structureKey = initialStack.map((i) => i.type).join("|");
|
|
5855
|
-
const geometry = (0,
|
|
5870
|
+
const geometry = (0, import_react13.useMemo)(() => {
|
|
5856
5871
|
const floor = stackMinSegments(initialStack, config.sheet);
|
|
5857
5872
|
const want = [0, 0];
|
|
5858
5873
|
for (const p of PROGRESS_SAMPLES2) {
|
|
@@ -5886,9 +5901,9 @@ function FieldGroup({
|
|
|
5886
5901
|
geo.setAttribute("aBias", new THREE13.InstancedBufferAttribute(bias, 1));
|
|
5887
5902
|
return geo;
|
|
5888
5903
|
}, [JSON.stringify(config.sheet), structureKey, count, autoCeiling]);
|
|
5889
|
-
(0,
|
|
5904
|
+
(0, import_react13.useEffect)(() => () => geometry.dispose(), [geometry]);
|
|
5890
5905
|
const atlas = useContentAtlas(contents, config.sheet, stock);
|
|
5891
|
-
const shader = (0,
|
|
5906
|
+
const shader = (0, import_react13.useMemo)(() => {
|
|
5892
5907
|
const composed = buildDisplacementGLSL(initialStack, config.sheet);
|
|
5893
5908
|
const uniforms = {};
|
|
5894
5909
|
for (const [name, value] of Object.entries(composed.uniforms)) {
|
|
@@ -5917,19 +5932,19 @@ function FieldGroup({
|
|
|
5917
5932
|
config.surface.showThrough,
|
|
5918
5933
|
config.surface.translucency
|
|
5919
5934
|
]);
|
|
5920
|
-
(0,
|
|
5935
|
+
(0, import_react13.useEffect)(() => {
|
|
5921
5936
|
const values = translucencyValues(config.surface.translucency ?? stock.translucency, rig);
|
|
5922
5937
|
shader.uniforms.uTranslucency.value = values.translucency;
|
|
5923
5938
|
shader.uniforms.uBackLightDir.value.copy(values.direction);
|
|
5924
5939
|
shader.uniforms.uBackLightColor.value.copy(values.color);
|
|
5925
5940
|
shader.uniforms.uAmbientTransmission.value = values.ambient;
|
|
5926
5941
|
}, [shader, rig, config.surface.translucency, stock.translucency]);
|
|
5927
|
-
(0,
|
|
5942
|
+
(0, import_react13.useEffect)(() => {
|
|
5928
5943
|
if (!atlas) return;
|
|
5929
5944
|
shader.uniforms.uAtlas.value = atlas.texture;
|
|
5930
5945
|
shader.uniforms.uAtlasGrid.value.set(atlas.cols, atlas.rows);
|
|
5931
5946
|
}, [atlas, shader]);
|
|
5932
|
-
(0,
|
|
5947
|
+
(0, import_react13.useEffect)(() => {
|
|
5933
5948
|
if (!behavior || shared.reduced) return;
|
|
5934
5949
|
const state = { p: progressRef.current };
|
|
5935
5950
|
const tween = import_gsap3.gsap.to(state, {
|
|
@@ -5946,8 +5961,8 @@ function FieldGroup({
|
|
|
5946
5961
|
tween.kill();
|
|
5947
5962
|
};
|
|
5948
5963
|
}, [structureKey, shared.reduced]);
|
|
5949
|
-
const meshRef = (0,
|
|
5950
|
-
(0,
|
|
5964
|
+
const meshRef = (0, import_react13.useRef)(null);
|
|
5965
|
+
(0, import_fiber5.useFrame)(({ clock }) => {
|
|
5951
5966
|
const mesh = meshRef.current;
|
|
5952
5967
|
if (!mesh) return;
|
|
5953
5968
|
const elapsed = clock.elapsedTime - Math.max(shared.mountTimeRef.current, 0);
|
|
@@ -6094,7 +6109,7 @@ var easeInOut = (t) => t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2;
|
|
|
6094
6109
|
|
|
6095
6110
|
// src/field/backingSheet.tsx
|
|
6096
6111
|
var THREE14 = __toESM(require("three"), 1);
|
|
6097
|
-
var
|
|
6112
|
+
var import_react14 = require("react");
|
|
6098
6113
|
|
|
6099
6114
|
// src/content/backing.ts
|
|
6100
6115
|
function silhouetteRects(o, count) {
|
|
@@ -6167,7 +6182,7 @@ function BackingSheet({
|
|
|
6167
6182
|
removed
|
|
6168
6183
|
}) {
|
|
6169
6184
|
const { width, height } = sheetBackingSize(options);
|
|
6170
|
-
const canvas = (0,
|
|
6185
|
+
const canvas = (0, import_react14.useMemo)(() => {
|
|
6171
6186
|
if (typeof document === "undefined") return null;
|
|
6172
6187
|
const c = document.createElement("canvas");
|
|
6173
6188
|
const scale = Math.min(1024, Math.round(360 * Math.max(width, height))) / Math.max(width, height);
|
|
@@ -6175,14 +6190,14 @@ function BackingSheet({
|
|
|
6175
6190
|
c.height = Math.max(2, Math.round(height * scale));
|
|
6176
6191
|
return c;
|
|
6177
6192
|
}, [width, height]);
|
|
6178
|
-
const texture = (0,
|
|
6193
|
+
const texture = (0, import_react14.useMemo)(() => canvas ? new THREE14.CanvasTexture(canvas) : null, [canvas]);
|
|
6179
6194
|
const removedKey = [...removed].sort((a, b) => a - b).join(",");
|
|
6180
|
-
(0,
|
|
6195
|
+
(0, import_react14.useEffect)(() => {
|
|
6181
6196
|
if (!canvas || !texture) return;
|
|
6182
6197
|
drawBacking(canvas, { options, count, tint: BACKING_TINT, removed });
|
|
6183
6198
|
texture.needsUpdate = true;
|
|
6184
6199
|
}, [canvas, texture, JSON.stringify(options), count, removedKey]);
|
|
6185
|
-
(0,
|
|
6200
|
+
(0, import_react14.useEffect)(() => () => texture?.dispose(), [texture]);
|
|
6186
6201
|
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("mesh", { receiveShadow: true, children: [
|
|
6187
6202
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("planeGeometry", { args: [width, height] }),
|
|
6188
6203
|
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)("meshStandardMaterial", { map: texture, color: "#ffffff", roughness: 0.92, metalness: 0 })
|
|
@@ -6192,8 +6207,8 @@ function BackingSheet({
|
|
|
6192
6207
|
// src/field/interactiveField.tsx
|
|
6193
6208
|
var THREE15 = __toESM(require("three"), 1);
|
|
6194
6209
|
var import_gsap4 = require("gsap");
|
|
6195
|
-
var
|
|
6196
|
-
var
|
|
6210
|
+
var import_fiber6 = require("@react-three/fiber");
|
|
6211
|
+
var import_react15 = require("react");
|
|
6197
6212
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
6198
6213
|
var PICK_BEHAVIORS = /* @__PURE__ */ new Set(["peel", "carry"]);
|
|
6199
6214
|
function InteractiveField(props) {
|
|
@@ -6201,15 +6216,15 @@ function InteractiveField(props) {
|
|
|
6201
6216
|
const total = papers.length;
|
|
6202
6217
|
const layout = getLayout(layoutId);
|
|
6203
6218
|
const reduced = usePrefersReducedMotion(props.reducedMotion);
|
|
6204
|
-
const contextRegistry = (0,
|
|
6205
|
-
const registry4 = (0,
|
|
6206
|
-
const camera = (0,
|
|
6207
|
-
const gl = (0,
|
|
6208
|
-
const controls = (0,
|
|
6209
|
-
const [removed, setRemoved] = (0,
|
|
6210
|
-
const [slotPatches, setSlotPatches] = (0,
|
|
6211
|
-
const [slotStates, setSlotStates] = (0,
|
|
6212
|
-
const slotConfigs = (0,
|
|
6219
|
+
const contextRegistry = (0, import_react15.useContext)(DropZoneContext);
|
|
6220
|
+
const registry4 = (0, import_react15.useMemo)(() => contextRegistry ?? new DropZoneRegistry(), [contextRegistry]);
|
|
6221
|
+
const camera = (0, import_fiber6.useThree)((s) => s.camera);
|
|
6222
|
+
const gl = (0, import_fiber6.useThree)((s) => s.gl);
|
|
6223
|
+
const controls = (0, import_fiber6.useThree)((s) => s.controls);
|
|
6224
|
+
const [removed, setRemoved] = (0, import_react15.useState)(EMPTY_SET);
|
|
6225
|
+
const [slotPatches, setSlotPatches] = (0, import_react15.useState)({});
|
|
6226
|
+
const [slotStates, setSlotStates] = (0, import_react15.useState)({});
|
|
6227
|
+
const slotConfigs = (0, import_react15.useMemo)(
|
|
6213
6228
|
() => papers.map((slot, i) => {
|
|
6214
6229
|
const config = resolveFieldSlotConfig(slot, fallback, i, layoutId, layoutOptions);
|
|
6215
6230
|
const patch = slotPatches[i];
|
|
@@ -6223,14 +6238,14 @@ function InteractiveField(props) {
|
|
|
6223
6238
|
slotPatches
|
|
6224
6239
|
]
|
|
6225
6240
|
);
|
|
6226
|
-
const poses = (0,
|
|
6241
|
+
const poses = (0, import_react15.useMemo)(
|
|
6227
6242
|
() => slotConfigs.map((_, i) => layout.pose(i, total, layoutOptions, 0, props.sheet)),
|
|
6228
6243
|
[layoutId, JSON.stringify(layoutOptions), total, props.sheet.width, props.sheet.height]
|
|
6229
6244
|
);
|
|
6230
|
-
const groupRefs = (0,
|
|
6231
|
-
const handleRefs = (0,
|
|
6232
|
-
const pressRef = (0,
|
|
6233
|
-
const carriedRef = (0,
|
|
6245
|
+
const groupRefs = (0, import_react15.useRef)([]);
|
|
6246
|
+
const handleRefs = (0, import_react15.useRef)([]);
|
|
6247
|
+
const pressRef = (0, import_react15.useRef)(null);
|
|
6248
|
+
const carriedRef = (0, import_react15.useRef)(null);
|
|
6234
6249
|
const zonesLive = () => [...props.zones ?? [], ...registry4.list()];
|
|
6235
6250
|
const slotName = (i) => {
|
|
6236
6251
|
const preset = papers[i]?.preset ?? fallback;
|
|
@@ -6243,10 +6258,10 @@ function InteractiveField(props) {
|
|
|
6243
6258
|
}
|
|
6244
6259
|
props.onSlotStateChange?.(i, state);
|
|
6245
6260
|
};
|
|
6246
|
-
const raycaster = (0,
|
|
6247
|
-
const planeScratch = (0,
|
|
6248
|
-
const pointScratch = (0,
|
|
6249
|
-
const ndcScratch = (0,
|
|
6261
|
+
const raycaster = (0, import_react15.useMemo)(() => new THREE15.Raycaster(), []);
|
|
6262
|
+
const planeScratch = (0, import_react15.useMemo)(() => new THREE15.Plane(new THREE15.Vector3(0, 0, 1), 0), []);
|
|
6263
|
+
const pointScratch = (0, import_react15.useMemo)(() => new THREE15.Vector3(), []);
|
|
6264
|
+
const ndcScratch = (0, import_react15.useMemo)(() => new THREE15.Vector2(), []);
|
|
6250
6265
|
const planePoint = (clientX, clientY, planeZ) => {
|
|
6251
6266
|
const rect = gl.domElement.getBoundingClientRect();
|
|
6252
6267
|
ndcScratch.set(
|
|
@@ -6376,7 +6391,7 @@ function InteractiveField(props) {
|
|
|
6376
6391
|
import_gsap4.gsap.to(group.rotation, { x: home.rotation[0], y: home.rotation[1], z: home.rotation[2], duration });
|
|
6377
6392
|
import_gsap4.gsap.to(group.scale, { x: home.scale, y: home.scale, z: home.scale, duration: duration * 0.5 });
|
|
6378
6393
|
};
|
|
6379
|
-
const onPointerMoveRef = (0,
|
|
6394
|
+
const onPointerMoveRef = (0, import_react15.useRef)(() => {
|
|
6380
6395
|
});
|
|
6381
6396
|
onPointerMoveRef.current = (e) => {
|
|
6382
6397
|
const press = pressRef.current;
|
|
@@ -6400,7 +6415,7 @@ function InteractiveField(props) {
|
|
|
6400
6415
|
pick(slot, hit[0], hit[1], pointerId);
|
|
6401
6416
|
}
|
|
6402
6417
|
};
|
|
6403
|
-
const onPointerUpRef = (0,
|
|
6418
|
+
const onPointerUpRef = (0, import_react15.useRef)(() => {
|
|
6404
6419
|
});
|
|
6405
6420
|
onPointerUpRef.current = (e) => {
|
|
6406
6421
|
pressRef.current = null;
|
|
@@ -6414,7 +6429,7 @@ function InteractiveField(props) {
|
|
|
6414
6429
|
if (zone) settleInto(carried, zone);
|
|
6415
6430
|
else returnHome(carried);
|
|
6416
6431
|
};
|
|
6417
|
-
(0,
|
|
6432
|
+
(0, import_react15.useEffect)(() => {
|
|
6418
6433
|
const move = (e) => onPointerMoveRef.current(e);
|
|
6419
6434
|
const up = (e) => onPointerUpRef.current(e);
|
|
6420
6435
|
window.addEventListener("pointermove", move);
|
|
@@ -6424,7 +6439,7 @@ function InteractiveField(props) {
|
|
|
6424
6439
|
window.removeEventListener("pointerup", up);
|
|
6425
6440
|
};
|
|
6426
6441
|
}, []);
|
|
6427
|
-
(0,
|
|
6442
|
+
(0, import_fiber6.useFrame)((_, delta) => {
|
|
6428
6443
|
const carried = carriedRef.current;
|
|
6429
6444
|
if (!carried || carried.settling) return;
|
|
6430
6445
|
const group = groupRefs.current[carried.slot];
|
|
@@ -6462,7 +6477,7 @@ function InteractiveField(props) {
|
|
|
6462
6477
|
group.scale.x += (targetScale - group.scale.x) * 0.15;
|
|
6463
6478
|
group.scale.y = group.scale.z = group.scale.x;
|
|
6464
6479
|
});
|
|
6465
|
-
const a11yImplRef = (0,
|
|
6480
|
+
const a11yImplRef = (0, import_react15.useRef)(null);
|
|
6466
6481
|
a11yImplRef.current = {
|
|
6467
6482
|
pick: (slot) => {
|
|
6468
6483
|
const home = poses[slot];
|
|
@@ -6487,7 +6502,7 @@ function InteractiveField(props) {
|
|
|
6487
6502
|
zoneIds: () => zonesLive().map((z30) => z30.id),
|
|
6488
6503
|
slotState: (slot) => slotStates[slot] ?? "rest"
|
|
6489
6504
|
};
|
|
6490
|
-
(0,
|
|
6505
|
+
(0, import_react15.useEffect)(() => {
|
|
6491
6506
|
const ref = props.a11yRef;
|
|
6492
6507
|
if (!ref) return;
|
|
6493
6508
|
ref.current = {
|
|
@@ -6540,7 +6555,7 @@ function InteractiveField(props) {
|
|
|
6540
6555
|
}
|
|
6541
6556
|
|
|
6542
6557
|
// src/field/keyboardMirror.tsx
|
|
6543
|
-
var
|
|
6558
|
+
var import_react16 = require("react");
|
|
6544
6559
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
6545
6560
|
function fieldKeyboardStep(carry2, slot, key, controller) {
|
|
6546
6561
|
if (!carry2) {
|
|
@@ -6586,7 +6601,7 @@ function FieldKeyboardMirror({
|
|
|
6586
6601
|
papers,
|
|
6587
6602
|
controller
|
|
6588
6603
|
}) {
|
|
6589
|
-
const [carrying, setCarrying] = (0,
|
|
6604
|
+
const [carrying, setCarrying] = (0, import_react16.useState)(null);
|
|
6590
6605
|
const paperLabel = (slot, i) => {
|
|
6591
6606
|
try {
|
|
6592
6607
|
const config = resolveConfig({ preset: slot.preset });
|
|
@@ -6689,16 +6704,16 @@ function fitCamera(layout, n, options, sheet2, fovDeg, aspect, margin = 1.06) {
|
|
|
6689
6704
|
|
|
6690
6705
|
// src/PaperField.tsx
|
|
6691
6706
|
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
6692
|
-
var PaperFieldMesh = (0,
|
|
6707
|
+
var PaperFieldMesh = (0, import_react17.forwardRef)(
|
|
6693
6708
|
function PaperFieldMesh2(props, ref) {
|
|
6694
6709
|
const reduced = usePrefersReducedMotion(props.reducedMotion);
|
|
6695
|
-
const papers = (0,
|
|
6710
|
+
const papers = (0, import_react17.useMemo)(
|
|
6696
6711
|
() => effectiveFieldPapers(props.papers, props.images),
|
|
6697
6712
|
[props.papers, props.images]
|
|
6698
6713
|
);
|
|
6699
6714
|
const stablePapers = useStable(papers);
|
|
6700
6715
|
const stablePreset = useStable(props.preset ?? null);
|
|
6701
|
-
const groups = (0,
|
|
6716
|
+
const groups = (0, import_react17.useMemo)(
|
|
6702
6717
|
() => groupFieldPapers(stablePapers, stablePreset ?? void 0),
|
|
6703
6718
|
[stablePapers, stablePreset]
|
|
6704
6719
|
);
|
|
@@ -6707,22 +6722,22 @@ var PaperFieldMesh = (0, import_react16.forwardRef)(
|
|
|
6707
6722
|
const layout = getLayout(layoutId);
|
|
6708
6723
|
const firstSheet = groups[0]?.config.sheet;
|
|
6709
6724
|
const stableLayoutOptions = useStable(props.layoutOptions ?? {});
|
|
6710
|
-
const layoutOptions = (0,
|
|
6725
|
+
const layoutOptions = (0, import_react17.useMemo)(
|
|
6711
6726
|
// Sheet grids size their cells from the papers themselves — gutter is
|
|
6712
6727
|
// then literally the spacing between stamps (explicit cell dims win).
|
|
6713
6728
|
() => resolveLayoutOptions(layoutId, layout, stableLayoutOptions, firstSheet),
|
|
6714
6729
|
[layoutId, stableLayoutOptions, firstSheet?.width, firstSheet?.height]
|
|
6715
6730
|
);
|
|
6716
|
-
const phaseRef = (0,
|
|
6717
|
-
const dragVelRef = (0,
|
|
6718
|
-
const mountTimeRef = (0,
|
|
6719
|
-
const morphRef = (0,
|
|
6720
|
-
const prevLayout = (0,
|
|
6721
|
-
const gl = (0,
|
|
6731
|
+
const phaseRef = (0, import_react17.useRef)(0);
|
|
6732
|
+
const dragVelRef = (0, import_react17.useRef)(0);
|
|
6733
|
+
const mountTimeRef = (0, import_react17.useRef)(-1);
|
|
6734
|
+
const morphRef = (0, import_react17.useRef)({ from: null, t: 1 });
|
|
6735
|
+
const prevLayout = (0, import_react17.useRef)({ id: layoutId, options: layoutOptions });
|
|
6736
|
+
const gl = (0, import_fiber7.useThree)((s) => s.gl);
|
|
6722
6737
|
const driver = reduced ? "none" : props.motion?.driver ?? "autoplay";
|
|
6723
6738
|
const speed = props.motion?.speed ?? 0.5;
|
|
6724
6739
|
const entranceType = reduced ? "none" : props.entrance?.type ?? "rise";
|
|
6725
|
-
(0,
|
|
6740
|
+
(0, import_react17.useEffect)(() => {
|
|
6726
6741
|
const prev = prevLayout.current;
|
|
6727
6742
|
if (prev.id !== layoutId || JSON.stringify(prev.options) !== JSON.stringify(layoutOptions)) {
|
|
6728
6743
|
morphRef.current = { from: prev, t: 0 };
|
|
@@ -6730,7 +6745,7 @@ var PaperFieldMesh = (0, import_react16.forwardRef)(
|
|
|
6730
6745
|
prevLayout.current = { id: layoutId, options: layoutOptions };
|
|
6731
6746
|
}
|
|
6732
6747
|
}, [layoutId, layoutOptions]);
|
|
6733
|
-
(0,
|
|
6748
|
+
(0, import_react17.useEffect)(() => {
|
|
6734
6749
|
if (driver !== "drag") return;
|
|
6735
6750
|
const el = gl.domElement;
|
|
6736
6751
|
let lastX = null;
|
|
@@ -6756,7 +6771,7 @@ var PaperFieldMesh = (0, import_react16.forwardRef)(
|
|
|
6756
6771
|
window.removeEventListener("pointerup", up);
|
|
6757
6772
|
};
|
|
6758
6773
|
}, [driver, gl]);
|
|
6759
|
-
(0,
|
|
6774
|
+
(0, import_fiber7.useFrame)(({ clock }, delta) => {
|
|
6760
6775
|
if (mountTimeRef.current < 0) mountTimeRef.current = clock.elapsedTime;
|
|
6761
6776
|
if (driver === "autoplay") phaseRef.current += delta * speed * 0.02;
|
|
6762
6777
|
if (driver === "drag") {
|
|
@@ -6814,14 +6829,14 @@ var PaperFieldMesh = (0, import_react16.forwardRef)(
|
|
|
6814
6829
|
}
|
|
6815
6830
|
);
|
|
6816
6831
|
function FitCamera(meshProps) {
|
|
6817
|
-
const camera = (0,
|
|
6818
|
-
const width = (0,
|
|
6819
|
-
const height = (0,
|
|
6832
|
+
const camera = (0, import_fiber7.useThree)((s) => s.camera);
|
|
6833
|
+
const width = (0, import_fiber7.useThree)((s) => s.size.width);
|
|
6834
|
+
const height = (0, import_fiber7.useThree)((s) => s.size.height);
|
|
6820
6835
|
const papersProp = useStable(meshProps.papers ?? null);
|
|
6821
6836
|
const imagesProp = useStable(meshProps.images ?? null);
|
|
6822
6837
|
const presetProp = useStable(meshProps.preset ?? null);
|
|
6823
6838
|
const optionsProp = useStable(meshProps.layoutOptions ?? {});
|
|
6824
|
-
const field = (0,
|
|
6839
|
+
const field = (0, import_react17.useMemo)(() => {
|
|
6825
6840
|
const papers = effectiveFieldPapers(papersProp ?? void 0, imagesProp ?? void 0);
|
|
6826
6841
|
const layoutId = meshProps.layout ?? "ring";
|
|
6827
6842
|
const layout = getLayout(layoutId);
|
|
@@ -6829,7 +6844,7 @@ function FitCamera(meshProps) {
|
|
|
6829
6844
|
const options = resolveLayoutOptions(layoutId, layout, optionsProp, sheet2);
|
|
6830
6845
|
return { layout, n: papers.length, options, sheet: sheet2 ?? DEFAULT_SHEET };
|
|
6831
6846
|
}, [papersProp, imagesProp, presetProp, meshProps.layout, optionsProp]);
|
|
6832
|
-
(0,
|
|
6847
|
+
(0, import_react17.useEffect)(() => {
|
|
6833
6848
|
if (!(camera instanceof THREE16.PerspectiveCamera)) return;
|
|
6834
6849
|
const { position, target } = fitCamera(
|
|
6835
6850
|
field.layout,
|
|
@@ -6845,27 +6860,28 @@ function FitCamera(meshProps) {
|
|
|
6845
6860
|
}, [camera, width, height, field]);
|
|
6846
6861
|
return null;
|
|
6847
6862
|
}
|
|
6848
|
-
var PaperField = (0,
|
|
6863
|
+
var PaperField = (0, import_react17.forwardRef)(function PaperField2({ children, className, style, scene, ...meshProps }, ref) {
|
|
6849
6864
|
const rig = sceneSchema.parse(scene ?? {});
|
|
6850
|
-
const registry4 = (0,
|
|
6851
|
-
const a11yRef = (0,
|
|
6852
|
-
const papers = (0,
|
|
6865
|
+
const registry4 = (0, import_react17.useMemo)(() => new DropZoneRegistry(), []);
|
|
6866
|
+
const a11yRef = (0, import_react17.useRef)(null);
|
|
6867
|
+
const papers = (0, import_react17.useMemo)(
|
|
6853
6868
|
() => effectiveFieldPapers(meshProps.papers, meshProps.images),
|
|
6854
6869
|
[meshProps.papers, meshProps.images]
|
|
6855
6870
|
);
|
|
6856
6871
|
const stablePapers = useStable(papers);
|
|
6857
6872
|
const stablePreset = useStable(meshProps.preset ?? null);
|
|
6858
|
-
const interactive = (0,
|
|
6873
|
+
const interactive = (0, import_react17.useMemo)(
|
|
6859
6874
|
() => fieldIsInteractive(stablePapers, stablePreset ?? void 0, meshProps.interactive),
|
|
6860
6875
|
[stablePapers, stablePreset, meshProps.interactive]
|
|
6861
6876
|
);
|
|
6862
6877
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className, style: { width: "100%", height: "100%", ...style }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(DropZoneContext.Provider, { value: registry4, children: [
|
|
6863
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
6878
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_fiber7.Canvas, { shadows: true, camera: { position: [0, 0.6, 5.2], fov: 45 }, dpr: [1, 2], children: [
|
|
6864
6879
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(FitCamera, { ...meshProps }),
|
|
6865
6880
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PaperBackdrop, { backdrop: rig.backdrop }),
|
|
6866
6881
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PaperLighting, { preset: rig.lighting, light: rig.light, floor: -2.4, scale: 14 }),
|
|
6867
6882
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(PaperFieldMesh, { ref, a11yControllerRef: a11yRef, ...meshProps }),
|
|
6868
|
-
children
|
|
6883
|
+
children,
|
|
6884
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ReleaseContextOnUnmount, {})
|
|
6869
6885
|
] }),
|
|
6870
6886
|
interactive && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(FieldKeyboardMirror, { papers, controller: a11yRef })
|
|
6871
6887
|
] }) });
|
|
@@ -6962,13 +6978,13 @@ function stageCamera(path, walked, scale, options) {
|
|
|
6962
6978
|
|
|
6963
6979
|
// src/stage/Figure.tsx
|
|
6964
6980
|
var THREE18 = __toESM(require("three"), 1);
|
|
6965
|
-
var
|
|
6966
|
-
var
|
|
6981
|
+
var import_react19 = require("react");
|
|
6982
|
+
var import_fiber9 = require("@react-three/fiber");
|
|
6967
6983
|
|
|
6968
6984
|
// src/stage/RiggedFigure.tsx
|
|
6969
6985
|
var import_drei2 = require("@react-three/drei");
|
|
6970
|
-
var
|
|
6971
|
-
var
|
|
6986
|
+
var import_fiber8 = require("@react-three/fiber");
|
|
6987
|
+
var import_react18 = require("react");
|
|
6972
6988
|
var THREE17 = __toESM(require("three"), 1);
|
|
6973
6989
|
var import_SkeletonUtils = require("three/examples/jsm/utils/SkeletonUtils.js");
|
|
6974
6990
|
|
|
@@ -7144,7 +7160,7 @@ function placeFigure(path, distance, o) {
|
|
|
7144
7160
|
|
|
7145
7161
|
// src/stage/RiggedFigure.tsx
|
|
7146
7162
|
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
7147
|
-
var ModelBoundary = class extends
|
|
7163
|
+
var ModelBoundary = class extends import_react18.Component {
|
|
7148
7164
|
state = { failed: false };
|
|
7149
7165
|
static getDerivedStateFromError() {
|
|
7150
7166
|
return { failed: true };
|
|
@@ -7158,14 +7174,14 @@ var ModelBoundary = class extends import_react17.Component {
|
|
|
7158
7174
|
};
|
|
7159
7175
|
function Rigged({ url, options, distance, frozen }) {
|
|
7160
7176
|
const gltf = (0, import_drei2.useGLTF)(url);
|
|
7161
|
-
const scene = (0,
|
|
7177
|
+
const scene = (0, import_react18.useMemo)(() => (0, import_SkeletonUtils.clone)(gltf.scene), [gltf.scene]);
|
|
7162
7178
|
const silhouette = options.finish === "silhouette";
|
|
7163
|
-
const material = (0,
|
|
7179
|
+
const material = (0, import_react18.useMemo)(
|
|
7164
7180
|
() => silhouette ? new THREE17.MeshBasicMaterial({ color: options.color, toneMapped: false }) : null,
|
|
7165
7181
|
[silhouette, options.color]
|
|
7166
7182
|
);
|
|
7167
|
-
(0,
|
|
7168
|
-
const scale = (0,
|
|
7183
|
+
(0, import_react18.useEffect)(() => () => material?.dispose(), [material]);
|
|
7184
|
+
const scale = (0, import_react18.useMemo)(() => {
|
|
7169
7185
|
scene.traverse((child) => {
|
|
7170
7186
|
const mesh = child;
|
|
7171
7187
|
if (!mesh.isMesh) return;
|
|
@@ -7179,13 +7195,13 @@ function Rigged({ url, options, distance, frozen }) {
|
|
|
7179
7195
|
const height = box.max.y - box.min.y;
|
|
7180
7196
|
return height > 0 ? options.height / height : 1;
|
|
7181
7197
|
}, [scene, material, silhouette, options.height]);
|
|
7182
|
-
const mixer = (0,
|
|
7183
|
-
const clip = (0,
|
|
7198
|
+
const mixer = (0, import_react18.useMemo)(() => new THREE17.AnimationMixer(scene), [scene]);
|
|
7199
|
+
const clip = (0, import_react18.useMemo)(() => {
|
|
7184
7200
|
const names = gltf.animations.map((a) => a.name);
|
|
7185
7201
|
const wanted = frozen ? pickStillClip(names) : pickClip(names, isRunning(options));
|
|
7186
7202
|
return gltf.animations.find((a) => a.name === wanted) ?? gltf.animations[0];
|
|
7187
7203
|
}, [gltf.animations, options, frozen]);
|
|
7188
|
-
(0,
|
|
7204
|
+
(0, import_react18.useEffect)(() => {
|
|
7189
7205
|
if (!clip) return;
|
|
7190
7206
|
mixer.clipAction(clip).play();
|
|
7191
7207
|
return () => {
|
|
@@ -7193,7 +7209,7 @@ function Rigged({ url, options, distance, frozen }) {
|
|
|
7193
7209
|
mixer.uncacheClip(clip);
|
|
7194
7210
|
};
|
|
7195
7211
|
}, [mixer, clip]);
|
|
7196
|
-
(0,
|
|
7212
|
+
(0, import_fiber8.useFrame)(() => {
|
|
7197
7213
|
if (!clip) return;
|
|
7198
7214
|
mixer.setTime(frozen ? 0 : clipTimeFor(distance.current, options, clip.duration));
|
|
7199
7215
|
});
|
|
@@ -7212,29 +7228,29 @@ function Segment({ length, radius, material }) {
|
|
|
7212
7228
|
function Figure({ path, figure, distance, distanceRef, walkLength, frozen }) {
|
|
7213
7229
|
const reducedMotion = usePrefersReducedMotion();
|
|
7214
7230
|
const still = frozen ?? reducedMotion;
|
|
7215
|
-
const options = (0,
|
|
7216
|
-
const walk = (0,
|
|
7217
|
-
const root = (0,
|
|
7218
|
-
const walkedRef = (0,
|
|
7219
|
-
const hips = (0,
|
|
7220
|
-
const chest = (0,
|
|
7221
|
-
const legL = (0,
|
|
7222
|
-
const legR = (0,
|
|
7223
|
-
const kneeL = (0,
|
|
7224
|
-
const kneeR = (0,
|
|
7225
|
-
const armL = (0,
|
|
7226
|
-
const armR = (0,
|
|
7227
|
-
const elbowL = (0,
|
|
7228
|
-
const elbowR = (0,
|
|
7229
|
-
const material = (0,
|
|
7231
|
+
const options = (0, import_react19.useMemo)(() => figureSchema.parse(figure ?? {}), [figure]);
|
|
7232
|
+
const walk = (0, import_react19.useMemo)(() => getWalkPath(walkPathSchema.parse(path ?? {})), [path]);
|
|
7233
|
+
const root = (0, import_react19.useRef)(null);
|
|
7234
|
+
const walkedRef = (0, import_react19.useRef)(0);
|
|
7235
|
+
const hips = (0, import_react19.useRef)(null);
|
|
7236
|
+
const chest = (0, import_react19.useRef)(null);
|
|
7237
|
+
const legL = (0, import_react19.useRef)(null);
|
|
7238
|
+
const legR = (0, import_react19.useRef)(null);
|
|
7239
|
+
const kneeL = (0, import_react19.useRef)(null);
|
|
7240
|
+
const kneeR = (0, import_react19.useRef)(null);
|
|
7241
|
+
const armL = (0, import_react19.useRef)(null);
|
|
7242
|
+
const armR = (0, import_react19.useRef)(null);
|
|
7243
|
+
const elbowL = (0, import_react19.useRef)(null);
|
|
7244
|
+
const elbowR = (0, import_react19.useRef)(null);
|
|
7245
|
+
const material = (0, import_react19.useMemo)(
|
|
7230
7246
|
() => new THREE18.MeshBasicMaterial({ color: options.color, toneMapped: false }),
|
|
7231
7247
|
[options.color]
|
|
7232
7248
|
);
|
|
7233
|
-
(0,
|
|
7249
|
+
(0, import_react19.useEffect)(() => () => material.dispose(), [material]);
|
|
7234
7250
|
const h = options.height;
|
|
7235
7251
|
const p = PROPORTIONS;
|
|
7236
7252
|
const torso = (p.shoulder - p.hip) * h;
|
|
7237
|
-
(0,
|
|
7253
|
+
(0, import_fiber9.useFrame)((state) => {
|
|
7238
7254
|
const walked = distanceRef !== void 0 ? distanceRef.current * (walkLength ?? walk.length) : distance ?? (still ? 0 : state.clock.elapsedTime * options.speed);
|
|
7239
7255
|
walkedRef.current = walked;
|
|
7240
7256
|
const { position, yaw, pose } = placeFigure(walk, walked, options);
|
|
@@ -7289,7 +7305,7 @@ function Figure({ path, figure, distance, distanceRef, walkLength, frozen }) {
|
|
|
7289
7305
|
// The capsules are both the fallback and the thing being replaced, so
|
|
7290
7306
|
// a model that is still downloading shows a walking figure rather than
|
|
7291
7307
|
// a hole, and one that never arrives leaves the stage as it was.
|
|
7292
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
7308
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react19.Suspense, { fallback: capsules, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
7293
7309
|
RiggedFigure,
|
|
7294
7310
|
{
|
|
7295
7311
|
url: options.model,
|
|
@@ -7304,7 +7320,7 @@ function Figure({ path, figure, distance, distanceRef, walkLength, frozen }) {
|
|
|
7304
7320
|
|
|
7305
7321
|
// src/stage/Surround.tsx
|
|
7306
7322
|
var THREE19 = __toESM(require("three"), 1);
|
|
7307
|
-
var
|
|
7323
|
+
var import_react20 = require("react");
|
|
7308
7324
|
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
7309
7325
|
function makeSkyTexture(sky) {
|
|
7310
7326
|
const canvas = document.createElement("canvas");
|
|
@@ -7333,8 +7349,7 @@ function makeGlowTexture(color) {
|
|
|
7333
7349
|
const ctx = canvas.getContext("2d");
|
|
7334
7350
|
const glow = ctx.createRadialGradient(size / 2, size / 2, 0, size / 2, size / 2, size / 2);
|
|
7335
7351
|
const c = new THREE19.Color(color);
|
|
7336
|
-
const
|
|
7337
|
-
for (const [stop, alpha] of [
|
|
7352
|
+
for (const [stop, level] of [
|
|
7338
7353
|
[0, 1],
|
|
7339
7354
|
[0.5, 1],
|
|
7340
7355
|
[0.62, 0.66],
|
|
@@ -7343,7 +7358,8 @@ function makeGlowTexture(color) {
|
|
|
7343
7358
|
[0.94, 0.03],
|
|
7344
7359
|
[1, 0]
|
|
7345
7360
|
]) {
|
|
7346
|
-
|
|
7361
|
+
const scaled = `${c.r * 255 * level | 0}, ${c.g * 255 * level | 0}, ${c.b * 255 * level | 0}`;
|
|
7362
|
+
glow.addColorStop(stop, `rgb(${scaled})`);
|
|
7347
7363
|
}
|
|
7348
7364
|
ctx.fillStyle = glow;
|
|
7349
7365
|
ctx.fillRect(0, 0, size, size);
|
|
@@ -7359,8 +7375,8 @@ function Source({
|
|
|
7359
7375
|
color,
|
|
7360
7376
|
intensity = SOURCE_INTENSITY
|
|
7361
7377
|
}) {
|
|
7362
|
-
const texture = (0,
|
|
7363
|
-
(0,
|
|
7378
|
+
const texture = (0, import_react20.useMemo)(() => makeGlowTexture(color), [color]);
|
|
7379
|
+
(0, import_react20.useEffect)(() => () => texture.dispose(), [texture]);
|
|
7364
7380
|
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("mesh", { position, rotation: [0, yaw, 0], children: [
|
|
7365
7381
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("planeGeometry", { args: [size * 2.4, size * 1.8] }),
|
|
7366
7382
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
@@ -7368,6 +7384,7 @@ function Source({
|
|
|
7368
7384
|
{
|
|
7369
7385
|
map: texture,
|
|
7370
7386
|
transparent: true,
|
|
7387
|
+
blending: THREE19.AdditiveBlending,
|
|
7371
7388
|
color: new THREE19.Color(intensity, intensity, intensity),
|
|
7372
7389
|
depthWrite: false,
|
|
7373
7390
|
fog: false
|
|
@@ -7377,8 +7394,8 @@ function Source({
|
|
|
7377
7394
|
}
|
|
7378
7395
|
function Surround({ radius, sky }) {
|
|
7379
7396
|
const { zenith, horizon, ground } = sky;
|
|
7380
|
-
const texture = (0,
|
|
7381
|
-
(0,
|
|
7397
|
+
const texture = (0, import_react20.useMemo)(() => makeSkyTexture({ zenith, horizon, ground }), [zenith, horizon, ground]);
|
|
7398
|
+
(0, import_react20.useEffect)(() => () => texture.dispose(), [texture]);
|
|
7382
7399
|
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("mesh", { children: [
|
|
7383
7400
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("sphereGeometry", { args: [radius, 32, 24] }),
|
|
7384
7401
|
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("meshBasicMaterial", { map: texture, side: THREE19.BackSide, fog: false })
|
|
@@ -7387,7 +7404,7 @@ function Surround({ radius, sky }) {
|
|
|
7387
7404
|
|
|
7388
7405
|
// src/stage/Room.tsx
|
|
7389
7406
|
var THREE20 = __toESM(require("three"), 1);
|
|
7390
|
-
var
|
|
7407
|
+
var import_react21 = require("react");
|
|
7391
7408
|
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
7392
7409
|
function makeFloorTexture(color, repeats) {
|
|
7393
7410
|
const size = 256;
|
|
@@ -7419,8 +7436,8 @@ function Floor({
|
|
|
7419
7436
|
slab
|
|
7420
7437
|
}) {
|
|
7421
7438
|
const repeats = slab > 0 ? Math.max(1, Math.round(size / slab)) : 0;
|
|
7422
|
-
const texture = (0,
|
|
7423
|
-
(0,
|
|
7439
|
+
const texture = (0, import_react21.useMemo)(() => repeats > 0 ? makeFloorTexture(color, repeats) : null, [color, repeats]);
|
|
7440
|
+
(0, import_react21.useEffect)(() => () => texture?.dispose(), [texture]);
|
|
7424
7441
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("mesh", { rotation: [-Math.PI / 2, 0, 0], receiveShadow: true, children: [
|
|
7425
7442
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("planeGeometry", { args: [size, size] }),
|
|
7426
7443
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("meshStandardMaterial", { map: texture, color: texture ? "#ffffff" : color, roughness: 1 })
|
|
@@ -7440,7 +7457,7 @@ function Columns({
|
|
|
7440
7457
|
offset,
|
|
7441
7458
|
color
|
|
7442
7459
|
}) {
|
|
7443
|
-
const placements = (0,
|
|
7460
|
+
const placements = (0, import_react21.useMemo)(() => {
|
|
7444
7461
|
if (!(spacing > 0) || !(path.length > 0)) return [];
|
|
7445
7462
|
const bays = Math.max(1, Math.round(path.length / spacing));
|
|
7446
7463
|
const out = [];
|
|
@@ -7456,12 +7473,12 @@ function Columns({
|
|
|
7456
7473
|
}
|
|
7457
7474
|
return out;
|
|
7458
7475
|
}, [path, spacing, offset]);
|
|
7459
|
-
const shaft = (0,
|
|
7460
|
-
const base = (0,
|
|
7461
|
-
const capital = (0,
|
|
7476
|
+
const shaft = (0, import_react21.useRef)(null);
|
|
7477
|
+
const base = (0, import_react21.useRef)(null);
|
|
7478
|
+
const capital = (0, import_react21.useRef)(null);
|
|
7462
7479
|
const plate = width * 1.45;
|
|
7463
7480
|
const plateHeight = width * 0.24;
|
|
7464
|
-
(0,
|
|
7481
|
+
(0, import_react21.useEffect)(() => {
|
|
7465
7482
|
const m = new THREE20.Matrix4();
|
|
7466
7483
|
const q = new THREE20.Quaternion();
|
|
7467
7484
|
const scale = new THREE20.Vector3(1, 1, 1);
|
|
@@ -7505,7 +7522,7 @@ function Doorway({
|
|
|
7505
7522
|
color,
|
|
7506
7523
|
extent
|
|
7507
7524
|
}) {
|
|
7508
|
-
const geometry = (0,
|
|
7525
|
+
const geometry = (0, import_react21.useMemo)(() => {
|
|
7509
7526
|
const w = size * 2.4 * opening;
|
|
7510
7527
|
const h = size * 1.8 * opening;
|
|
7511
7528
|
const shape = new THREE20.Shape();
|
|
@@ -7523,8 +7540,8 @@ function Doorway({
|
|
|
7523
7540
|
shape.holes.push(hole);
|
|
7524
7541
|
return new THREE20.ShapeGeometry(shape);
|
|
7525
7542
|
}, [size, opening, extent]);
|
|
7526
|
-
(0,
|
|
7527
|
-
const stood = (0,
|
|
7543
|
+
(0, import_react21.useEffect)(() => () => geometry.dispose(), [geometry]);
|
|
7544
|
+
const stood = (0, import_react21.useMemo)(
|
|
7528
7545
|
() => [position[0] + Math.sin(yaw) * NUDGE, position[1], position[2] + Math.cos(yaw) * NUDGE],
|
|
7529
7546
|
[position, yaw]
|
|
7530
7547
|
);
|
|
@@ -7533,7 +7550,7 @@ function Doorway({
|
|
|
7533
7550
|
|
|
7534
7551
|
// src/stage/Suspension.tsx
|
|
7535
7552
|
var THREE21 = __toESM(require("three"), 1);
|
|
7536
|
-
var
|
|
7553
|
+
var import_react22 = require("react");
|
|
7537
7554
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
7538
7555
|
var euler = (pose) => new THREE21.Euler(pose.rotation[0], pose.rotation[1], pose.rotation[2]);
|
|
7539
7556
|
function rodLength(sheet2, pose) {
|
|
@@ -7557,13 +7574,13 @@ function Suspension({
|
|
|
7557
7574
|
type,
|
|
7558
7575
|
hardware
|
|
7559
7576
|
}) {
|
|
7560
|
-
const poses = (0,
|
|
7577
|
+
const poses = (0, import_react22.useMemo)(() => {
|
|
7561
7578
|
const entry = getLayout(layout);
|
|
7562
7579
|
if (!entry) return [];
|
|
7563
7580
|
const options = entry.optionsSchema.parse(layoutOptions);
|
|
7564
7581
|
return Array.from({ length: count }, (_, i) => entry.pose(i, count, options, 0, sheet2));
|
|
7565
7582
|
}, [layout, layoutOptions, count, sheet2]);
|
|
7566
|
-
const geometry = (0,
|
|
7583
|
+
const geometry = (0, import_react22.useMemo)(() => {
|
|
7567
7584
|
const points = [];
|
|
7568
7585
|
const end = new THREE21.Vector3();
|
|
7569
7586
|
for (const pose of poses) {
|
|
@@ -7583,17 +7600,17 @@ function Suspension({
|
|
|
7583
7600
|
g.setAttribute("position", new THREE21.Float32BufferAttribute(points, 3));
|
|
7584
7601
|
return g;
|
|
7585
7602
|
}, [poses, paperHeight, ceiling, type, sheet2]);
|
|
7586
|
-
(0,
|
|
7587
|
-
const clipRef = (0,
|
|
7588
|
-
const rodRef = (0,
|
|
7589
|
-
const rodGeometry = (0,
|
|
7603
|
+
(0, import_react22.useEffect)(() => () => geometry.dispose(), [geometry]);
|
|
7604
|
+
const clipRef = (0, import_react22.useRef)(null);
|
|
7605
|
+
const rodRef = (0, import_react22.useRef)(null);
|
|
7606
|
+
const rodGeometry = (0, import_react22.useMemo)(() => {
|
|
7590
7607
|
const r = sheet2.width * 0.018;
|
|
7591
7608
|
const g = new THREE21.CylinderGeometry(r, r, sheet2.width * 1.22, 8);
|
|
7592
7609
|
g.rotateZ(Math.PI / 2);
|
|
7593
7610
|
return g;
|
|
7594
7611
|
}, [sheet2.width]);
|
|
7595
|
-
(0,
|
|
7596
|
-
(0,
|
|
7612
|
+
(0, import_react22.useEffect)(() => () => rodGeometry.dispose(), [rodGeometry]);
|
|
7613
|
+
(0, import_react22.useEffect)(() => {
|
|
7597
7614
|
const m = new THREE21.Matrix4();
|
|
7598
7615
|
const q = new THREE21.Quaternion();
|
|
7599
7616
|
const at = new THREE21.Vector3();
|
|
@@ -7984,8 +8001,8 @@ function travelBetween(from, to, t, closed) {
|
|
|
7984
8001
|
}
|
|
7985
8002
|
|
|
7986
8003
|
// src/stage/useWalk.ts
|
|
7987
|
-
var
|
|
7988
|
-
var
|
|
8004
|
+
var import_react23 = require("react");
|
|
8005
|
+
var import_fiber10 = require("@react-three/fiber");
|
|
7989
8006
|
function useWalk({
|
|
7990
8007
|
path,
|
|
7991
8008
|
motion,
|
|
@@ -7995,15 +8012,15 @@ function useWalk({
|
|
|
7995
8012
|
reduced,
|
|
7996
8013
|
onProgress
|
|
7997
8014
|
}) {
|
|
7998
|
-
const gl = (0,
|
|
7999
|
-
const walk = (0,
|
|
8000
|
-
const velocity = (0,
|
|
8001
|
-
const dragged = (0,
|
|
8002
|
-
const travel = (0,
|
|
8015
|
+
const gl = (0, import_fiber10.useThree)((s) => s.gl);
|
|
8016
|
+
const walk = (0, import_react23.useRef)(progress ?? 0);
|
|
8017
|
+
const velocity = (0, import_react23.useRef)(0);
|
|
8018
|
+
const dragged = (0, import_react23.useRef)(false);
|
|
8019
|
+
const travel = (0, import_react23.useRef)(null);
|
|
8003
8020
|
const controlled = progress !== void 0;
|
|
8004
8021
|
const interactive = !controlled && motion.driver === "drag";
|
|
8005
|
-
const engaged = (0,
|
|
8006
|
-
const travelTo = (0,
|
|
8022
|
+
const engaged = (0, import_react23.useRef)(false);
|
|
8023
|
+
const travelTo = (0, import_react23.useCallback)(
|
|
8007
8024
|
(target) => {
|
|
8008
8025
|
engaged.current = true;
|
|
8009
8026
|
velocity.current = 0;
|
|
@@ -8017,14 +8034,14 @@ function useWalk({
|
|
|
8017
8034
|
},
|
|
8018
8035
|
[path.closed, reduced]
|
|
8019
8036
|
);
|
|
8020
|
-
const step = (0,
|
|
8037
|
+
const step = (0, import_react23.useCallback)(
|
|
8021
8038
|
(direction) => {
|
|
8022
8039
|
const from = travel.current?.to ?? walk.current;
|
|
8023
8040
|
travelTo(nextStop(stops, from, direction, path.closed));
|
|
8024
8041
|
},
|
|
8025
8042
|
[stops, path.closed, travelTo]
|
|
8026
8043
|
);
|
|
8027
|
-
(0,
|
|
8044
|
+
(0, import_react23.useEffect)(() => {
|
|
8028
8045
|
if (controlled) {
|
|
8029
8046
|
walk.current = progress;
|
|
8030
8047
|
travel.current = null;
|
|
@@ -8032,7 +8049,7 @@ function useWalk({
|
|
|
8032
8049
|
}
|
|
8033
8050
|
}, [controlled, progress]);
|
|
8034
8051
|
const canvas = gl.domElement;
|
|
8035
|
-
(0,
|
|
8052
|
+
(0, import_react23.useEffect)(() => {
|
|
8036
8053
|
if (!interactive) return;
|
|
8037
8054
|
const hadTabIndex = canvas.hasAttribute("tabindex");
|
|
8038
8055
|
if (!hadTabIndex) canvas.tabIndex = 0;
|
|
@@ -8123,8 +8140,8 @@ function useWalk({
|
|
|
8123
8140
|
if (!hadLabel) canvas.removeAttribute("aria-label");
|
|
8124
8141
|
};
|
|
8125
8142
|
}, [canvas, interactive, motion.speed, motion.capture, path.closed, step, travelTo, stops]);
|
|
8126
|
-
const reported = (0,
|
|
8127
|
-
(0,
|
|
8143
|
+
const reported = (0, import_react23.useRef)(-1);
|
|
8144
|
+
(0, import_fiber10.useFrame)((_, delta) => {
|
|
8128
8145
|
if (onProgress && Math.abs(walk.current - reported.current) > 1e-4) {
|
|
8129
8146
|
reported.current = walk.current;
|
|
8130
8147
|
onProgress(walk.current);
|
|
@@ -8150,7 +8167,7 @@ function useWalk({
|
|
|
8150
8167
|
if (!path.closed && (walk.current <= 0 || walk.current >= 1)) velocity.current = 0;
|
|
8151
8168
|
}
|
|
8152
8169
|
});
|
|
8153
|
-
return (0,
|
|
8170
|
+
return (0, import_react23.useMemo)(() => ({ walk, travelTo, step, dragged }), [travelTo, step]);
|
|
8154
8171
|
}
|
|
8155
8172
|
|
|
8156
8173
|
// src/stage/quality.ts
|
|
@@ -8270,13 +8287,13 @@ function ShotRig({
|
|
|
8270
8287
|
paperHeight,
|
|
8271
8288
|
walk
|
|
8272
8289
|
}) {
|
|
8273
|
-
const camera = (0,
|
|
8274
|
-
const path = (0,
|
|
8275
|
-
const scale = (0,
|
|
8290
|
+
const camera = (0, import_fiber11.useThree)((s) => s.camera);
|
|
8291
|
+
const path = (0, import_react24.useMemo)(() => getWalkPath(stage.path), [stage.path]);
|
|
8292
|
+
const scale = (0, import_react24.useMemo)(
|
|
8276
8293
|
() => ({ figure: stage.figure.height, paper: paperHeight }),
|
|
8277
8294
|
[stage.figure.height, paperHeight]
|
|
8278
8295
|
);
|
|
8279
|
-
(0,
|
|
8296
|
+
(0, import_fiber11.useFrame)(() => {
|
|
8280
8297
|
const { position, target } = stageCamera(path, walk.current * path.length, scale, stage.shot);
|
|
8281
8298
|
camera.position.set(position[0], position[1], position[2]);
|
|
8282
8299
|
camera.lookAt(target[0], target[1], target[2]);
|
|
@@ -8284,17 +8301,17 @@ function ShotRig({
|
|
|
8284
8301
|
return null;
|
|
8285
8302
|
}
|
|
8286
8303
|
function QualityWatch({ tier, onChange }) {
|
|
8287
|
-
const samples = (0,
|
|
8288
|
-
const settle2 = (0,
|
|
8289
|
-
const window2 = (0,
|
|
8290
|
-
const failed = (0,
|
|
8291
|
-
const settled = (0,
|
|
8304
|
+
const samples = (0, import_react24.useRef)([]);
|
|
8305
|
+
const settle2 = (0, import_react24.useRef)(SETTLE_FRAMES);
|
|
8306
|
+
const window2 = (0, import_react24.useRef)(FIRST_WINDOW);
|
|
8307
|
+
const failed = (0, import_react24.useRef)(null);
|
|
8308
|
+
const settled = (0, import_react24.useCallback)((next) => {
|
|
8292
8309
|
samples.current = [];
|
|
8293
8310
|
settle2.current = SETTLE_FRAMES;
|
|
8294
8311
|
window2.current = STEADY_WINDOW;
|
|
8295
8312
|
return next;
|
|
8296
8313
|
}, []);
|
|
8297
|
-
(0,
|
|
8314
|
+
(0, import_fiber11.useFrame)((_, delta) => {
|
|
8298
8315
|
if (settle2.current > 0) {
|
|
8299
8316
|
settle2.current -= 1;
|
|
8300
8317
|
return;
|
|
@@ -8331,41 +8348,41 @@ function PaperStageScene({
|
|
|
8331
8348
|
reducedMotion
|
|
8332
8349
|
}) {
|
|
8333
8350
|
const still = usePrefersReducedMotion(reducedMotion);
|
|
8334
|
-
const [tier, setTier] = (0,
|
|
8335
|
-
(0,
|
|
8351
|
+
const [tier, setTier] = (0, import_react24.useState)(quality === "auto" ? INITIAL_TIER : quality);
|
|
8352
|
+
(0, import_react24.useEffect)(() => {
|
|
8336
8353
|
if (quality !== "auto") setTier(quality);
|
|
8337
8354
|
}, [quality]);
|
|
8338
|
-
const reportQuality = (0,
|
|
8339
|
-
(0,
|
|
8355
|
+
const reportQuality = (0, import_react24.useRef)(onQualityChange);
|
|
8356
|
+
(0, import_react24.useEffect)(() => {
|
|
8340
8357
|
reportQuality.current = onQualityChange;
|
|
8341
8358
|
});
|
|
8342
|
-
(0,
|
|
8359
|
+
(0, import_react24.useEffect)(() => {
|
|
8343
8360
|
reportQuality.current?.(tier);
|
|
8344
8361
|
}, [tier]);
|
|
8345
8362
|
const settings = quality === "auto" ? qualityTiers[tier] : qualityFor(quality);
|
|
8346
8363
|
const stageKey = JSON.stringify(stageInput ?? {});
|
|
8347
|
-
const stage = (0,
|
|
8348
|
-
const path = (0,
|
|
8349
|
-
const rig = (0,
|
|
8364
|
+
const stage = (0, import_react24.useMemo)(() => stageSchema.parse(stageInput ?? {}), [stageKey]);
|
|
8365
|
+
const path = (0, import_react24.useMemo)(() => getWalkPath(stage.path), [stage.path]);
|
|
8366
|
+
const rig = (0, import_react24.useMemo)(() => {
|
|
8350
8367
|
const resolved = resolveLighting(stage.lighting, stage.light);
|
|
8351
8368
|
return {
|
|
8352
8369
|
...resolved,
|
|
8353
8370
|
sky: { zenith: stage.source.zenith, horizon: stage.source.color, ground: stage.ground.color }
|
|
8354
8371
|
};
|
|
8355
8372
|
}, [stage.lighting, stage.light, stage.source.zenith, stage.source.color, stage.ground.color]);
|
|
8356
|
-
const sheetDims = (0,
|
|
8373
|
+
const sheetDims = (0, import_react24.useMemo)(() => {
|
|
8357
8374
|
const { width, height } = resolveConfig({ preset: preset ?? BANNER }).sheet;
|
|
8358
8375
|
return { width, height };
|
|
8359
8376
|
}, [preset]);
|
|
8360
8377
|
const paperHeight = sheetDims.height;
|
|
8361
8378
|
const paperWidth = sheetDims.width;
|
|
8362
8379
|
const paper = preset ?? BANNER;
|
|
8363
|
-
const resolvedLayoutOptions = (0,
|
|
8380
|
+
const resolvedLayoutOptions = (0, import_react24.useMemo)(() => {
|
|
8364
8381
|
const schema = getLayout(layout).optionsSchema;
|
|
8365
8382
|
const takesPath = schema instanceof import_zod29.z.ZodObject && "path" in schema.shape;
|
|
8366
8383
|
return takesPath ? { ...layoutOptions, path: stage.path } : layoutOptions;
|
|
8367
8384
|
}, [layout, layoutOptions, stage.path]);
|
|
8368
|
-
const slots = (0,
|
|
8385
|
+
const slots = (0, import_react24.useMemo)(() => {
|
|
8369
8386
|
if (papers) return papers;
|
|
8370
8387
|
if (images) return void 0;
|
|
8371
8388
|
if (text !== void 0) {
|
|
@@ -8403,7 +8420,7 @@ function PaperStageScene({
|
|
|
8403
8420
|
}, [papers, images, text, count, sheetDims]);
|
|
8404
8421
|
const drive = stageMotionSchema.parse(motion ?? {});
|
|
8405
8422
|
const slotCount = slots?.length ?? images?.length ?? count;
|
|
8406
|
-
const stops = (0,
|
|
8423
|
+
const stops = (0, import_react24.useMemo)(() => {
|
|
8407
8424
|
const spec = getLayout(layout);
|
|
8408
8425
|
const placed = spec.walkStops?.(slotCount, spec.optionsSchema.parse(resolvedLayoutOptions ?? {}));
|
|
8409
8426
|
if (placed && placed.length > 0) return placed;
|
|
@@ -8418,11 +8435,11 @@ function PaperStageScene({
|
|
|
8418
8435
|
reduced: still,
|
|
8419
8436
|
onProgress
|
|
8420
8437
|
});
|
|
8421
|
-
const surroundRadius = (0,
|
|
8438
|
+
const surroundRadius = (0, import_react24.useMemo)(
|
|
8422
8439
|
() => Math.max(path.length * 1.6, paperHeight * 9),
|
|
8423
8440
|
[path.length, paperHeight]
|
|
8424
8441
|
);
|
|
8425
|
-
const source = (0,
|
|
8442
|
+
const source = (0, import_react24.useMemo)(() => {
|
|
8426
8443
|
const [x, z30] = walkPoint(path, path.length + stage.source.beyond);
|
|
8427
8444
|
const [tx, tz] = path.tangentAt(1);
|
|
8428
8445
|
const size = paperHeight * stage.source.spread;
|
|
@@ -8525,7 +8542,7 @@ function PaperStageScene({
|
|
|
8525
8542
|
function PaperStage({ children, className, style, ...sceneProps }) {
|
|
8526
8543
|
const dpr = qualityFor(sceneProps.quality ?? "auto").dpr;
|
|
8527
8544
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className, style: { width: "100%", height: "100%", ...style }, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(
|
|
8528
|
-
|
|
8545
|
+
import_fiber11.Canvas,
|
|
8529
8546
|
{
|
|
8530
8547
|
shadows: true,
|
|
8531
8548
|
dpr: [1, dpr],
|
|
@@ -8535,7 +8552,8 @@ function PaperStage({ children, className, style, ...sceneProps }) {
|
|
|
8535
8552
|
},
|
|
8536
8553
|
children: [
|
|
8537
8554
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PaperStageScene, { ...sceneProps }),
|
|
8538
|
-
children
|
|
8555
|
+
children,
|
|
8556
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ReleaseContextOnUnmount, {})
|
|
8539
8557
|
]
|
|
8540
8558
|
}
|
|
8541
8559
|
) });
|
|
@@ -8964,7 +8982,11 @@ function describeStage(input) {
|
|
|
8964
8982
|
);
|
|
8965
8983
|
const moved = Object.entries(stage.light).filter(([, value]) => value !== void 0).map(([key]) => key);
|
|
8966
8984
|
if (moved.length > 0) parts.push(`with its ${moved.join(", ")} set by hand`);
|
|
8967
|
-
if (input.scroll)
|
|
8985
|
+
if (input.scroll) {
|
|
8986
|
+
parts.push(
|
|
8987
|
+
stage.showFigure ? "and scrolling the page walks the figure deeper into it" : "and scrolling the page carries the camera deeper into it"
|
|
8988
|
+
);
|
|
8989
|
+
}
|
|
8968
8990
|
return parts.join(", ");
|
|
8969
8991
|
}
|
|
8970
8992
|
function exportableImages(images) {
|
|
@@ -9005,6 +9027,7 @@ const banner = ${stringifyStage(diffConfig(paperConfigSchema.parse(input.paper))
|
|
|
9005
9027
|
const textConst = input.text?.trim() ? `
|
|
9006
9028
|
|
|
9007
9029
|
const text = ${JSON.stringify(input.text)}` : "";
|
|
9030
|
+
const scrolls = stageSchema.parse(input.stage).showFigure ? "walk the figure" : "move the camera";
|
|
9008
9031
|
const images = input.images?.length ? exportableImages(input.images) : null;
|
|
9009
9032
|
const imagesConst = images ? `
|
|
9010
9033
|
${images.substituted ? "\n// Your uploaded pictures cannot travel in a snippet \u2014 these are\n// placeholders in the same order. Point them at your own files." : ""}
|
|
@@ -9031,7 +9054,7 @@ export function ${name}() {
|
|
|
9031
9054
|
const ref = useRef<HTMLDivElement>(null)
|
|
9032
9055
|
const [progress, setProgress] = useState(0)
|
|
9033
9056
|
|
|
9034
|
-
// Scroll the section,
|
|
9057
|
+
// Scroll the section, ${scrolls}. The stage is pinned for the height
|
|
9035
9058
|
// of the section, so the page scrolling past it IS the walk.
|
|
9036
9059
|
useEffect(() => {
|
|
9037
9060
|
const el = ref.current
|
|
@@ -9068,7 +9091,8 @@ function buildStageAgentPayload(input) {
|
|
|
9068
9091
|
heights of scroll and pins the canvas inside that. Drop it into the page
|
|
9069
9092
|
flow as a section; do NOT wrap it in a fixed-height container.` : `4. Sizing: the component fills its parent container. Place it where I ask;
|
|
9070
9093
|
give the parent an explicit height.`;
|
|
9071
|
-
|
|
9094
|
+
const subject = stageSchema.parse(input.stage).showFigure ? "paper as architecture, with a figure walking through it" : "paper as architecture, banners hung along a walk you move through";
|
|
9095
|
+
return `Integrate a Paperlab stage \u2014 ${subject} \u2014 into this project. (paperlab agent-payload v${AGENT_PAYLOAD_VERSION})
|
|
9072
9096
|
|
|
9073
9097
|
1. Install the dependencies:
|
|
9074
9098
|
|