@3driseai/3drise-viewer 0.1.18 → 0.1.19
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/dist/components/AnimatedObject.d.ts.map +1 -1
- package/dist/components/AnimatedObject.js +3 -2
- package/dist/components/ObjectNode.d.ts.map +1 -1
- package/dist/components/ObjectNode.js +10 -6
- package/dist/components/ParticlesGenerator.js +5 -5
- package/dist/components/particles/BioluminescentWakeParticles.d.ts +5 -2
- package/dist/components/particles/BioluminescentWakeParticles.d.ts.map +1 -1
- package/dist/components/particles/BioluminescentWakeParticles.js +28 -6
- package/dist/components/particles/BrownianDustParticles.d.ts +5 -2
- package/dist/components/particles/BrownianDustParticles.d.ts.map +1 -1
- package/dist/components/particles/BrownianDustParticles.js +28 -6
- package/dist/components/particles/ElectronOrbitalsParticles.d.ts +5 -2
- package/dist/components/particles/ElectronOrbitalsParticles.d.ts.map +1 -1
- package/dist/components/particles/ElectronOrbitalsParticles.js +28 -6
- package/dist/components/particles/GrinderSparksParticles.d.ts +5 -2
- package/dist/components/particles/GrinderSparksParticles.d.ts.map +1 -1
- package/dist/components/particles/GrinderSparksParticles.js +37 -13
- package/dist/components/particles/TidalStreamParticles.d.ts +5 -2
- package/dist/components/particles/TidalStreamParticles.d.ts.map +1 -1
- package/dist/components/particles/TidalStreamParticles.js +28 -6
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useConfigLive.d.ts +54 -0
- package/dist/hooks/useConfigLive.d.ts.map +1 -0
- package/dist/hooks/useConfigLive.js +100 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/utils/configAnimations.d.ts +43 -0
- package/dist/utils/configAnimations.d.ts.map +1 -0
- package/dist/utils/configAnimations.js +73 -0
- package/dist/utils/particleTrails.d.ts.map +1 -1
- package/dist/utils/particleTrails.js +17 -8
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnimatedObject.d.ts","sourceRoot":"","sources":["../../src/components/AnimatedObject.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAM7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACtG,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,iBAAiB,CAAC;IACtC,aAAa,EAAE,qBAAqB,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACtC,iBAAiB,CAAC,EAAE,CAAC,aAAa,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IACjH,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACvD,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACvD,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAGD,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,
|
|
1
|
+
{"version":3,"file":"AnimatedObject.d.ts","sourceRoot":"","sources":["../../src/components/AnimatedObject.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAM7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACtG,MAAM,WAAW,mBAAoB,SAAQ,gBAAgB;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,iBAAiB,CAAC;IACtC,aAAa,EAAE,qBAAqB,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACtC,iBAAiB,CAAC,EAAE,CAAC,aAAa,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IACjH,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACvD,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,UAAU,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACvD,MAAM,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAGD,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAqFvD,CAAC;AAEH,eAAe,cAAc,CAAC"}
|
|
@@ -64,12 +64,13 @@ visible = true, children, parentRef, handleObjectClick, onPointerEnter, onPointe
|
|
|
64
64
|
}
|
|
65
65
|
};
|
|
66
66
|
if (createdObject.type === 'particles' || createdObject.type === 'gallery' || (!hasHoverFunctionalities && !hasMouseInteraction)) {
|
|
67
|
-
return _jsx(_Fragment, { children: _jsxs("group", { ref: groupRef, position: position, scale: scale, rotation: rotation, visible: visible,
|
|
67
|
+
return _jsx(_Fragment, { children: _jsxs("group", { ref: groupRef, position: position, scale: scale, rotation: rotation, visible: visible,
|
|
68
|
+
// onClick={onClick}
|
|
68
69
|
// onPointerEnter={onPointerEnter}
|
|
69
70
|
// onPointerLeave={onPointerLeave}
|
|
70
71
|
name: createdObject.meshSettings.name, userData: { id: createdObject.id }, children: [children, _jsx(EffectsGroup, { createdObject: createdObject, objectRef: groupRef, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose })] }) });
|
|
71
72
|
}
|
|
72
|
-
return (
|
|
73
|
+
return (_jsxs("group", { ref: groupRef, position: position, scale: scale, rotation: rotation, visible: visible, onClick: onClick, onPointerEnter: onPointerEnter, onPointerLeave: onPointerLeave, name: createdObject.meshSettings.name, userData: { id: createdObject.id }, children: [children, _jsx(EffectsGroup, { createdObject: createdObject, objectRef: groupRef, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose })] }));
|
|
73
74
|
});
|
|
74
75
|
AnimatedObject.displayName = 'AnimatedObject';
|
|
75
76
|
export default AnimatedObject;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectNode.d.ts","sourceRoot":"","sources":["../../src/components/ObjectNode.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAe,qBAAqB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAChG,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAiBrD,KAAK,eAAe,GAAG,gBAAgB,GAAG;IACtC,IAAI,EAAE,cAAc,CAAC;IACrB,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;CAC7G,CAAC;AAkBF,QAAA,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,
|
|
1
|
+
{"version":3,"file":"ObjectNode.d.ts","sourceRoot":"","sources":["../../src/components/ObjectNode.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,KAAK,EAAe,qBAAqB,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAChG,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAiBrD,KAAK,eAAe,GAAG,gBAAgB,GAAG;IACtC,IAAI,EAAE,cAAc,CAAC;IACrB,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;CAC7G,CAAC;AAkBF,QAAA,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAsIzC,CAAC;AACF,eAAe,UAAU,CAAC"}
|
|
@@ -8,8 +8,6 @@ import PathRenderer from './PathRenderer.js';
|
|
|
8
8
|
import GalleryLayout from './GalleryLayout.js';
|
|
9
9
|
import EffectsGenerator from './EffectsGenerator.js';
|
|
10
10
|
import ParticlesGenerator from './ParticlesGenerator.js';
|
|
11
|
-
import ParticlesR3f from "./ParticlesR3f.js";
|
|
12
|
-
import Lines from "./Lines.js";
|
|
13
11
|
import LightObject from "./LightObject.js";
|
|
14
12
|
import EnvironmentObject from "./EnvironmentObject.js";
|
|
15
13
|
import Galaxy from "./Galaxy.js";
|
|
@@ -95,10 +93,16 @@ const ObjectNode = ({ node, onObjectReady, onObjectDispose, handleObjectClick })
|
|
|
95
93
|
particles: (obj, onObjectReady) => {
|
|
96
94
|
// Generative particle objects (config.type) render through ParticlesGenerator;
|
|
97
95
|
// the legacy shape particles keep their own path.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
96
|
+
return (_jsx(ParticlesGenerator, { settings: { id: obj.id, config: obj.config, animations: obj.animations }, ...relabel(obj) }, obj.id));
|
|
97
|
+
// if (isGenerativeParticlesConfig(obj.config))
|
|
98
|
+
// return (<ParticlesGenerator key={obj.id} settings={{ config: obj.config }} {...relabel(obj)} />);
|
|
99
|
+
// const particlesSettings = obj;
|
|
100
|
+
// return (<>
|
|
101
|
+
// {particlesSettings.config?.particles && (
|
|
102
|
+
// <ParticlesR3f particlesSettings={particlesSettings} duration={1} transitionSettings={particlesSettings.meshSettings} {...relabel(obj)} />
|
|
103
|
+
// )}
|
|
104
|
+
// {particlesSettings.config?.paths && (<Lines createdObject={particlesSettings} {...relabel(obj)} />)}
|
|
105
|
+
// </>);
|
|
102
106
|
},
|
|
103
107
|
path: (obj, onObjectReady) => (_jsx(PathRenderer, { pathSettings: obj.config, ...relabel(obj) }, obj.id)),
|
|
104
108
|
grid: (obj, onObjectReady) => (
|
|
@@ -12,11 +12,11 @@ const ParticlesGenerator = ({ settings, onObjectReady, onObjectDispose }) => {
|
|
|
12
12
|
const size = config.size ?? 1;
|
|
13
13
|
const ready = { onObjectReady, onObjectDispose };
|
|
14
14
|
switch (config.type) {
|
|
15
|
-
case 'tidalStream': return _jsx(TidalStreamParticles, { size: size, config: config, animations: animations, ...ready });
|
|
16
|
-
case 'brownianDust': return _jsx(BrownianDustParticles, { size: size, config: config, animations: animations, ...ready });
|
|
17
|
-
case 'bioluminescentWake': return _jsx(BioluminescentWakeParticles, { size: size, config: config, animations: animations, ...ready });
|
|
18
|
-
case 'electronOrbitals': return _jsx(ElectronOrbitalsParticles, { size: size, config: config, animations: animations, ...ready });
|
|
19
|
-
case 'grinderSparks': return _jsx(GrinderSparksParticles, { size: size, config: config, animations: animations, ...ready });
|
|
15
|
+
case 'tidalStream': return _jsx(TidalStreamParticles, { id: settings.id, size: size, config: config, animations: animations, ...ready });
|
|
16
|
+
case 'brownianDust': return _jsx(BrownianDustParticles, { id: settings.id, size: size, config: config, animations: animations, ...ready });
|
|
17
|
+
case 'bioluminescentWake': return _jsx(BioluminescentWakeParticles, { id: settings.id, size: size, config: config, animations: animations, ...ready });
|
|
18
|
+
case 'electronOrbitals': return _jsx(ElectronOrbitalsParticles, { id: settings.id, size: size, config: config, animations: animations, ...ready });
|
|
19
|
+
case 'grinderSparks': return _jsx(GrinderSparksParticles, { id: settings.id, size: size, config: config, animations: animations, ...ready });
|
|
20
20
|
default: return null;
|
|
21
21
|
}
|
|
22
22
|
};
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ObjectAnimations, BioluminescentWakeParticlesConfig } from '@3driseai/3drise-core';
|
|
3
3
|
import type { ObjectReadyProps } from '../../types/objectReady';
|
|
4
4
|
export interface BioluminescentWakeParticlesProps extends ObjectReadyProps {
|
|
5
|
+
/** Scene object id: the controller finds the live-edit handle by it. */
|
|
6
|
+
id?: string;
|
|
5
7
|
/** World size of the object (units); the object's transform scales it further. */
|
|
6
8
|
size: number;
|
|
7
9
|
config: BioluminescentWakeParticlesConfig;
|
|
8
|
-
|
|
10
|
+
/** Per-domain keyframes; the `particles` domain drives this object's config knobs. */
|
|
11
|
+
animations?: ObjectAnimations;
|
|
9
12
|
}
|
|
10
13
|
declare const BioluminescentWakeParticles: React.FC<BioluminescentWakeParticlesProps>;
|
|
11
14
|
export default BioluminescentWakeParticles;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BioluminescentWakeParticles.d.ts","sourceRoot":"","sources":["../../../src/components/particles/BioluminescentWakeParticles.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"BioluminescentWakeParticles.d.ts","sourceRoot":"","sources":["../../../src/components/particles/BioluminescentWakeParticles.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmE,MAAM,OAAO,CAAC;AAIxF,OAAO,KAAK,EAAE,gBAAgB,EAAE,iCAAiC,EAAE,MAAM,uBAAuB,CAAC;AAMjG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,WAAW,gCAAiC,SAAQ,gBAAgB;IACtE,wEAAwE;IACxE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,iCAAiC,CAAC;IAC1C,sFAAsF;IACtF,UAAU,CAAC,EAAE,gBAAgB,CAAC;CACjC;AA09BD,QAAA,MAAM,2BAA2B,EAAE,KAAK,CAAC,EAAE,CAAC,gCAAgC,CAiD3E,CAAC;AAEF,eAAe,2BAA2B,CAAC"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
|
3
3
|
import * as THREE from 'three';
|
|
4
4
|
import { useFrame } from '@react-three/fiber';
|
|
5
|
-
import {
|
|
5
|
+
import { GENERATIVE_PARTICLES_ANIMATABLE } from '@3driseai/3drise-core';
|
|
6
|
+
import { applyConfigKeyframeAnimations } from '../../utils/configAnimations.js';
|
|
6
7
|
import { createPointerUniforms, stepPointerField, usePointerField } from '../../utils/pointerField.js';
|
|
7
8
|
import { createTrailUniforms, applyTrailConfig, createCpuTrail } from '../../utils/particleTrails.js';
|
|
8
9
|
import { useObjectReady } from '../../hooks/useObjectReady.js';
|
|
10
|
+
import { useConfigLiveHandle } from '../../hooks/useConfigLive.js';
|
|
9
11
|
/**
|
|
10
12
|
* Sea Sparkle — Bioluminescent plankton that flash when the water shears: swell orbits, excitable cells that tire and recover, moon glitter; the cursor is a hand, falling pebbles or a hunting fish. Use for night sea and fantasy scenes.
|
|
11
13
|
*/
|
|
@@ -1097,9 +1099,12 @@ const DEFAULTS = {
|
|
|
1097
1099
|
trailColor: '#2f7dff',
|
|
1098
1100
|
trailShare: 1,
|
|
1099
1101
|
};
|
|
1100
|
-
|
|
1102
|
+
/** Knobs that rebuild the simulation: they change on commit, never through the live path. */
|
|
1103
|
+
const STRUCTURAL = ['particleCount', 'seed', 'quality'];
|
|
1104
|
+
/** Knobs an animation (or mouse move) may drive per frame — generated from applyConfig. */
|
|
1105
|
+
const ANIMATABLE = new Set(GENERATIVE_PARTICLES_ANIMATABLE.bioluminescentWake.map((p) => p.value));
|
|
1106
|
+
const BioluminescentWakeParticles = ({ id, size, config, animations, onObjectReady, onObjectDispose }) => {
|
|
1101
1107
|
const rootRef = useRef(null);
|
|
1102
|
-
const animCache = useRef({});
|
|
1103
1108
|
useObjectReady(rootRef, config, onObjectReady, onObjectDispose);
|
|
1104
1109
|
const s = size > 0 ? size : 1;
|
|
1105
1110
|
const cfg = useMemo(() => ({ ...DEFAULTS, ...config }), [config]);
|
|
@@ -1112,11 +1117,28 @@ const BioluminescentWakeParticles = ({ size, config, animations, onObjectReady,
|
|
|
1112
1117
|
applyConfig(uniforms, cfg, s);
|
|
1113
1118
|
instance.apply(cfg);
|
|
1114
1119
|
}, [instance, uniforms, cfg, s]);
|
|
1120
|
+
// Slider drags and keyframe animations are both overrides on the committed config.
|
|
1121
|
+
// This is the one place they are merged and pushed, so they compose instead of
|
|
1122
|
+
// overwriting each other; the animation wins, because it is the active driver.
|
|
1123
|
+
const keyframes = animations?.particles?.animations;
|
|
1124
|
+
const animOverride = useRef({});
|
|
1125
|
+
const animFrom = useRef({});
|
|
1126
|
+
const animStart = useRef(0);
|
|
1127
|
+
// Editing a keyframe restarts its cycle rather than dropping the user mid-way.
|
|
1128
|
+
useEffect(() => { animStart.current = performance.now(); animFrom.current = {}; }, [keyframes]);
|
|
1129
|
+
const push = useCallback((overrides) => {
|
|
1130
|
+
const merged = { ...cfg, ...overrides, ...animOverride.current };
|
|
1131
|
+
const z = merged.size;
|
|
1132
|
+
applyConfig(uniforms, merged, z && z > 0 ? z : s);
|
|
1133
|
+
}, [cfg, uniforms, s]);
|
|
1134
|
+
const live = useConfigLiveHandle(rootRef, id, 'particles', cfg, STRUCTURAL, push);
|
|
1115
1135
|
const pointer = usePointerField();
|
|
1116
1136
|
useFrame((state, delta) => {
|
|
1117
1137
|
instance.update(Math.min(delta, 0.1), state.camera, pointer);
|
|
1118
|
-
if (
|
|
1119
|
-
|
|
1138
|
+
if (keyframes?.length) {
|
|
1139
|
+
applyConfigKeyframeAnimations(keyframes, animFrom.current, cfg, animOverride.current, performance.now() - animStart.current, ANIMATABLE);
|
|
1140
|
+
push(live.current);
|
|
1141
|
+
}
|
|
1120
1142
|
});
|
|
1121
1143
|
return (_jsx("group", { ref: rootRef, children: _jsx("primitive", { object: instance.object }) }));
|
|
1122
1144
|
};
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ObjectAnimations, BrownianDustParticlesConfig } from '@3driseai/3drise-core';
|
|
3
3
|
import type { ObjectReadyProps } from '../../types/objectReady';
|
|
4
4
|
export interface BrownianDustParticlesProps extends ObjectReadyProps {
|
|
5
|
+
/** Scene object id: the controller finds the live-edit handle by it. */
|
|
6
|
+
id?: string;
|
|
5
7
|
/** World size of the object (units); the object's transform scales it further. */
|
|
6
8
|
size: number;
|
|
7
9
|
config: BrownianDustParticlesConfig;
|
|
8
|
-
|
|
10
|
+
/** Per-domain keyframes; the `particles` domain drives this object's config knobs. */
|
|
11
|
+
animations?: ObjectAnimations;
|
|
9
12
|
}
|
|
10
13
|
declare const BrownianDustParticles: React.FC<BrownianDustParticlesProps>;
|
|
11
14
|
export default BrownianDustParticles;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrownianDustParticles.d.ts","sourceRoot":"","sources":["../../../src/components/particles/BrownianDustParticles.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"BrownianDustParticles.d.ts","sourceRoot":"","sources":["../../../src/components/particles/BrownianDustParticles.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmE,MAAM,OAAO,CAAC;AAIxF,OAAO,KAAK,EAAE,gBAAgB,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAM3F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,WAAW,0BAA2B,SAAQ,gBAAgB;IAChE,wEAAwE;IACxE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,2BAA2B,CAAC;IACpC,sFAAsF;IACtF,UAAU,CAAC,EAAE,gBAAgB,CAAC;CACjC;AA4qBD,QAAA,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAiD/D,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
|
3
3
|
import * as THREE from 'three';
|
|
4
4
|
import { useFrame } from '@react-three/fiber';
|
|
5
|
-
import {
|
|
5
|
+
import { GENERATIVE_PARTICLES_ANIMATABLE } from '@3driseai/3drise-core';
|
|
6
|
+
import { applyConfigKeyframeAnimations } from '../../utils/configAnimations.js';
|
|
6
7
|
import { createPointerUniforms, stepPointerField, usePointerField } from '../../utils/pointerField.js';
|
|
7
8
|
import { createTrailUniforms, applyTrailConfig, createCpuTrail } from '../../utils/particleTrails.js';
|
|
8
9
|
import { useObjectReady } from '../../hooks/useObjectReady.js';
|
|
10
|
+
import { useConfigLiveHandle } from '../../hooks/useConfigLive.js';
|
|
9
11
|
/**
|
|
10
12
|
* Sunbeam Dust — Dust drifting in window light: Langevin motion in Kolmogorov turbulence, mullion shadows, forward scattering, glints and bokeh; the cursor is a hand, a torch or a charged rod. Use for interiors and cinematic scenes.
|
|
11
13
|
*/
|
|
@@ -731,9 +733,12 @@ const DEFAULTS = {
|
|
|
731
733
|
trailColor: '#ffb870',
|
|
732
734
|
trailShare: 0.3,
|
|
733
735
|
};
|
|
734
|
-
|
|
736
|
+
/** Knobs that rebuild the simulation: they change on commit, never through the live path. */
|
|
737
|
+
const ANIMATABLE = new Set(GENERATIVE_PARTICLES_ANIMATABLE.brownianDust.map((p) => p.value));
|
|
738
|
+
/** Knobs that rebuild the simulation: they change on commit, never through the live path. */
|
|
739
|
+
const STRUCTURAL = ['particleCount'];
|
|
740
|
+
const BrownianDustParticles = ({ id, size, config, animations, onObjectReady, onObjectDispose }) => {
|
|
735
741
|
const rootRef = useRef(null);
|
|
736
|
-
const animCache = useRef({});
|
|
737
742
|
useObjectReady(rootRef, config, onObjectReady, onObjectDispose);
|
|
738
743
|
const s = size > 0 ? size : 1;
|
|
739
744
|
const cfg = useMemo(() => ({ ...DEFAULTS, ...config }), [config]);
|
|
@@ -746,11 +751,28 @@ const BrownianDustParticles = ({ size, config, animations, onObjectReady, onObje
|
|
|
746
751
|
applyConfig(uniforms, cfg, s);
|
|
747
752
|
instance.apply(cfg);
|
|
748
753
|
}, [instance, uniforms, cfg, s]);
|
|
754
|
+
// Slider drags and keyframe animations are both overrides on the committed config.
|
|
755
|
+
// This is the one place they are merged and pushed, so they compose instead of
|
|
756
|
+
// overwriting each other; the animation wins, because it is the active driver.
|
|
757
|
+
const keyframes = animations?.particles?.animations;
|
|
758
|
+
const animOverride = useRef({});
|
|
759
|
+
const animFrom = useRef({});
|
|
760
|
+
const animStart = useRef(0);
|
|
761
|
+
// Editing a keyframe restarts its cycle rather than dropping the user mid-way.
|
|
762
|
+
useEffect(() => { animStart.current = performance.now(); animFrom.current = {}; }, [keyframes]);
|
|
763
|
+
const push = useCallback((overrides) => {
|
|
764
|
+
const merged = { ...cfg, ...overrides, ...animOverride.current };
|
|
765
|
+
const z = merged.size;
|
|
766
|
+
applyConfig(uniforms, merged, z && z > 0 ? z : s);
|
|
767
|
+
}, [cfg, uniforms, s]);
|
|
768
|
+
const live = useConfigLiveHandle(rootRef, id, 'particles', cfg, STRUCTURAL, push);
|
|
749
769
|
const pointer = usePointerField();
|
|
750
770
|
useFrame((state, delta) => {
|
|
751
771
|
instance.update(Math.min(delta, 0.1), state.camera, pointer);
|
|
752
|
-
if (
|
|
753
|
-
|
|
772
|
+
if (keyframes?.length) {
|
|
773
|
+
applyConfigKeyframeAnimations(keyframes, animFrom.current, cfg, animOverride.current, performance.now() - animStart.current, ANIMATABLE);
|
|
774
|
+
push(live.current);
|
|
775
|
+
}
|
|
754
776
|
});
|
|
755
777
|
return (_jsx("group", { ref: rootRef, children: _jsx("primitive", { object: instance.object }) }));
|
|
756
778
|
};
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ObjectAnimations, ElectronOrbitalsParticlesConfig } from '@3driseai/3drise-core';
|
|
3
3
|
import type { ObjectReadyProps } from '../../types/objectReady';
|
|
4
4
|
export interface ElectronOrbitalsParticlesProps extends ObjectReadyProps {
|
|
5
|
+
/** Scene object id: the controller finds the live-edit handle by it. */
|
|
6
|
+
id?: string;
|
|
5
7
|
/** World size of the object (units); the object's transform scales it further. */
|
|
6
8
|
size: number;
|
|
7
9
|
config: ElectronOrbitalsParticlesConfig;
|
|
8
|
-
|
|
10
|
+
/** Per-domain keyframes; the `particles` domain drives this object's config knobs. */
|
|
11
|
+
animations?: ObjectAnimations;
|
|
9
12
|
}
|
|
10
13
|
declare const ElectronOrbitalsParticles: React.FC<ElectronOrbitalsParticlesProps>;
|
|
11
14
|
export default ElectronOrbitalsParticles;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ElectronOrbitalsParticles.d.ts","sourceRoot":"","sources":["../../../src/components/particles/ElectronOrbitalsParticles.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ElectronOrbitalsParticles.d.ts","sourceRoot":"","sources":["../../../src/components/particles/ElectronOrbitalsParticles.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmE,MAAM,OAAO,CAAC;AAIxF,OAAO,KAAK,EAAE,gBAAgB,EAAE,+BAA+B,EAAE,MAAM,uBAAuB,CAAC;AAM/F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,WAAW,8BAA+B,SAAQ,gBAAgB;IACpE,wEAAwE;IACxE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,+BAA+B,CAAC;IACxC,sFAAsF;IACtF,UAAU,CAAC,EAAE,gBAAgB,CAAC;CACjC;AA0xBD,QAAA,MAAM,yBAAyB,EAAE,KAAK,CAAC,EAAE,CAAC,8BAA8B,CAiDvE,CAAC;AAEF,eAAe,yBAAyB,CAAC"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
|
3
3
|
import * as THREE from 'three';
|
|
4
4
|
import { useFrame } from '@react-three/fiber';
|
|
5
|
-
import {
|
|
5
|
+
import { GENERATIVE_PARTICLES_ANIMATABLE } from '@3driseai/3drise-core';
|
|
6
|
+
import { applyConfigKeyframeAnimations } from '../../utils/configAnimations.js';
|
|
6
7
|
import { createPointerUniforms, stepPointerField, usePointerField } from '../../utils/pointerField.js';
|
|
7
8
|
import { createTrailUniforms, applyTrailConfig, createCpuTrail } from '../../utils/particleTrails.js';
|
|
8
9
|
import { useObjectReady } from '../../hooks/useObjectReady.js';
|
|
10
|
+
import { useConfigLiveHandle } from '../../hooks/useConfigLive.js';
|
|
9
11
|
/**
|
|
10
12
|
* Quantum Orbitals — A hydrogen electron cloud as Bohmian trajectories: a superposition of two orbitals breathing at the Bohr frequency, coloured by quantum phase; the cursor is a photon, a magnet or a detector. Use for science and tech scenes.
|
|
11
13
|
*/
|
|
@@ -918,9 +920,12 @@ const DEFAULTS = {
|
|
|
918
920
|
trailColor: '#7a8cff',
|
|
919
921
|
trailShare: 0.3,
|
|
920
922
|
};
|
|
921
|
-
|
|
923
|
+
/** Knobs that rebuild the simulation: they change on commit, never through the live path. */
|
|
924
|
+
const STRUCTURAL = ['particleCount', 'stateA', 'stateB', 'seed', 'quality'];
|
|
925
|
+
/** Knobs an animation (or mouse move) may drive per frame — generated from applyConfig. */
|
|
926
|
+
const ANIMATABLE = new Set(GENERATIVE_PARTICLES_ANIMATABLE.electronOrbitals.map((p) => p.value));
|
|
927
|
+
const ElectronOrbitalsParticles = ({ id, size, config, animations, onObjectReady, onObjectDispose }) => {
|
|
922
928
|
const rootRef = useRef(null);
|
|
923
|
-
const animCache = useRef({});
|
|
924
929
|
useObjectReady(rootRef, config, onObjectReady, onObjectDispose);
|
|
925
930
|
const s = size > 0 ? size : 1;
|
|
926
931
|
const cfg = useMemo(() => ({ ...DEFAULTS, ...config }), [config]);
|
|
@@ -933,11 +938,28 @@ const ElectronOrbitalsParticles = ({ size, config, animations, onObjectReady, on
|
|
|
933
938
|
applyConfig(uniforms, cfg, s);
|
|
934
939
|
instance.apply(cfg);
|
|
935
940
|
}, [instance, uniforms, cfg, s]);
|
|
941
|
+
// Slider drags and keyframe animations are both overrides on the committed config.
|
|
942
|
+
// This is the one place they are merged and pushed, so they compose instead of
|
|
943
|
+
// overwriting each other; the animation wins, because it is the active driver.
|
|
944
|
+
const keyframes = animations?.particles?.animations;
|
|
945
|
+
const animOverride = useRef({});
|
|
946
|
+
const animFrom = useRef({});
|
|
947
|
+
const animStart = useRef(0);
|
|
948
|
+
// Editing a keyframe restarts its cycle rather than dropping the user mid-way.
|
|
949
|
+
useEffect(() => { animStart.current = performance.now(); animFrom.current = {}; }, [keyframes]);
|
|
950
|
+
const push = useCallback((overrides) => {
|
|
951
|
+
const merged = { ...cfg, ...overrides, ...animOverride.current };
|
|
952
|
+
const z = merged.size;
|
|
953
|
+
applyConfig(uniforms, merged, z && z > 0 ? z : s);
|
|
954
|
+
}, [cfg, uniforms, s]);
|
|
955
|
+
const live = useConfigLiveHandle(rootRef, id, 'particles', cfg, STRUCTURAL, push);
|
|
936
956
|
const pointer = usePointerField();
|
|
937
957
|
useFrame((state, delta) => {
|
|
938
958
|
instance.update(Math.min(delta, 0.1), state.camera, pointer);
|
|
939
|
-
if (
|
|
940
|
-
|
|
959
|
+
if (keyframes?.length) {
|
|
960
|
+
applyConfigKeyframeAnimations(keyframes, animFrom.current, cfg, animOverride.current, performance.now() - animStart.current, ANIMATABLE);
|
|
961
|
+
push(live.current);
|
|
962
|
+
}
|
|
941
963
|
});
|
|
942
964
|
return (_jsx("group", { ref: rootRef, children: _jsx("primitive", { object: instance.object }) }));
|
|
943
965
|
};
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ObjectAnimations, GrinderSparksParticlesConfig } from '@3driseai/3drise-core';
|
|
3
3
|
import type { ObjectReadyProps } from '../../types/objectReady';
|
|
4
4
|
export interface GrinderSparksParticlesProps extends ObjectReadyProps {
|
|
5
|
+
/** Scene object id: the controller finds the live-edit handle by it. */
|
|
6
|
+
id?: string;
|
|
5
7
|
/** World size of the object (units); the object's transform scales it further. */
|
|
6
8
|
size: number;
|
|
7
9
|
config: GrinderSparksParticlesConfig;
|
|
8
|
-
|
|
10
|
+
/** Per-domain keyframes; the `particles` domain drives this object's config knobs. */
|
|
11
|
+
animations?: ObjectAnimations;
|
|
9
12
|
}
|
|
10
13
|
declare const GrinderSparksParticles: React.FC<GrinderSparksParticlesProps>;
|
|
11
14
|
export default GrinderSparksParticles;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrinderSparksParticles.d.ts","sourceRoot":"","sources":["../../../src/components/particles/GrinderSparksParticles.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"GrinderSparksParticles.d.ts","sourceRoot":"","sources":["../../../src/components/particles/GrinderSparksParticles.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmE,MAAM,OAAO,CAAC;AAIxF,OAAO,KAAK,EAAE,gBAAgB,EAAE,4BAA4B,EAAE,MAAM,uBAAuB,CAAC;AAM5F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,WAAW,2BAA4B,SAAQ,gBAAgB;IACjE,wEAAwE;IACxE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,4BAA4B,CAAC;IACrC,sFAAsF;IACtF,UAAU,CAAC,EAAE,gBAAgB,CAAC;CACjC;AA8pBD,QAAA,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAAE,CAAC,2BAA2B,CAiDjE,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
|
3
3
|
import * as THREE from 'three';
|
|
4
4
|
import { useFrame } from '@react-three/fiber';
|
|
5
|
-
import {
|
|
5
|
+
import { GENERATIVE_PARTICLES_ANIMATABLE } from '@3driseai/3drise-core';
|
|
6
|
+
import { applyConfigKeyframeAnimations } from '../../utils/configAnimations.js';
|
|
6
7
|
import { createPointerUniforms, stepPointerField, usePointerField } from '../../utils/pointerField.js';
|
|
7
8
|
import { createTrailUniforms, applyTrailConfig, createCpuTrail } from '../../utils/particleTrails.js';
|
|
8
9
|
import { useObjectReady } from '../../hooks/useObjectReady.js';
|
|
10
|
+
import { useConfigLiveHandle } from '../../hooks/useConfigLive.js';
|
|
9
11
|
/**
|
|
10
12
|
* Grinder Sparks — Slow-motion grinder sparks: drag-limited ballistics, radiative cooling on the blackbody scale, carbon bursts, floor bounces and reflections; the cursor moves the grinder, aims the spray or sweeps the air. Use for industrial and cinematic scenes.
|
|
11
13
|
*/
|
|
@@ -133,9 +135,11 @@ const SLOWMO = 0.2; // physics seconds per shown second (a high-speed camera)
|
|
|
133
135
|
const H_STEP = 1 / 120; // shown-time step (physics step = H_STEP * SLOWMO)
|
|
134
136
|
const TR = 0.006; // physics seconds per trail unit (the shutter) for streaks
|
|
135
137
|
const TR_MODE = { streak: TR, comet: 0.03, echo: 0.04 }; // arcs and smoulder look back further
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
const
|
|
138
|
+
// The rig is laid out so the spray (wheel on the left, sparks flying right) straddles the object origin:
|
|
139
|
+
// the editor's selection box and gizmo centre on the visible spray, not on the wheel.
|
|
140
|
+
const C0 = [-1.3, 0.95, 0]; // contact point at rest (m)
|
|
141
|
+
const SPRAY_MID = [-0.4, 0.6, 0];
|
|
142
|
+
const BOUNDS = { center: [-0.2, 0.7, 0], radius: 2.3 };
|
|
139
143
|
const RHO_C = 7800 * 600; // steel density x heat capacity
|
|
140
144
|
const SIGMA = 5.67e-8, EPS = 0.8, T_AIR = 300;
|
|
141
145
|
const EL0 = -0.26; // rest elevation of the fan (rad)
|
|
@@ -223,7 +227,7 @@ void main() {
|
|
|
223
227
|
vec4 mv = modelViewMatrix * vec4(p * uSize, 1.0);
|
|
224
228
|
float lum = dot(L, vec3(0.3, 0.5, 0.2));
|
|
225
229
|
float px = uSize * uViewH * (0.0045 + 0.004 * aD) * (1.0 + 0.8 * min(lum, 2.0)) / -mv.z;
|
|
226
|
-
${mirror ? 'px *= 1.6; float fade = uFloorReflect * 0.45 * exp(-position.y * 1.2) * smoothstep(3.0, 1.5, length(position.xz - vec2(0.
|
|
230
|
+
${mirror ? 'px *= 1.6; float fade = uFloorReflect * 0.45 * exp(-position.y * 1.2) * smoothstep(3.0, 1.5, length(position.xz - vec2(-0.1, 0.0)));' : 'float fade = 1.0;'}
|
|
227
231
|
vCol = L * uIntensity;
|
|
228
232
|
vA = uOpacity * fade * step(600.0, aT);
|
|
229
233
|
gl_PointSize = clamp(px, 1.0, 40.0) * step(0.001, vA);
|
|
@@ -263,7 +267,7 @@ void main() {
|
|
|
263
267
|
float r2 = dot(d, d);
|
|
264
268
|
float E = uContact.w * max(d.y, 0.0) / pow(r2 + 0.02, 1.5);
|
|
265
269
|
vec3 c = blackbody(2100.0); c /= max(max(c.r, c.g), c.b);
|
|
266
|
-
float edge = smoothstep(2.8, 1.8, length(vP.xz - vec2(0.
|
|
270
|
+
float edge = smoothstep(2.8, 1.8, length(vP.xz - vec2(-0.2, 0.0)));
|
|
267
271
|
vec3 rgb = c * uColor * E * 0.14 * uIntensity * edge;
|
|
268
272
|
float I = max(max(rgb.r, rgb.g), rgb.b);
|
|
269
273
|
if (I < 0.001) discard;
|
|
@@ -538,7 +542,7 @@ function build(u, c, size) {
|
|
|
538
542
|
vel[j] = vx;
|
|
539
543
|
vel[j + 1] = vy;
|
|
540
544
|
vel[j + 2] = vz;
|
|
541
|
-
if (t < 700 || age[i] > 6 || x > 3.
|
|
545
|
+
if (t < 700 || age[i] > 6 || x > 3.0 || x < -3.0 || Math.abs(z) > 3 || y > 3.5) {
|
|
542
546
|
st[i] = 2;
|
|
543
547
|
hold[i] = 0.05;
|
|
544
548
|
T[i] = 0;
|
|
@@ -571,7 +575,7 @@ function build(u, c, size) {
|
|
|
571
575
|
mirror.frustumCulled = false;
|
|
572
576
|
const fgeo = new THREE.CircleGeometry(2.8, 64);
|
|
573
577
|
fgeo.rotateX(-Math.PI / 2);
|
|
574
|
-
fgeo.translate(0.
|
|
578
|
+
fgeo.translate(-0.2, 0.002, 0);
|
|
575
579
|
const fmat = new THREE.ShaderMaterial({
|
|
576
580
|
uniforms: u, vertexShader: floorVertex, fragmentShader: floorFragment,
|
|
577
581
|
transparent: true, depthWrite: false, blending: THREE.AdditiveBlending,
|
|
@@ -718,9 +722,12 @@ const DEFAULTS = {
|
|
|
718
722
|
trailColor: '#ff7a2e',
|
|
719
723
|
trailShare: 1,
|
|
720
724
|
};
|
|
721
|
-
|
|
725
|
+
/** Knobs that rebuild the simulation: they change on commit, never through the live path. */
|
|
726
|
+
const STRUCTURAL = ['particleCount', 'seed', 'quality'];
|
|
727
|
+
/** Knobs an animation (or mouse move) may drive per frame — generated from applyConfig. */
|
|
728
|
+
const ANIMATABLE = new Set(GENERATIVE_PARTICLES_ANIMATABLE.grinderSparks.map((p) => p.value));
|
|
729
|
+
const GrinderSparksParticles = ({ id, size, config, animations, onObjectReady, onObjectDispose }) => {
|
|
722
730
|
const rootRef = useRef(null);
|
|
723
|
-
const animCache = useRef({});
|
|
724
731
|
useObjectReady(rootRef, config, onObjectReady, onObjectDispose);
|
|
725
732
|
const s = size > 0 ? size : 1;
|
|
726
733
|
const cfg = useMemo(() => ({ ...DEFAULTS, ...config }), [config]);
|
|
@@ -733,11 +740,28 @@ const GrinderSparksParticles = ({ size, config, animations, onObjectReady, onObj
|
|
|
733
740
|
applyConfig(uniforms, cfg, s);
|
|
734
741
|
instance.apply(cfg);
|
|
735
742
|
}, [instance, uniforms, cfg, s]);
|
|
743
|
+
// Slider drags and keyframe animations are both overrides on the committed config.
|
|
744
|
+
// This is the one place they are merged and pushed, so they compose instead of
|
|
745
|
+
// overwriting each other; the animation wins, because it is the active driver.
|
|
746
|
+
const keyframes = animations?.particles?.animations;
|
|
747
|
+
const animOverride = useRef({});
|
|
748
|
+
const animFrom = useRef({});
|
|
749
|
+
const animStart = useRef(0);
|
|
750
|
+
// Editing a keyframe restarts its cycle rather than dropping the user mid-way.
|
|
751
|
+
useEffect(() => { animStart.current = performance.now(); animFrom.current = {}; }, [keyframes]);
|
|
752
|
+
const push = useCallback((overrides) => {
|
|
753
|
+
const merged = { ...cfg, ...overrides, ...animOverride.current };
|
|
754
|
+
const z = merged.size;
|
|
755
|
+
applyConfig(uniforms, merged, z && z > 0 ? z : s);
|
|
756
|
+
}, [cfg, uniforms, s]);
|
|
757
|
+
const live = useConfigLiveHandle(rootRef, id, 'particles', cfg, STRUCTURAL, push);
|
|
736
758
|
const pointer = usePointerField();
|
|
737
759
|
useFrame((state, delta) => {
|
|
738
760
|
instance.update(Math.min(delta, 0.1), state.camera, pointer);
|
|
739
|
-
if (
|
|
740
|
-
|
|
761
|
+
if (keyframes?.length) {
|
|
762
|
+
applyConfigKeyframeAnimations(keyframes, animFrom.current, cfg, animOverride.current, performance.now() - animStart.current, ANIMATABLE);
|
|
763
|
+
push(live.current);
|
|
764
|
+
}
|
|
741
765
|
});
|
|
742
766
|
return (_jsx("group", { ref: rootRef, children: _jsx("primitive", { object: instance.object }) }));
|
|
743
767
|
};
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ObjectAnimations, TidalStreamParticlesConfig } from '@3driseai/3drise-core';
|
|
3
3
|
import type { ObjectReadyProps } from '../../types/objectReady';
|
|
4
4
|
export interface TidalStreamParticlesProps extends ObjectReadyProps {
|
|
5
|
+
/** Scene object id: the controller finds the live-edit handle by it. */
|
|
6
|
+
id?: string;
|
|
5
7
|
/** World size of the object (units); the object's transform scales it further. */
|
|
6
8
|
size: number;
|
|
7
9
|
config: TidalStreamParticlesConfig;
|
|
8
|
-
|
|
10
|
+
/** Per-domain keyframes; the `particles` domain drives this object's config knobs. */
|
|
11
|
+
animations?: ObjectAnimations;
|
|
9
12
|
}
|
|
10
13
|
declare const TidalStreamParticles: React.FC<TidalStreamParticlesProps>;
|
|
11
14
|
export default TidalStreamParticles;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TidalStreamParticles.d.ts","sourceRoot":"","sources":["../../../src/components/particles/TidalStreamParticles.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"TidalStreamParticles.d.ts","sourceRoot":"","sources":["../../../src/components/particles/TidalStreamParticles.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmE,MAAM,OAAO,CAAC;AAIxF,OAAO,KAAK,EAAE,gBAAgB,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AAM1F,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IAC/D,wEAAwE;IACxE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,0BAA0B,CAAC;IACnC,sFAAsF;IACtF,UAAU,CAAC,EAAE,gBAAgB,CAAC;CACjC;AAmtBD,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAiD7D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react';
|
|
3
3
|
import * as THREE from 'three';
|
|
4
4
|
import { useFrame } from '@react-three/fiber';
|
|
5
|
-
import {
|
|
5
|
+
import { GENERATIVE_PARTICLES_ANIMATABLE } from '@3driseai/3drise-core';
|
|
6
|
+
import { applyConfigKeyframeAnimations } from '../../utils/configAnimations.js';
|
|
6
7
|
import { createPointerUniforms, stepPointerField, usePointerField } from '../../utils/pointerField.js';
|
|
7
8
|
import { createTrailUniforms, applyTrailConfig, createCpuTrail } from '../../utils/particleTrails.js';
|
|
8
9
|
import { useObjectReady } from '../../hooks/useObjectReady.js';
|
|
10
|
+
import { useConfigLiveHandle } from '../../hooks/useConfigLive.js';
|
|
9
11
|
/**
|
|
10
12
|
* Tidal Stream — A spiral galaxy shredding dwarf satellites into tidal streams: symplectic orbits, density-wave arms, Doppler-shifted blackbody stars; the cursor is a subhalo, black hole or spectroscope. Use for space scenes.
|
|
11
13
|
*/
|
|
@@ -762,9 +764,12 @@ const DEFAULTS = {
|
|
|
762
764
|
trailColor: '#7fa8ff',
|
|
763
765
|
trailShare: 0.25,
|
|
764
766
|
};
|
|
765
|
-
|
|
767
|
+
/** Knobs that rebuild the simulation: they change on commit, never through the live path. */
|
|
768
|
+
const ANIMATABLE = new Set(GENERATIVE_PARTICLES_ANIMATABLE.tidalStream.map((p) => p.value));
|
|
769
|
+
/** Knobs that rebuild the simulation: they change on commit, never through the live path. */
|
|
770
|
+
const STRUCTURAL = ['particleCount', 'satelliteCount', 'orbitEccentricity', 'streamAge', 'discStars'];
|
|
771
|
+
const TidalStreamParticles = ({ id, size, config, animations, onObjectReady, onObjectDispose }) => {
|
|
766
772
|
const rootRef = useRef(null);
|
|
767
|
-
const animCache = useRef({});
|
|
768
773
|
useObjectReady(rootRef, config, onObjectReady, onObjectDispose);
|
|
769
774
|
const s = size > 0 ? size : 1;
|
|
770
775
|
const cfg = useMemo(() => ({ ...DEFAULTS, ...config }), [config]);
|
|
@@ -777,11 +782,28 @@ const TidalStreamParticles = ({ size, config, animations, onObjectReady, onObjec
|
|
|
777
782
|
applyConfig(uniforms, cfg, s);
|
|
778
783
|
instance.apply(cfg);
|
|
779
784
|
}, [instance, uniforms, cfg, s]);
|
|
785
|
+
// Slider drags and keyframe animations are both overrides on the committed config.
|
|
786
|
+
// This is the one place they are merged and pushed, so they compose instead of
|
|
787
|
+
// overwriting each other; the animation wins, because it is the active driver.
|
|
788
|
+
const keyframes = animations?.particles?.animations;
|
|
789
|
+
const animOverride = useRef({});
|
|
790
|
+
const animFrom = useRef({});
|
|
791
|
+
const animStart = useRef(0);
|
|
792
|
+
// Editing a keyframe restarts its cycle rather than dropping the user mid-way.
|
|
793
|
+
useEffect(() => { animStart.current = performance.now(); animFrom.current = {}; }, [keyframes]);
|
|
794
|
+
const push = useCallback((overrides) => {
|
|
795
|
+
const merged = { ...cfg, ...overrides, ...animOverride.current };
|
|
796
|
+
const z = merged.size;
|
|
797
|
+
applyConfig(uniforms, merged, z && z > 0 ? z : s);
|
|
798
|
+
}, [cfg, uniforms, s]);
|
|
799
|
+
const live = useConfigLiveHandle(rootRef, id, 'particles', cfg, STRUCTURAL, push);
|
|
780
800
|
const pointer = usePointerField();
|
|
781
801
|
useFrame((state, delta) => {
|
|
782
802
|
instance.update(Math.min(delta, 0.1), state.camera, pointer);
|
|
783
|
-
if (
|
|
784
|
-
|
|
803
|
+
if (keyframes?.length) {
|
|
804
|
+
applyConfigKeyframeAnimations(keyframes, animFrom.current, cfg, animOverride.current, performance.now() - animStart.current, ANIMATABLE);
|
|
805
|
+
push(live.current);
|
|
806
|
+
}
|
|
785
807
|
});
|
|
786
808
|
return (_jsx("group", { ref: rootRef, children: _jsx("primitive", { object: instance.object }) }));
|
|
787
809
|
};
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,gBAAgB,oCAA2B,CAAC;AACzD,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,gBAAgB,oCAA2B,CAAC;AACzD,eAAO,MAAM,qBAAqB,aAehC,CAAC"}
|
package/dist/constants.js
CHANGED
|
@@ -12,10 +12,11 @@ export const SELF_MANAGED_MATERIAL = new Set([
|
|
|
12
12
|
'effect',
|
|
13
13
|
'space',
|
|
14
14
|
'grid',
|
|
15
|
+
'particles',
|
|
15
16
|
// The water surface owns its shader — one material for both hosts, built
|
|
16
17
|
// around the wave field. Left out of this set, useMaterialApplication
|
|
17
18
|
// overwrites it with whatever the registry has under materialType, which for
|
|
18
19
|
// a legacy ocean is the old flat-plane water material.
|
|
19
|
-
'ocean',
|
|
20
|
+
// 'ocean',
|
|
20
21
|
// 'moon'
|
|
21
22
|
]);
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export { useClipmap } from './useClipmap';
|
|
|
17
17
|
export type { OceanLiveHandle } from './useOceanLive';
|
|
18
18
|
export { OCEAN_LIVE_KEY, useOceanLive } from './useOceanLive';
|
|
19
19
|
export { useOceanMaterial } from './useOceanMaterial';
|
|
20
|
+
export type { ConfigLiveHandle, ConfigLiveValue, ConfigLiveFamily } from './useConfigLive';
|
|
21
|
+
export { CONFIG_LIVE_KEY, useConfigLive, useConfigLiveHandle } from './useConfigLive';
|
|
20
22
|
export type { UseOceanMaterialOptions, OceanMaterialHandle } from './useOceanMaterial';
|
|
21
23
|
export type { UseContinuousEffectsOptions, UseContinuousEffectsResult } from './useContinuousEffects';
|
|
22
24
|
export { useContinuousEffects } from './useContinuousEffects';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"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"}
|
package/dist/hooks/index.js
CHANGED
|
@@ -13,6 +13,7 @@ export { useTerrainClipmap } from './useTerrainClipmap.js';
|
|
|
13
13
|
export { useClipmap } from './useClipmap.js';
|
|
14
14
|
export { OCEAN_LIVE_KEY, useOceanLive } from './useOceanLive.js';
|
|
15
15
|
export { useOceanMaterial } from './useOceanMaterial.js';
|
|
16
|
+
export { CONFIG_LIVE_KEY, useConfigLive, useConfigLiveHandle } from './useConfigLive.js';
|
|
16
17
|
export { useContinuousEffects } from './useContinuousEffects.js';
|
|
17
18
|
export { useCubeCamera } from './useCubeCamera.js';
|
|
18
19
|
export { useEnvironmentProbe } from './useEnvironmentProbe.js';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type MutableRefObject, type RefObject } from 'react';
|
|
2
|
+
import type { Object3D } from 'three';
|
|
3
|
+
/**
|
|
4
|
+
* Live config editing for the generative families (particles now, effects next),
|
|
5
|
+
* the counterpart to `useOceanLive` / `useTerrainLive`.
|
|
6
|
+
*
|
|
7
|
+
* A slider drag fires on every pointer-move. Routing that through Redux hands the
|
|
8
|
+
* component a new config sixty times a second; every continuous knob only touches
|
|
9
|
+
* uniforms, so the controller writes straight into them instead, and Redux only
|
|
10
|
+
* hears about it on slider end.
|
|
11
|
+
*
|
|
12
|
+
* const live = useConfigLive(settings.id);
|
|
13
|
+
* <ParticlesControllerUi onLiveChange={live.set} onSettingsChange={dispatch} ... />
|
|
14
|
+
*
|
|
15
|
+
* The renderer side registers the handle and owns the merge:
|
|
16
|
+
*
|
|
17
|
+
* const liveRef = useConfigLiveHandle(rootRef, id, 'particles', STRUCTURAL, push);
|
|
18
|
+
* // push(overrides) -> applyConfig(uniforms, { ...config, ...overrides, ...animated }, size)
|
|
19
|
+
*
|
|
20
|
+
* Structural knobs rebuild the object, so the handle ignores them: they change on
|
|
21
|
+
* release, through the committed config, exactly once.
|
|
22
|
+
*
|
|
23
|
+
* The handle is found by the object's id, resolved at call time (see the note on
|
|
24
|
+
* useOceanLive: an object resolved once while the panel opens before the object
|
|
25
|
+
* exists stays null forever). It lives on its own userData key and carries its own
|
|
26
|
+
* id, so it never competes with the scene's `userData.id` used by selection.
|
|
27
|
+
*/
|
|
28
|
+
/** Where a generative component stashes its handle on its root group's userData. */
|
|
29
|
+
export declare const CONFIG_LIVE_KEY = "__configLive";
|
|
30
|
+
export type ConfigLiveValue = number | string | boolean;
|
|
31
|
+
/** Generative families that support live config editing. */
|
|
32
|
+
export type ConfigLiveFamily = 'particles' | 'effects';
|
|
33
|
+
export interface ConfigLiveHandle {
|
|
34
|
+
id: string;
|
|
35
|
+
family: ConfigLiveFamily;
|
|
36
|
+
/** False once the component has unmounted or re-registered. */
|
|
37
|
+
alive: boolean;
|
|
38
|
+
set(key: string, value: ConfigLiveValue): void;
|
|
39
|
+
}
|
|
40
|
+
/** Client side: a stable `set(key, value)` for the generative object with this id. */
|
|
41
|
+
export declare function useConfigLive(id?: string | null): {
|
|
42
|
+
set(key: string, value: ConfigLiveValue): void;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Renderer side: registers the live handle and returns the ref holding everything
|
|
46
|
+
* dragged since the last commit. `apply` is called with that ref's contents on every
|
|
47
|
+
* live change; the component owns the merge, so keyframe animations compose with it.
|
|
48
|
+
*
|
|
49
|
+
* Pass `config` so a committed config drops the drag state — the commit *is* the
|
|
50
|
+
* same value, and keeping the override would pin the knob against later edits.
|
|
51
|
+
*/
|
|
52
|
+
export declare function useConfigLiveHandle(rootRef: RefObject<Object3D | null>, id: string | undefined, family: ConfigLiveFamily, config: object, structural: readonly string[], apply: (overrides: Record<string, ConfigLiveValue>) => void): MutableRefObject<Record<string, ConfigLiveValue>>;
|
|
53
|
+
export default useConfigLive;
|
|
54
|
+
//# sourceMappingURL=useConfigLive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useConfigLive.d.ts","sourceRoot":"","sources":["../../src/hooks/useConfigLive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAChG,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGtC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,oFAAoF;AACpF,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAE9C,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAExD,4DAA4D;AAC5D,MAAM,MAAM,gBAAgB,GAAG,WAAW,GAAG,SAAS,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,gBAAgB,CAAC;IACzB,+DAA+D;IAC/D,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;CAClD;AAgBD,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG;IAAE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAAA;CAAE,CAYpG;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAC/B,OAAO,EAAE,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC,EACnC,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,KAAK,IAAI,GAC5D,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CA8BnD;AAED,eAAe,aAAa,CAAC"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { useLayoutEffect, useMemo, useRef } from 'react';
|
|
2
|
+
import { SceneStore } from '@3driseai/3drise-core';
|
|
3
|
+
/**
|
|
4
|
+
* Live config editing for the generative families (particles now, effects next),
|
|
5
|
+
* the counterpart to `useOceanLive` / `useTerrainLive`.
|
|
6
|
+
*
|
|
7
|
+
* A slider drag fires on every pointer-move. Routing that through Redux hands the
|
|
8
|
+
* component a new config sixty times a second; every continuous knob only touches
|
|
9
|
+
* uniforms, so the controller writes straight into them instead, and Redux only
|
|
10
|
+
* hears about it on slider end.
|
|
11
|
+
*
|
|
12
|
+
* const live = useConfigLive(settings.id);
|
|
13
|
+
* <ParticlesControllerUi onLiveChange={live.set} onSettingsChange={dispatch} ... />
|
|
14
|
+
*
|
|
15
|
+
* The renderer side registers the handle and owns the merge:
|
|
16
|
+
*
|
|
17
|
+
* const liveRef = useConfigLiveHandle(rootRef, id, 'particles', STRUCTURAL, push);
|
|
18
|
+
* // push(overrides) -> applyConfig(uniforms, { ...config, ...overrides, ...animated }, size)
|
|
19
|
+
*
|
|
20
|
+
* Structural knobs rebuild the object, so the handle ignores them: they change on
|
|
21
|
+
* release, through the committed config, exactly once.
|
|
22
|
+
*
|
|
23
|
+
* The handle is found by the object's id, resolved at call time (see the note on
|
|
24
|
+
* useOceanLive: an object resolved once while the panel opens before the object
|
|
25
|
+
* exists stays null forever). It lives on its own userData key and carries its own
|
|
26
|
+
* id, so it never competes with the scene's `userData.id` used by selection.
|
|
27
|
+
*/
|
|
28
|
+
/** Where a generative component stashes its handle on its root group's userData. */
|
|
29
|
+
export const CONFIG_LIVE_KEY = '__configLive';
|
|
30
|
+
/** Keys that never go through the live path, whatever the family. */
|
|
31
|
+
const ALWAYS_COMMIT = ['trailMode', 'trailShare', 'enabled', 'type'];
|
|
32
|
+
function findHandle(id) {
|
|
33
|
+
if (!id || !SceneStore.scene)
|
|
34
|
+
return undefined;
|
|
35
|
+
let found;
|
|
36
|
+
SceneStore.scene.traverse((o) => {
|
|
37
|
+
if (found)
|
|
38
|
+
return;
|
|
39
|
+
const h = o.userData?.[CONFIG_LIVE_KEY];
|
|
40
|
+
if (h && h.id === id)
|
|
41
|
+
found = h;
|
|
42
|
+
});
|
|
43
|
+
return found;
|
|
44
|
+
}
|
|
45
|
+
/** Client side: a stable `set(key, value)` for the generative object with this id. */
|
|
46
|
+
export function useConfigLive(id) {
|
|
47
|
+
return useMemo(() => {
|
|
48
|
+
let cached;
|
|
49
|
+
return {
|
|
50
|
+
set: (key, value) => {
|
|
51
|
+
if (!id)
|
|
52
|
+
return;
|
|
53
|
+
// one scene traversal per drag, not per pointer-move
|
|
54
|
+
if (!cached || !cached.alive || cached.id !== id)
|
|
55
|
+
cached = findHandle(id);
|
|
56
|
+
cached?.set(key, value);
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}, [id]);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Renderer side: registers the live handle and returns the ref holding everything
|
|
63
|
+
* dragged since the last commit. `apply` is called with that ref's contents on every
|
|
64
|
+
* live change; the component owns the merge, so keyframe animations compose with it.
|
|
65
|
+
*
|
|
66
|
+
* Pass `config` so a committed config drops the drag state — the commit *is* the
|
|
67
|
+
* same value, and keeping the override would pin the knob against later edits.
|
|
68
|
+
*/
|
|
69
|
+
export function useConfigLiveHandle(rootRef, id, family, config, structural, apply) {
|
|
70
|
+
const live = useRef({});
|
|
71
|
+
const applyRef = useRef(apply);
|
|
72
|
+
applyRef.current = apply;
|
|
73
|
+
// the committed config supersedes whatever the drag wrote
|
|
74
|
+
useLayoutEffect(() => { live.current = {}; }, [config]);
|
|
75
|
+
useLayoutEffect(() => {
|
|
76
|
+
const root = rootRef.current;
|
|
77
|
+
if (!root || !id)
|
|
78
|
+
return;
|
|
79
|
+
const skip = new Set([...structural, ...ALWAYS_COMMIT]);
|
|
80
|
+
const handle = {
|
|
81
|
+
id,
|
|
82
|
+
family,
|
|
83
|
+
alive: true,
|
|
84
|
+
set(key, value) {
|
|
85
|
+
if (!handle.alive || skip.has(key))
|
|
86
|
+
return;
|
|
87
|
+
live.current = { ...live.current, [key]: value };
|
|
88
|
+
applyRef.current(live.current);
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
root.userData[CONFIG_LIVE_KEY] = handle;
|
|
92
|
+
return () => {
|
|
93
|
+
handle.alive = false;
|
|
94
|
+
if (root.userData[CONFIG_LIVE_KEY] === handle)
|
|
95
|
+
delete root.userData[CONFIG_LIVE_KEY];
|
|
96
|
+
};
|
|
97
|
+
}, [rootRef, id, family, structural]);
|
|
98
|
+
return live;
|
|
99
|
+
}
|
|
100
|
+
export default useConfigLive;
|
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,8 @@ export { applyOceanUniforms, buildWaveTable, seaState } from './utils/oceanUnifo
|
|
|
30
30
|
export type { WaveTable } from './utils/oceanUniforms';
|
|
31
31
|
export { applyCameraUniforms, applyCirrusUniforms, applyDeckUniforms, applySunUniforms, applyThunderUniforms, } from './utils/cloudUniforms';
|
|
32
32
|
export { applyCloudsKeyframeAnimations, applyCloudsMouseMove, resolveDeckConfig, } from './utils/handleCloudsAnimations';
|
|
33
|
+
export { applyConfigKeyframeAnimations, applyConfigMouseMove, hasConfigOverrides, resolveConfig, } from './utils/configAnimations';
|
|
34
|
+
export type { ConfigOverride, ConfigStartValues } from './utils/configAnimations';
|
|
33
35
|
export { volumetricCloudPresets, cirrusPresets, getCloudPresetsForType, getCloudPresetByName, getCirrusPresetByName, searchCloudPresetsByTags, } from './presets/volumetricCloudPresets';
|
|
34
36
|
export type { VolumetricCloudPreset, CirrusPreset } from './presets/volumetricCloudPresets';
|
|
35
37
|
export { terrainPresets, getTerrainPresetsForType, getTerrainPresetByName, searchTerrainPresetsByTags, } from './presets/terrainPresets';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAG1F,OAAO,EAAE,iBAAiB,IAAI,iBAAiB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAG5F,cAAc,SAAS,CAAC;AAGxB,cAAc,cAAc,CAAC;AAG7B,cAAc,SAAS,CAAC;AAExB,YAAY,EAAE,oBAAoB,IAAI,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAGjG,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,GAAG,MAAM,iBAAiB,CAAC;AACrG,OAAO,EAAE,mBAAmB,IAAI,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACvF,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC7F,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC/E,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACvF,YAAY,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EACL,oBAAoB,EACpB,4BAA4B,EAC5B,qBAAqB,EACrB,eAAe,EACf,8BAA8B,GAC/B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpG,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnF,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC1F,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACrF,YAAY,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,6BAA6B,EAC7B,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@ export { buildTextureArray, decodeHeightmap, loadImage } from './utils/landscape
|
|
|
26
26
|
export { applyOceanUniforms, buildWaveTable, seaState } from './utils/oceanUniforms.js';
|
|
27
27
|
export { applyCameraUniforms, applyCirrusUniforms, applyDeckUniforms, applySunUniforms, applyThunderUniforms, } from './utils/cloudUniforms.js';
|
|
28
28
|
export { applyCloudsKeyframeAnimations, applyCloudsMouseMove, resolveDeckConfig, } from './utils/handleCloudsAnimations.js';
|
|
29
|
+
export { applyConfigKeyframeAnimations, applyConfigMouseMove, hasConfigOverrides, resolveConfig, } from './utils/configAnimations.js';
|
|
29
30
|
// Presets
|
|
30
31
|
export { volumetricCloudPresets, cirrusPresets, getCloudPresetsForType, getCloudPresetByName, getCirrusPresetByName, searchCloudPresetsByTags, } from './presets/volumetricCloudPresets.js';
|
|
31
32
|
export { terrainPresets, getTerrainPresetsForType, getTerrainPresetByName, searchTerrainPresetsByTags, } from './presets/terrainPresets.js';
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { AnimationOptions, MouseMoveProperty } from '@3driseai/3drise-core';
|
|
2
|
+
/**
|
|
3
|
+
* Keyframe animations and mouse-move, applied to a *config object* rather than to
|
|
4
|
+
* materials — the shape every generative family shares (particles, effects, and the
|
|
5
|
+
* clouds / rain helpers this generalises).
|
|
6
|
+
*
|
|
7
|
+
* The renderer keeps one override record per frame and lays it over the committed
|
|
8
|
+
* config before pushing uniforms:
|
|
9
|
+
*
|
|
10
|
+
* applyConfigKeyframeAnimations(anims, startValues, config, override, elapsedMs, ANIMATABLE);
|
|
11
|
+
* applyConfig(uniforms, { ...config, ...live, ...override }, size);
|
|
12
|
+
*
|
|
13
|
+
* Only knobs in `allowed` are eligible: that set is generated from the component's
|
|
14
|
+
* own applyConfig (see core's GENERATIVE_ANIMATABLE), so a keyframe can never target
|
|
15
|
+
* something that would need a rebuild to take effect.
|
|
16
|
+
*
|
|
17
|
+
* Both numbers and colours work — `interpolateValue` is type-aware and reads hex
|
|
18
|
+
* strings as colours.
|
|
19
|
+
*/
|
|
20
|
+
export type ConfigOverride = Record<string, number | string>;
|
|
21
|
+
/** Cache of the value a property started at, so `from`-less keyframes have an origin. */
|
|
22
|
+
export type ConfigStartValues = Record<string, number | string>;
|
|
23
|
+
/**
|
|
24
|
+
* @param elapsedMs Milliseconds since this animation set started — NOT `Date.now()`,
|
|
25
|
+
* and not seconds. `calculateTimeProgress` divides by `duration`, so a wall
|
|
26
|
+
* clock makes a one-shot finish on its first frame, and seconds make it crawl.
|
|
27
|
+
* Reset the origin (and `startValues`) whenever the animation list changes, so
|
|
28
|
+
* editing a keyframe restarts it instead of dropping the user mid-cycle.
|
|
29
|
+
*
|
|
30
|
+
* Clears `override` first: a keyframe that was removed must stop driving its knob.
|
|
31
|
+
* Call this before `applyConfigMouseMove`, which layers on top.
|
|
32
|
+
*/
|
|
33
|
+
export declare function applyConfigKeyframeAnimations(animations: AnimationOptions[] | undefined, startValues: ConfigStartValues, config: Record<string, unknown>, override: ConfigOverride, elapsedMs: number, allowed?: ReadonlySet<string>): void;
|
|
34
|
+
/** Pointer-driven overrides, layered on top of whatever the keyframes produced. */
|
|
35
|
+
export declare function applyConfigMouseMove(properties: MouseMoveProperty[] | undefined, config: Record<string, unknown>, override: ConfigOverride, pointer: {
|
|
36
|
+
x: number;
|
|
37
|
+
y: number;
|
|
38
|
+
}, allowed?: ReadonlySet<string>): void;
|
|
39
|
+
/** True when anything is currently being driven. */
|
|
40
|
+
export declare function hasConfigOverrides(override: ConfigOverride): boolean;
|
|
41
|
+
/** Merge overrides into a config, returning the original when nothing is driving it. */
|
|
42
|
+
export declare function resolveConfig<T extends object>(config: T, ...overrides: (ConfigOverride | undefined)[]): T;
|
|
43
|
+
//# sourceMappingURL=configAnimations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"configAnimations.d.ts","sourceRoot":"","sources":["../../src/utils/configAnimations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAEjF;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAE7D,yFAAyF;AACzF,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;AAEhE;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CACzC,UAAU,EAAE,gBAAgB,EAAE,GAAG,SAAS,EAC1C,WAAW,EAAE,iBAAiB,EAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAC9B,IAAI,CAqBN;AAED,mFAAmF;AACnF,wBAAgB,oBAAoB,CAChC,UAAU,EAAE,iBAAiB,EAAE,GAAG,SAAS,EAC3C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EACjC,OAAO,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,GAC9B,IAAI,CAYN;AAED,oDAAoD;AACpD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,GAAG,OAAO,CAGpE;AAED,wFAAwF;AACxF,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,GAAG,SAAS,EAAE,CAAC,cAAc,GAAG,SAAS,CAAC,EAAE,GAAG,CAAC,CAK1G"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { calculateTimeProgress, applyEasing, gsapEasingMap, interpolateValue, interpolateMouseMoveProperty } from '@3driseai/3drise-core';
|
|
2
|
+
/**
|
|
3
|
+
* @param elapsedMs Milliseconds since this animation set started — NOT `Date.now()`,
|
|
4
|
+
* and not seconds. `calculateTimeProgress` divides by `duration`, so a wall
|
|
5
|
+
* clock makes a one-shot finish on its first frame, and seconds make it crawl.
|
|
6
|
+
* Reset the origin (and `startValues`) whenever the animation list changes, so
|
|
7
|
+
* editing a keyframe restarts it instead of dropping the user mid-cycle.
|
|
8
|
+
*
|
|
9
|
+
* Clears `override` first: a keyframe that was removed must stop driving its knob.
|
|
10
|
+
* Call this before `applyConfigMouseMove`, which layers on top.
|
|
11
|
+
*/
|
|
12
|
+
export function applyConfigKeyframeAnimations(animations, startValues, config, override, elapsedMs, allowed) {
|
|
13
|
+
for (const k of Object.keys(override))
|
|
14
|
+
delete override[k];
|
|
15
|
+
if (!animations?.length)
|
|
16
|
+
return;
|
|
17
|
+
for (const anim of animations) {
|
|
18
|
+
const { property, to, duration, ease, loop = false, yoyo = false, active } = anim;
|
|
19
|
+
if (active === false || to === undefined)
|
|
20
|
+
continue;
|
|
21
|
+
if (allowed && !allowed.has(property))
|
|
22
|
+
continue;
|
|
23
|
+
let from = anim.from;
|
|
24
|
+
if (from === undefined) {
|
|
25
|
+
from = startValues[property] ??= config[property];
|
|
26
|
+
}
|
|
27
|
+
if (from === undefined || from === null)
|
|
28
|
+
continue;
|
|
29
|
+
let p = calculateTimeProgress(elapsedMs, duration, yoyo, loop);
|
|
30
|
+
if (ease) {
|
|
31
|
+
const fn = gsapEasingMap[ease] || ease;
|
|
32
|
+
p = applyEasing(fn, p);
|
|
33
|
+
}
|
|
34
|
+
override[property] = interpolateValue(property, from, to, p);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Pointer-driven overrides, layered on top of whatever the keyframes produced. */
|
|
38
|
+
export function applyConfigMouseMove(properties, config, override, pointer, allowed) {
|
|
39
|
+
if (!properties?.length)
|
|
40
|
+
return;
|
|
41
|
+
for (const { property, enabled, propertySettings } of properties) {
|
|
42
|
+
if (!enabled)
|
|
43
|
+
continue;
|
|
44
|
+
if (allowed && !allowed.has(property))
|
|
45
|
+
continue;
|
|
46
|
+
const { axis = 'both', sensitivity = 1, inverted = false, min, max } = propertySettings || {};
|
|
47
|
+
// Compose with the keyframed value when there is one, so the two stack instead
|
|
48
|
+
// of the pointer snapping back to the config every frame.
|
|
49
|
+
const base = override[property] ?? config[property];
|
|
50
|
+
if (base === undefined)
|
|
51
|
+
continue;
|
|
52
|
+
override[property] = interpolateMouseMoveProperty(base, min, max, pointer, axis, sensitivity, inverted);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** True when anything is currently being driven. */
|
|
56
|
+
export function hasConfigOverrides(override) {
|
|
57
|
+
for (const k in override)
|
|
58
|
+
if (override[k] !== undefined)
|
|
59
|
+
return true;
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
/** Merge overrides into a config, returning the original when nothing is driving it. */
|
|
63
|
+
export function resolveConfig(config, ...overrides) {
|
|
64
|
+
let dirty = false;
|
|
65
|
+
for (const o of overrides)
|
|
66
|
+
if (o && hasConfigOverrides(o)) {
|
|
67
|
+
dirty = true;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
if (!dirty)
|
|
71
|
+
return config;
|
|
72
|
+
return Object.assign({}, config, ...overrides.filter(Boolean));
|
|
73
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"particleTrails.d.ts","sourceRoot":"","sources":["../../src/utils/particleTrails.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAc/B,eAAO,MAAM,WAAW,UAAsC,CAAC;AAK/D,wBAAgB,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;EAWlC;AAED,wBAAgB,gBAAgB,CAAC,CAAC,KAAA,EAAE,CAAC,KAAA,QAKpC;AAED,oFAAoF;AACpF,wBAAgB,SAAS,CAAC,MAAM,KAAA;;;YAES,CAAC,MAAM,CAAC,MAAM,CAAC,SAAU;YAAE,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS;YAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAQ;;;;;;;;;;;;;;;;;;;;EAMjH;
|
|
1
|
+
{"version":3,"file":"particleTrails.d.ts","sourceRoot":"","sources":["../../src/utils/particleTrails.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAc/B,eAAO,MAAM,WAAW,UAAsC,CAAC;AAK/D,wBAAgB,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;EAWlC;AAED,wBAAgB,gBAAgB,CAAC,CAAC,KAAA,EAAE,CAAC,KAAA,QAKpC;AAED,oFAAoF;AACpF,wBAAgB,SAAS,CAAC,MAAM,KAAA;;;YAES,CAAC,MAAM,CAAC,MAAM,CAAC,SAAU;YAAE,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS;YAAE,CAAC,MAAM,CAAC,IAAI,CAAC,SAAQ;;;;;;;;;;;;;;;;;;;;EAMjH;AAuID;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,KAAA,EAAE,IAAI,KAAA;;;;;;;EAyJxC"}
|
|
@@ -94,6 +94,13 @@ function finish(sizePx) {
|
|
|
94
94
|
gl_Position = projectionMatrix * vec4(mv, 1.0);
|
|
95
95
|
`;
|
|
96
96
|
}
|
|
97
|
+
// The per-vertex template parameter lives in its own attribute (aT). `position` must exist for
|
|
98
|
+
// InstancedBufferGeometry to draw, but it stays all zeros: Box3.expandByObject(obj, true) reads it,
|
|
99
|
+
// and a 0..10 template in position.x would drag an editor's selection gizmo ten units sideways.
|
|
100
|
+
function setTemplate(g, tpl) {
|
|
101
|
+
g.setAttribute('position', new THREE.BufferAttribute(new Float32Array(tpl.length * 3), 3));
|
|
102
|
+
g.setAttribute('aT', new THREE.BufferAttribute(tpl, 1));
|
|
103
|
+
}
|
|
97
104
|
const K_ON = '#define TRAIL_K aK\nattribute float aK;\n';
|
|
98
105
|
const K_OFF = '#define TRAIL_K 1.0\n';
|
|
99
106
|
function streakShader(glsl, sizePx, spacing, kdef) {
|
|
@@ -102,12 +109,13 @@ function streakShader(glsl, sizePx, spacing, kdef) {
|
|
|
102
109
|
S,
|
|
103
110
|
vertex: /* glsl */ `
|
|
104
111
|
${HEAD}
|
|
112
|
+
attribute float aT;
|
|
105
113
|
attribute vec3 aP;
|
|
106
114
|
attribute vec3 aV;
|
|
107
115
|
${kdef}
|
|
108
116
|
${glsl}
|
|
109
117
|
void main() {
|
|
110
|
-
float f =
|
|
118
|
+
float f = aT; // 0 head .. 1 tail
|
|
111
119
|
vec3 dv = aV * uVelScale * uTrailLength;
|
|
112
120
|
float len = length(dv);
|
|
113
121
|
vec3 p = aP - dv * f;
|
|
@@ -123,6 +131,7 @@ function cometShader(glsl, sizePx, spacing, kdef, SUB) {
|
|
|
123
131
|
const pick = Array.from({ length: SLOTS }, (_, i) => ` ${i === 0 ? 'if' : 'else if'} (i == ${i}) return h${i};`).join('\n');
|
|
124
132
|
return /* glsl */ `
|
|
125
133
|
${HEAD}
|
|
134
|
+
attribute float aT;
|
|
126
135
|
attribute vec3 aP;
|
|
127
136
|
${slots}
|
|
128
137
|
${kdef}
|
|
@@ -142,7 +151,7 @@ vec3 catmull(vec3 a, vec3 b, vec3 c, vec3 d, float t) {
|
|
|
142
151
|
return 0.5 * ((2.0 * b) + (-a + c) * t + (2.0 * a - 5.0 * b + 4.0 * c - d) * t2 + (-a + 3.0 * b - 3.0 * c + d) * t3);
|
|
143
152
|
}
|
|
144
153
|
void main() {
|
|
145
|
-
float s =
|
|
154
|
+
float s = aT; // 0 .. ${SLOTS} along the chain
|
|
146
155
|
int k = int(floor(s));
|
|
147
156
|
float t = s - float(k);
|
|
148
157
|
vec3 p0 = L(k - 1), p1 = L(k), p2 = L(k + 1), p3 = L(k + 2);
|
|
@@ -204,10 +213,10 @@ export function createCpuTrail(mode, opts) {
|
|
|
204
213
|
if (mode === 'streak') {
|
|
205
214
|
const sh = streakShader(glsl, sizePx, spacing, kdef);
|
|
206
215
|
const g = new THREE.InstancedBufferGeometry();
|
|
207
|
-
const tpl = new Float32Array(sh.S
|
|
216
|
+
const tpl = new Float32Array(sh.S);
|
|
208
217
|
for (let i = 0; i < sh.S; i++)
|
|
209
|
-
tpl[i
|
|
210
|
-
g
|
|
218
|
+
tpl[i] = i / (sh.S - 1);
|
|
219
|
+
setTemplate(g, tpl);
|
|
211
220
|
const aP = new THREE.InstancedBufferAttribute(pos, 3).setUsage(THREE.DynamicDrawUsage);
|
|
212
221
|
const aV = new THREE.InstancedBufferAttribute(vel, 3).setUsage(THREE.DynamicDrawUsage);
|
|
213
222
|
g.setAttribute('aP', aP);
|
|
@@ -232,10 +241,10 @@ export function createCpuTrail(mode, opts) {
|
|
|
232
241
|
const g = new THREE.InstancedBufferGeometry();
|
|
233
242
|
const SUBn = opts.sub || SUB; // spline samples per history segment (fast particles need more)
|
|
234
243
|
const M = SLOTS * SUBn + 1;
|
|
235
|
-
const tpl = new Float32Array(M
|
|
244
|
+
const tpl = new Float32Array(M);
|
|
236
245
|
for (let i = 0; i < M; i++)
|
|
237
|
-
tpl[i
|
|
238
|
-
g
|
|
246
|
+
tpl[i] = i / SUBn;
|
|
247
|
+
setTemplate(g, tpl);
|
|
239
248
|
const aP = new THREE.InstancedBufferAttribute(pos, 3).setUsage(THREE.DynamicDrawUsage);
|
|
240
249
|
g.setAttribute('aP', aP);
|
|
241
250
|
const aK = kArr ? new THREE.InstancedBufferAttribute(kArr, 1).setUsage(THREE.DynamicDrawUsage) : null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@3driseai/3drise-viewer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.19",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -39,6 +39,6 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@3driseai/3drise-common": "^1.0.1",
|
|
42
|
-
"@3driseai/3drise-core": "^1.0.
|
|
42
|
+
"@3driseai/3drise-core": "^1.0.13"
|
|
43
43
|
}
|
|
44
44
|
}
|