@3driseai/3drise-viewer 0.1.24 → 0.1.26
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/animationsV2/ClipPlayer.d.ts +13 -0
- package/dist/animationsV2/ClipPlayer.d.ts.map +1 -0
- package/dist/animationsV2/ClipPlayer.js +140 -0
- package/dist/animationsV2/ClipsRuntime.d.ts +111 -0
- package/dist/animationsV2/ClipsRuntime.d.ts.map +1 -0
- package/dist/animationsV2/ClipsRuntime.js +476 -0
- package/dist/animationsV2/appliers.d.ts +16 -0
- package/dist/animationsV2/appliers.d.ts.map +1 -0
- package/dist/animationsV2/appliers.js +204 -0
- package/dist/animationsV2/clipUtils.d.ts +33 -0
- package/dist/animationsV2/clipUtils.d.ts.map +1 -0
- package/dist/animationsV2/clipUtils.js +164 -0
- package/dist/animationsV2/elementSettings.d.ts +15 -0
- package/dist/animationsV2/elementSettings.d.ts.map +1 -0
- package/dist/animationsV2/elementSettings.js +16 -0
- package/dist/animationsV2/index.d.ts +16 -0
- package/dist/animationsV2/index.d.ts.map +1 -0
- package/dist/animationsV2/index.js +12 -0
- package/dist/animationsV2/nodeTracks.d.ts +13 -0
- package/dist/animationsV2/nodeTracks.d.ts.map +1 -0
- package/dist/animationsV2/nodeTracks.js +165 -0
- package/dist/animationsV2/normalize.d.ts +4 -0
- package/dist/animationsV2/normalize.d.ts.map +1 -0
- package/dist/animationsV2/normalize.js +49 -0
- package/dist/animationsV2/sequenceUtils.d.ts +57 -0
- package/dist/animationsV2/sequenceUtils.d.ts.map +1 -0
- package/dist/animationsV2/sequenceUtils.js +120 -0
- package/dist/animationsV2/types.d.ts +95 -0
- package/dist/animationsV2/types.d.ts.map +1 -0
- package/dist/animationsV2/types.js +8 -0
- package/dist/api/sceneHandle.d.ts +102 -0
- package/dist/api/sceneHandle.d.ts.map +1 -0
- package/dist/api/sceneHandle.js +237 -0
- package/dist/components/CameraController.d.ts.map +1 -1
- package/dist/components/CameraController.js +3 -44
- package/dist/components/Clouds.d.ts.map +1 -1
- package/dist/components/Clouds.js +0 -34
- package/dist/components/CreatedObject.d.ts.map +1 -1
- package/dist/components/CreatedObject.js +19 -1
- package/dist/components/EnvironmentManager.d.ts.map +1 -1
- package/dist/components/EnvironmentManager.js +6 -4
- package/dist/components/ObjectNode.d.ts.map +1 -1
- package/dist/components/ObjectNode.js +5 -1
- package/dist/components/ObjectsRenderer.d.ts +5 -1
- package/dist/components/ObjectsRenderer.d.ts.map +1 -1
- package/dist/components/ObjectsRenderer.js +24 -3
- package/dist/components/Ocean.d.ts.map +1 -1
- package/dist/components/Ocean.js +0 -63
- package/dist/components/ProjectLoader.d.ts +9 -3
- package/dist/components/ProjectLoader.d.ts.map +1 -1
- package/dist/components/ProjectLoader.js +5 -4
- package/dist/components/SceneBuilder.d.ts +9 -1
- package/dist/components/SceneBuilder.d.ts.map +1 -1
- package/dist/components/SceneBuilder.js +30 -5
- package/dist/components/SkyController.d.ts.map +1 -1
- package/dist/components/SkyController.js +0 -39
- package/dist/components/Stars.d.ts.map +1 -1
- package/dist/components/Stars.js +3 -46
- package/dist/components/terrain/TerrainSurface.d.ts.map +1 -1
- package/dist/components/terrain/TerrainSurface.js +0 -5
- package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts.map +1 -1
- package/dist/components/volumetricClouds/VolumetricCloudsPass.js +0 -6
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -2
- package/dist/hooks/useInteraction.d.ts +7 -7
- package/dist/hooks/useInteraction.d.ts.map +1 -1
- package/dist/hooks/useInteraction.js +87 -233
- package/dist/hooks/useLightConfig.d.ts.map +1 -1
- package/dist/hooks/useLightConfig.js +7 -0
- package/dist/hooks/useLightLive.d.ts.map +1 -1
- package/dist/hooks/useLightLive.js +2 -0
- package/dist/hooks/useLightTargets.d.ts +7 -0
- package/dist/hooks/useLightTargets.d.ts.map +1 -0
- package/dist/hooks/useLightTargets.js +132 -0
- package/dist/hooks/useObjectAnimation.d.ts.map +1 -1
- package/dist/hooks/useObjectAnimation.js +0 -2
- package/dist/hooks/useOceanMaterial.d.ts.map +1 -1
- package/dist/hooks/useOceanMaterial.js +0 -5
- package/dist/hooks/useRuntimeSettings.d.ts +15 -0
- package/dist/hooks/useRuntimeSettings.d.ts.map +1 -0
- package/dist/hooks/useRuntimeSettings.js +22 -0
- package/dist/hooks/useSequenceAnimation.d.ts.map +1 -1
- package/dist/hooks/useSequenceAnimation.js +27 -9
- package/dist/index.d.ts +6 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/interactions/index.d.ts +3 -0
- package/dist/interactions/index.d.ts.map +1 -0
- package/dist/interactions/index.js +1 -0
- package/dist/interactions/runner.d.ts +9 -0
- package/dist/interactions/runner.d.ts.map +1 -0
- package/dist/interactions/runner.js +23 -0
- package/dist/operations/catalogue/displayImage.d.ts +3 -0
- package/dist/operations/catalogue/displayImage.d.ts.map +1 -0
- package/dist/operations/catalogue/displayImage.js +39 -0
- package/dist/operations/catalogue/fade.d.ts +3 -0
- package/dist/operations/catalogue/fade.d.ts.map +1 -0
- package/dist/operations/catalogue/fade.js +44 -0
- package/dist/operations/catalogue/focus.d.ts +3 -0
- package/dist/operations/catalogue/focus.d.ts.map +1 -0
- package/dist/operations/catalogue/focus.js +22 -0
- package/dist/operations/catalogue/glow.d.ts +3 -0
- package/dist/operations/catalogue/glow.d.ts.map +1 -0
- package/dist/operations/catalogue/glow.js +49 -0
- package/dist/operations/catalogue/materialFx.d.ts +6 -0
- package/dist/operations/catalogue/materialFx.d.ts.map +1 -0
- package/dist/operations/catalogue/materialFx.js +13 -0
- package/dist/operations/catalogue/moveToFront.d.ts +3 -0
- package/dist/operations/catalogue/moveToFront.d.ts.map +1 -0
- package/dist/operations/catalogue/moveToFront.js +25 -0
- package/dist/operations/catalogue/visibility.d.ts +3 -0
- package/dist/operations/catalogue/visibility.d.ts.map +1 -0
- package/dist/operations/catalogue/visibility.js +24 -0
- package/dist/operations/catalogue/zoom.d.ts +3 -0
- package/dist/operations/catalogue/zoom.d.ts.map +1 -0
- package/dist/operations/catalogue/zoom.js +32 -0
- package/dist/operations/index.d.ts +5 -0
- package/dist/operations/index.d.ts.map +1 -0
- package/dist/operations/index.js +4 -0
- package/dist/operations/registry.d.ts +11 -0
- package/dist/operations/registry.d.ts.map +1 -0
- package/dist/operations/registry.js +21 -0
- package/dist/operations/runtime.d.ts +22 -0
- package/dist/operations/runtime.d.ts.map +1 -0
- package/dist/operations/runtime.js +161 -0
- package/dist/operations/types.d.ts +96 -0
- package/dist/operations/types.d.ts.map +1 -0
- package/dist/operations/types.js +3 -0
- package/dist/operations/useOperationsRuntime.d.ts +3 -0
- package/dist/operations/useOperationsRuntime.d.ts.map +1 -0
- package/dist/operations/useOperationsRuntime.js +31 -0
- package/package.json +2 -2
|
@@ -1,248 +1,102 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* useInteraction.
|
|
2
|
+
* useInteraction — runs an object's interactions.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* An interaction (core `Interaction`) is a trigger plus three kinds of reaction,
|
|
5
|
+
* run in this order:
|
|
6
|
+
*
|
|
7
|
+
* effects operations on their targets, through the shared operations runtime
|
|
8
|
+
* (../operations) — a triggered interaction toggles an operation that
|
|
9
|
+
* can be undone, and applies one that can't. 'self' = the object the
|
|
10
|
+
* interaction is on.
|
|
11
|
+
* animations play / pause / stop / toggle a clip or a sequence (ClipsRuntime).
|
|
12
|
+
* play starts from the beginning, or resumes if paused; toggle plays
|
|
13
|
+
* forward, then back — "back" is the opposite of a sequence's own
|
|
14
|
+
* reverse.
|
|
15
|
+
* actions apply / revert / toggle an action (SceneActions; its own effects
|
|
16
|
+
* run through the same runtime).
|
|
9
17
|
*/
|
|
10
|
-
import { useCallback, useRef } from 'react';
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
defaultDuration: 1,
|
|
32
|
-
defaultEase: "power2.out"
|
|
33
|
-
});
|
|
34
|
-
const { moveToFront, zoomToFrame, restoreOriginalTransform, restoreCamera } = useFrameAnimations(cameraSettings);
|
|
35
|
-
const { vanishObject, restoreVanishedObject, animateGlowEffect, removeGlow, isVanished, isGlowing, glowingObjects, vanishedObjects, } = useObjectEffects();
|
|
36
|
-
// ===========================================================================
|
|
37
|
-
// UTILITY: Resolve Target Objects
|
|
38
|
-
// ===========================================================================
|
|
39
|
-
const resolveTargets = useCallback((interaction, currentRef) => {
|
|
40
|
-
const { targetIds, targetMode } = interaction;
|
|
41
|
-
// If no targetIds specified, return current object only
|
|
42
|
-
if (!targetIds || targetIds.length === 0) {
|
|
43
|
-
return [currentRef];
|
|
44
|
-
}
|
|
45
|
-
const targetRefs = [];
|
|
46
|
-
// Add current object if mode is 'add'
|
|
47
|
-
if (targetMode === 'add') {
|
|
48
|
-
targetRefs.push(currentRef);
|
|
49
|
-
}
|
|
50
|
-
// Lookup targets from scene
|
|
51
|
-
targetIds.forEach(id => {
|
|
52
|
-
const obj = findById(id);
|
|
53
|
-
if (obj) {
|
|
54
|
-
targetRefs.push(obj);
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
return targetRefs.length > 0 ? targetRefs : [currentRef];
|
|
18
|
+
import { useCallback, useMemo, useRef } from 'react';
|
|
19
|
+
import { SceneActions } from '@3driseai/3drise-core';
|
|
20
|
+
import ClipsRuntime from '../animationsV2/ClipsRuntime.js';
|
|
21
|
+
import { clipMap } from '../animationsV2/sequenceUtils.js';
|
|
22
|
+
import { runEffect } from '../operations/runtime.js';
|
|
23
|
+
import { useOperationsRuntime } from '../operations/useOperationsRuntime.js';
|
|
24
|
+
export function useInteraction({ cameraSettings, sequences = [], clips = [], actionSequences = [], }) {
|
|
25
|
+
// The scene's operation tools (camera, bring-to-front…) for the shared runtime.
|
|
26
|
+
useOperationsRuntime(cameraSettings);
|
|
27
|
+
// Toggle state: animation ids whose last toggle went "forward".
|
|
28
|
+
const toggledRef = useRef(new Set());
|
|
29
|
+
const clipsById = useMemo(() => clipMap(clips), [clips]);
|
|
30
|
+
/** First trigger → forward (false), next → back (true), … per key. */
|
|
31
|
+
const nextIsBack = useCallback((key) => {
|
|
32
|
+
const toggled = toggledRef.current;
|
|
33
|
+
const back = toggled.has(key);
|
|
34
|
+
if (back)
|
|
35
|
+
toggled.delete(key);
|
|
36
|
+
else
|
|
37
|
+
toggled.add(key);
|
|
38
|
+
return back;
|
|
58
39
|
}, []);
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (!animationIds || animationIds.length === 0)
|
|
40
|
+
// ---------------------------------------------------------------- run
|
|
41
|
+
const executeInteraction = useCallback((params) => {
|
|
42
|
+
const { interaction, ref } = params;
|
|
43
|
+
if (!interaction?.enabled)
|
|
64
44
|
return;
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
45
|
+
// 1. Effects — each on its own targets.
|
|
46
|
+
for (const effect of interaction.effects ?? [])
|
|
47
|
+
runEffect(effect, 'trigger', ref);
|
|
48
|
+
// 2. Animations.
|
|
49
|
+
for (const a of interaction.animations ?? []) {
|
|
50
|
+
if (a.kind === 'clip') {
|
|
51
|
+
const clip = clipsById.get(a.ref);
|
|
52
|
+
if (!clip)
|
|
53
|
+
continue;
|
|
54
|
+
if (a.command === 'pause')
|
|
55
|
+
ClipsRuntime.pause(clip.id);
|
|
56
|
+
else if (a.command === 'stop')
|
|
57
|
+
ClipsRuntime.stop(clip.id);
|
|
58
|
+
else if (a.command === 'toggle')
|
|
59
|
+
ClipsRuntime.play(clip, { reverse: nextIsBack(`clip:${clip.id}`) });
|
|
60
|
+
else if (ClipsRuntime.isActive(clip.id) && !ClipsRuntime.isPlaying(clip.id) && ClipsRuntime.getTime(clip.id) < clip.duration)
|
|
61
|
+
ClipsRuntime.resume(clip.id);
|
|
62
|
+
else
|
|
63
|
+
ClipsRuntime.play(clip, { from: 0 });
|
|
69
64
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const isCurrentlySelected = currentAnimatedRef.current !== null;
|
|
82
|
-
const isSameObject = currentAnimatedRef.current?.uuid === ref.uuid;
|
|
83
|
-
switch (operation) {
|
|
84
|
-
case 'vanish': {
|
|
85
|
-
if (isVanished(ref.uuid)) {
|
|
86
|
-
restoreVanishedObject(ref, defaultDuration, defaultEase);
|
|
65
|
+
else {
|
|
66
|
+
const seq = sequences.find(s => s.id === a.ref);
|
|
67
|
+
if (!seq)
|
|
68
|
+
continue;
|
|
69
|
+
if (a.command === 'pause')
|
|
70
|
+
ClipsRuntime.pauseSequence(seq.id);
|
|
71
|
+
else if (a.command === 'stop')
|
|
72
|
+
ClipsRuntime.stopSequence(seq.id);
|
|
73
|
+
else if (a.command === 'toggle') {
|
|
74
|
+
const back = nextIsBack(`seq:${seq.id}`);
|
|
75
|
+
ClipsRuntime.playSequence(seq, clipsById, { reverse: back ? !seq.reverse : seq.reverse });
|
|
87
76
|
}
|
|
88
|
-
else {
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
case 'glow': {
|
|
94
|
-
if (isGlowing(ref.uuid)) {
|
|
95
|
-
removeGlow(ref);
|
|
77
|
+
else if (ClipsRuntime.isSequenceActive(seq.id) && !ClipsRuntime.isSequencePlaying(seq.id) && ClipsRuntime.getSequenceProgress(seq.id) < 1) {
|
|
78
|
+
ClipsRuntime.resumeSequence(seq.id);
|
|
96
79
|
}
|
|
97
80
|
else {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
case 'focus': {
|
|
103
|
-
animateCamera({}, defaultDuration, defaultEase, createdObject.meshSettings.position);
|
|
104
|
-
break;
|
|
105
|
-
}
|
|
106
|
-
case 'moveToFront': {
|
|
107
|
-
// Toggle: if clicking the same object, restore it
|
|
108
|
-
if (isCurrentlySelected && isSameObject) {
|
|
109
|
-
restoreOriginalTransform(currentAnimatedRef.current, {
|
|
110
|
-
duration: defaultDuration,
|
|
111
|
-
ease: defaultEase
|
|
112
|
-
});
|
|
113
|
-
currentAnimatedRef.current = null;
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
// Restore previous object if different
|
|
117
|
-
if (isCurrentlySelected && !isSameObject) {
|
|
118
|
-
restoreOriginalTransform(currentAnimatedRef.current, {
|
|
119
|
-
duration: defaultDuration,
|
|
120
|
-
ease: defaultEase
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
// Apply new animation
|
|
124
|
-
moveToFront(ref, {
|
|
125
|
-
distance: defaultDistance,
|
|
126
|
-
scale: [6, 4],
|
|
127
|
-
duration: defaultDuration,
|
|
128
|
-
ease: defaultEase
|
|
129
|
-
});
|
|
130
|
-
currentAnimatedRef.current = ref;
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
case 'zoom': {
|
|
134
|
-
// Toggle: if clicking the same object, restore camera
|
|
135
|
-
if (isCurrentlySelected && isSameObject) {
|
|
136
|
-
restoreCamera({ duration: defaultDuration, ease: defaultEase });
|
|
137
|
-
currentAnimatedRef.current = null;
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
// Restore previous camera if different object
|
|
141
|
-
if (isCurrentlySelected && !isSameObject) {
|
|
142
|
-
restoreCamera({ duration: defaultDuration, ease: defaultEase });
|
|
81
|
+
// From the start edge of its own direction.
|
|
82
|
+
const total = ClipsRuntime.getSequenceDuration(seq.id);
|
|
83
|
+
ClipsRuntime.playSequence(seq, clipsById, { from: seq.reverse && total > 0 ? total : 0 });
|
|
143
84
|
}
|
|
144
|
-
// Apply new zoom
|
|
145
|
-
zoomToFrame(ref, {
|
|
146
|
-
distance: defaultDistance,
|
|
147
|
-
duration: defaultDuration,
|
|
148
|
-
ease: defaultEase
|
|
149
|
-
});
|
|
150
|
-
currentAnimatedRef.current = ref;
|
|
151
|
-
break;
|
|
152
85
|
}
|
|
153
|
-
case 'playAnimation':
|
|
154
|
-
// Handled by triggerAnimations
|
|
155
|
-
break;
|
|
156
|
-
case 'displayImage': {
|
|
157
|
-
if (!textureUrl)
|
|
158
|
-
break;
|
|
159
|
-
let applier;
|
|
160
|
-
let meshWithMap = null;
|
|
161
|
-
ref.traverse((child) => {
|
|
162
|
-
if (!applier && typeof child.userData?.applyTexture === 'function') {
|
|
163
|
-
applier = child.userData.applyTexture;
|
|
164
|
-
}
|
|
165
|
-
else if (!meshWithMap && child.material) {
|
|
166
|
-
meshWithMap = child;
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
if (applier) {
|
|
170
|
-
applier(textureUrl);
|
|
171
|
-
}
|
|
172
|
-
else if (meshWithMap) {
|
|
173
|
-
const name = textureUrl.split('/').pop()?.split('.')[0] || `texture-${Date.now()}`;
|
|
174
|
-
try {
|
|
175
|
-
const loaded = await texturesManager.loadTexture(name, textureUrl, 'images');
|
|
176
|
-
const mat = meshWithMap.material;
|
|
177
|
-
mat.map = loaded;
|
|
178
|
-
mat.needsUpdate = true;
|
|
179
|
-
}
|
|
180
|
-
catch (err) {
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
break;
|
|
184
|
-
}
|
|
185
|
-
case 'create':
|
|
186
|
-
case 'update':
|
|
187
|
-
case 'delete':
|
|
188
|
-
case 'toggle':
|
|
189
|
-
case 'loadProject':
|
|
190
|
-
break;
|
|
191
86
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
restoreCamera,
|
|
204
|
-
]);
|
|
205
|
-
// ===========================================================================
|
|
206
|
-
// UTILITY: Execute Multiple Operations
|
|
207
|
-
// ===========================================================================
|
|
208
|
-
const executeOperations = useCallback((operations, ref, createdObject, textureUrl) => {
|
|
209
|
-
if (!operations || operations.length === 0)
|
|
210
|
-
return;
|
|
211
|
-
operations.forEach(operation => {
|
|
212
|
-
executeOperation(operation, ref, createdObject, textureUrl);
|
|
213
|
-
});
|
|
214
|
-
}, [executeOperation]);
|
|
215
|
-
// ===========================================================================
|
|
216
|
-
// MAIN: Execute Interaction
|
|
217
|
-
// ===========================================================================
|
|
218
|
-
const executeInteraction = useCallback((params) => {
|
|
219
|
-
const { interaction, ref, createdObject } = params;
|
|
220
|
-
if (!interaction.enabled)
|
|
221
|
-
return;
|
|
222
|
-
let textureUrl = undefined;
|
|
223
|
-
if (interaction.operations?.includes('displayImage')) {
|
|
224
|
-
textureUrl = ref.userData?.url;
|
|
87
|
+
// 3. Actions.
|
|
88
|
+
for (const a of interaction.actions ?? []) {
|
|
89
|
+
const action = actionSequences.find(x => x.id === a.ref);
|
|
90
|
+
if (!action)
|
|
91
|
+
continue;
|
|
92
|
+
if (a.command === 'revert')
|
|
93
|
+
SceneActions.revertAction(action);
|
|
94
|
+
else if (a.command === 'toggle')
|
|
95
|
+
SceneActions.toggleAction(action);
|
|
96
|
+
else
|
|
97
|
+
SceneActions.applyAction(action);
|
|
225
98
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
// 2. Execute operations on each target
|
|
229
|
-
targets.forEach(targetRef => {
|
|
230
|
-
// Find the createdObject for this target (if different from original)
|
|
231
|
-
// For now, use the original createdObject for position data
|
|
232
|
-
executeOperations(interaction.operations, targetRef, createdObject, textureUrl);
|
|
233
|
-
});
|
|
234
|
-
// 3. Trigger animations
|
|
235
|
-
triggerAnimations(interaction.animationIds);
|
|
236
|
-
}, [resolveTargets, executeOperations, triggerAnimations]);
|
|
237
|
-
// ===========================================================================
|
|
238
|
-
// RETURN
|
|
239
|
-
// ===========================================================================
|
|
240
|
-
return {
|
|
241
|
-
executeInteraction,
|
|
242
|
-
// Expose refs for context to share
|
|
243
|
-
currentAnimatedRef,
|
|
244
|
-
glowingObjects,
|
|
245
|
-
vanishedObjects,
|
|
246
|
-
};
|
|
99
|
+
}, [clipsById, sequences, actionSequences, nextIsBack]);
|
|
100
|
+
return { executeInteraction };
|
|
247
101
|
}
|
|
248
102
|
export default useInteraction;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLightConfig.d.ts","sourceRoot":"","sources":["../../src/hooks/useLightConfig.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"useLightConfig.d.ts","sourceRoot":"","sources":["../../src/hooks/useLightConfig.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzD,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE7C,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAU/E;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CA6B7E;AAED,MAAM,WAAW,oBAAoB;IACjC,kFAAkF;IAClF,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;IAC9C,gEAAgE;IAChE,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;CACrE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC1B,OAAO,EAAE,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC,EACnC,QAAQ,EAAE,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC,EACjC,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,UAAU,EAAE,gBAAgB,EAAE,GAAG,SAAS,EAC1C,SAAS,CAAC,EAAE,eAAe,GAC5B,oBAAoB,CAiEtB;AAED,eAAe,cAAc,CAAC"}
|
|
@@ -26,6 +26,7 @@ import { DEFAULT_LIGHTS, getGenerativeAnimatable } from '@3driseai/3drise-core';
|
|
|
26
26
|
import { useFrame } from '@react-three/fiber';
|
|
27
27
|
import { applyConfigKeyframeAnimations, applyConfigMouseMove } from '../utils/configAnimations.js';
|
|
28
28
|
import { useLightLive } from './useLightLive.js';
|
|
29
|
+
import { useLightTargets } from './useLightTargets.js';
|
|
29
30
|
import { kelvinToColor } from '../components/lightBulb/kelvin.js';
|
|
30
31
|
const tmpColor = new Color();
|
|
31
32
|
/**
|
|
@@ -84,6 +85,12 @@ export function useLightConfig(rootRef, lightRef, id, config, animations, mouseM
|
|
|
84
85
|
return merged;
|
|
85
86
|
}, [config]);
|
|
86
87
|
const live = useLightLive(rootRef, lightRef, id, base);
|
|
88
|
+
// Objects this light drives (a shade, a diffuser, a cover). Its own useFrame,
|
|
89
|
+
// so it is unaffected by the early-out below, and it reads the light one
|
|
90
|
+
// frame behind the component that sets it — invisible, and cheaper than
|
|
91
|
+
// fighting R3F's frame ordering, where a non-zero priority would take the
|
|
92
|
+
// render loop over.
|
|
93
|
+
useLightTargets(lightRef, base.targetIds, base.targetMeshes, base.intensity ?? 1);
|
|
87
94
|
const merged = useRef(base);
|
|
88
95
|
const animOverride = useRef({});
|
|
89
96
|
const animFrom = useRef({});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLightLive.d.ts","sourceRoot":"","sources":["../../src/hooks/useLightLive.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGvD,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,
|
|
1
|
+
{"version":3,"file":"useLightLive.d.ts","sourceRoot":"","sources":["../../src/hooks/useLightLive.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAE7C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAGvD,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EAe7C,CAAC;AAKF,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAyB1H;AAED;;;GAGG;AACH,wBAAgB,YAAY,CACxB,OAAO,EAAE,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC,EACnC,QAAQ,EAAE,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC,EACjC,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC5B,gBAAgB,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC,CAMnD;AAED,eAAe,YAAY,CAAC"}
|
|
@@ -2,6 +2,8 @@ import { useConfigLiveHandle } from './useConfigLive.js';
|
|
|
2
2
|
import { kelvinToColor } from '../components/lightBulb/kelvin.js';
|
|
3
3
|
export const LIGHT_STRUCTURAL = [
|
|
4
4
|
'shape', 'glass', 'glassTint', 'colorMode', 'on', 'targetPosition',
|
|
5
|
+
// Which objects the light drives: a selection, never a drag.
|
|
6
|
+
'targetIds', 'targetMeshes',
|
|
5
7
|
// spotBeam: the gobo is redrawn and the beam/emitter geometry is rebuilt.
|
|
6
8
|
'pattern', 'patternSoftness', 'patternRotation', 'beamMode', 'emitter',
|
|
7
9
|
// ledArray: the die layout is rebuilt. fluorescentTube: the tube geometry is.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Light } from 'three';
|
|
2
|
+
import type { RefObject } from 'react';
|
|
3
|
+
export declare function useLightTargets(lightRef: RefObject<Light | null>, targetIds: string[] | undefined, targetMeshes: Record<string, string[]> | undefined,
|
|
4
|
+
/** The light's committed intensity — what "full output" means for it. */
|
|
5
|
+
baseIntensity: number): void;
|
|
6
|
+
export default useLightTargets;
|
|
7
|
+
//# sourceMappingURL=useLightTargets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useLightTargets.d.ts","sourceRoot":"","sources":["../../src/hooks/useLightTargets.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAS,KAAK,EAA4B,MAAM,OAAO,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAmBvC,wBAAgB,eAAe,CAC3B,QAAQ,EAAE,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC,EACjC,SAAS,EAAE,MAAM,EAAE,GAAG,SAAS,EAC/B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS;AAClD,yEAAyE;AACzE,aAAa,EAAE,MAAM,GACtB,IAAI,CA0FN;AAED,eAAe,eAAe,CAAC"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// useLightTargets — a light pushes its live state onto objects it does not own
|
|
3
|
+
// =============================================================================
|
|
4
|
+
//
|
|
5
|
+
// `config.targetIds` names scene objects ('mesh' / 'model') that a light drives:
|
|
6
|
+
// a lampshade round a bulb, a diffuser over an LED panel, a glass cover. The
|
|
7
|
+
// light never moves or owns them — it only writes their emissive, so they glow
|
|
8
|
+
// with it. Because the value read is the light's LIVE intensity rather than its
|
|
9
|
+
// config, everything the light does comes along for nothing: the bulb's tungsten
|
|
10
|
+
// warm-up, the candle's flicker, the fluorescent's starter stutter, keyframes,
|
|
11
|
+
// pointer bindings.
|
|
12
|
+
//
|
|
13
|
+
// Three decisions worth knowing:
|
|
14
|
+
//
|
|
15
|
+
// - The driven object's own `emissiveIntensity` is the strength. There is no
|
|
16
|
+
// new knob: every mesh already has that control, per object, in the material
|
|
17
|
+
// panel.
|
|
18
|
+
//
|
|
19
|
+
// - Lights ACCUMULATE. The first light to touch a material in a frame clears
|
|
20
|
+
// it, every light after adds. Two bulbs in one pendant sum correctly, and
|
|
21
|
+
// there is no question of which one wins.
|
|
22
|
+
//
|
|
23
|
+
// - Each driven mesh gets a CLONE of its material. The 3drise material system
|
|
24
|
+
// hands out shared instances from MaterialLibrary, so writing emissive on
|
|
25
|
+
// the original would light every other mesh using that material too. The
|
|
26
|
+
// clone is re-made whenever the material system swaps the source out, so
|
|
27
|
+
// editing a material still reaches a driven object (one frame later).
|
|
28
|
+
//
|
|
29
|
+
// Resolution is a runtime lookup inside useFrame — the use `findById` is for —
|
|
30
|
+
// never at render time. See the object-resolution rule.
|
|
31
|
+
//
|
|
32
|
+
import { useEffect, useRef } from 'react';
|
|
33
|
+
import { useFrame } from '@react-three/fiber';
|
|
34
|
+
import { findById } from '../utils/sceneQuery.js';
|
|
35
|
+
const hasEmissive = (m) => !!m && 'emissive' in m && !!m.emissive;
|
|
36
|
+
/** A light contributing more than a few times its own configured output is a
|
|
37
|
+
* keyframe overshooting, not a design intent — clamp so a shade cannot blow out. */
|
|
38
|
+
const MAX_OUTPUT = 4;
|
|
39
|
+
export function useLightTargets(lightRef, targetIds, targetMeshes,
|
|
40
|
+
/** The light's committed intensity — what "full output" means for it. */
|
|
41
|
+
baseIntensity) {
|
|
42
|
+
const driven = useRef([]);
|
|
43
|
+
const key = useRef('');
|
|
44
|
+
/** Hand every material back and drop our clones. */
|
|
45
|
+
const release = () => {
|
|
46
|
+
for (const d of driven.current) {
|
|
47
|
+
if (d.mesh.material === d.clone)
|
|
48
|
+
d.mesh.material = d.source;
|
|
49
|
+
d.clone.dispose();
|
|
50
|
+
}
|
|
51
|
+
driven.current = [];
|
|
52
|
+
};
|
|
53
|
+
useEffect(() => release, []);
|
|
54
|
+
useFrame((state) => {
|
|
55
|
+
const light = lightRef.current;
|
|
56
|
+
const ids = targetIds ?? [];
|
|
57
|
+
// --- resolve, and only when the selection actually changed -----------
|
|
58
|
+
const wanted = ids.join(',') + '|' + JSON.stringify(targetMeshes ?? {});
|
|
59
|
+
const stale = driven.current.some((d) => !d.mesh.parent);
|
|
60
|
+
if (wanted !== key.current || stale) {
|
|
61
|
+
release();
|
|
62
|
+
key.current = wanted;
|
|
63
|
+
for (const id of ids) {
|
|
64
|
+
const root = findById(id);
|
|
65
|
+
if (!root) {
|
|
66
|
+
// Not mounted yet, or deleted. Re-resolved next frame because
|
|
67
|
+
// the key is only committed once everything is found.
|
|
68
|
+
key.current = '';
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const names = targetMeshes?.[id];
|
|
72
|
+
root.traverse((o) => {
|
|
73
|
+
const mesh = o;
|
|
74
|
+
if (!mesh.isMesh)
|
|
75
|
+
return;
|
|
76
|
+
// A model target can be narrowed to named meshes inside it;
|
|
77
|
+
// no list means the whole model.
|
|
78
|
+
if (names && names.length && !names.includes(mesh.name))
|
|
79
|
+
return;
|
|
80
|
+
const source = mesh.material;
|
|
81
|
+
if (Array.isArray(mesh.material) || !hasEmissive(source))
|
|
82
|
+
return;
|
|
83
|
+
const clone = source.clone();
|
|
84
|
+
clone.userData = { ...clone.userData, __litClone: true };
|
|
85
|
+
mesh.material = clone;
|
|
86
|
+
driven.current.push({ mesh, source, clone });
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if (!driven.current.length)
|
|
91
|
+
return;
|
|
92
|
+
// --- the material system may have swapped a source out from under us --
|
|
93
|
+
for (const d of driven.current) {
|
|
94
|
+
if (d.mesh.material !== d.clone && !d.mesh.material?.userData?.__litClone) {
|
|
95
|
+
const next = d.mesh.material;
|
|
96
|
+
if (hasEmissive(next)) {
|
|
97
|
+
d.clone.dispose();
|
|
98
|
+
d.source = next;
|
|
99
|
+
d.clone = next.clone();
|
|
100
|
+
d.clone.userData = { ...d.clone.userData, __litClone: true };
|
|
101
|
+
d.mesh.material = d.clone;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// --- accumulate -------------------------------------------------------
|
|
106
|
+
// One key per frame: whoever gets there first clears, the rest add. If a
|
|
107
|
+
// renderer ever hands two lights different clock values in one frame the
|
|
108
|
+
// worst case is last-writer-wins, which is where this started.
|
|
109
|
+
const frame = state.clock.elapsedTime;
|
|
110
|
+
const output = light
|
|
111
|
+
? Math.min(Math.max(light.intensity / Math.max(baseIntensity, 1e-6), 0), MAX_OUTPUT)
|
|
112
|
+
: 0;
|
|
113
|
+
for (const d of driven.current) {
|
|
114
|
+
const m = d.clone;
|
|
115
|
+
if (!m.emissive)
|
|
116
|
+
continue;
|
|
117
|
+
if (m.userData.__litFrame !== frame) {
|
|
118
|
+
m.userData.__litFrame = frame;
|
|
119
|
+
m.emissive.setRGB(0, 0, 0);
|
|
120
|
+
// The object's own value is the strength; the colour is what the
|
|
121
|
+
// lights sum into.
|
|
122
|
+
m.emissiveIntensity = d.source.emissiveIntensity ?? 1;
|
|
123
|
+
}
|
|
124
|
+
if (light && output > 0) {
|
|
125
|
+
m.emissive.r += light.color.r * output;
|
|
126
|
+
m.emissive.g += light.color.g * output;
|
|
127
|
+
m.emissive.b += light.color.b * output;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
export default useLightTargets;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useObjectAnimation.d.ts","sourceRoot":"","sources":["../../src/hooks/useObjectAnimation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAEnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEzE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"useObjectAnimation.d.ts","sourceRoot":"","sources":["../../src/hooks/useObjectAnimation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAEnE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEzE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE/D,UAAU,yBAAyB;IAC/B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,UAAU,wBAAyB,SAAQ,0BAA0B,EAAE,2BAA2B;CACjG;AAGD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB,GAAI,gBAAgB,qBAAqB,GAAG,IAAI,EAAE,iBAAiB,OAAO,EAAE,UAAS,yBAA8B,EAAE,SAAS,cAAc,KAAG,wBAAwB,GAAG,IAcxM,CAAC"}
|
|
@@ -3,7 +3,6 @@ import { useFrame } from '@react-three/fiber';
|
|
|
3
3
|
import { findById } from '@3driseai/3drise-core';
|
|
4
4
|
import { useContinuousEffects } from "./useContinuousEffects.js";
|
|
5
5
|
import { useMouseMove } from "./useInteractionEffects.js";
|
|
6
|
-
import { useSequenceAnimation } from "./useSequenceAnimation.js";
|
|
7
6
|
/**
|
|
8
7
|
* Drive every continuous animation for one scene object.
|
|
9
8
|
*
|
|
@@ -28,6 +27,5 @@ export const useObjectAnimation = (objectSettings, animateMaterial, options = {}
|
|
|
28
27
|
const source = object ?? fallbackRef;
|
|
29
28
|
const continuousResult = useContinuousEffects(objectSettings, { enabled, animateMaterial, hovered }, source);
|
|
30
29
|
const mouseMoveResult = useMouseMove(objectSettings, { enabled, animateMaterial }, source);
|
|
31
|
-
useSequenceAnimation(objectSettings?.id, source);
|
|
32
30
|
return { ...continuousResult, ...mouseMoveResult };
|
|
33
31
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useOceanMaterial.d.ts","sourceRoot":"","sources":["../../src/hooks/useOceanMaterial.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"useOceanMaterial.d.ts","sourceRoot":"","sources":["../../src/hooks/useOceanMaterial.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGvE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAI7E,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAE7E;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,uBAAuB;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,kBAAkB,CAAC;IAC5B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;gFAE4E;IAC5E,OAAO,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;CACtF;AAED,MAAM,WAAW,mBAAmB;IAChC,QAAQ,EAAE,oBAAoB,CAAC;IAC/B;0DACsD;IACtD,OAAO,EAAE,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;CAChD;AAED,wBAAgB,gBAAgB,CAAC,EAC7B,EAAE,EACF,MAAM,EACN,OAAO,EACP,WAAW,EACX,YAAY,EACZ,YAAgB,EAChB,OAAO,GACV,EAAE,uBAAuB,GAAG,mBAAmB,CAkE/C;AAED,eAAe,gBAAgB,CAAC"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef } from 'react';
|
|
2
2
|
import { useFrame } from '@react-three/fiber';
|
|
3
3
|
import { useCloudSun } from './useCloudSun.js';
|
|
4
|
-
import { useLiveTransitionEvents } from './useLiveTransitionEvents.js';
|
|
5
4
|
import { OCEAN_LIVE_KEY } from './useOceanLive.js';
|
|
6
5
|
import { OceanSurfaceMaterial } from '../shaders/ocean/OceanSurfaceMaterial.js';
|
|
7
6
|
import { applySunUniforms } from '../utils/cloudUniforms.js';
|
|
@@ -36,10 +35,6 @@ export function useOceanMaterial({ id, config, quality, skySettings, timeSetting
|
|
|
36
35
|
root.userData[OCEAN_LIVE_KEY] = liveHandle;
|
|
37
36
|
return () => { delete root.userData[OCEAN_LIVE_KEY]; };
|
|
38
37
|
}, [id, liveHandle]);
|
|
39
|
-
// Sequence-authored transitions (`transition.state === 'ocean'`) — shared by
|
|
40
|
-
// both hosts (OceanSurface, WaterBody), the same way the material and the
|
|
41
|
-
// live handle already are.
|
|
42
|
-
useLiveTransitionEvents('ocean', liveConfig, config, rootRef);
|
|
43
38
|
useFrame((state) => {
|
|
44
39
|
const shader = material;
|
|
45
40
|
updateSun();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An element's settings with any applied action patches laid over them.
|
|
3
|
+
*
|
|
4
|
+
* `state` is the element's action address: its object id, or 'camera' | 'sky' |
|
|
5
|
+
* 'ocean' | 'clouds' | 'terrain'. Subscribes to that one element only, so applying an action
|
|
6
|
+
* re-renders the elements it touches and nothing else. With no patch applied this
|
|
7
|
+
* returns `base` itself — no copy, no identity change.
|
|
8
|
+
*
|
|
9
|
+
* Call it where authored settings enter the renderer (ObjectNode, CameraController,
|
|
10
|
+
* EnvironmentManager, the editor's environment connectors), never deeper: everything
|
|
11
|
+
* downstream should see one consistent, patched settings object.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useRuntimeSettings<T>(state: string | undefined | null, base: T): T;
|
|
14
|
+
export default useRuntimeSettings;
|
|
15
|
+
//# sourceMappingURL=useRuntimeSettings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRuntimeSettings.d.ts","sourceRoot":"","sources":["../../src/hooks/useRuntimeSettings.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,CAQlF;AAED,eAAe,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { useCallback, useMemo, useSyncExternalStore } from 'react';
|
|
2
|
+
import { SceneActions, applySettingsPatch } from '@3driseai/3drise-core';
|
|
3
|
+
const noopUnsubscribe = () => { };
|
|
4
|
+
/**
|
|
5
|
+
* An element's settings with any applied action patches laid over them.
|
|
6
|
+
*
|
|
7
|
+
* `state` is the element's action address: its object id, or 'camera' | 'sky' |
|
|
8
|
+
* 'ocean' | 'clouds' | 'terrain'. Subscribes to that one element only, so applying an action
|
|
9
|
+
* re-renders the elements it touches and nothing else. With no patch applied this
|
|
10
|
+
* returns `base` itself — no copy, no identity change.
|
|
11
|
+
*
|
|
12
|
+
* Call it where authored settings enter the renderer (ObjectNode, CameraController,
|
|
13
|
+
* EnvironmentManager, the editor's environment connectors), never deeper: everything
|
|
14
|
+
* downstream should see one consistent, patched settings object.
|
|
15
|
+
*/
|
|
16
|
+
export function useRuntimeSettings(state, base) {
|
|
17
|
+
const subscribe = useCallback((listener) => (state ? SceneActions.subscribe(state, listener) : noopUnsubscribe), [state]);
|
|
18
|
+
const getSnapshot = useCallback(() => SceneActions.getPatch(state), [state]);
|
|
19
|
+
const patch = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
20
|
+
return useMemo(() => (patch && base ? applySettingsPatch(base, patch) : base), [base, patch]);
|
|
21
|
+
}
|
|
22
|
+
export default useRuntimeSettings;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSequenceAnimation.d.ts","sourceRoot":"","sources":["../../src/hooks/useSequenceAnimation.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"useSequenceAnimation.d.ts","sourceRoot":"","sources":["../../src/hooks/useSequenceAnimation.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAgC/D;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAAI,UAAU,MAAM,GAAG,SAAS,EAAE,eAAe,cAAc,KAAG,IAoKlG,CAAC;AACF,eAAe,oBAAoB,CAAC"}
|