@3driseai/3drise-viewer 0.1.12 → 0.1.14

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.
@@ -61,6 +61,9 @@ export interface EnvironmentManagerProps extends ObjectReadyProps {
61
61
  playerPosition?: Vector3;
62
62
  onTimeOfDayChange?: SkySystemProps['onTimeOfDayChange'];
63
63
  onTimeUpdate?: SkySystemProps['onTimeUpdate'];
64
+ /** False for a secondary canvas (preview, thumbnail) that must not take over
65
+ * the shared time-of-day clock. See SkySystemProps.driveTime. */
66
+ driveTime?: boolean;
64
67
  }
65
68
  declare const EnvironmentManager: React.ForwardRefExoticComponent<EnvironmentManagerProps & React.RefAttributes<SkySystemRef>>;
66
69
  export default EnvironmentManager;
@@ -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;CACjD;AAoBD,QAAA,MAAM,kBAAkB,8FAiGtB,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;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"}
@@ -23,7 +23,7 @@ const DEFAULT_HDR = {
23
23
  },
24
24
  };
25
25
  const ORIGIN = new Vector3(0, 0, 0);
26
- const EnvironmentManager = forwardRef(({ timeSettings, environment, hdrSettings, skySettings, cloudsSettings, terrainSettings, landscapeSettings, oceanSettings, fogSettings, cubeCameraResolution = 512, skyboxScale = 100000, playerPosition = ORIGIN, onTimeOfDayChange, onTimeUpdate, onObjectReady, onObjectDispose, }, ref) => {
26
+ 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
27
  const hdr = hdrSettings ?? environment?.hdr ?? DEFAULT_HDR;
28
28
  const sky = skySettings ?? environment?.sky;
29
29
  const clouds = cloudsSettings ?? environment?.clouds;
@@ -37,12 +37,17 @@ const EnvironmentManager = forwardRef(({ timeSettings, environment, hdrSettings,
37
37
  const skyActive = !!sky?.visible || sunSystemVisible;
38
38
  const sunIntensity = sky?.sunSystem?.intensity ?? 1;
39
39
  useEnvironmentProbe({
40
+ // Real-time sync moves the sun just as much as autoAnimate does; gating
41
+ // the refresh on autoAnimate alone left the capture frozen at whatever
42
+ // the sky looked like when the probe was built, so reflections drifted
43
+ // out of step with the sky and popped when something else forced a
44
+ // capture.
45
+ autoAnimate: !!timeSettings.autoAnimate || !!timeSettings.syncWithRealTime,
40
46
  hdrActive: isHdrActive(hdr),
41
47
  skyActive,
42
- autoAnimate: !!timeSettings.autoAnimate,
43
48
  resolution: cubeCameraResolution,
44
49
  });
45
- return (_jsxs(_Fragment, { children: [_jsx(HdrEnvironment, { hdr: hdr, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), _jsx(TerrainBuilder, { settings: terrain, skySettings: sky, timeSettings: timeSettings, sunIntensity: sunIntensity, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), _jsx(LandscapeBuilder, { settings: landscape, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), _jsx(OceanBuilder, { settings: ocean, skySettings: sky, timeSettings: timeSettings, sunIntensity: sunIntensity, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), _jsx(SkySystem, { ref: ref, timeSettings: timeSettings, visible: true, sunSystemVisible: sunSystemVisible, sunSize: sky?.sunSystem?.sunSize, moonSize: sky?.sunSystem?.moonSize, skyboxScale: skyboxScale, sunIntensity: sunIntensity, castShadow: sky?.sunSystem?.castShadow, shadowMapSize: sky?.sunSystem?.shadowMapSize, playerPosition: playerPosition, cloudsSettings: clouds, skyControllerSettings: sky, fogSettings: fog, onTimeOfDayChange: onTimeOfDayChange, onTimeUpdate: onTimeUpdate, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose })] }));
50
+ return (_jsxs(_Fragment, { children: [_jsx(HdrEnvironment, { hdr: hdr, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), _jsx(TerrainBuilder, { settings: terrain, skySettings: sky, timeSettings: timeSettings, sunIntensity: sunIntensity, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), _jsx(LandscapeBuilder, { settings: landscape, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), _jsx(OceanBuilder, { settings: ocean, skySettings: sky, timeSettings: timeSettings, sunIntensity: sunIntensity, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), _jsx(SkySystem, { ref: ref, timeSettings: timeSettings, driveTime: driveTime, visible: true, sunSystemVisible: sunSystemVisible, sunSize: sky?.sunSystem?.sunSize, moonSize: sky?.sunSystem?.moonSize, skyboxScale: skyboxScale, sunIntensity: sunIntensity, castShadow: sky?.sunSystem?.castShadow, shadowMapSize: sky?.sunSystem?.shadowMapSize, playerPosition: playerPosition, cloudsSettings: clouds, skyControllerSettings: sky, fogSettings: fog, onTimeOfDayChange: onTimeOfDayChange, onTimeUpdate: onTimeUpdate, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose })] }));
46
51
  });
47
52
  EnvironmentManager.displayName = 'EnvironmentManager';
48
53
  export default EnvironmentManager;
@@ -1 +1 @@
1
- {"version":3,"file":"Frame.d.ts","sourceRoot":"","sources":["../../src/components/Frame.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAI7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEtC,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAE,qBAAqB,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzJ,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKtD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,CAAC;AAE/B,MAAM,WAAW,UAAW,SAAQ,gBAAgB;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,cAAc,EAAE,qBAAqB,CAAC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,iBAAiB,CAAC,EAAE,CAAC,aAAa,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;CACpH;AAGD,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAoB,EAAE,aAAa,EAAE,gBAAqB,EAAE,YAAiB,EAAE,cAAc,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,GAAG,EAAE,UAAU,+BA2ClR"}
1
+ {"version":3,"file":"Frame.d.ts","sourceRoot":"","sources":["../../src/components/Frame.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAI7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEtC,OAAO,KAAK,EAAE,qBAAqB,EAAE,aAAa,EAAE,qBAAqB,EAAE,eAAe,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzJ,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKtD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EAAE,cAAc,EAAE,CAAC;AAE/B,MAAM,WAAW,UAAW,SAAQ,gBAAgB;IAChD,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,aAAa,EAAE,aAAa,CAAC;IAC7B,gBAAgB,CAAC,EAAE,eAAe,EAAE,CAAC;IACrC,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,cAAc,EAAE,qBAAqB,CAAC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,iBAAiB,CAAC,EAAE,CAAC,aAAa,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;CACpH;AAGD,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,aAAa,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAoB,EAAE,aAAa,EAAE,gBAAqB,EAAE,YAAiB,EAAE,cAAc,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,GAAG,EAAE,UAAU,+BAqDlR"}
@@ -33,7 +33,8 @@ export default function Frame({ url, isActive, createdObject, position, rotation
33
33
  useCursor(hovered);
34
34
  const enabledEffects = transformEffects.filter(e => e.enabled !== false);
35
35
  const animateMaterial = enabledEffects.length > 0 || colorEffects.some(e => e.enabled !== false);
36
- useObjectAnimation(createdObject, animateMaterial, { enabled: true, hovered }, frameRef);
36
+ // console.log(isActive)
37
+ useObjectAnimation(createdObject, animateMaterial, { enabled: !isActive, hovered }, frameRef);
37
38
  const scale = [
38
39
  0.9 * (layoutSettings.width || 1),
39
40
  0.9 * (layoutSettings.height || 1),
@@ -50,7 +51,8 @@ export default function Frame({ url, isActive, createdObject, position, rotation
50
51
  };
51
52
  if (!texture)
52
53
  return null;
53
- return (_jsx("mesh", { name: url, ref: frameRef, position: position, rotation: rotation, scale: scale, raycast: () => null, onPointerEnter: handlePointerEnter, onPointerLeave: handlePointerLeave, onClick: onClick, userData: {
54
+ return (_jsx("mesh", { name: url, ref: frameRef, position: position, rotation: rotation, scale: scale, onPointerEnter: handlePointerEnter, onPointerLeave: handlePointerLeave, onClick: onClick, userData: {
54
55
  url,
55
- }, children: children ? children : (_jsxs(_Fragment, { children: [_jsx(FrameGeometry, { shapeType: 'rectangle', layoutSettings: layoutSettings, scale: layoutSettings.outerFrameScale }), _jsx(MaterialLibrary, { materialSettings: materialSettings }), showFront && (_jsx(FrameImage, { ref: imageRef, texture: texture, shapeType: 'rectangle', position: [0, 0, 0.02] })), showBack && (_jsx(FrameImage, { texture: texture, shapeType: 'rectangle', position: [0, 0, -0.02], rotation: [0, Math.PI, 0], isBack: true }))] })) }));
56
+ }, children: children ? children :
57
+ (_jsxs(_Fragment, { children: [_jsx(FrameGeometry, { shapeType: 'rectangle', layoutSettings: layoutSettings, scale: layoutSettings.outerFrameScale }), _jsx(MaterialLibrary, { materialSettings: materialSettings }), showFront && (_jsx(FrameImage, { ref: imageRef, texture: texture, shapeType: 'rectangle', position: [0, 0, 0.02] })), showBack && (_jsx(FrameImage, { texture: texture, shapeType: 'rectangle', position: [0, 0, -0.02], rotation: [0, Math.PI, 0], isBack: true }))] })) }));
56
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FrameImage.d.ts","sourceRoot":"","sources":["../../src/components/FrameImage.tsx"],"names":[],"mappings":"AAeA,eAAO,MAAM,UAAU,EAUjB,GAAI,CAAC"}
1
+ {"version":3,"file":"FrameImage.d.ts","sourceRoot":"","sources":["../../src/components/FrameImage.tsx"],"names":[],"mappings":"AAgBA,eAAO,MAAM,UAAU,EAYjB,GAAI,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
+ import { IMAGE_KEY } from "@3driseai/3drise-core";
3
4
  import { FrameGeometry } from "./FrameGeometry.js";
4
5
  export const FrameImage = forwardRef(({ texture, shapeType, position, rotation, isBack = false, layoutSettings, }, ref) => {
5
6
  const width = layoutSettings?.width || 1;
@@ -10,6 +11,6 @@ export const FrameImage = forwardRef(({ texture, shapeType, position, rotation,
10
11
  width: width * imageScale,
11
12
  height: height * imageScale,
12
13
  };
13
- return (_jsxs("mesh", { ref: ref, raycast: () => null, position: position, rotation: rotation, children: [_jsx(FrameGeometry, { shapeType: shapeType, layoutSettings: scaledSettings }), _jsx("meshBasicMaterial", { map: texture, toneMapped: false, transparent: true })] }));
14
+ return (_jsxs("mesh", { ref: ref, raycast: () => null, userData: { [IMAGE_KEY]: true }, position: position, rotation: rotation, children: [_jsx(FrameGeometry, { shapeType: shapeType, layoutSettings: scaledSettings }), _jsx("meshBasicMaterial", { map: texture, toneMapped: false, transparent: true })] }));
14
15
  });
15
16
  FrameImage.displayName = 'FrameImage';
@@ -5,7 +5,6 @@ import { Object3D } from "three";
5
5
  import { type ThreeEvent } from "@react-three/fiber";
6
6
  export interface GalleryLayoutProps extends ObjectReadyProps {
7
7
  createdObject: CreatedObjectSettings;
8
- selectedFrameUrl?: string;
9
8
  handleObjectClick?: (createdObject: CreatedObjectSettings, ref: Object3D, event: ThreeEvent<MouseEvent>) => void;
10
9
  }
11
10
  declare const GalleryLayout: React.FC<GalleryLayoutProps>;
@@ -1 +1 @@
1
- {"version":3,"file":"GalleryLayout.d.ts","sourceRoot":"","sources":["../../src/components/GalleryLayout.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAGnE,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IACxD,aAAa,EAAE,qBAAqB,CAAC;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,aAAa,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;CACpH;AAGD,QAAA,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAW/C,CAAC;AACF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"GalleryLayout.d.ts","sourceRoot":"","sources":["../../src/components/GalleryLayout.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAG7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAGnE,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjC,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IACxD,aAAa,EAAE,qBAAqB,CAAC;IAErC,iBAAiB,CAAC,EAAE,CAAC,aAAa,EAAE,qBAAqB,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;CACpH;AAGD,QAAA,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAiC/C,CAAC;AACF,eAAe,aAAa,CAAC"}
@@ -1,10 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useObjectReady } from '../hooks/useObjectReady.js';
3
- import { useMemo, useRef } from 'react';
3
+ import { useMemo, useRef, useState } from 'react';
4
4
  import { updateCurrentLayoutSettings } from '@3driseai/3drise-core';
5
5
  import Frame from './Frame.js';
6
6
  import { ImageGeometry } from './ImageGeometry.js';
7
- const GalleryLayout = ({ createdObject, selectedFrameUrl, handleObjectClick, onObjectReady, onObjectDispose, }) => {
7
+ const GalleryLayout = ({ createdObject, handleObjectClick, onObjectReady, onObjectDispose, }) => {
8
+ const [selectedFrameUrl, setSelectedFrameUrl] = useState(undefined);
8
9
  const groupRef = useRef(null);
9
10
  useObjectReady(groupRef, createdObject, onObjectReady, onObjectDispose);
10
11
  const { config, materialSettings, animations } = createdObject;
@@ -14,6 +15,9 @@ const GalleryLayout = ({ createdObject, selectedFrameUrl, handleObjectClick, onO
14
15
  outerFrameScale: 1,
15
16
  };
16
17
  const { frames, layoutSettings } = useMemo(() => updateCurrentLayoutSettings(galleryLayout), [galleryLayout]);
17
- return (_jsx("group", { ref: groupRef, scale: [1, 1, 1], position: [0, 0, 0], rotation: [0, 0, 0], children: frames.map((frame, index) => (_jsx(Frame, { url: frame.url, isActive: selectedFrameUrl === frame.url, createdObject: createdObject, position: frame.position, rotation: frame.rotation, hoverSettings: { sensitivity: 0.5, applyToChildren: false }, transformEffects: animations?.transform?.effects || [], layoutSettings: layoutSettings, side: galleryLayout?.side || 2, materialSettings: materialSettings, handleObjectClick: handleObjectClick, children: layoutSettings.geometryType !== 'none' && (_jsx(ImageGeometry, { url: frame.url, geometryType: layoutSettings.geometryType, outerFrameScale: layoutSettings.outerFrameScale })) }, index))) }));
18
+ return (_jsx("group", { ref: groupRef, scale: [1, 1, 1], position: [0, 0, 0], rotation: [0, 0, 0], children: frames.map((frame, index) => (_jsx(Frame, { url: frame.url, isActive: selectedFrameUrl === frame.url, createdObject: createdObject, position: frame.position, rotation: frame.rotation, hoverSettings: { sensitivity: 0.5, applyToChildren: false }, transformEffects: animations?.transform?.effects || [], layoutSettings: layoutSettings, side: galleryLayout?.side ?? 2, materialSettings: materialSettings, handleObjectClick: (createdObject, ref, event) => {
19
+ setSelectedFrameUrl(frame.url);
20
+ handleObjectClick?.(createdObject, ref, event);
21
+ }, children: layoutSettings.geometryType !== 'none' && (_jsx(ImageGeometry, { url: frame.url, geometryType: layoutSettings.geometryType, outerFrameScale: layoutSettings.outerFrameScale, side: galleryLayout?.side ?? 2 })) }, index))) }));
18
22
  };
19
23
  export default GalleryLayout;
@@ -1 +1 @@
1
- {"version":3,"file":"ImageGeometry.d.ts","sourceRoot":"","sources":["../../src/components/ImageGeometry.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzF,MAAM,WAAW,kBAAkB;IAC/B,YAAY,EAAE,YAAY,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,aAAa,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,eAAO,MAAM,aAAa,EAuDpB,GAAI,CAAC"}
1
+ {"version":3,"file":"ImageGeometry.d.ts","sourceRoot":"","sources":["../../src/components/ImageGeometry.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzF,MAAM,WAAW,kBAAkB;IAC/B,YAAY,EAAE,YAAY,CAAC;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,aAAa,CAAC,EAAE,WAAW,CAAC;CAC/B;AASD,eAAO,MAAM,aAAa,EAiFpB,GAAI,CAAC"}
@@ -1,9 +1,15 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { forwardRef, useEffect, useMemo, useState } from 'react';
3
- import { DoubleSide, Mesh, MeshBasicMaterial } from 'three';
3
+ import { Mesh, MeshBasicMaterial } from 'three';
4
4
  import { createMeshByType } from '@3driseai/3drise-core';
5
- import { texturesManager } from '@3driseai/3drise-core';
6
- export const ImageGeometry = forwardRef(({ geometryType, url, position = [0, 0, 0], rotation = [0, 0, 0], scale = [1, 1, 1], }, ref) => {
5
+ import { texturesManager, IMAGE_KEY } from '@3driseai/3drise-core';
6
+ // Stable references so unrelated re-renders (e.g. hover state toggles on the
7
+ // parent Frame) don't invalidate the meshConfig/createdMesh memos below and
8
+ // leak a fresh Mesh/BufferGeometry/Material every render.
9
+ const DEFAULT_POSITION = [0, 0, 0];
10
+ const DEFAULT_ROTATION = [0, 0, 0];
11
+ const DEFAULT_SCALE = [1, 1, 1];
12
+ export const ImageGeometry = forwardRef(({ geometryType, url, position = DEFAULT_POSITION, rotation = DEFAULT_ROTATION, scale = DEFAULT_SCALE, side = 2, outerFrameScale = 1, }, ref) => {
7
13
  const [texture, setTexture] = useState(null);
8
14
  useEffect(() => {
9
15
  const textureName = url.split('/').pop()?.split('.')[0] || `texture-${Date.now()}`;
@@ -40,12 +46,13 @@ export const ImageGeometry = forwardRef(({ geometryType, url, position = [0, 0,
40
46
  }, [geometryType, position, rotation, scale]);
41
47
  const createdMesh = useMemo(() => {
42
48
  const mesh = createMeshByType(meshConfig)?.mesh;
49
+ mesh.userData = { [IMAGE_KEY]: true };
43
50
  if (!(mesh instanceof Mesh))
44
51
  return null;
45
52
  if (texture) {
46
53
  mesh.material = new MeshBasicMaterial({
47
54
  map: texture,
48
- side: DoubleSide,
55
+ side: side,
49
56
  toneMapped: false,
50
57
  transparent: true,
51
58
  polygonOffset: true,
@@ -55,6 +62,31 @@ export const ImageGeometry = forwardRef(({ geometryType, url, position = [0, 0,
55
62
  }
56
63
  return mesh;
57
64
  }, [meshConfig, texture]);
65
+ // Every recompute above allocates a new geometry + material; dispose the
66
+ // previous instance so they don't leak GPU resources.
67
+ useEffect(() => {
68
+ return () => {
69
+ createdMesh?.geometry?.dispose();
70
+ const material = createdMesh?.material;
71
+ if (Array.isArray(material))
72
+ material.forEach((m) => m.dispose());
73
+ else
74
+ material?.dispose();
75
+ };
76
+ }, [createdMesh]);
77
+ // `side` isn't a createdMesh dependency (changing it shouldn't rebuild the
78
+ // geometry), so apply it to the existing material reactively instead.
79
+ useEffect(() => {
80
+ const material = createdMesh?.material;
81
+ if (!material)
82
+ return;
83
+ if (Array.isArray(material))
84
+ material.forEach((m) => { m.side = side; m.needsUpdate = true; });
85
+ else {
86
+ material.side = side;
87
+ material.needsUpdate = true;
88
+ }
89
+ }, [createdMesh, side]);
58
90
  if (!createdMesh)
59
91
  return null;
60
92
  return (_jsx("group", { position: position, rotation: rotation, children: _jsx("primitive", { name: url, ref: ref, object: createdMesh }) }));
@@ -1 +1 @@
1
- {"version":3,"file":"ObjectNode.d.ts","sourceRoot":"","sources":["../../src/components/ObjectNode.tsx"],"names":[],"mappings":"AAgBA,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;AAErD,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;AAgBF,QAAA,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAmHzC,CAAC;AACF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"ObjectNode.d.ts","sourceRoot":"","sources":["../../src/components/ObjectNode.tsx"],"names":[],"mappings":"AAgBA,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;AAErD,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;AAgBF,QAAA,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAqHzC,CAAC;AACF,eAAe,UAAU,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"SkyController.d.ts","sourceRoot":"","sources":["../../src/components/SkyController.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAS7D,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEvE,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IACxD,QAAQ,EAAE,WAAW,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,CAAC;CACtD;AAED,iBAAS,aAAa,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,GAAG,EAAE,kBAAkB,GAwK8H,GAAG,CACtQ;AA6BD,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"SkyController.d.ts","sourceRoot":"","sources":["../../src/components/SkyController.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAS7D,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAEvE,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IACxD,QAAQ,EAAE,WAAW,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,KAAK,IAAI,CAAC;CACtD;AAED,iBAAS,aAAa,CAAC,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,GAAG,EAAE,kBAAkB,GAqL8H,GAAG,CACtQ;AA6BD,eAAe,aAAa,CAAC"}
@@ -74,8 +74,15 @@ function SkyController({ settings, timeSettings, scale = 1000, onSettingsChange,
74
74
  azimuth: sunAzimuth,
75
75
  ...atmosphericParams,
76
76
  };
77
- handleSettings(newSettings);
78
- if (!state.autoAnimate) {
77
+ // While time is advancing, the environment probe is already re-capturing
78
+ // the cube map on its own timer. Letting handleSettings capture as well
79
+ // meant six faces rendered from two independent schedulers for the same
80
+ // moving sun.
81
+ const applied = handleSettings(newSettings, state.advancing);
82
+ // Only on a real change, and only when time is not running: this runs
83
+ // every frame now, and an unconditional call would dispatch a settings
84
+ // write per frame in a host that supplies this callback.
85
+ if (applied && !state.advancing) {
79
86
  onSettingsChange?.(newSettings);
80
87
  }
81
88
  }, [settings, onSettingsChange]);
@@ -132,22 +139,28 @@ function SkyController({ settings, timeSettings, scale = 1000, onSettingsChange,
132
139
  isAnimatingRef.current = false;
133
140
  cubeCameraManager.updateEnvironment();
134
141
  };
135
- const handleSettings = (newSettings) => {
142
+ /** Returns whether the settings were actually applied, so callers can tell a
143
+ * real change from a no-op. `skipEnvUpdate` leaves the cube-camera capture
144
+ * to whoever else is already scheduling it. */
145
+ const handleSettings = (newSettings, skipEnvUpdate = false) => {
136
146
  if (!skyRef.current || isAnimatingRef.current || !newSettings)
137
- return;
147
+ return false;
138
148
  if (!hasActualChanges(newSettings, previousSettings.current))
139
- return;
149
+ return false;
140
150
  if (previousSettings.current?.visible !== newSettings.visible) {
141
151
  toggleSky(newSettings.visible);
142
152
  }
143
153
  if (!skyRef.current.visible) {
144
154
  previousSettings.current = { ...newSettings };
145
- return;
155
+ return false;
146
156
  }
147
157
  updateUniforms(newSettings);
148
158
  updateSun();
149
- cubeCameraManager.updateEnvironment();
159
+ if (!skipEnvUpdate) {
160
+ cubeCameraManager.updateEnvironment();
161
+ }
150
162
  previousSettings.current = { ...newSettings };
163
+ return true;
151
164
  };
152
165
  const handleMouseMove = (mouse) => {
153
166
  const handlers = settings.handlers;
@@ -48,6 +48,18 @@ export interface SkySystemProps extends ObjectReadyProps {
48
48
  fogSettings?: FogSettings;
49
49
  onTimeOfDayChange?: (timeOfDay: string, elapsedTime: number) => void;
50
50
  onTimeUpdate?: (timeOfDay: number) => void;
51
+ /** Whether this instance drives skySystemManager's clock.
52
+ *
53
+ * The manager is a singleton, so every mounted SkySystem shares one clock.
54
+ * A second one that writes to it — a market preview, a thumbnail canvas,
55
+ * an embed on the same page — pushes its own timeSettings in and stops
56
+ * whatever the first one was doing. Pass false for any secondary canvas:
57
+ * it then renders the scene's real time of day instead of fighting for it.
58
+ *
59
+ * Defaulting to true is safe because the manager hands the clock to the
60
+ * first claimant only; a forgotten `driveTime={false}` degrades to a
61
+ * read-only mount rather than to two components ticking the same clock. */
62
+ driveTime?: boolean;
51
63
  }
52
64
  declare const SkySystem: React.ForwardRefExoticComponent<SkySystemProps & React.RefAttributes<SkySystemRef>>;
53
65
  export default SkySystem;
@@ -1 +1 @@
1
- {"version":3,"file":"SkySystem.d.ts","sourceRoot":"","sources":["../../src/components/SkySystem.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAOtE,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,YAAY;IACzB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,KAAK,CAAC,OAAO,CAAC;CACxC;AAED,MAAM,WAAW,cAAe,SAAQ,gBAAgB;IACpD,YAAY,EAAE,YAAY,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;yDAEqD;IACrD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC;IAC/B;;;uBAGmB;IACnB,cAAc,CAAC,EAAE,wBAAwB,CAAC;IAC1C,qBAAqB,CAAC,EAAE,WAAW,CAAC;IACpC;wDACoD;IACpD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C;AAED,QAAA,MAAM,SAAS,qFAmHb,CAAC;AAGH,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"SkySystem.d.ts","sourceRoot":"","sources":["../../src/components/SkySystem.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpF,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAOtE,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,YAAY;IACzB,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,KAAK,CAAC,OAAO,CAAC;CACxC;AAED,MAAM,WAAW,cAAe,SAAQ,gBAAgB;IACpD,YAAY,EAAE,YAAY,CAAC;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;yDAEqD;IACrD,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC;IAC/B;;;uBAGmB;IACnB,cAAc,CAAC,EAAE,wBAAwB,CAAC;IAC1C,qBAAqB,CAAC,EAAE,WAAW,CAAC;IACpC;wDACoD;IACpD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C;;;;;;;;;;gFAU4E;IAC5E,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,QAAA,MAAM,SAAS,qFAwJb,CAAC;AAGH,eAAe,SAAS,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useObjectReady } from '../hooks/useObjectReady.js';
3
- import { useEffect, useLayoutEffect, useRef, forwardRef, useImperativeHandle } from 'react';
3
+ import { useEffect, useLayoutEffect, useMemo, useRef, forwardRef, useImperativeHandle } from 'react';
4
4
  import { useFrame } from '@react-three/fiber';
5
5
  import { skySystemManager } from '@3driseai/3drise-core';
6
6
  import Skybox from './Skybox.js';
@@ -9,10 +9,15 @@ import SunLight from './SunLight.js';
9
9
  import SkyController from './SkyController.js';
10
10
  import SceneFog from './SceneFog.js';
11
11
  import CloudsGenerator from './CloudsGenerator.js';
12
- const SkySystem = forwardRef(({ timeSettings, visible = true, sunSystemVisible = false, sunSize = 1, moonSize = 1, skyboxScale = 100000, sunIntensity = 1, castShadow = true, shadowMapSize = 2048, playerPosition, cloudsSettings, skyControllerSettings, fogSettings, onTimeOfDayChange, onTimeUpdate, onObjectReady, onObjectDispose, }, ref) => {
12
+ const SkySystem = forwardRef(({ timeSettings, visible = true, sunSystemVisible = false, sunSize = 1, moonSize = 1, skyboxScale = 100000, sunIntensity = 1, castShadow = true, shadowMapSize = 2048, playerPosition, cloudsSettings, skyControllerSettings, fogSettings, onTimeOfDayChange, onTimeUpdate, driveTime = true, onObjectReady, onObjectDispose, }, ref) => {
13
13
  const previousTimeOfDayRef = useRef(null);
14
14
  const rootRef = useRef(null);
15
15
  const ready = { onObjectReady, onObjectDispose };
16
+ // Identity for the driver claim. A plain object rather than a boolean flag so
17
+ // the manager can tell instances apart and release the clock to the next one
18
+ // when this one unmounts.
19
+ const driverToken = useMemo(() => ({}), []);
20
+ const isDriverRef = useRef(false);
16
21
  useObjectReady(rootRef, { timeSettings, sunSystemVisible, skyboxScale, sunIntensity, skyControllerSettings, fogSettings }, onObjectReady, onObjectDispose);
17
22
  useImperativeHandle(ref, () => ({
18
23
  setTime: (h, m) => skySystemManager.setTime(h, m),
@@ -20,20 +25,51 @@ const SkySystem = forwardRef(({ timeSettings, visible = true, sunSystemVisible =
20
25
  getTimeOfDay: () => skySystemManager.getTimeOfDay(),
21
26
  getSunDirection: () => skySystemManager.getSunDirection(),
22
27
  }));
23
- // useLayoutEffect so the manager is registered before useFrame's first rAF
24
- // callback — a regular useEffect runs after paint, and the first tick is
25
- // dropped with manager.enabled still false.
28
+ // Claim the clock before anything reads it. useLayoutEffect for the same
29
+ // reason the settings push below uses one — a regular useEffect runs after
30
+ // paint, and the first rAF would find the manager still disabled.
26
31
  useLayoutEffect(() => {
32
+ if (!driveTime) {
33
+ isDriverRef.current = false;
34
+ return;
35
+ }
36
+ isDriverRef.current = skySystemManager.claimDriver(driverToken);
37
+ return () => {
38
+ isDriverRef.current = false;
39
+ skySystemManager.releaseDriver(driverToken);
40
+ };
41
+ }, [driveTime, driverToken]);
42
+ // Only the driver writes. This is the push half of the loop; the manager
43
+ // ignores a timeOfDay that is merely its own echo coming back through the
44
+ // host's store, so a write-back during playback does not rewind the clock.
45
+ useLayoutEffect(() => {
46
+ if (!isDriverRef.current)
47
+ return;
27
48
  skySystemManager.setTimeSettings(timeSettings);
28
- }, [timeSettings]);
49
+ }, [timeSettings, driveTime]);
29
50
  useEffect(() => {
30
- if (!onTimeUpdate)
51
+ if (!onTimeUpdate || !driveTime)
31
52
  return;
32
53
  skySystemManager.setOnTimeSync(onTimeUpdate);
33
54
  return () => { skySystemManager.setOnTimeSync(null); };
34
- }, [onTimeUpdate]);
55
+ }, [onTimeUpdate, driveTime]);
56
+ // Ticked whenever time is enabled, not only while it animates: `elapsedTime`
57
+ // and `delta` come out of here, and those are what every consumer's colour
58
+ // smoothing and the stars' twinkle read. Gating this on autoAnimate froze
59
+ // both and collapsed every smoothing lerp to an instant snap, which is what
60
+ // made each discontinuity in the sun curve so visible.
35
61
  useFrame((_, delta) => {
36
- if (!timeSettings.enabled || !timeSettings.autoAnimate)
62
+ if (!isDriverRef.current) {
63
+ // Pick the clock up if the instance that held it has gone (a preview
64
+ // canvas unmounting, an embed swapping scenes). Without this a
65
+ // failed claim at mount time would leave the clock permanently
66
+ // unowned and nothing would ever tick it again.
67
+ if (!driveTime || !skySystemManager.claimDriver(driverToken))
68
+ return;
69
+ isDriverRef.current = true;
70
+ skySystemManager.setTimeSettings(timeSettings);
71
+ }
72
+ if (!timeSettings.enabled)
37
73
  return;
38
74
  skySystemManager.tick(delta);
39
75
  const current = skySystemManager.getTimeOfDay();
@@ -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,CAwK/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,CA2K/B,CAAC;AACF,eAAe,KAAK,CAAC"}
@@ -165,8 +165,11 @@ const Stars = ({ settings, timeSettings, sunSystemEnabled = false, onObjectReady
165
165
  },
166
166
  });
167
167
  const handleTimeUpdate = useCallback((state) => {
168
- const { normalizedTime, isDaytime, elapsedTime, delta, autoAnimate } = state;
169
- if (!autoAnimate || !sunSystemEnabled)
168
+ // Not gated on autoAnimate any more: scrubbing the time slider to
169
+ // midnight has to bring the stars up the same way playing into midnight
170
+ // does, and elapsedTime (the twinkle clock) now advances in manual mode.
171
+ const { normalizedTime, isDaytime, elapsedTime, delta } = state;
172
+ if (!sunSystemEnabled)
170
173
  return;
171
174
  if (!isDaytime) {
172
175
  targetOpacityRef.current = 1;
@@ -1 +1 @@
1
- {"version":3,"file":"LightningEffect.d.ts","sourceRoot":"","sources":["../../../src/components/effects/LightningEffect.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,UAAU,oBAAqB,SAAQ,gBAAgB;IACnD,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,eAAe,CAAC;IACxB,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;AAsDD,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAwLnD,CAAC;AACF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"LightningEffect.d.ts","sourceRoot":"","sources":["../../../src/components/effects/LightningEffect.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE/E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,UAAU,oBAAqB,SAAQ,gBAAgB;IACnD,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,eAAe,CAAC;IACxB,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;AAsDD,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA2LnD,CAAC;AACF,eAAe,eAAe,CAAC"}
@@ -60,7 +60,10 @@ const LightningEffect = ({ boundingRadius, config, animations, onObjectReady, on
60
60
  const startValuesCacheRef = useRef({});
61
61
  const rootRef = useRef(null);
62
62
  useObjectReady(rootRef, config, onObjectReady, onObjectDispose);
63
- const depth = Math.min(Math.max(branchDepth, 2), 6);
63
+ const requestedDepth = Number(branchDepth);
64
+ const depth = Number.isFinite(requestedDepth)
65
+ ? Math.min(Math.max(Math.floor(requestedDepth), 2), 6)
66
+ : 2;
64
67
  const N = Math.pow(2, depth) + 1; // vertex count: 5, 9, 17, 33, 65
65
68
  const coreCol = useMemo(() => new THREE.Color(color), [color]);
66
69
  const glowCol = useMemo(() => new THREE.Color(glowColor), [glowColor]);
@@ -22,7 +22,8 @@ export interface UseEnvironmentProbeOptions {
22
22
  hdrActive: boolean;
23
23
  /** Analytic sky or the sun rig is visible — something worth capturing. */
24
24
  skyActive: boolean;
25
- /** Time of day is animating, so the capture goes stale and needs refreshing. */
25
+ /** Time of day is advancing autoAnimate OR real-time sync so the capture
26
+ * goes stale and needs refreshing. */
26
27
  autoAnimate: boolean;
27
28
  resolution?: number;
28
29
  intervalMs?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"useEnvironmentProbe.d.ts","sourceRoot":"","sources":["../../src/hooks/useEnvironmentProbe.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,0BAA0B;IACvC,sEAAsE;IACtE,SAAS,EAAE,OAAO,CAAC;IACnB,0EAA0E;IAC1E,SAAS,EAAE,OAAO,CAAC;IACnB,gFAAgF;IAChF,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,mBAAmB,CAAC,EAChC,SAAS,EACT,SAAS,EACT,WAAW,EACX,UAAgB,EAChB,UAAgB,GACnB,EAAE,0BAA0B,GAAG,IAAI,CA6BnC;AAED,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"useEnvironmentProbe.d.ts","sourceRoot":"","sources":["../../src/hooks/useEnvironmentProbe.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,0BAA0B;IACvC,sEAAsE;IACtE,SAAS,EAAE,OAAO,CAAC;IACnB,0EAA0E;IAC1E,SAAS,EAAE,OAAO,CAAC;IACnB;2CACuC;IACvC,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,mBAAmB,CAAC,EAChC,SAAS,EACT,SAAS,EACT,WAAW,EACX,UAAgB,EAChB,UAAgB,GACnB,EAAE,0BAA0B,GAAG,IAAI,CA6BnC;AAED,eAAe,mBAAmB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"useObjectEdges.d.ts","sourceRoot":"","sources":["../../src/hooks/useObjectEdges.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAmH/D,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE,cAAc,GAAG,IAAI,CA6ChH"}
1
+ {"version":3,"file":"useObjectEdges.d.ts","sourceRoot":"","sources":["../../src/hooks/useObjectEdges.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAmH/D,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,CAAC,EAAE,cAAc,GAAG,IAAI,CA8DhH"}
@@ -131,13 +131,30 @@ export function useObjectEdges(objectId, edgesSettings, objectSource) {
131
131
  }
132
132
  setObject(resolveObject3D(objectSource) ?? findById(objectId));
133
133
  }, [edgesEnabled, objectId, objectSource]);
134
+ // Descendant meshes (e.g. gallery images) can still be loading their
135
+ // texture asynchronously when `object` first resolves, so the initial
136
+ // build below can run before there's anything to outline. Poll the real
137
+ // mesh count each frame and bump a tick when it changes so edges get
138
+ // rebuilt once the subtree actually has geometry.
139
+ const meshCountRef = useRef(-1);
140
+ const [structureTick, setStructureTick] = useState(0);
141
+ useFrame(() => {
142
+ if (!object)
143
+ return;
144
+ const count = collectMeshes(object).length;
145
+ if (count !== meshCountRef.current) {
146
+ meshCountRef.current = count;
147
+ setStructureTick((t) => t + 1);
148
+ }
149
+ });
134
150
  const edgesGroup = useMemo(() => {
135
151
  if (!object || !edgesSettings.enabled)
136
152
  return null;
137
153
  return buildEdgesGroup(object, edgesSettings);
138
- // Rebuild when geometry-affecting settings change
154
+ // Rebuild when geometry-affecting settings change, or the subtree's
155
+ // mesh count changes (structureTick — see the polling effect above).
139
156
  // eslint-disable-next-line react-hooks/exhaustive-deps
140
- }, [object, edgesSettings.type, edgesSettings.enabled, edgesSettings.tubeRadius, edgesSettings.cubeSize]);
157
+ }, [object, edgesSettings.type, edgesSettings.enabled, edgesSettings.tubeRadius, edgesSettings.cubeSize, structureTick]);
141
158
  // Attach edges to the live object so they move with it
142
159
  useEffect(() => {
143
160
  if (!object || !edgesGroup)
@@ -1 +1 @@
1
- {"version":3,"file":"useSkySystem.d.ts","sourceRoot":"","sources":["../../src/hooks/useSkySystem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAIpC,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACxF,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC;AAE7C,MAAM,WAAW,mBAAmB;IAChC,YAAY,EAAE,YAAY,CAAC;IAC3B,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC7C,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC;IAC5B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,KAAK,CAAC,OAAO,CAAC;CACxC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CAqD7E;AACD,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"useSkySystem.d.ts","sourceRoot":"","sources":["../../src/hooks/useSkySystem.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAIpC,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACxF,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC;AAE7C,MAAM,WAAW,mBAAmB;IAChC,YAAY,EAAE,YAAY,CAAC;IAC3B,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IAC7C,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,KAAK,CAAC,OAAO,CAAC;IAC5B,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,eAAe,EAAE,MAAM,KAAK,CAAC,OAAO,CAAC;CACxC;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CA6D7E;AACD,eAAe,YAAY,CAAC"}
@@ -1,15 +1,20 @@
1
- import { useRef, useCallback, useEffect, useLayoutEffect } from 'react';
1
+ import { useRef, useCallback, useEffect } from 'react';
2
2
  import { useFrame } from '@react-three/fiber';
3
3
  import { skySystemManager } from '@3driseai/3drise-core';
4
4
  export function useSkySystem(options) {
5
5
  const { timeSettings, onTimeUpdate, onTimeOfDayChange, enabled = true } = options;
6
6
  const previousTimeOfDayRef = useRef(null);
7
- // Sync time settings to the manager whenever they change.
8
- // useLayoutEffect ensures the manager is registered before useFrame's
9
- // first rAF callback runs (regular useEffect runs after paint, too late).
10
- useLayoutEffect(() => {
11
- skySystemManager.setTimeSettings(timeSettings);
12
- }, [timeSettings]);
7
+ // READ-ONLY, deliberately. This hook used to push timeSettings into the
8
+ // manager as well, which meant every leaf that used it — Skybox, SunLight,
9
+ // SkyController, Stars, Clouds was a writer to a singleton clock. A
10
+ // preview canvas mounting its own Skybox with its own timeSettings could
11
+ // therefore stop the editor's day cycle and snap it to noon, and nothing
12
+ // put it back. SkySystem owns the write now; see its `driveTime` prop.
13
+ //
14
+ // Ordering is fine without a layout effect here: React runs child layout
15
+ // effects before the parent's, so SkySystem's push lands before the first
16
+ // rAF either way, and the manual-mode branch below computes from the passed
17
+ // timeOfDay rather than from manager state.
13
18
  // Manual time mode: respond immediately when timeOfDay changes
14
19
  useEffect(() => {
15
20
  if (!enabled || !timeSettings.enabled || timeSettings.autoAnimate)
@@ -22,9 +27,11 @@ export function useSkySystem(options) {
22
27
  previousTimeOfDayRef.current = state.timeOfDay;
23
28
  onTimeUpdate?.(state);
24
29
  }, [timeSettings.timeOfDay, timeSettings.enabled, timeSettings.autoAnimate, enabled, onTimeUpdate, onTimeOfDayChange]);
25
- // Auto-animate mode: read state every frame (SkySystem or user is responsible for ticking)
30
+ // Read manager state every frame while time is enabled. Not gated on
31
+ // autoAnimate: `delta` and `elapsedTime` advance in manual mode too now, and
32
+ // consumers use them for colour smoothing and twinkle.
26
33
  useFrame(() => {
27
- if (!enabled || !timeSettings.enabled || !timeSettings.autoAnimate)
34
+ if (!enabled || !timeSettings.enabled)
28
35
  return;
29
36
  const state = skySystemManager.getState();
30
37
  if (previousTimeOfDayRef.current !== null &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@3driseai/3drise-viewer",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
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.7"
42
+ "@3driseai/3drise-core": "^1.0.9"
43
43
  }
44
44
  }