@3driseai/3drise-viewer 0.1.24 → 0.1.25

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 (42) hide show
  1. package/dist/api/sceneHandle.d.ts +63 -0
  2. package/dist/api/sceneHandle.d.ts.map +1 -0
  3. package/dist/api/sceneHandle.js +160 -0
  4. package/dist/components/CameraController.d.ts.map +1 -1
  5. package/dist/components/CameraController.js +4 -1
  6. package/dist/components/EnvironmentManager.d.ts.map +1 -1
  7. package/dist/components/EnvironmentManager.js +5 -3
  8. package/dist/components/ObjectNode.d.ts.map +1 -1
  9. package/dist/components/ObjectNode.js +5 -1
  10. package/dist/components/ObjectsRenderer.d.ts +2 -1
  11. package/dist/components/ObjectsRenderer.d.ts.map +1 -1
  12. package/dist/components/ObjectsRenderer.js +2 -1
  13. package/dist/components/ProjectLoader.d.ts +9 -3
  14. package/dist/components/ProjectLoader.d.ts.map +1 -1
  15. package/dist/components/ProjectLoader.js +5 -4
  16. package/dist/components/SceneBuilder.d.ts +9 -1
  17. package/dist/components/SceneBuilder.d.ts.map +1 -1
  18. package/dist/components/SceneBuilder.js +14 -4
  19. package/dist/components/Stars.d.ts.map +1 -1
  20. package/dist/components/Stars.js +2 -1
  21. package/dist/hooks/index.d.ts +2 -0
  22. package/dist/hooks/index.d.ts.map +1 -1
  23. package/dist/hooks/index.js +2 -0
  24. package/dist/hooks/useInteraction.d.ts +3 -2
  25. package/dist/hooks/useInteraction.d.ts.map +1 -1
  26. package/dist/hooks/useInteraction.js +43 -8
  27. package/dist/hooks/useLightConfig.d.ts.map +1 -1
  28. package/dist/hooks/useLightConfig.js +7 -0
  29. package/dist/hooks/useLightLive.d.ts.map +1 -1
  30. package/dist/hooks/useLightLive.js +2 -0
  31. package/dist/hooks/useLightTargets.d.ts +7 -0
  32. package/dist/hooks/useLightTargets.d.ts.map +1 -0
  33. package/dist/hooks/useLightTargets.js +132 -0
  34. package/dist/hooks/useRuntimeSettings.d.ts +15 -0
  35. package/dist/hooks/useRuntimeSettings.d.ts.map +1 -0
  36. package/dist/hooks/useRuntimeSettings.js +22 -0
  37. package/dist/hooks/useSequenceAnimation.d.ts.map +1 -1
  38. package/dist/hooks/useSequenceAnimation.js +27 -9
  39. package/dist/index.d.ts +2 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +2 -0
  42. package/package.json +2 -2
