@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.
Files changed (133) hide show
  1. package/dist/animationsV2/ClipPlayer.d.ts +13 -0
  2. package/dist/animationsV2/ClipPlayer.d.ts.map +1 -0
  3. package/dist/animationsV2/ClipPlayer.js +140 -0
  4. package/dist/animationsV2/ClipsRuntime.d.ts +111 -0
  5. package/dist/animationsV2/ClipsRuntime.d.ts.map +1 -0
  6. package/dist/animationsV2/ClipsRuntime.js +476 -0
  7. package/dist/animationsV2/appliers.d.ts +16 -0
  8. package/dist/animationsV2/appliers.d.ts.map +1 -0
  9. package/dist/animationsV2/appliers.js +204 -0
  10. package/dist/animationsV2/clipUtils.d.ts +33 -0
  11. package/dist/animationsV2/clipUtils.d.ts.map +1 -0
  12. package/dist/animationsV2/clipUtils.js +164 -0
  13. package/dist/animationsV2/elementSettings.d.ts +15 -0
  14. package/dist/animationsV2/elementSettings.d.ts.map +1 -0
  15. package/dist/animationsV2/elementSettings.js +16 -0
  16. package/dist/animationsV2/index.d.ts +16 -0
  17. package/dist/animationsV2/index.d.ts.map +1 -0
  18. package/dist/animationsV2/index.js +12 -0
  19. package/dist/animationsV2/nodeTracks.d.ts +13 -0
  20. package/dist/animationsV2/nodeTracks.d.ts.map +1 -0
  21. package/dist/animationsV2/nodeTracks.js +165 -0
  22. package/dist/animationsV2/normalize.d.ts +4 -0
  23. package/dist/animationsV2/normalize.d.ts.map +1 -0
  24. package/dist/animationsV2/normalize.js +49 -0
  25. package/dist/animationsV2/sequenceUtils.d.ts +57 -0
  26. package/dist/animationsV2/sequenceUtils.d.ts.map +1 -0
  27. package/dist/animationsV2/sequenceUtils.js +120 -0
  28. package/dist/animationsV2/types.d.ts +95 -0
  29. package/dist/animationsV2/types.d.ts.map +1 -0
  30. package/dist/animationsV2/types.js +8 -0
  31. package/dist/api/sceneHandle.d.ts +102 -0
  32. package/dist/api/sceneHandle.d.ts.map +1 -0
  33. package/dist/api/sceneHandle.js +237 -0
  34. package/dist/components/CameraController.d.ts.map +1 -1
  35. package/dist/components/CameraController.js +3 -44
  36. package/dist/components/Clouds.d.ts.map +1 -1
  37. package/dist/components/Clouds.js +0 -34
  38. package/dist/components/CreatedObject.d.ts.map +1 -1
  39. package/dist/components/CreatedObject.js +19 -1
  40. package/dist/components/EnvironmentManager.d.ts.map +1 -1
  41. package/dist/components/EnvironmentManager.js +6 -4
  42. package/dist/components/ObjectNode.d.ts.map +1 -1
  43. package/dist/components/ObjectNode.js +5 -1
  44. package/dist/components/ObjectsRenderer.d.ts +5 -1
  45. package/dist/components/ObjectsRenderer.d.ts.map +1 -1
  46. package/dist/components/ObjectsRenderer.js +24 -3
  47. package/dist/components/Ocean.d.ts.map +1 -1
  48. package/dist/components/Ocean.js +0 -63
  49. package/dist/components/ProjectLoader.d.ts +9 -3
  50. package/dist/components/ProjectLoader.d.ts.map +1 -1
  51. package/dist/components/ProjectLoader.js +5 -4
  52. package/dist/components/SceneBuilder.d.ts +9 -1
  53. package/dist/components/SceneBuilder.d.ts.map +1 -1
  54. package/dist/components/SceneBuilder.js +30 -5
  55. package/dist/components/SkyController.d.ts.map +1 -1
  56. package/dist/components/SkyController.js +0 -39
  57. package/dist/components/Stars.d.ts.map +1 -1
  58. package/dist/components/Stars.js +3 -46
  59. package/dist/components/terrain/TerrainSurface.d.ts.map +1 -1
  60. package/dist/components/terrain/TerrainSurface.js +0 -5
  61. package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts.map +1 -1
  62. package/dist/components/volumetricClouds/VolumetricCloudsPass.js +0 -6
  63. package/dist/hooks/index.d.ts +2 -2
  64. package/dist/hooks/index.d.ts.map +1 -1
  65. package/dist/hooks/index.js +2 -2
  66. package/dist/hooks/useInteraction.d.ts +7 -7
  67. package/dist/hooks/useInteraction.d.ts.map +1 -1
  68. package/dist/hooks/useInteraction.js +87 -233
  69. package/dist/hooks/useLightConfig.d.ts.map +1 -1
  70. package/dist/hooks/useLightConfig.js +7 -0
  71. package/dist/hooks/useLightLive.d.ts.map +1 -1
  72. package/dist/hooks/useLightLive.js +2 -0
  73. package/dist/hooks/useLightTargets.d.ts +7 -0
  74. package/dist/hooks/useLightTargets.d.ts.map +1 -0
  75. package/dist/hooks/useLightTargets.js +132 -0
  76. package/dist/hooks/useObjectAnimation.d.ts.map +1 -1
  77. package/dist/hooks/useObjectAnimation.js +0 -2
  78. package/dist/hooks/useOceanMaterial.d.ts.map +1 -1
  79. package/dist/hooks/useOceanMaterial.js +0 -5
  80. package/dist/hooks/useRuntimeSettings.d.ts +15 -0
  81. package/dist/hooks/useRuntimeSettings.d.ts.map +1 -0
  82. package/dist/hooks/useRuntimeSettings.js +22 -0
  83. package/dist/hooks/useSequenceAnimation.d.ts.map +1 -1
  84. package/dist/hooks/useSequenceAnimation.js +27 -9
  85. package/dist/index.d.ts +6 -1
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +5 -0
  88. package/dist/interactions/index.d.ts +3 -0
  89. package/dist/interactions/index.d.ts.map +1 -0
  90. package/dist/interactions/index.js +1 -0
  91. package/dist/interactions/runner.d.ts +9 -0
  92. package/dist/interactions/runner.d.ts.map +1 -0
  93. package/dist/interactions/runner.js +23 -0
  94. package/dist/operations/catalogue/displayImage.d.ts +3 -0
  95. package/dist/operations/catalogue/displayImage.d.ts.map +1 -0
  96. package/dist/operations/catalogue/displayImage.js +39 -0
  97. package/dist/operations/catalogue/fade.d.ts +3 -0
  98. package/dist/operations/catalogue/fade.d.ts.map +1 -0
  99. package/dist/operations/catalogue/fade.js +44 -0
  100. package/dist/operations/catalogue/focus.d.ts +3 -0
  101. package/dist/operations/catalogue/focus.d.ts.map +1 -0
  102. package/dist/operations/catalogue/focus.js +22 -0
  103. package/dist/operations/catalogue/glow.d.ts +3 -0
  104. package/dist/operations/catalogue/glow.d.ts.map +1 -0
  105. package/dist/operations/catalogue/glow.js +49 -0
  106. package/dist/operations/catalogue/materialFx.d.ts +6 -0
  107. package/dist/operations/catalogue/materialFx.d.ts.map +1 -0
  108. package/dist/operations/catalogue/materialFx.js +13 -0
  109. package/dist/operations/catalogue/moveToFront.d.ts +3 -0
  110. package/dist/operations/catalogue/moveToFront.d.ts.map +1 -0
  111. package/dist/operations/catalogue/moveToFront.js +25 -0
  112. package/dist/operations/catalogue/visibility.d.ts +3 -0
  113. package/dist/operations/catalogue/visibility.d.ts.map +1 -0
  114. package/dist/operations/catalogue/visibility.js +24 -0
  115. package/dist/operations/catalogue/zoom.d.ts +3 -0
  116. package/dist/operations/catalogue/zoom.d.ts.map +1 -0
  117. package/dist/operations/catalogue/zoom.js +32 -0
  118. package/dist/operations/index.d.ts +5 -0
  119. package/dist/operations/index.d.ts.map +1 -0
  120. package/dist/operations/index.js +4 -0
  121. package/dist/operations/registry.d.ts +11 -0
  122. package/dist/operations/registry.d.ts.map +1 -0
  123. package/dist/operations/registry.js +21 -0
  124. package/dist/operations/runtime.d.ts +22 -0
  125. package/dist/operations/runtime.d.ts.map +1 -0
  126. package/dist/operations/runtime.js +161 -0
  127. package/dist/operations/types.d.ts +96 -0
  128. package/dist/operations/types.d.ts.map +1 -0
  129. package/dist/operations/types.js +3 -0
  130. package/dist/operations/useOperationsRuntime.d.ts +3 -0
  131. package/dist/operations/useOperationsRuntime.d.ts.map +1 -0
  132. package/dist/operations/useOperationsRuntime.js +31 -0
  133. package/package.json +2 -2
