@3driseai/3drise-viewer 0.1.18 → 0.1.20
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/CreatedObject.d.ts.map +1 -1
- package/dist/components/CreatedObject.js +18 -14
- package/dist/components/ModelMaterialPassContext.d.ts +7 -0
- package/dist/components/ModelMaterialPassContext.d.ts.map +1 -0
- package/dist/components/ModelMaterialPassContext.js +7 -0
- package/dist/components/ModelPrimitive.d.ts.map +1 -1
- package/dist/components/ModelPrimitive.js +7 -1
- package/dist/components/ObjectNode.d.ts.map +1 -1
- package/dist/components/ObjectNode.js +10 -6
- package/dist/components/ParticlesGenerator.d.ts.map +1 -1
- package/dist/components/ParticlesGenerator.js +11 -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/ChladniSandParticles.d.ts +15 -0
- package/dist/components/particles/ChladniSandParticles.d.ts.map +1 -0
- package/dist/components/particles/ChladniSandParticles.js +912 -0
- 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/FaradayPowderParticles.d.ts +15 -0
- package/dist/components/particles/FaradayPowderParticles.d.ts.map +1 -0
- package/dist/components/particles/FaradayPowderParticles.js +783 -0
- 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/NeonRainParticles.d.ts +15 -0
- package/dist/components/particles/NeonRainParticles.d.ts.map +1 -0
- package/dist/components/particles/NeonRainParticles.js +716 -0
- 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/components/particles/index.d.ts +6 -0
- package/dist/components/particles/index.d.ts.map +1 -1
- package/dist/components/particles/index.js +3 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -1
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -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/hooks/useMaterialApplication.d.ts.map +1 -1
- package/dist/hooks/useMaterialApplication.js +1 -0
- package/dist/hooks/useNodeOverrides.d.ts +13 -0
- package/dist/hooks/useNodeOverrides.d.ts.map +1 -0
- package/dist/hooks/useNodeOverrides.js +254 -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":"CreatedObject.d.ts","sourceRoot":"","sources":["../../src/components/CreatedObject.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CreatedObject.d.ts","sourceRoot":"","sources":["../../src/components/CreatedObject.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAUnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,UAAU,kBAAmB,SAAQ,gBAAgB;IACjD,aAAa,EAAE,qBAAqB,CAAC;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,iBAAiB,CAAC,EAAE,CAAC,aAAa,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;CACpH;AAGD,QAAA,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAmF9C,CAAC;AAEH,eAAe,aAAa,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useRef, useEffect, useState, memo } from "react";
|
|
2
|
+
import { useRef, useEffect, useState, useReducer, memo } from "react";
|
|
3
|
+
import { ModelMaterialPassContext } from "./ModelMaterialPassContext.js";
|
|
3
4
|
import { DEFAULT_EDGES_SETTINGS } from "@3driseai/3drise-core";
|
|
4
5
|
import { useMaterialApplication } from "../hooks/useMaterialApplication.js";
|
|
5
6
|
import { useShadowApplication } from "../hooks/useShadowApplication.js";
|
|
@@ -29,7 +30,10 @@ const CreatedObject = memo(({ createdObject, children, shouldApply3driseMaterial
|
|
|
29
30
|
const [mountedObject, setMountedObject] = useState(null);
|
|
30
31
|
useObjectEdges(createdObject.id, createdObject.edgesSettings ?? DEFAULT_EDGES_SETTINGS, meshRef);
|
|
31
32
|
// useObjectGenerativeEffects(mountedObject, createdObject.effects);
|
|
32
|
-
|
|
33
|
+
// Bumped when the model-level material pass lands, so per-mesh overrides
|
|
34
|
+
// (useNodeOverrides in ModelPrimitive) re-apply on top of it.
|
|
35
|
+
const [materialPass, bumpMaterialPass] = useReducer((n) => n + 1, 0);
|
|
36
|
+
useMaterialApplication(meshRef, createdObject.materialSettings, shouldApply3driseMaterial, bumpMaterialPass);
|
|
33
37
|
useShadowApplication(meshRef, createdObject.meshSettings.castShadow, createdObject.meshSettings.receiveShadow);
|
|
34
38
|
const anchoredPosition = cameraManager.getAnchorPosition(createdObject.meshSettings.anchor?.anchor || 'center', 0, createdObject.meshSettings.anchor?.offset || { y: 0, x: 0, z: 0 }, createdObject.meshSettings.anchor?.padding || 0);
|
|
35
39
|
useEffect(() => {
|
|
@@ -77,19 +81,19 @@ const CreatedObject = memo(({ createdObject, children, shouldApply3driseMaterial
|
|
|
77
81
|
e.stopPropagation();
|
|
78
82
|
};
|
|
79
83
|
const anchorEnabled = createdObject.meshSettings.anchor && createdObject.meshSettings.anchor.enabled;
|
|
80
|
-
return (_jsx(AnimatedObject
|
|
81
|
-
// animationId={createdObject.animationId || ''}
|
|
82
|
-
, {
|
|
84
|
+
return (_jsx(ModelMaterialPassContext.Provider, { value: materialPass, children: _jsx(AnimatedObject
|
|
83
85
|
// animationId={createdObject.animationId || ''}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
, {
|
|
87
|
+
// animationId={createdObject.animationId || ''}
|
|
88
|
+
stateKey: createdObject.id, transitionSettings: {
|
|
89
|
+
...animatedTransform,
|
|
90
|
+
position: anchorEnabled ? [anchoredPosition.x, anchoredPosition.y, anchoredPosition.z] : animatedTransform.position
|
|
91
|
+
}, createdObject: createdObject,
|
|
92
|
+
// animateMaterial={!useDreiMaterials}
|
|
93
|
+
parentRef: meshRef, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose, visible: createdObject.meshSettings.visible, handleObjectClick: handleObjectClick, onPointerEnter: handleObjectEnter, onPointerLeave: e => handleObjectLeave(e), hovered: hovered, children: createdObject.rigidBodySettings?.enabled ? (_jsx(RigidBody, { type: createdObject.rigidBodySettings?.type || 'dynamic', mass: createdObject.rigidBodySettings?.mass || 1, colliders: createdObject.userData?.type === 'plane'
|
|
94
|
+
? 'cuboid' // Force box collider for planes
|
|
95
|
+
: undefined // Auto-detect for others
|
|
96
|
+
, friction: createdObject.rigidBodySettings?.friction, restitution: createdObject.rigidBodySettings?.restitution, gravityScale: createdObject.rigidBodySettings?.gravityScale ?? 1, linearDamping: createdObject.rigidBodySettings?.linearDamping ?? 0.01, angularDamping: createdObject.rigidBodySettings?.angularDamping ?? 0.01, children: children })) : (children) }) }));
|
|
93
97
|
});
|
|
94
98
|
CreatedObject.displayName = 'CreatedObject';
|
|
95
99
|
export default CreatedObject;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bumped by CreatedObject every time its model-level material pass
|
|
3
|
+
* (useMaterialApplication) finishes. Per-mesh overrides re-apply on top of it, because
|
|
4
|
+
* the pass replaces every material in the model — including the ones an override set.
|
|
5
|
+
*/
|
|
6
|
+
export declare const ModelMaterialPassContext: import("react").Context<number>;
|
|
7
|
+
//# sourceMappingURL=ModelMaterialPassContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModelMaterialPassContext.d.ts","sourceRoot":"","sources":["../../src/components/ModelMaterialPassContext.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,iCAAmB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { createContext } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Bumped by CreatedObject every time its model-level material pass
|
|
4
|
+
* (useMaterialApplication) finishes. Per-mesh overrides re-apply on top of it, because
|
|
5
|
+
* the pass replaces every material in the model — including the ones an override set.
|
|
6
|
+
*/
|
|
7
|
+
export const ModelMaterialPassContext = createContext(0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModelPrimitive.d.ts","sourceRoot":"","sources":["../../src/components/ModelPrimitive.tsx"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"ModelPrimitive.d.ts","sourceRoot":"","sources":["../../src/components/ModelPrimitive.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA6C,MAAM,OAAO,CAAC;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAKnE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,UAAU,mBAAoB,SAAQ,gBAAgB;IAClD,aAAa,EAAE,qBAAqB,CAAC;IACrC,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,QAAA,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAkChD,CAAC;AAIH,eAAe,cAAc,CAAC"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { memo, useCallback, useRef } from 'react';
|
|
2
|
+
import { memo, useCallback, useMemo, useRef } from 'react';
|
|
3
3
|
import { useModelObject } from '../hooks/useModelObject.js';
|
|
4
|
+
import { useNodeOverrides } from '../hooks/useNodeOverrides.js';
|
|
5
|
+
import { getNodeOverrides, peekModelAsset } from '@3driseai/3drise-core';
|
|
4
6
|
import { useObjectReadyReporter } from '../hooks/useObjectReady.js';
|
|
5
7
|
/**
|
|
6
8
|
* Mounts the Object3D behind a `type: 'model'` scene object, and hands it to the host
|
|
@@ -32,6 +34,10 @@ import { useObjectReadyReporter } from '../hooks/useObjectReady.js';
|
|
|
32
34
|
const ModelPrimitive = memo(({ createdObject, slot = 0, onObjectReady, onObjectDispose, children }) => {
|
|
33
35
|
const attachedRef = useRef(null);
|
|
34
36
|
const object = useModelObject(createdObject, slot);
|
|
37
|
+
// Per-mesh overrides (ModelTree). Originals come from the never-mounted cache master.
|
|
38
|
+
const url = createdObject.userData?.url;
|
|
39
|
+
const master = useMemo(() => (url ? peekModelAsset(url)?.scene ?? null : null), [url, object]);
|
|
40
|
+
useNodeOverrides(object, getNodeOverrides(createdObject), master);
|
|
35
41
|
const { report, reportDisposed } = useObjectReadyReporter(createdObject, onObjectReady, onObjectDispose);
|
|
36
42
|
const setObjectRef = useCallback((instance) => {
|
|
37
43
|
if (instance) {
|
|
@@ -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) => (
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ParticlesGenerator.d.ts","sourceRoot":"","sources":["../../src/components/ParticlesGenerator.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"ParticlesGenerator.d.ts","sourceRoot":"","sources":["../../src/components/ParticlesGenerator.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AACzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAU7D,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB;IAC7D,QAAQ,EAAE,2BAA2B,CAAC;CACzC;AAED,0FAA0F;AAC1F,QAAA,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAgBzD,CAAC;AACF,eAAe,kBAAkB,CAAC"}
|
|
@@ -4,6 +4,9 @@ import BrownianDustParticles from './particles/BrownianDustParticles.js';
|
|
|
4
4
|
import BioluminescentWakeParticles from './particles/BioluminescentWakeParticles.js';
|
|
5
5
|
import ElectronOrbitalsParticles from './particles/ElectronOrbitalsParticles.js';
|
|
6
6
|
import GrinderSparksParticles from './particles/GrinderSparksParticles.js';
|
|
7
|
+
import ChladniSandParticles from './particles/ChladniSandParticles.js';
|
|
8
|
+
import FaradayPowderParticles from './particles/FaradayPowderParticles.js';
|
|
9
|
+
import NeonRainParticles from './particles/NeonRainParticles.js';
|
|
7
10
|
/** Standalone generative particle objects (type 'particles'), switched on config.type. */
|
|
8
11
|
const ParticlesGenerator = ({ settings, onObjectReady, onObjectDispose }) => {
|
|
9
12
|
const { config, animations } = settings;
|
|
@@ -12,11 +15,14 @@ const ParticlesGenerator = ({ settings, onObjectReady, onObjectDispose }) => {
|
|
|
12
15
|
const size = config.size ?? 1;
|
|
13
16
|
const ready = { onObjectReady, onObjectDispose };
|
|
14
17
|
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 });
|
|
18
|
+
case 'tidalStream': return _jsx(TidalStreamParticles, { id: settings.id, size: size, config: config, animations: animations, ...ready });
|
|
19
|
+
case 'brownianDust': return _jsx(BrownianDustParticles, { id: settings.id, size: size, config: config, animations: animations, ...ready });
|
|
20
|
+
case 'bioluminescentWake': return _jsx(BioluminescentWakeParticles, { id: settings.id, size: size, config: config, animations: animations, ...ready });
|
|
21
|
+
case 'electronOrbitals': return _jsx(ElectronOrbitalsParticles, { id: settings.id, size: size, config: config, animations: animations, ...ready });
|
|
22
|
+
case 'grinderSparks': return _jsx(GrinderSparksParticles, { id: settings.id, size: size, config: config, animations: animations, ...ready });
|
|
23
|
+
case 'chladniSand': return _jsx(ChladniSandParticles, { id: settings.id, size: size, config: config, animations: animations, ...ready });
|
|
24
|
+
case 'faradayPowder': return _jsx(FaradayPowderParticles, { id: settings.id, size: size, config: config, animations: animations, ...ready });
|
|
25
|
+
case 'neonRain': return _jsx(NeonRainParticles, { id: settings.id, size: size, config: config, animations: animations, ...ready });
|
|
20
26
|
default: return null;
|
|
21
27
|
}
|
|
22
28
|
};
|
|
@@ -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
|
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ObjectAnimations, ChladniSandParticlesConfig } from '@3driseai/3drise-core';
|
|
3
|
+
import type { ObjectReadyProps } from '../../types/objectReady';
|
|
4
|
+
export interface ChladniSandParticlesProps extends ObjectReadyProps {
|
|
5
|
+
/** Scene object id: the controller finds the live-edit handle by it. */
|
|
6
|
+
id?: string;
|
|
7
|
+
/** World size of the object (units); the object's transform scales it further. */
|
|
8
|
+
size: number;
|
|
9
|
+
config: ChladniSandParticlesConfig;
|
|
10
|
+
/** Per-domain keyframes; the `particles` domain drives this object's config knobs. */
|
|
11
|
+
animations?: ObjectAnimations;
|
|
12
|
+
}
|
|
13
|
+
declare const ChladniSandParticles: React.FC<ChladniSandParticlesProps>;
|
|
14
|
+
export default ChladniSandParticles;
|
|
15
|
+
//# sourceMappingURL=ChladniSandParticles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChladniSandParticles.d.ts","sourceRoot":"","sources":["../../../src/components/particles/ChladniSandParticles.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;AAsvBD,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAiD7D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|