@@ -0,0 +1,63 @@
1
+ import type { ActionSequence, AnimationSequence } from '@3driseai/3drise-core';
2
+ export interface SceneActionInfo {
3
+ id: string;
4
+ key?: string;
5
+ name: string;
6
+ description?: string;
7
+ applied: boolean;
8
+ }
9
+ export interface SceneAnimationInfo {
10
+ id: string;
11
+ name: string;
12
+ description?: string;
13
+ /** Seconds, one forward pass: Σ(delay + duration) over steps */
14
+ duration: number;
15
+ loop: boolean;
16
+ yoyo: boolean;
17
+ playing: boolean;
18
+ }
19
+ export interface ScenePlayOptions {
20
+ speed?: number;
21
+ reverse?: boolean;
22
+ }
23
+ export type SceneHandleEventType = 'actionApplied' | 'actionReverted' | 'animationStart' | 'animationEnd';
24
+ export interface SceneHandleEvent {
25
+ type: SceneHandleEventType;
26
+ id: string;
27
+ key?: string;
28
+ name: string;
29
+ }
30
+ export interface SceneHandle {
31
+ actions: {
32
+ list(): SceneActionInfo[];
33
+ apply(ref: string): boolean;
34
+ revert(ref: string): boolean;
35
+ /** Returns true when it applied, false when it reverted (or the action was not found). */
36
+ toggle(ref: string): boolean;
37
+ isApplied(ref: string): boolean;
38
+ /** Revert every applied action of this project — back to the authored scene. */
39
+ reset(): void;
40
+ };
41
+ animations: {
42
+ list(): SceneAnimationInfo[];
43
+ play(ref: string, options?: ScenePlayOptions): boolean;
44
+ pause(ref: string): boolean;
45
+ resume(ref: string): boolean;
46
+ stop(ref: string): boolean;
47
+ /** Jump to a point in the animation, 0–1. */
48
+ seek(ref: string, progress: number): boolean;
49
+ isPlaying(ref: string): boolean;
50
+ };
51
+ /** Subscribe to this project's action / animation events. Returns the unsubscribe. */
52
+ on(type: SceneHandleEventType, listener: (event: SceneHandleEvent) => void): () => void;
53
+ }
54
+ export interface SceneHandleSource {
55
+ actions: ActionSequence[];
56
+ animations: AnimationSequence[];
57
+ }
58
+ /**
59
+ * Build a handle over one project's actions and animations. `getSource` is read on
60
+ * every call, so the handle stays valid if the project data is replaced.
61
+ */
62
+ export declare function createSceneHandle(getSource: () => SceneHandleSource): SceneHandle;
63
+ //# sourceMappingURL=sceneHandle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sceneHandle.d.ts","sourceRoot":"","sources":["../../src/api/sceneHandle.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,cAAc,EAAkB,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/F,MAAM,WAAW,eAAe;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,MAAM,oBAAoB,GAAG,eAAe,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,cAAc,CAAC;AAE1G,MAAM,WAAW,gBAAgB;IAC7B,IAAI,EAAE,oBAAoB,CAAC;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE;QACL,IAAI,IAAI,eAAe,EAAE,CAAC;QAC1B,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAC5B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAC7B,0FAA0F;QAC1F,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAC7B,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAChC,gFAAgF;QAChF,KAAK,IAAI,IAAI,CAAC;KACjB,CAAC;IACF,UAAU,EAAE;QACR,IAAI,IAAI,kBAAkB,EAAE,CAAC;QAC7B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC;QACvD,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAC5B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAC7B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAC3B,6CAA6C;QAC7C,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAC7C,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACnC,CAAC;IACF,sFAAsF;IACtF,EAAE,CAAC,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,gBAAgB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAC3F;AAED,MAAM,WAAW,iBAAiB;IAC9B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,UAAU,EAAE,iBAAiB,EAAE,CAAC;CACnC;AA0BD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,iBAAiB,GAAG,WAAW,CAuGjF"}
@@ -0,0 +1,160 @@
1
+ // =============================================================================
2
+ // SceneHandle — control a loaded 3drise project from outside it
3
+ // =============================================================================
4
+ //
5
+ // What a developer extending a project gets from <ProjectLoader ref={…} /> or
6
+ // onSceneReady(handle): trigger the project's actions and animations from their
7
+ // own UI, and hear when they run.
8
+ //
9
+ // scene.current?.actions.toggle('open-door');
10
+ // scene.current?.animations.play('intro', { speed: 1.5 });
11
+ // const off = scene.current?.on('actionApplied', (e) => console.log(e.key));
12
+ //
13
+ // Addressing (`ref`): an action's `key` first (stable across renames and project
14
+ // copies — prefer it), then its id, then its exact name. Animations have no key
15
+ // yet, so id, then name. An ambiguous name warns and uses the first match.
16
+ //
17
+ // This is a thin layer: object clicks go through the same SceneActions /
18
+ // AnimationsManager calls, so a button and a click behave identically.
19
+ //
20
+ import { AnimationsManager, SceneActions } from '@3driseai/3drise-core';
21
+ function resolve(items, ref, kind) {
22
+ if (!ref)
23
+ return undefined;
24
+ const byKey = items.find(i => i.key === ref);
25
+ if (byKey)
26
+ return byKey;
27
+ const byId = items.find(i => i.id === ref);
28
+ if (byId)
29
+ return byId;
30
+ const byName = items.filter(i => i.name === ref);
31
+ if (byName.length > 1) {
32
+ console.warn(`[3drise] ${byName.length} ${kind}s are named "${ref}"; using the first.${kind === 'action' ? ' Address it by its key instead.' : ''}`);
33
+ }
34
+ if (byName.length === 0) {
35
+ console.warn(`[3drise] No ${kind} "${ref}" in this project. Known: ${items.map(i => i.key ?? i.name).join(', ') || 'none'}`);
36
+ }
37
+ return byName[0];
38
+ }
39
+ function animationDuration(seq) {
40
+ return (seq.steps ?? []).reduce((sum, s) => sum + (s.delay || 0) + (s.duration || 0), 0);
41
+ }
42
+ /**
43
+ * Build a handle over one project's actions and animations. `getSource` is read on
44
+ * every call, so the handle stays valid if the project data is replaced.
45
+ */
46
+ export function createSceneHandle(getSource) {
47
+ const actions = () => getSource().actions ?? [];
48
+ const animations = () => getSource().animations ?? [];
49
+ const findAction = (ref) => resolve(actions(), ref, 'action');
50
+ const findAnimation = (ref) => resolve(animations(), ref, 'animation');
51
+ return {
52
+ actions: {
53
+ list: () => actions().map(a => ({
54
+ id: a.id,
55
+ key: a.key,
56
+ name: a.name,
57
+ description: a.description,
58
+ applied: SceneActions.isActionApplied(a.id),
59
+ })),
60
+ apply(ref) {
61
+ const a = findAction(ref);
62
+ if (!a)
63
+ return false;
64
+ SceneActions.applyAction(a);
65
+ return true;
66
+ },
67
+ revert(ref) {
68
+ const a = findAction(ref);
69
+ if (!a)
70
+ return false;
71
+ SceneActions.revertAction(a);
72
+ return true;
73
+ },
74
+ toggle(ref) {
75
+ const a = findAction(ref);
76
+ return a ? SceneActions.toggleAction(a) : false;
77
+ },
78
+ isApplied(ref) {
79
+ const a = findAction(ref);
80
+ return a ? SceneActions.isActionApplied(a.id) : false;
81
+ },
82
+ reset() {
83
+ // Only this project's actions — another scene on the page keeps its state.
84
+ for (const a of actions())
85
+ SceneActions.revertAction(a.id);
86
+ },
87
+ },
88
+ animations: {
89
+ list: () => animations().map(s => ({
90
+ id: s.id,
91
+ name: s.name,
92
+ description: s.description,
93
+ duration: animationDuration(s),
94
+ loop: !!s.loop,
95
+ yoyo: !!s.yoyo,
96
+ playing: AnimationsManager.isSequencePlaying(s.id),
97
+ })),
98
+ play(ref, options = {}) {
99
+ const s = findAnimation(ref);
100
+ if (!s)
101
+ return false;
102
+ AnimationsManager.playSequence(s, { speed: options.speed, reverse: options.reverse });
103
+ return true;
104
+ },
105
+ pause(ref) {
106
+ const s = findAnimation(ref);
107
+ if (!s)
108
+ return false;
109
+ AnimationsManager.pauseSequence(s.id);
110
+ return true;
111
+ },
112
+ resume(ref) {
113
+ const s = findAnimation(ref);
114
+ if (!s)
115
+ return false;
116
+ AnimationsManager.resumeSequence(s.id);
117
+ return true;
118
+ },
119
+ stop(ref) {
120
+ const s = findAnimation(ref);
121
+ if (!s)
122
+ return false;
123
+ AnimationsManager.stopSequence(s.id);
124
+ return true;
125
+ },
126
+ seek(ref, progress) {
127
+ const s = findAnimation(ref);
128
+ if (!s)
129
+ return false;
130
+ AnimationsManager.seekToProgress(s.id, progress);
131
+ return true;
132
+ },
133
+ isPlaying(ref) {
134
+ const s = findAnimation(ref);
135
+ return s ? AnimationsManager.isSequencePlaying(s.id) : false;
136
+ },
137
+ },
138
+ on(type, listener) {
139
+ if (type === 'actionApplied' || type === 'actionReverted') {
140
+ return SceneActions.onEvent((e) => {
141
+ if (e.type === 'reset')
142
+ return;
143
+ if ((type === 'actionApplied') !== (e.type === 'applied'))
144
+ return;
145
+ const a = actions().find(x => x.id === e.actionId);
146
+ if (a)
147
+ listener({ type, id: a.id, key: a.key, name: a.name });
148
+ });
149
+ }
150
+ const managerEvent = type === 'animationStart' ? 'sequenceStart' : 'sequenceEnd';
151
+ const handler = (e) => {
152
+ const s = animations().find(x => x.id === e.sequenceId);
153
+ if (s)
154
+ listener({ type, id: s.id, name: s.name });
155
+ };
156
+ AnimationsManager.on(managerEvent, handler);
157
+ return () => AnimationsManager.off(managerEvent, handler);
158
+ },
159
+ };
160
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"CameraController.d.ts","sourceRoot":"","sources":["../../src/components/CameraController.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAQ7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,UAAU,qBAAsB,SAAQ,gBAAgB;IACpD,QAAQ,EAAE,WAAW,CAAC;IACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,CAAC;IAC1C,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,CAAC;CAC/C;AAGD,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAwJ5D,CAAC;AACF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"CameraController.d.ts","sourceRoot":"","sources":["../../src/components/CameraController.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAS7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,UAAU,qBAAsB,SAAQ,gBAAgB;IACpD,QAAQ,EAAE,WAAW,CAAC;IACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,CAAC;IAC1C,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,KAAK,IAAI,CAAC;CAC/C;AAGD,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CA0J5D,CAAC;AACF,eAAe,gBAAgB,CAAC"}
@@ -7,7 +7,10 @@ import { cameraManager } from '../utils/CameraSingleton.js';
7
7
  import { useAnimationEvents } from '../hooks/useAnimationEvents.js';
8
8
  import { usePathAnimation } from '../hooks/usePathAnimation.js';
9
9
  import { OrbitControls } from "@react-three/drei";
10
+ import { useRuntimeSettings } from '../hooks/useRuntimeSettings.js';
10
11
  export const CameraController = ({ enableAutoAnimation = true, animationDuration = 1, animationEase = "power2.out", settings, onObjectReady, onObjectDispose, onControlsReady, onControlsDispose, }) => {
12
+ // Authored camera + any applied action patch ('camera').
13
+ settings = useRuntimeSettings('camera', settings);
11
14
  const { camera, set } = useThree();
12
15
  const cameraRef = useRef(camera);
13
16
  const transformAnimationProgress = useRef(0);
@@ -104,7 +107,7 @@ export const CameraController = ({ enableAutoAnimation = true, animationDuration
104
107
  useAnimationEvents({
105
108
  onStepStart: (event) => {
106
109
  if (event.step?.transitions) {
107
- const stepDuration = event.step.duration || 1;
110
+ const stepDuration = event.step.duration ?? 1; // 0 = instant (actions)
108
111
  event.step.transitions.forEach((transition) => {
109
112
  const { state, properties, pathId } = transition;
110
113
  if (state === 'camera') {
@@ -1 +1 @@
1
- {"version":3,"file":"EnvironmentManager.d.ts","sourceRoot":"","sources":["../../src/components/EnvironmentManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAkB,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAGhF,OAAO,KAAK,EACR,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAIhE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;;;;;iFAWiF;AACjF,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG;IAChF,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAClC,OAAO,CAAC,EAAE,yBAAyB,CAAC;IACpC,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC9B,CAAC;AAEF,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB;IAC7D,YAAY,EAAE,YAAY,CAAC;IAC3B,iFAAiF;IACjF,WAAW,CAAC,EAAE,uBAAuB,CAAC;IACtC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,cAAc,CAAC,EAAE,wBAAwB,CAAC;IAC1C,eAAe,CAAC,EAAE,yBAAyB,CAAC;IAC5C,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iBAAiB,CAAC,EAAE,cAAc,CAAC,mBAAmB,CAAC,CAAC;IACxD,YAAY,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;IAC9C;sEACkE;IAClE,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAoBD,QAAA,MAAM,kBAAkB,8FAwGtB,CAAC;AAGH,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"EnvironmentManager.d.ts","sourceRoot":"","sources":["../../src/components/EnvironmentManager.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAkB,EAAE,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAGhF,OAAO,KAAK,EACR,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAIhE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG7D;;;;;;;;;;;;;;;;;;;GAmBG;AAEH;;;;;;;;;;;iFAWiF;AACjF,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG;IAChF,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAClC,OAAO,CAAC,EAAE,yBAAyB,CAAC;IACpC,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC9B,CAAC;AAEF,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB;IAC7D,YAAY,EAAE,YAAY,CAAC;IAC3B,iFAAiF;IACjF,WAAW,CAAC,EAAE,uBAAuB,CAAC;IACtC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,cAAc,CAAC,EAAE,wBAAwB,CAAC;IAC1C,eAAe,CAAC,EAAE,yBAAyB,CAAC;IAC5C,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iBAAiB,CAAC,EAAE,cAAc,CAAC,mBAAmB,CAAC,CAAC;IACxD,YAAY,CAAC,EAAE,cAAc,CAAC,cAAc,CAAC,CAAC;IAC9C;sEACkE;IAClE,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAoBD,QAAA,MAAM,kBAAkB,8FAyGtB,CAAC;AAGH,eAAe,kBAAkB,CAAC"}
@@ -7,6 +7,7 @@ import { useEnvironmentProbe } from '../hooks/useEnvironmentProbe.js';
7
7
  import TerrainBuilder from './TerrainBuilder.js';
8
8
  import LandscapeBuilder from './LandscapeBuilder.js';
9
9
  import OceanBuilder from './OceanBuilder.js';
10
+ import { useRuntimeSettings } from '../hooks/useRuntimeSettings.js';
10
11
  const DEFAULT_HDR = {
11
12
  visible: false,
12
13
  name: null,
@@ -25,11 +26,12 @@ const DEFAULT_HDR = {
25
26
  const ORIGIN = new Vector3(0, 0, 0);
26
27
  const EnvironmentManager = forwardRef(({ timeSettings, environment, hdrSettings, skySettings, cloudsSettings, terrainSettings, landscapeSettings, oceanSettings, fogSettings, cubeCameraResolution = 512, skyboxScale = 100000, playerPosition = ORIGIN, onTimeOfDayChange, onTimeUpdate, driveTime = true, onObjectReady, onObjectDispose, }, ref) => {
27
28
  const hdr = hdrSettings ?? environment?.hdr ?? DEFAULT_HDR;
28
- const sky = skySettings ?? environment?.sky;
29
- const clouds = cloudsSettings ?? environment?.clouds;
29
+ // Authored settings + applied action patches (runtime only).
30
+ const sky = useRuntimeSettings('sky', skySettings ?? environment?.sky);
31
+ const clouds = useRuntimeSettings('clouds', cloudsSettings ?? environment?.clouds);
30
32
  const terrain = terrainSettings ?? environment?.terrain;
31
33
  const landscape = landscapeSettings ?? environment?.landscape;
32
- const ocean = oceanSettings ?? environment?.ocean;
34
+ const ocean = useRuntimeSettings('ocean', oceanSettings ?? environment?.ocean);
33
35
  const fog = fogSettings ?? environment?.fog;
34
36
  const sunSystemVisible = !!sky?.sunSystem?.visible;
35
37
  // Previously hardcoded true, which kept a cube camera alive — and re-captured
@@ -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,CAsIzC,CAAC;AACF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"ObjectNode.d.ts","sourceRoot":"","sources":["../../src/components/ObjectNode.tsx"],"names":[],"mappings":"AAmBA,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,CAyIzC,CAAC;AACF,eAAe,UAAU,CAAC"}
@@ -15,6 +15,7 @@ import GridGenerator from "./GridsGenerator.js";
15
15
  import OceanBuilder from "./OceanBuilder.js";
16
16
  import LandscapeObject from "./LandscapeObject.js";
17
17
  import LayoutInstances from "./LayoutInstances.js";
18
+ import { useRuntimeSettings } from "../hooks/useRuntimeSettings.js";
18
19
  import { SELF_MANAGED_MATERIAL } from "../constants.js";
19
20
  import { LAYOUT_CAPABLE_TYPES, getObjectLayoutSupport, normalizeObjectLayout, isGenerativeParticlesConfig } from "@3driseai/3drise-core";
20
21
  // Slots after the first render with no ready callbacks: one object reports once.
@@ -47,7 +48,10 @@ const GroupWithChildren = ({ createdObject, children, onObjectReady, onObjectDis
47
48
  return (_jsxs(CreatedObject, { createdObject: createdObject, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose, handleObjectClick: handleObjectClick, shouldApply3driseMaterial: !isGroup && !selfManagedMaterial, children: [!isGroup && renderObject(createdObject, handleObjectClick), children.map(childNode => (_jsx(ObjectNode, { node: childNode, handleObjectClick: handleObjectClick, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }, childNode.objectId)))] }, createdObject.id));
48
49
  };
49
50
  const ObjectNode = ({ node, onObjectReady, onObjectDispose, handleObjectClick }) => {
50
- const { children, createdObject } = node;
51
+ const { children } = node;
52
+ // Authored settings + any applied action patches (runtime only). Every renderer
53
+ // below sees the patched object, so an action can change anything an edit can.
54
+ const createdObject = useRuntimeSettings(node.createdObject?.id, node.createdObject);
51
55
  // Children describe themselves with their own settings; the scene above
52
56
  // knows them by the node's createdObject, so relabel on the way up.
53
57
  const relabel = useCallback((obj) => ({
@@ -1,4 +1,4 @@
1
- import type { AnimationSequence, GeneralObjectSettings, CameraState, CreatedObjectSettings } from '@3driseai/3drise-core';
1
+ import type { ActionSequence, AnimationSequence, GeneralObjectSettings, CameraState, CreatedObjectSettings } from '@3driseai/3drise-core';
2
2
  import type { ObjectReadyProps } from '../types/objectReady';
3
3
  import React from "react";
4
4
  import { Object3D } from "three";
@@ -10,6 +10,7 @@ interface ObjectsRendererProps extends ObjectReadyProps {
10
10
  onObjectsReady?: () => void;
11
11
  handleObjectClick?: (object: CreatedObjectSettings, ref: Object3D, event: ThreeEvent<MouseEvent>) => void;
12
12
  sequences?: AnimationSequence[];
13
+ actionSequences?: ActionSequence[];
13
14
  }
14
15
  declare const ObjectsRenderer: React.FC<ObjectsRendererProps>;
15
16
  export default ObjectsRenderer;
@@ -1 +1 @@
1
- {"version":3,"file":"ObjectsRenderer.d.ts","sourceRoot":"","sources":["../../src/components/ObjectsRenderer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAI1H,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,oBAAqB,SAAQ,gBAAgB;IACnD,cAAc,EAAE,WAAW,CAAC;IAC5B,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C,cAAc,EAAE,qBAAqB,EAAE,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IAC1G,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACnC;AAGD,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA0ClD,CAAC;AAEH,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"ObjectsRenderer.d.ts","sourceRoot":"","sources":["../../src/components/ObjectsRenderer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAI1I,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,oBAAqB,SAAQ,gBAAgB;IACnD,cAAc,EAAE,WAAW,CAAC;IAC5B,qBAAqB,EAAE,qBAAqB,CAAC;IAC7C,cAAc,EAAE,qBAAqB,EAAE,CAAC;IACxC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IAC1G,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAChC,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;CACtC;AAGD,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA2ClD,CAAC;AAEH,eAAe,eAAe,CAAC"}
@@ -4,7 +4,7 @@ import { buildObjectTree } from '@3driseai/3drise-core';
4
4
  import ObjectNode from './ObjectNode.js';
5
5
  import useInteraction from '../hooks/useInteraction.js';
6
6
  import { useObjectReady } from '../hooks/useObjectReady.js';
7
- const ObjectsRenderer = memo(({ cameraSettings, createdObjects, generalObjectSettings, onObjectsReady, onObjectReady, onObjectDispose, handleObjectClick, sequences = [], }) => {
7
+ const ObjectsRenderer = memo(({ cameraSettings, createdObjects, generalObjectSettings, onObjectsReady, onObjectReady, onObjectDispose, handleObjectClick, sequences = [], actionSequences = [], }) => {
8
8
  const groupRef = useRef(null);
9
9
  const objectsTree = useMemo(() => buildObjectTree(createdObjects), [createdObjects]);
10
10
  const readyObjectsCount = useRef(0);
@@ -32,6 +32,7 @@ const ObjectsRenderer = memo(({ cameraSettings, createdObjects, generalObjectSet
32
32
  const { executeInteraction } = useInteraction({
33
33
  cameraSettings,
34
34
  sequences,
35
+ actionSequences,
35
36
  });
36
37
  const handleObjectClickHandler = (createdObject, ref, event) => {
37
38
  const clickInteractions = filterInteractionsByEvent(createdObject.actions, "click");
@@ -1,9 +1,10 @@
1
+ import type { SceneHandle } from "../api/sceneHandle";
1
2
  import type { CreatedObjectSettings, HtmlElement } from '@3driseai/3drise-core';
2
3
  import React from "react";
3
4
  import { Object3D } from "three";
4
5
  import { type ThreeEvent } from "@react-three/fiber";
5
6
  import type { ObjectReadyProps } from "../types/objectReady";
6
- type ProjectProps = ObjectReadyProps & {
7
+ declare const ProjectLoader: React.ForwardRefExoticComponent<ObjectReadyProps & {
7
8
  projectId: string;
8
9
  loadingIndicator?: React.ReactNode;
9
10
  onObjectClick?: (object: CreatedObjectSettings, ref: Object3D, event: ThreeEvent<MouseEvent>) => void;
@@ -11,7 +12,12 @@ type ProjectProps = ObjectReadyProps & {
11
12
  onElementClick?: (element: HtmlElement) => void;
12
13
  onElementHover?: (element: HtmlElement | null) => void;
13
14
  onSceneInitialized?: () => void;
14
- };
15
- declare const ProjectLoader: React.FC<ProjectProps>;
15
+ /**
16
+ * Called once the project is loaded and its canvas exists, with the handle for
17
+ * driving its actions and animations from your own UI. The same handle is also
18
+ * available through `ref`.
19
+ */
20
+ onSceneReady?: (scene: SceneHandle) => void;
21
+ } & React.RefAttributes<SceneHandle>>;
16
22
  export default ProjectLoader;
17
23
  //# sourceMappingURL=ProjectLoader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProjectLoader.d.ts","sourceRoot":"","sources":["../../src/components/ProjectLoader.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGhF,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,KAAK,YAAY,GAAG,gBAAgB,GAAG;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACnC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;IACtG,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,KAAK,IAAI,CAAC;IACvE,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;IAChD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;CACnC,CAAC;AAGF,QAAA,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,YAAY,CAsDzC,CAAC;AACF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"ProjectLoader.d.ts","sourceRoot":"","sources":["../../src/components/ProjectLoader.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGhF,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAkB7D,QAAA,MAAM,aAAa;eAhBJ,MAAM;uBACE,KAAK,CAAC,SAAS;oBAClB,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI;oBACrF,CAAC,MAAM,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,KAAK,IAAI;qBACrD,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI;qBAC9B,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI;yBACjC,MAAM,IAAI;IAC/B;;;;OAIG;mBACY,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI;qCA0D7C,CAAC;AAEH,eAAe,aAAa,CAAC"}
@@ -1,11 +1,11 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useState } from "react";
2
+ import { forwardRef, useEffect, useState } from "react";
3
3
  import { dataCenterServer } from '../constants.js';
4
4
  import SceneBuilder from "./SceneBuilder.js";
5
5
  import { loadAssets, } from "@3driseai/3drise-core";
6
6
  import LoadingIndicator from "./LoadingIndicator.js";
7
7
  import { useMeshController } from "../hooks/useMeshController.js";
8
- const ProjectLoader = ({ projectId, onObjectClick, onObjectHover, onElementClick, onElementHover, onSceneInitialized, onObjectReady, onObjectDispose, loadingIndicator = _jsx(LoadingIndicator, { text: "Loading project...", fullScreen: true, animate: true }) }) => {
8
+ const ProjectLoader = forwardRef(({ projectId, onObjectClick, onObjectHover, onElementClick, onElementHover, onSceneInitialized, onSceneReady, onObjectReady, onObjectDispose, loadingIndicator = _jsx(LoadingIndicator, { text: "Loading project...", fullScreen: true, animate: true }) }, ref) => {
9
9
  const [project, setProject] = useState(null);
10
10
  const meshController = useMeshController();
11
11
  useEffect(() => {
@@ -56,6 +56,7 @@ const ProjectLoader = ({ projectId, onObjectClick, onObjectHover, onElementClick
56
56
  flexDirection: 'column', gap: '1rem'
57
57
  }, children: loadingIndicator });
58
58
  }
59
- return _jsx(_Fragment, { children: _jsx(SceneBuilder, { project: project, onSceneInitialized: onSceneInitialized, onUiElementClick: onElementClick, onUiElementHover: onElementHover, onObjectClick: onObjectClick, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }) });
60
- };
59
+ return _jsx(_Fragment, { children: _jsx(SceneBuilder, { ref: ref, project: project, onSceneReady: onSceneReady, onSceneInitialized: onSceneInitialized, onUiElementClick: onElementClick, onUiElementHover: onElementHover, onObjectClick: onObjectClick, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }) });
60
+ });
61
+ ProjectLoader.displayName = 'ProjectLoader';
61
62
  export default ProjectLoader;
@@ -1,6 +1,14 @@
1
+ import { type SceneHandle } from "../api/sceneHandle";
1
2
  import type { SceneBuilderProps } from '@3driseai/3drise-core';
2
3
  import React from "react";
3
4
  import type { ObjectReadyProps } from "../types/objectReady";
4
- declare const SceneBuilder: React.FC<SceneBuilderProps & ObjectReadyProps>;
5
+ export type SceneBuilderViewerProps = SceneBuilderProps & ObjectReadyProps & {
6
+ /** Called once the canvas exists, with the handle for driving this project's actions and animations. */
7
+ onSceneReady?: (scene: SceneHandle) => void;
8
+ };
9
+ declare const SceneBuilder: React.ForwardRefExoticComponent<SceneBuilderProps & ObjectReadyProps & {
10
+ /** Called once the canvas exists, with the handle for driving this project's actions and animations. */
11
+ onSceneReady?: (scene: SceneHandle) => void;
12
+ } & React.RefAttributes<SceneHandle>>;
5
13
  export default SceneBuilder;
6
14
  //# sourceMappingURL=SceneBuilder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SceneBuilder.d.ts","sourceRoot":"","sources":["../../src/components/SceneBuilder.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAQ/D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,GAAG,gBAAgB,CAuIhE,CAAC;AACF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"SceneBuilder.d.ts","sourceRoot":"","sources":["../../src/components/SceneBuilder.tsx"],"names":[],"mappings":"AACA,OAAO,EAAqB,KAAK,WAAW,EAA0B,MAAM,oBAAoB,CAAC;AAGjG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAQ/D,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,GAAG,gBAAgB,GAAG;IACzE,wGAAwG;IACxG,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;CAC/C,CAAC;AAEF,QAAA,MAAM,YAAY;IAJd,wGAAwG;mBACzF,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI;qCAkJ7C,CAAC;AAEH,eAAe,YAAY,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from "react";
2
+ import { forwardRef, useImperativeHandle, useMemo, useRef, useState } from "react";
3
+ import { createSceneHandle } from "../api/sceneHandle.js";
3
4
  import { Canvas } from "@react-three/fiber";
4
5
  import { LIGHTING_PRESETS, SceneStore } from "@3driseai/3drise-core";
5
6
  import { NoToneMapping } from "three";
@@ -9,7 +10,7 @@ import CameraController from "./CameraController.js";
9
10
  import ObjectsRenderer from "./ObjectsRenderer.js";
10
11
  import CursorController from "./cursor/CursorController.js";
11
12
  import { Physics } from "@react-three/rapier";
12
- const SceneBuilder = ({ project, width = "100%", height = "100vh", style = {}, className = "", onSceneInitialized, onUiElementClick, onObjectClick, onObjectReady, onObjectDispose, }) => {
13
+ const SceneBuilder = forwardRef(({ project, width = "100%", height = "100vh", style = {}, className = "", onSceneInitialized, onSceneReady, onUiElementClick, onObjectClick, onObjectReady, onObjectDispose, }, ref) => {
13
14
  const sceneSettings = (project.sceneSettingsData || {});
14
15
  // const meshController = useMeshController();
15
16
  const [isThreeJsMounted, setIsThreeJsMounted] = useState(false);
@@ -41,6 +42,13 @@ const SceneBuilder = ({ project, width = "100%", height = "100vh", style = {}, c
41
42
  }
42
43
  });
43
44
  const animationSequences = project.animationSequences || [];
45
+ const actionSequences = project.actionSequences || [];
46
+ // The external control handle (see api/sceneHandle). Built once; reads the
47
+ // current project lists through a ref, so it never goes stale.
48
+ const handleSource = useRef({ actions: actionSequences, animations: animationSequences });
49
+ handleSource.current = { actions: actionSequences, animations: animationSequences };
50
+ const sceneHandle = useMemo(() => createSceneHandle(() => handleSource.current), []);
51
+ useImperativeHandle(ref, () => sceneHandle, [sceneHandle]);
44
52
  const sceneObjects = project.sceneObjects || sceneSettings.scene?.objectSettings || [];
45
53
  const modelObjects = sceneObjects.filter((obj) => obj.type === "model");
46
54
  const meshObjects = sceneObjects.filter((obj) => obj.type === "mesh");
@@ -131,6 +139,8 @@ const SceneBuilder = ({ project, width = "100%", height = "100vh", style = {}, c
131
139
  if (onSceneInitialized) {
132
140
  onSceneInitialized();
133
141
  }
134
- }, children: _jsxs(Physics, { gravity: physicsSettings.gravity, paused: !physicsSettings.enabled, debug: physicsSettings.debug, children: [_jsx(LightsManager, { config: lighting[0], onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), environment && _jsx(EnvironmentManager, { environment: environment, timeSettings: timeSettings, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), _jsx(CameraController, { settings: camera, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), _jsx(ObjectsRenderer, { cameraSettings: camera, generalObjectSettings: generalObjectSettings, createdObjects: sceneObjects, onObjectsReady: undefined, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose, sequences: animationSequences, handleObjectClick: onObjectClick ? (object, ref, event) => onObjectClick(object, ref, event) : undefined }), _jsx(CursorController, { effects: project.cursor?.effects, clickActions: project.cursor?.clickActions, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose })] }) }) }));
135
- };
142
+ onSceneReady?.(sceneHandle);
143
+ }, children: _jsxs(Physics, { gravity: physicsSettings.gravity, paused: !physicsSettings.enabled, debug: physicsSettings.debug, children: [_jsx(LightsManager, { config: lighting[0], onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), environment && _jsx(EnvironmentManager, { environment: environment, timeSettings: timeSettings, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), _jsx(CameraController, { settings: camera, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), _jsx(ObjectsRenderer, { cameraSettings: camera, generalObjectSettings: generalObjectSettings, createdObjects: sceneObjects, onObjectsReady: undefined, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose, sequences: animationSequences, actionSequences: actionSequences, handleObjectClick: onObjectClick ? (object, ref, event) => onObjectClick(object, ref, event) : undefined }), _jsx(CursorController, { effects: project.cursor?.effects, clickActions: project.cursor?.clickActions, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose })] }) }) }));
144
+ });
145
+ SceneBuilder.displayName = 'SceneBuilder';
136
146
  export default SceneBuilder;
@@ -1 +1 @@
1
- {"version":3,"file":"Stars.d.ts","sourceRoot":"","sources":["../../src/components/Stars.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAA4C,MAAM,OAAO,CAAC;AAQjF,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,MAAM,WAAW,UAAW,SAAQ,gBAAgB;IAChD,QAAQ,EAAE,qBAAqB,CAAC;IAChC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAOD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAuDnE;AAYD,QAAA,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CA2K/B,CAAC;AACF,eAAe,KAAK,CAAC"}
1
+ {"version":3,"file":"Stars.d.ts","sourceRoot":"","sources":["../../src/components/Stars.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAA4C,MAAM,OAAO,CAAC;AAQjF,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC1D,MAAM,WAAW,UAAW,SAAQ,gBAAgB;IAChD,QAAQ,EAAE,qBAAqB,CAAC;IAChC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAOD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAuDnE;AAYD,QAAA,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CA4K/B,CAAC;AACF,eAAe,KAAK,CAAC"}
@@ -135,7 +135,8 @@ const Stars = ({ settings, timeSettings, sunSystemEnabled = false, onObjectReady
135
135
  pointsRef.current.visible = toProps.visible;
136
136
  }
137
137
  // color — existing path
138
- setDuration(event.step.duration);
138
+ // speed = 1 / duration below; keep an instant (0) step finite.
139
+ setDuration(Math.max(event.step.duration ?? 1, 0.001));
139
140
  if (toProps.color !== undefined) {
140
141
  setColors({
141
142
  baseColor: fromProps.color,
@@ -45,6 +45,7 @@ export type { UseLightMouseMoveOptions } from './useLightMouseMove';
45
45
  export { useLightMouseMove } from './useLightMouseMove';
46
46
  export { useLightShadow } from './useLightShadow';
47
47
  export { LIGHT_STRUCTURAL, applyLightLive, useLightLive } from './useLightLive';
48
+ export { useLightTargets } from './useLightTargets';
48
49
  export type { UseLightConfigResult } from './useLightConfig';
49
50
  export { applyLightConfig, useLightConfig } from './useLightConfig';
50
51
  export { useMaterialApplication } from './useMaterialApplication';
@@ -88,4 +89,5 @@ export type { LandscapeLiveHandle } from './useLandscapeLive';
88
89
  export { LANDSCAPE_LIVE_KEY, useLandscapeLive } from './useLandscapeLive';
89
90
  export { useLandscapeMaps } from './useLandscapeMaps';
90
91
  export type { LandscapeMapsState } from './useLandscapeMaps';
92
+ export { useRuntimeSettings } from './useRuntimeSettings';
91
93
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"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"}
@@ -31,6 +31,7 @@ export { useLightHandlers } from './useLightHandlers.js';
31
31
  export { useLightMouseMove } from './useLightMouseMove.js';
32
32
  export { useLightShadow } from './useLightShadow.js';
33
33
  export { LIGHT_STRUCTURAL, applyLightLive, useLightLive } from './useLightLive.js';
34
+ export { useLightTargets } from './useLightTargets.js';
34
35
  export { applyLightConfig, useLightConfig } from './useLightConfig.js';
35
36
  export { useMaterialApplication } from './useMaterialApplication.js';
36
37
  export { useMaterialOptions } from './useMaterialOptions.js';
@@ -64,3 +65,4 @@ export { useWaterEnvironment } from './useWaterEnvironment.js';
64
65
  export { useWaterReflections } from './useWaterReflections.js';
65
66
  export { LANDSCAPE_LIVE_KEY, useLandscapeLive } from './useLandscapeLive.js';
66
67
  export { useLandscapeMaps } from './useLandscapeMaps.js';
68
+ export { useRuntimeSettings } from './useRuntimeSettings.js';
@@ -1,7 +1,8 @@
1
- import type { AnimationSequence, CameraState } from '@3driseai/3drise-core';
2
- export declare function useInteraction({ cameraSettings, sequences, }: {
1
+ import type { ActionSequence, AnimationSequence, CameraState } from '@3driseai/3drise-core';
2
+ export declare function useInteraction({ cameraSettings, sequences, actionSequences, }: {
3
3
  cameraSettings: CameraState;
4
4
  sequences: AnimationSequence[];
5
+ actionSequences?: ActionSequence[];
5
6
  }): {
6
7
  executeInteraction: (params: any) => void;
7
8
  currentAnimatedRef: import("react").RefObject<any>;
@@ -1 +1 @@
1
- {"version":3,"file":"useInteraction.d.ts","sourceRoot":"","sources":["../../src/hooks/useInteraction.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAA4B,MAAM,uBAAuB,CAAC;AAatG,wBAAgB,cAAc,CAAC,EAE/B,cAAc,EAAE,SAAS,GAAG,EAAE;IAClB,cAAc,EAAE,WAAW,CAAC;IAC5B,SAAS,EAAE,iBAAiB,EAAE,CAAC;CAClC;;;;;EA+NR;AACD,eAAe,cAAc,CAAC"}
1
+ {"version":3,"file":"useInteraction.d.ts","sourceRoot":"","sources":["../../src/hooks/useInteraction.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,WAAW,EAA4B,MAAM,uBAAuB,CAAC;AAatH,wBAAgB,cAAc,CAAC,EAE/B,cAAc,EAAE,SAAS,EAAE,eAAoB,GAAG,EAAE;IACxC,cAAc,EAAE,WAAW,CAAC;IAC5B,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;CACtC;;;;;EAkQR;AACD,eAAe,cAAc,CAAC"}
@@ -8,7 +8,7 @@
8
8
  * - Triggering animations
9
9
  */
10
10
  import { useCallback, useRef } from 'react';
11
- import { AnimationsManager, texturesManager } from '@3driseai/3drise-core';
11
+ import { AnimationsManager, SceneActions, texturesManager } from '@3driseai/3drise-core';
12
12
  import useCameraAnimation from '../hooks/useCameraAnimation.js';
13
13
  import { useFrameAnimations } from '../hooks/useFrameAnimations.js';
14
14
  import { useObjectEffects } from '../hooks/useObjectEffects.js';
@@ -21,10 +21,12 @@ import { findById } from '../utils/sceneQuery.js';
21
21
  // =============================================================================
22
22
  export function useInteraction({
23
23
  // mode = 'default',
24
- cameraSettings, sequences, }) {
24
+ cameraSettings, sequences, actionSequences = [], }) {
25
25
  // Redux state
26
26
  // Track currently animated object for toggle behavior
27
27
  const currentAnimatedRef = useRef(null);
28
+ // Animation ids whose last toggle played forward — the next toggle plays them reversed.
29
+ const toggledAnimationsRef = useRef(new Set());
28
30
  // Hooks
29
31
  const { animateCamera } = useCameraAnimation({
30
32
  autoAnimate: false,
@@ -59,17 +61,46 @@ cameraSettings, sequences, }) {
59
61
  // ===========================================================================
60
62
  // UTILITY: Trigger Animations
61
63
  // ===========================================================================
62
- const triggerAnimations = useCallback((animationIds) => {
64
+ // 'toggle' in an interaction's operations is a modifier, not an effect of its own:
65
+ // it makes that interaction's animations and actions two-state. Animations play
66
+ // forward then reversed; actions apply then revert (their patches are removed).
67
+ const triggerAnimations = useCallback((animationIds, toggle = false) => {
63
68
  if (!animationIds || animationIds.length === 0)
64
69
  return;
65
70
  animationIds.forEach(animationId => {
66
71
  const sequence = sequences.find(s => s.id === animationId);
67
- if (sequence) {
72
+ if (!sequence)
73
+ return;
74
+ if (!toggle) {
68
75
  AnimationsManager.playSequence(sequence);
76
+ return;
69
77
  }
78
+ const toggled = toggledAnimationsRef.current;
79
+ const reverse = toggled.has(animationId);
80
+ if (reverse)
81
+ toggled.delete(animationId);
82
+ else
83
+ toggled.add(animationId);
84
+ AnimationsManager.playSequence(sequence, { reverse });
70
85
  });
71
86
  }, [sequences]);
72
87
  // ===========================================================================
88
+ // UTILITY: Trigger Actions (instant)
89
+ // ===========================================================================
90
+ const triggerActions = useCallback((actionIds, toggle = false) => {
91
+ if (!actionIds || actionIds.length === 0)
92
+ return;
93
+ actionIds.forEach(actionId => {
94
+ const action = actionSequences.find(a => a.id === actionId);
95
+ if (!action)
96
+ return;
97
+ if (toggle)
98
+ SceneActions.toggleAction(action);
99
+ else
100
+ SceneActions.applyAction(action);
101
+ });
102
+ }, [actionSequences]);
103
+ // ===========================================================================
73
104
  // UTILITY: Execute Single Operation
74
105
  // ===========================================================================
75
106
  const executeOperation = useCallback(async (operation, ref, createdObject, textureUrl) => {
@@ -182,10 +213,12 @@ cameraSettings, sequences, }) {
182
213
  }
183
214
  break;
184
215
  }
216
+ case 'toggle':
217
+ // Modifier for animationIds/actionIds — handled in executeInteraction.
218
+ break;
185
219
  case 'create':
186
220
  case 'update':
187
221
  case 'delete':
188
- case 'toggle':
189
222
  case 'loadProject':
190
223
  break;
191
224
  }
@@ -231,9 +264,11 @@ cameraSettings, sequences, }) {
231
264
  // For now, use the original createdObject for position data
232
265
  executeOperations(interaction.operations, targetRef, createdObject, textureUrl);
233
266
  });
234
- // 3. Trigger animations
235
- triggerAnimations(interaction.animationIds);
236
- }, [resolveTargets, executeOperations, triggerAnimations]);
267
+ // 3. Trigger animations and actions ('toggle' makes both two-state)
268
+ const toggle = interaction.operations?.includes('toggle') ?? false;
269
+ triggerAnimations(interaction.animationIds, toggle);
270
+ triggerActions(interaction.actionIds, toggle);
271
+ }, [resolveTargets, executeOperations, triggerAnimations, triggerActions]);
237
272
  // ===========================================================================
238
273
  // RETURN
239
274
  // ===========================================================================
@@ -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;
@@ -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'. 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'. 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"}
@@ -15,6 +15,17 @@ function lerp(a, b, t) {
15
15
  function lerpVec3(a, b, t) {
16
16
  return [lerp(a[0], b[0], t), lerp(a[1], b[1], t), lerp(a[2], b[2], t)];
17
17
  }
18
+ /** Transform lerp for one step at progress p (non-path). */
19
+ function applyTransform(obj, step, p) {
20
+ obj.position.set(...lerpVec3(step.fromPosition, step.toPosition, p));
21
+ obj.rotation.set(...lerpVec3(step.fromRotation, step.toRotation, p));
22
+ obj.scale.set(...lerpVec3(step.fromScale, step.toScale, p));
23
+ }
24
+ /** Transform + material for one step at progress p (non-path). */
25
+ function applyTransformAndMaterial(obj, step, p) {
26
+ applyTransform(obj, step, p);
27
+ interpolateMaterialProps(obj, step.materialFrom, step.materialTo, p);
28
+ }
18
29
  /** Get material-related properties from a transition properties record */
19
30
  function extractMaterialProps(props) {
20
31
  if (!props)
@@ -67,7 +78,8 @@ export const useSequenceAnimation = (objectId, objectSource) => {
67
78
  const transition = event.step.transitions[transitionIndex];
68
79
  const stagger = event.step.stagger || 0;
69
80
  const staggerOffsetMs = transitionIndex * stagger * 1000;
70
- const d = event.step.duration || 1;
81
+ // `?? 1`, not `|| 1`: a 0 duration is an instant change (actions), not a missing value.
82
+ const d = event.step.duration ?? 1;
71
83
  const ease = event.step.ease || 'linear';
72
84
  const { properties, pathId = null } = transition;
73
85
  // Visibility shortcut
@@ -120,6 +132,18 @@ export const useSequenceAnimation = (objectId, objectSource) => {
120
132
  visibilityOverride: null,
121
133
  pathId,
122
134
  });
135
+ // Instant step (an action, or a 0-length animation step): land on `to` now.
136
+ // The manager emits stepStart and sequenceEnd in the same tick for these, and
137
+ // sequenceEnd clears stepRef, so waiting for useFrame would apply nothing.
138
+ if (d === 0) {
139
+ stopPathAnimation();
140
+ if (resolvedObject && stepRef.current) {
141
+ applyTransformAndMaterial(resolvedObject, stepRef.current, 1);
142
+ }
143
+ updateStepRef(null);
144
+ updateProgressRef(1);
145
+ return;
146
+ }
123
147
  updateProgressRef(0);
124
148
  if (pathId) {
125
149
  startPathAnimation(pathId, d, { ease });
@@ -176,15 +200,9 @@ export const useSequenceAnimation = (objectId, objectSource) => {
176
200
  resolvedObject.scale.set(...sca);
177
201
  }
178
202
  else {
179
- // — Transform —
180
- const pos = lerpVec3(step.fromPosition, step.toPosition, p);
181
- const rot = lerpVec3(step.fromRotation, step.toRotation, p);
182
- const sca = lerpVec3(step.fromScale, step.toScale, p);
183
- resolvedObject.position.set(...pos);
184
- resolvedObject.rotation.set(...rot);
185
- resolvedObject.scale.set(...sca);
203
+ applyTransform(resolvedObject, step, p);
186
204
  }
187
- // — Material properties —
205
+ // Material properties
188
206
  interpolateMaterialProps(resolvedObject, step.materialFrom, step.materialTo, p);
189
207
  if (p >= 1) {
190
208
  updateProgressRef(1);
package/dist/index.d.ts CHANGED
@@ -3,6 +3,8 @@ export { AnimationsManager as animationsManager, fontManager } from '@3driseai/3
3
3
  export * from './types';
4
4
  export * from './components';
5
5
  export * from './hooks';
6
+ export { createSceneHandle } from './api/sceneHandle';
7
+ export type { SceneHandle, SceneHandleEvent, SceneHandleEventType, SceneActionInfo, SceneAnimationInfo, ScenePlayOptions } from './api/sceneHandle';
6
8
  export type { PathAnimationOptions as PathAnimationHookOptions } from './hooks/usePathAnimation';
7
9
  export { cameraManager } from './utils/CameraSingleton';
8
10
  export { applyAnchorSettings, createCurves, createSunPosition, randomRange, } from './utils/utils3d';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAG1F,OAAO,EAAE,iBAAiB,IAAI,iBAAiB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAG5F,cAAc,SAAS,CAAC;AAGxB,cAAc,cAAc,CAAC;AAG7B,cAAc,SAAS,CAAC;AAExB,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAEpJ,YAAY,EAAE,oBAAoB,IAAI,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAGjG,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,GAAG,MAAM,iBAAiB,CAAC;AACrG,OAAO,EAAE,mBAAmB,IAAI,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AACvF,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAC;AACtF,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAC7F,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC/E,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACvF,YAAY,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACtE,OAAO,EACL,oBAAoB,EACpB,4BAA4B,EAC5B,qBAAqB,EACrB,eAAe,EACf,8BAA8B,GAC/B,MAAM,yBAAyB,CAAC;AACjC,YAAY,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpG,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnF,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC1F,YAAY,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACrF,YAAY,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,6BAA6B,EAC7B,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EACL,6BAA6B,EAC7B,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,GACd,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAGlF,OAAO,EACL,sBAAsB,EACtB,aAAa,EACb,sBAAsB,EACtB,oBAAoB,EACpB,qBAAqB,EACrB,wBAAwB,GACzB,MAAM,kCAAkC,CAAC;AAC1C,YAAY,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAC;AAC5F,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,gBAAgB,EAChB,sBAAsB,EACtB,4BAA4B,GAC7B,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,sBAAsB,EACtB,eAAe,EACf,uBAAuB,GACxB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,EACjB,gBAAgB,EAChB,yBAAyB,EACzB,eAAe,EACf,kBAAkB,EAClB,yBAAyB,EACzB,cAAc,EACd,eAAe,EACf,oBAAoB,GACrB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,mBAAmB,EACnB,eAAe,EACf,gBAAgB,EAChB,iBAAiB,EACjB,yBAAyB,EACzB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,+BAA+B,CAAC;AACvC,YAAY,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC"}
package/dist/index.js CHANGED
@@ -6,6 +6,8 @@ export * from './types/index.js';
6
6
  export * from './components/index.js';
7
7
  // Hooks (hooks/index.ts owns the list)
8
8
  export * from './hooks/index.js';
9
+ // External control of a loaded project (ProjectLoader ref / onSceneReady)
10
+ export { createSceneHandle } from './api/sceneHandle.js';
9
11
  // Utils
10
12
  export { cameraManager } from './utils/CameraSingleton.js';
11
13
  export { applyAnchorSettings, createCurves, createSunPosition, randomRange, } from './utils/utils3d.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3driseai/3drise-viewer",
3
- "version": "0.1.24",
3
+ "version": "0.1.25",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -39,6 +39,6 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@3driseai/3drise-common": "^1.0.1",
42
- "@3driseai/3drise-core": "^1.0.17"
42
+ "@3driseai/3drise-core": "^1.0.18"
43
43
  }
44
44
  }