@@ -1,248 +1,102 @@
1
1
  /**
2
- * useInteraction.ts
2
+ * useInteraction — runs an object's interactions.
3
3
  *
4
- * Hook for handling Interactions on scene objects.
5
- * Provides executeInteraction function and utility functions for:
6
- * - Resolving target objects
7
- * - Executing operations
8
- * - Triggering animations
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 { AnimationsManager, texturesManager } from '@3driseai/3drise-core';
12
- import useCameraAnimation from '../hooks/useCameraAnimation.js';
13
- import { useFrameAnimations } from '../hooks/useFrameAnimations.js';
14
- import { useObjectEffects } from '../hooks/useObjectEffects.js';
15
- import { findById } from '../utils/sceneQuery.js';
16
- // =============================================================================
17
- // TYPES
18
- // =============================================================================
19
- // =============================================================================
20
- // HOOK
21
- // =============================================================================
22
- export function useInteraction({
23
- // mode = 'default',
24
- cameraSettings, sequences, }) {
25
- // Redux state
26
- // Track currently animated object for toggle behavior
27
- const currentAnimatedRef = useRef(null);
28
- // Hooks
29
- const { animateCamera } = useCameraAnimation({
30
- autoAnimate: false,
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
- // UTILITY: Trigger Animations
61
- // ===========================================================================
62
- const triggerAnimations = useCallback((animationIds) => {
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
- animationIds.forEach(animationId => {
66
- const sequence = sequences.find(s => s.id === animationId);
67
- if (sequence) {
68
- AnimationsManager.playSequence(sequence);
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
- }, [sequences]);
72
- // ===========================================================================
73
- // UTILITY: Execute Single Operation
74
- // ===========================================================================
75
- const executeOperation = useCallback(async (operation, ref, createdObject, textureUrl) => {
76
- if (!operation || operation === 'none')
77
- return;
78
- const defaultDuration = 1.0;
79
- const defaultEase = "power2.out";
80
- const defaultDistance = 2.0;
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
- vanishObject(ref, defaultDuration, defaultEase);
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
- animateGlowEffect(ref);
99
- }
100
- break;
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
- isVanished,
194
- isGlowing,
195
- vanishObject,
196
- restoreVanishedObject,
197
- animateGlowEffect,
198
- removeGlow,
199
- animateCamera,
200
- moveToFront,
201
- zoomToFrame,
202
- restoreOriginalTransform,
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
- // 1. Resolve target objects
227
- const targets = resolveTargets(interaction, ref);
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;AAS/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,CA2DtB;AAED,eAAe,cAAc,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,EAa7C,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"}
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;AAE3E,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,IAexM,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;AAIvE,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,CAuE/C;AAED,eAAe,gBAAgB,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;AAqB/D;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAAI,UAAU,MAAM,GAAG,SAAS,EAAE,eAAe,cAAc,KAAG,IA6JlG,CAAC;AACF,eAAe,oBAAoB,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"}