@3driseai/3drise-viewer 0.1.9 → 0.1.11

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 (60) hide show
  1. package/dist/components/CloudsGenerator.d.ts.map +1 -1
  2. package/dist/components/CloudsGenerator.js +3 -1
  3. package/dist/components/EnvironmentManager.d.ts +30 -14
  4. package/dist/components/EnvironmentManager.d.ts.map +1 -1
  5. package/dist/components/EnvironmentManager.js +7 -2
  6. package/dist/components/effects/DataStreamEffect.d.ts.map +1 -1
  7. package/dist/components/effects/DataStreamEffect.js +14 -8
  8. package/dist/components/effects/NeuralNetworkEffect.d.ts.map +1 -1
  9. package/dist/components/effects/NeuralNetworkEffect.js +11 -9
  10. package/dist/components/volumetricClouds/Cirrus.d.ts +4 -0
  11. package/dist/components/volumetricClouds/Cirrus.d.ts.map +1 -1
  12. package/dist/components/volumetricClouds/Cirrus.js +4 -0
  13. package/dist/components/volumetricClouds/Cumulonimbus.js +2 -2
  14. package/dist/components/volumetricClouds/Cumulus.js +2 -2
  15. package/dist/components/volumetricClouds/Stratocumulus.js +2 -2
  16. package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts +4 -1
  17. package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts.map +1 -1
  18. package/dist/components/volumetricClouds/VolumetricCloudsPass.js +45 -3
  19. package/dist/components/volumetricClouds/types.d.ts +3 -1
  20. package/dist/components/volumetricClouds/types.d.ts.map +1 -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 +1 -0
  24. package/dist/hooks/useCloudLive.d.ts +1 -0
  25. package/dist/hooks/useCloudLive.d.ts.map +1 -1
  26. package/dist/hooks/useCloudLive.js +2 -1
  27. package/dist/hooks/useThunder.d.ts +37 -0
  28. package/dist/hooks/useThunder.d.ts.map +1 -0
  29. package/dist/hooks/useThunder.js +145 -0
  30. package/dist/index.d.ts +1 -1
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +1 -1
  33. package/dist/shaders/clouds/CloudShadowMaterial.d.ts +52 -0
  34. package/dist/shaders/clouds/CloudShadowMaterial.d.ts.map +1 -0
  35. package/dist/shaders/clouds/CloudShadowMaterial.js +110 -0
  36. package/dist/shaders/clouds/CloudVolumeMaterial.d.ts +10 -0
  37. package/dist/shaders/clouds/CloudVolumeMaterial.d.ts.map +1 -1
  38. package/dist/shaders/clouds/CloudVolumeMaterial.js +38 -2
  39. package/dist/shaders/glsl/cloudCore.glsl.d.ts +3 -3
  40. package/dist/shaders/glsl/cloudCore.glsl.d.ts.map +1 -1
  41. package/dist/shaders/glsl/cloudCore.glsl.js +81 -9
  42. package/dist/shaders/glsl/cloudShadow.glsl.d.ts +15 -0
  43. package/dist/shaders/glsl/cloudShadow.glsl.d.ts.map +1 -0
  44. package/dist/shaders/glsl/cloudShadow.glsl.js +35 -0
  45. package/dist/types/cloudConfigs.d.ts +53 -0
  46. package/dist/types/cloudConfigs.d.ts.map +1 -1
  47. package/dist/types/cloudConfigs.js +83 -51
  48. package/dist/types/index.d.ts +2 -2
  49. package/dist/types/index.d.ts.map +1 -1
  50. package/dist/types/index.js +1 -1
  51. package/dist/utils/cloudShadowMap.d.ts +43 -0
  52. package/dist/utils/cloudShadowMap.d.ts.map +1 -0
  53. package/dist/utils/cloudShadowMap.js +60 -0
  54. package/dist/utils/cloudUniforms.d.ts +6 -1
  55. package/dist/utils/cloudUniforms.d.ts.map +1 -1
  56. package/dist/utils/cloudUniforms.js +18 -0
  57. package/dist/utils/gpuProfiler.d.ts +33 -0
  58. package/dist/utils/gpuProfiler.d.ts.map +1 -0
  59. package/dist/utils/gpuProfiler.js +115 -0
  60. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"CloudsGenerator.d.ts","sourceRoot":"","sources":["../../src/components/CloudsGenerator.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAOtE,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC1D;sFACkF;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,GAAG,IAAI,CAAC;IACpD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA4CnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"CloudsGenerator.d.ts","sourceRoot":"","sources":["../../src/components/CloudsGenerator.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAOtE,MAAM,WAAW,oBAAqB,SAAQ,gBAAgB;IAC1D;sFACkF;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,GAAG,IAAI,CAAC;IACpD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA8CnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useMemo } from 'react';
3
- import { CLOUD_DECK_DEFAULTS, normalizeCirrus, normalizeCloudDeck, normalizeCloudQuality } from '../types/cloudConfigs.js';
3
+ import { CLOUD_DECK_DEFAULTS, normalizeCirrus, normalizeCloudDeck, normalizeCloudQuality, normalizeThunder } from '../types/cloudConfigs.js';
4
4
  import Cumulus from './volumetricClouds/Cumulus.js';
5
5
  import Stratocumulus from './volumetricClouds/Stratocumulus.js';
6
6
  import Cumulonimbus from './volumetricClouds/Cumulonimbus.js';
@@ -25,6 +25,7 @@ const CloudsGenerator = ({ settings, skySettings, timeSettings, sunIntensity, on
25
25
  const deck = useMemo(() => normalizeCloudDeck(settings?.config), [settings?.config]);
26
26
  const cirrus = useMemo(() => normalizeCirrus(settings?.cirrus), [settings?.cirrus]);
27
27
  const quality = useMemo(() => normalizeCloudQuality(settings?.quality), [settings?.quality]);
28
+ const thunder = useMemo(() => normalizeThunder(settings?.thunder), [settings?.thunder]);
28
29
  const deckOn = !!deck?.enabled;
29
30
  const cirrusOn = !!cirrus?.enabled;
30
31
  // The cirrus-only branch ignores the deck entirely (it passes deck={null} to the
@@ -37,6 +38,7 @@ const CloudsGenerator = ({ settings, skySettings, timeSettings, sunIntensity, on
37
38
  deck: deckOrDefault,
38
39
  cirrus: cirrusOn ? cirrus : null,
39
40
  quality,
41
+ thunder,
40
42
  skySettings,
41
43
  timeSettings,
42
44
  sunIntensity,
@@ -4,32 +4,46 @@ import { type SkySystemRef, type SkySystemProps } from './SkySystem';
4
4
  import type { EnvironmentConfig, FogSettings, HdrSettings, SkySettings, TimeSettings } from '@3driseai/3drise-core';
5
5
  import type { VolumetricCloudsSettings } from '../types/cloudConfigs';
6
6
  import type { ProceduralTerrainSettings } from '../types/terrainConfigs';
7
+ import type { LandscapeSettings } from '../types/landscapeConfigs';
8
+ import type { OceanWaterSettings } from '../types/oceanConfigs';
7
9
  import type { ObjectReadyProps } from '../types/objectReady';
8
10
  /**
9
11
  * The whole environment in one component: HDR background, image-based lighting,
10
- * sky, sun, fog, clouds and terrain.
12
+ * sky, sun, fog, clouds, terrain, landscape and water.
11
13
  *
12
14
  * This is the *composed* entry point, for SceneBuilder and for anyone embedding a
13
15
  * published scene, where the settings arrive as one saved blob and nothing
14
16
  * re-renders unless the project changes.
15
17
  *
16
- * A host with fine-grained reactive state the editor should compose the same
17
- * pieces itself, one store subscription per slice, so a fog change cannot
18
- * re-render the sun. Every piece here is exported for exactly that:
18
+ * **Everything comes off `environment`.** That prop is the environment record as
19
+ * it is stored — one object with a key per feature and it is the same object
20
+ * the editor's `useLoadProject` fans out into Redux, key by key, before its
21
+ * connectors subscribe to the slices. Same blob, same components, two
22
+ * subscription granularities; that is the only thing that should ever differ
23
+ * between the editor and an embed.
24
+ *
25
+ * A host with fine-grained reactive state should compose the pieces itself, one
26
+ * store subscription per feature. Every piece here is exported for exactly that:
19
27
  * HdrEnvironment, useEnvironmentProbe, SkySystem, SceneFog, CloudsGenerator,
20
- * TerrainBuilder. Both paths run the same components; only the subscription
21
- * granularity differs, and that is the only thing that should ever differ.
28
+ * TerrainBuilder, LandscapeBuilder, OceanBuilder.
22
29
  */
23
- /** core's EnvironmentConfig still types `clouds` as the retired CloudsSettings.
24
- * Narrowed here rather than in core, which cannot reference the viewer's cloud
25
- * types they live next to the shader that consumes them. */
26
- export type ViewerEnvironmentConfig = Omit<EnvironmentConfig, 'clouds'> & {
30
+ /** The stored environment record.
31
+ *
32
+ * core's `EnvironmentConfig` still types `clouds` and `ocean` as the retired
33
+ * flat shapes and has no `terrain` or `landscape` at all. All four are declared
34
+ * here rather than in core for the same reason: a feature's config type lives
35
+ * next to the shader that consumes it, and core cannot reference the viewer.
36
+ *
37
+ * A project saved before any of these existed still carries the old shape at
38
+ * runtime. Each builder normalises its own blob on read and decides what an
39
+ * absent or legacy block means — see `normalizeTerrain` (drops it: a scene
40
+ * authored without ground should not gain a landscape) versus `normalizeOcean`
41
+ * (maps it: a scene authored with the old flat plane really did have water). */
42
+ export type ViewerEnvironmentConfig = Omit<EnvironmentConfig, 'clouds' | 'ocean'> & {
27
43
  clouds?: VolumetricCloudsSettings;
28
- /** core's EnvironmentConfig has no terrain field at all, and its
29
- * `TerrainSettings` is the retired flat shape. Declared here for the same
30
- * reason `clouds` is narrowed here: the config type lives next to the shader
31
- * that consumes it, and core cannot reference the viewer. */
32
44
  terrain?: ProceduralTerrainSettings;
45
+ landscape?: LandscapeSettings;
46
+ ocean?: OceanWaterSettings;
33
47
  };
34
48
  export interface EnvironmentManagerProps extends ObjectReadyProps {
35
49
  timeSettings: TimeSettings;
@@ -39,6 +53,8 @@ export interface EnvironmentManagerProps extends ObjectReadyProps {
39
53
  skySettings?: SkySettings;
40
54
  cloudsSettings?: VolumetricCloudsSettings;
41
55
  terrainSettings?: ProceduralTerrainSettings;
56
+ landscapeSettings?: LandscapeSettings;
57
+ oceanSettings?: OceanWaterSettings;
42
58
  fogSettings?: FogSettings;
43
59
  cubeCameraResolution?: number;
44
60
  skyboxScale?: number;
@@ -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;AAEzE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D;;;;;;;;;;;;;;GAcG;AAEH;;+DAE+D;AAC/D,MAAM,MAAM,uBAAuB,GAAG,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC,GAAG;IACtE,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAClC;;;kEAG8D;IAC9D,OAAO,CAAC,EAAE,yBAAyB,CAAC;CACvC,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,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,8FAwEtB,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;CACjD;AAoBD,QAAA,MAAM,kBAAkB,8FAiGtB,CAAC;AAGH,eAAe,kBAAkB,CAAC"}
@@ -5,6 +5,8 @@ import SkySystem from './SkySystem.js';
5
5
  import HdrEnvironment, { isHdrActive } from './HdrEnvironment.js';
6
6
  import { useEnvironmentProbe } from '../hooks/useEnvironmentProbe.js';
7
7
  import TerrainBuilder from './TerrainBuilder.js';
8
+ import LandscapeBuilder from './LandscapeBuilder.js';
9
+ import OceanBuilder from './OceanBuilder.js';
8
10
  const DEFAULT_HDR = {
9
11
  visible: false,
10
12
  name: null,
@@ -21,23 +23,26 @@ const DEFAULT_HDR = {
21
23
  },
22
24
  };
23
25
  const ORIGIN = new Vector3(0, 0, 0);
24
- const EnvironmentManager = forwardRef(({ timeSettings, environment, hdrSettings, skySettings, cloudsSettings, terrainSettings, 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, onObjectReady, onObjectDispose, }, ref) => {
25
27
  const hdr = hdrSettings ?? environment?.hdr ?? DEFAULT_HDR;
26
28
  const sky = skySettings ?? environment?.sky;
27
29
  const clouds = cloudsSettings ?? environment?.clouds;
28
30
  const terrain = terrainSettings ?? environment?.terrain;
31
+ const landscape = landscapeSettings ?? environment?.landscape;
32
+ const ocean = oceanSettings ?? environment?.ocean;
29
33
  const fog = fogSettings ?? environment?.fog;
30
34
  const sunSystemVisible = !!sky?.sunSystem?.visible;
31
35
  // Previously hardcoded true, which kept a cube camera alive — and re-captured
32
36
  // its six faces — for scenes that have no sky at all.
33
37
  const skyActive = !!sky?.visible || sunSystemVisible;
38
+ const sunIntensity = sky?.sunSystem?.intensity ?? 1;
34
39
  useEnvironmentProbe({
35
40
  hdrActive: isHdrActive(hdr),
36
41
  skyActive,
37
42
  autoAnimate: !!timeSettings.autoAnimate,
38
43
  resolution: cubeCameraResolution,
39
44
  });
40
- return (_jsxs(_Fragment, { children: [_jsx(HdrEnvironment, { hdr: hdr, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }), _jsx(TerrainBuilder, { settings: terrain, skySettings: sky, timeSettings: timeSettings, sunIntensity: sky?.sunSystem?.intensity ?? 1, 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: sky?.sunSystem?.intensity ?? 1, castShadow: sky?.sunSystem?.castShadow, shadowMapSize: sky?.sunSystem?.shadowMapSize, playerPosition: playerPosition, cloudsSettings: clouds, skyControllerSettings: sky, fogSettings: fog, onTimeOfDayChange: onTimeOfDayChange, onTimeUpdate: onTimeUpdate, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose })] }));
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 })] }));
41
46
  });
42
47
  EnvironmentManager.displayName = 'EnvironmentManager';
43
48
  export default EnvironmentManager;
@@ -1 +1 @@
1
- {"version":3,"file":"DataStreamEffect.d.ts","sourceRoot":"","sources":["../../../src/components/effects/DataStreamEffect.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEhF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,UAAU,qBAAsB,SAAQ,gBAAgB;IACpD,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;AAqFD,QAAA,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAmDrD,CAAC;AACF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"DataStreamEffect.d.ts","sourceRoot":"","sources":["../../../src/components/effects/DataStreamEffect.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEhF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,UAAU,qBAAsB,SAAQ,gBAAgB;IACpD,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,gBAAgB,CAAC;IACzB,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;AAuFD,QAAA,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAoErD,CAAC;AACF,eAAe,gBAAgB,CAAC"}
@@ -18,17 +18,19 @@ const vertexShader = /* glsl */ `
18
18
  uniform float uHeight;
19
19
  uniform float uPointSize;
20
20
  uniform float uIntensity;
21
+ uniform vec3 uColdColor;
22
+ uniform vec3 uMidColor;
23
+ uniform vec3 uHotColor;
24
+ uniform vec3 uTintColor;
21
25
 
22
26
  varying float vAlpha;
23
27
  varying vec3 vColor;
24
28
 
25
- // Palette: deep electric blue → cyan → white-gold
29
+ // Four-stop gradient: cold -> mid -> hot -> tint (config.color)
26
30
  vec3 palette(float t) {
27
- vec3 cold = vec3(0.05, 0.15, 0.9); // deep blue
28
- vec3 mid = vec3(0.0, 0.85, 1.0); // cyan
29
- vec3 hot = vec3(1.0, 0.92, 0.55); // warm gold-white
30
- if (t < 0.5) return mix(cold, mid, t * 2.0);
31
- else return mix(mid, hot, (t - 0.5) * 2.0);
31
+ if (t < 0.333) return mix(uColdColor, uMidColor, t * 3.0);
32
+ else if (t < 0.666) return mix(uMidColor, uHotColor, (t - 0.333) * 3.0);
33
+ else return mix(uHotColor, uTintColor, (t - 0.666) * 3.0);
32
34
  }
33
35
 
34
36
  void main() {
@@ -87,7 +89,7 @@ const fragmentShader = /* glsl */ `
87
89
  }
88
90
  `;
89
91
  const DataStreamEffect = ({ boundingRadius, config, animations, onObjectReady, onObjectDispose }) => {
90
- const { particleCount, spiralTurns, streamRadius, inward, particleSize, opacity, speed, intensity } = config;
92
+ const { particleCount, spiralTurns, streamRadius, inward, particleSize, opacity, speed, intensity, color = '#ffffff', coldColor = '#0d26e6', midColor = '#00d9ff', hotColor = '#ffeb8c', } = config;
91
93
  const startValuesCacheRef = useRef({});
92
94
  const rootRef = useRef(null);
93
95
  useObjectReady(rootRef, config, onObjectReady, onObjectDispose);
@@ -123,13 +125,17 @@ const DataStreamEffect = ({ boundingRadius, config, animations, onObjectReady, o
123
125
  uPointSize: { value: particleSize * 80 },
124
126
  uIntensity: { value: intensity },
125
127
  uOpacity: { value: opacity },
128
+ uColdColor: { value: new THREE.Color(coldColor) },
129
+ uMidColor: { value: new THREE.Color(midColor) },
130
+ uHotColor: { value: new THREE.Color(hotColor) },
131
+ uTintColor: { value: new THREE.Color(color) },
126
132
  },
127
133
  transparent: true,
128
134
  depthWrite: false,
129
135
  blending: THREE.AdditiveBlending,
130
136
  });
131
137
  return { geometry: geo, material: mat };
132
- }, [particleCount, spiralTurns, r, h, inward, particleSize, intensity, speed, opacity]);
138
+ }, [particleCount, spiralTurns, r, h, inward, particleSize, intensity, speed, opacity, coldColor, midColor, hotColor, color]);
133
139
  useFrame((state) => {
134
140
  material.uniforms.u_time.value = state.clock.getElapsedTime();
135
141
  if (animations?.length) {
@@ -1 +1 @@
1
- {"version":3,"file":"NeuralNetworkEffect.d.ts","sourceRoot":"","sources":["../../../src/components/effects/NeuralNetworkEffect.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,UAAU,wBAAyB,SAAQ,gBAAgB;IACvD,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;AA6BD,QAAA,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA4J3D,CAAC;AACF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"NeuralNetworkEffect.d.ts","sourceRoot":"","sources":["../../../src/components/effects/NeuralNetworkEffect.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEnF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,UAAU,wBAAyB,SAAQ,gBAAgB;IACvD,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,UAAU,CAAC,EAAE,gBAAgB,EAAE,CAAC;CACnC;AA+BD,QAAA,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CA4J3D,CAAC;AACF,eAAe,mBAAmB,CAAC"}
@@ -4,7 +4,7 @@ import { useFrame } from '@react-three/fiber';
4
4
  import * as THREE from 'three';
5
5
  import { applyGenerativeAnimations } from '../../utils/handleGenerativeEffectsAnimations.js';
6
6
  import { useObjectReady } from '../../hooks/useObjectReady.js';
7
- // Glow sprite for pulse signals and node flashes
7
+ // Tight point sprites for electrical signals moving through the connections.
8
8
  const pulseVert = /* glsl */ `
9
9
  attribute float aBright;
10
10
  uniform float uSize;
@@ -13,7 +13,7 @@ const pulseVert = /* glsl */ `
13
13
  vB = aBright;
14
14
  if (vB < 0.01) { gl_PointSize = 0.0; gl_Position = vec4(0); return; }
15
15
  vec4 mv = modelViewMatrix * vec4(position, 1.0);
16
- gl_PointSize = uSize * vB * (200.0 / -mv.z);
16
+ gl_PointSize = uSize * (0.75 + vB * 0.25) * (200.0 / -mv.z);
17
17
  gl_Position = projectionMatrix * mv;
18
18
  }
19
19
  `;
@@ -23,10 +23,12 @@ const pulseFrag = /* glsl */ `
23
23
  varying float vB;
24
24
  void main() {
25
25
  if (vB < 0.01) discard;
26
- vec2 c = gl_PointCoord - 0.5;
27
- if (length(c) > 0.5) discard;
28
- float g = exp(-dot(c, c) * 5.5);
29
- gl_FragColor = vec4(uColor, g * vB * uOpacity);
26
+ vec2 c = gl_PointCoord - 0.5;
27
+ float radius = length(c);
28
+ if (radius > 0.5) discard;
29
+ float core = smoothstep(0.24, 0.0, radius);
30
+ float halo = smoothstep(0.5, 0.12, radius) * 0.2;
31
+ gl_FragColor = vec4(uColor, (core + halo) * vB * uOpacity);
30
32
  }
31
33
  `;
32
34
  const MAX_PULSES = 4;
@@ -105,7 +107,7 @@ const NeuralNetworkEffect = ({ boundingRadius, config, animations, onObjectReady
105
107
  const pulseMat = new THREE.ShaderMaterial({
106
108
  vertexShader: pulseVert, fragmentShader: pulseFrag,
107
109
  uniforms: {
108
- uSize: { value: 20 * intensity },
110
+ uSize: { value: 7 * intensity },
109
111
  uColor: { value: new THREE.Vector3(pc.r, pc.g, pc.b) },
110
112
  uOpacity: { value: opacity },
111
113
  },
@@ -176,11 +178,11 @@ const NeuralNetworkEffect = ({ boundingRadius, config, animations, onObjectReady
176
178
  }
177
179
  const pos = curPos[p.fromIdx].clone().lerp(curPos[p.toIdx], p.progress);
178
180
  ptPos.setXYZ(pi, pos.x, pos.y, pos.z);
179
- ptBright.setX(pi, 0.7 + 0.3 * Math.sin(p.progress * Math.PI));
181
+ ptBright.setX(pi, 0.75 + 0.25 * Math.sin(p.progress * Math.PI * 3.0));
180
182
  });
181
183
  ptPos.needsUpdate = true;
182
184
  ptBright.needsUpdate = true;
183
- pulseMat.uniforms.uSize.value = 20 * intensity;
185
+ pulseMat.uniforms.uSize.value = 7 * intensity;
184
186
  if (animations?.length) {
185
187
  applyGenerativeAnimations([pulseMat], animations, startValuesCacheRef.current, Date.now(), false);
186
188
  }
@@ -8,6 +8,10 @@ import type { CloudLayerProps } from './types';
8
8
  * case where the deck is switched off entirely, so the deck march is skipped and
9
9
  * only the three-sample ice pass runs. That is a fraction of the cost of any
10
10
  * volumetric type, which is why a clear-with-cirrus sky is close to free.
11
+ *
12
+ * No thunder here, deliberately: a bolt needs a deck to sit inside and a volume to
13
+ * light. An ice sheet has neither, so the flash would have nowhere to originate and
14
+ * nothing to scatter through.
11
15
  */
12
16
  declare const Cirrus: React.FC<CloudLayerProps>;
13
17
  export default Cirrus;
@@ -1 +1 @@
1
- {"version":3,"file":"Cirrus.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/Cirrus.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;GAQG;AACH,QAAA,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAErC,CAAC;AACF,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"Cirrus.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/Cirrus.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C;;;;;;;;;;;;GAYG;AACH,QAAA,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAErC,CAAC;AACF,eAAe,MAAM,CAAC"}
@@ -8,6 +8,10 @@ import VolumetricCloudsPass from './VolumetricCloudsPass.js';
8
8
  * case where the deck is switched off entirely, so the deck march is skipped and
9
9
  * only the three-sample ice pass runs. That is a fraction of the cost of any
10
10
  * volumetric type, which is why a clear-with-cirrus sky is close to free.
11
+ *
12
+ * No thunder here, deliberately: a bolt needs a deck to sit inside and a volume to
13
+ * light. An ice sheet has neither, so the flash would have nowhere to originate and
14
+ * nothing to scatter through.
11
15
  */
12
16
  const Cirrus = ({ cirrus, quality, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => (_jsx(VolumetricCloudsPass, { deck: null, cirrus: cirrus, quality: quality, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
13
17
  export default Cirrus;
@@ -13,8 +13,8 @@ import VolumetricCloudsPass from './VolumetricCloudsPass.js';
13
13
  * Cost scales with depth, since the fine step is derived from it, so a shallow step
14
14
  * budget on a 9 km tower gives kilometre steps and loses the structure. Floored here.
15
15
  */
16
- const Cumulonimbus = ({ deck, cirrus, quality, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => {
16
+ const Cumulonimbus = ({ deck, cirrus, quality, thunder, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => {
17
17
  const resolvedQuality = useMemo(() => ({ ...quality, steps: Math.max(quality.steps, 96) }), [quality]);
18
- return (_jsx(VolumetricCloudsPass, { deck: deck, cirrus: cirrus, quality: resolvedQuality, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
18
+ return (_jsx(VolumetricCloudsPass, { deck: deck, cirrus: cirrus, quality: resolvedQuality, thunder: thunder, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
19
19
  };
20
20
  export default Cumulonimbus;
@@ -10,8 +10,8 @@ import VolumetricCloudsPass from './VolumetricCloudsPass.js';
10
10
  * inside the shader anyway, so leaving a stale value in the config would do nothing
11
11
  * visible while making the panel read as though it should.
12
12
  */
13
- const Cumulus = ({ deck, cirrus, quality, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => {
13
+ const Cumulus = ({ deck, cirrus, quality, thunder, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => {
14
14
  const resolved = useMemo(() => ({ ...deck, anvil: 0, precipitation: 0 }), [deck]);
15
- return (_jsx(VolumetricCloudsPass, { deck: resolved, cirrus: cirrus, quality: quality, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
15
+ return (_jsx(VolumetricCloudsPass, { deck: resolved, cirrus: cirrus, quality: quality, thunder: thunder, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
16
16
  };
17
17
  export default Cumulus;
@@ -8,9 +8,9 @@ import VolumetricCloudsPass from './VolumetricCloudsPass.js';
8
8
  * small and a large step budget is wasted; it is capped here. Anvil and
9
9
  * precipitation are off for the same reason as cumulus.
10
10
  */
11
- const Stratocumulus = ({ deck, cirrus, quality, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => {
11
+ const Stratocumulus = ({ deck, cirrus, quality, thunder, skySettings, timeSettings, sunIntensity, animations, mouseMove, id, onObjectReady, onObjectDispose }) => {
12
12
  const resolved = useMemo(() => ({ ...deck, anvil: 0, precipitation: 0 }), [deck]);
13
13
  const resolvedQuality = useMemo(() => ({ ...quality, steps: Math.min(quality.steps, 112) }), [quality]);
14
- return (_jsx(VolumetricCloudsPass, { deck: resolved, cirrus: cirrus, quality: resolvedQuality, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
14
+ return (_jsx(VolumetricCloudsPass, { deck: resolved, cirrus: cirrus, quality: resolvedQuality, thunder: thunder, skySettings: skySettings, timeSettings: timeSettings, sunIntensity: sunIntensity, animations: animations, mouseMove: mouseMove, id: id, onObjectReady: onObjectReady, onObjectDispose: onObjectDispose }));
15
15
  };
16
16
  export default Stratocumulus;
@@ -1,7 +1,7 @@
1
1
  import React from 'react';
2
2
  import type { ObjectReadyProps } from '../../types/objectReady';
3
3
  import type { SkySettings, TimeSettings } from '@3driseai/3drise-core';
4
- import type { CirrusLayerConfig, CloudDeckConfig, CloudsQualityConfig } from '../../types/cloudConfigs';
4
+ import type { CirrusLayerConfig, CloudDeckConfig, CloudsQualityConfig, ThunderConfig } from '../../types/cloudConfigs';
5
5
  import type { ObjectAnimations, MouseMoveInteractions } from '@3driseai/3drise-core';
6
6
  /**
7
7
  * The cloud render pipeline. The only component in this package that takes over
@@ -28,6 +28,9 @@ export interface VolumetricCloudsPassProps extends ObjectReadyProps {
28
28
  deck?: CloudDeckConfig | null;
29
29
  cirrus?: CirrusLayerConfig | null;
30
30
  quality: CloudsQualityConfig;
31
+ /** Lightning. Needs a deck — the bolt sits inside it and lights it from within —
32
+ * so it is ignored on the cirrus-only path. */
33
+ thunder?: ThunderConfig;
31
34
  skySettings?: SkySettings;
32
35
  timeSettings?: TimeSettings;
33
36
  /** Multiplies sun radiance for the clouds only. Matches SkySystem's sunIntensity. */
@@ -1 +1 @@
1
- {"version":3,"file":"VolumetricCloudsPass.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/VolumetricCloudsPass.tsx"],"names":[],"mappings":"AACA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAIvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAQvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAExG,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAErF;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IAC/D,6EAA6E;IAC7E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,MAAM,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,6DAA6D;IAC7D,SAAS,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAkBD,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA0S7D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"VolumetricCloudsPass.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/VolumetricCloudsPass.tsx"],"names":[],"mappings":"AACA,OAAO,KAAkD,MAAM,OAAO,CAAC;AAKvE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAQvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEvH,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAErF;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,WAAW,yBAA0B,SAAQ,gBAAgB;IAC/D,6EAA6E;IAC7E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC9B,MAAM,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAClC,OAAO,EAAE,mBAAmB,CAAC;IAC7B;oDACgD;IAChD,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,6DAA6D;IAC7D,SAAS,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAkBD,QAAA,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAyV7D,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -3,6 +3,7 @@ import * as THREE from 'three';
3
3
  import { useCallback, useEffect, useMemo, useRef } from 'react';
4
4
  import { useFrame, useThree } from '@react-three/fiber';
5
5
  import { useFrameRenderer } from '../../hooks/useFrameRenderer.js';
6
+ import { useThunder } from '../../hooks/useThunder.js';
6
7
  import { useObjectReady } from '../../hooks/useObjectReady.js';
7
8
  import { CLOUD_LIVE_KEY } from '../../hooks/useCloudLive.js';
8
9
  import { useCloudNoise } from '../../hooks/useCloudNoise.js';
@@ -11,7 +12,7 @@ import { CloudVolumeMaterial } from '../../shaders/clouds/CloudVolumeMaterial.js
11
12
  import { CirrusMaterial } from '../../shaders/clouds/CirrusMaterial.js';
12
13
  import { CloudResolveMaterial } from '../../shaders/clouds/CloudResolveMaterial.js';
13
14
  import { CloudCompositeMaterial } from '../../shaders/clouds/CloudCompositeMaterial.js';
14
- import { applyCameraUniforms, applyCirrusUniforms, applyDeckUniforms, applySunUniforms, } from '../../utils/cloudUniforms.js';
15
+ import { applyCameraUniforms, applyCirrusUniforms, applyDeckUniforms, applySunUniforms, applyThunderUniforms } from '../../utils/cloudUniforms.js';
15
16
  import { applyCloudsKeyframeAnimations, applyCloudsMouseMove, resolveDeckConfig, } from '../../utils/handleCloudsAnimations.js';
16
17
  const quad = new THREE.PlaneGeometry(2, 2);
17
18
  const orthoCam = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
@@ -26,7 +27,7 @@ function emptyTexture() {
26
27
  tex.needsUpdate = true;
27
28
  return tex;
28
29
  }
29
- const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, skySettings, timeSettings, sunIntensity = 1, animations, mouseMove, onObjectReady, onObjectDispose, }) => {
30
+ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, thunder, skySettings, timeSettings, sunIntensity = 1, animations, mouseMove, onObjectReady, onObjectDispose, }) => {
30
31
  const gl = useThree((s) => s.gl);
31
32
  const scene = useThree((s) => s.scene);
32
33
  const size = useThree((s) => s.size);
@@ -111,12 +112,16 @@ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, sky
111
112
  // frame loop reads it on top of the config, so the deck responds without a Redux
112
113
  // dispatch per frame. Cleared when the config identity changes, which is exactly
113
114
  // slider-end committing the same value.
115
+ const thunderDriver = useThunder();
116
+ const boltRef = useRef(null);
114
117
  const liveDeck = useRef({});
118
+ const liveThunder = useRef({});
115
119
  const liveCirrus = useRef({});
116
120
  const liveQuality = useRef({});
117
121
  useEffect(() => { liveDeck.current = {}; }, [deck]);
118
122
  useEffect(() => { liveCirrus.current = {}; }, [cirrus]);
119
123
  useEffect(() => { liveQuality.current = {}; }, [quality]);
124
+ useEffect(() => { liveThunder.current = {}; }, [thunder]);
120
125
  // The handle a controller reaches through findById(id).userData. Set in an effect,
121
126
  // never as a userData JSX prop: R3F replaces the whole userData object on every
122
127
  // render, which would drop the handle the moment anything above re-renders.
@@ -125,6 +130,7 @@ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, sky
125
130
  deck: (key, value) => { liveDeck.current[key] = value; },
126
131
  cirrus: (key, value) => { liveCirrus.current[key] = value; },
127
132
  quality: (key, value) => { liveQuality.current[key] = value; },
133
+ thunder: (key, value) => { liveThunder.current[key] = value; },
128
134
  }), []);
129
135
  useEffect(() => {
130
136
  const root = rootRef.current;
@@ -159,6 +165,29 @@ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, sky
159
165
  frame.current += 1;
160
166
  time.current += Math.min(delta, 0.05);
161
167
  updateSun();
168
+ // Lightning is scheduled on the CPU because three things need the same event:
169
+ // the emission uniforms, the scene light, and the temporal blend below.
170
+ const liveThunderCfg = (thunder
171
+ ? { ...thunder, ...liveThunder.current }
172
+ : undefined);
173
+ const bolt = (liveThunderCfg && deck)
174
+ ? thunderDriver.update(delta, deck, liveThunderCfg, camera)
175
+ : null;
176
+ // The scene light is what stops the flash looking like it happens in a
177
+ // separate universe from the ground. decay 0 / distance 0 on purpose: a bolt
178
+ // 2 km up with physical falloff contributes nothing at ground level, and what
179
+ // a distant flash actually does is brighten everything at once.
180
+ if (boltRef.current) {
181
+ const lit = bolt && liveThunderCfg
182
+ ? bolt.intensity * liveThunderCfg.sceneFlash
183
+ : 0;
184
+ boltRef.current.intensity = lit;
185
+ boltRef.current.visible = lit > 0.001;
186
+ if (lit > 0.001) {
187
+ boltRef.current.position.copy(bolt.position);
188
+ boltRef.current.color.set(liveThunderCfg.color);
189
+ }
190
+ }
162
191
  // ---- 1. scene ----
163
192
  const sceneRT = (frame.current & 1) ? targets.sceneA : targets.sceneB;
164
193
  const prevTarget = gl.getRenderTarget();
@@ -204,6 +233,12 @@ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, sky
204
233
  const liveQual = { ...quality, ...liveQuality.current };
205
234
  const m = passes.deckMat;
206
235
  applyDeckUniforms(m, live, liveQual);
236
+ if (liveThunderCfg && bolt) {
237
+ applyThunderUniforms(m, liveThunderCfg, bolt.intensity, bolt.position);
238
+ }
239
+ else if (m.uniforms.u_flash) {
240
+ m.uniforms.u_flash.value = 0;
241
+ }
207
242
  m.uniforms.u_base.value = noise.base;
208
243
  m.uniforms.u_detail.value = noise.detail;
209
244
  m.uniforms.u_weather.value = noise.weather;
@@ -236,6 +271,13 @@ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, sky
236
271
  // and a high history weight smears. Ease off, and restore it once still.
237
272
  const moved = camera.position.distanceToSquared(prevCamPos.current) > 1e-8
238
273
  || Math.abs(camera.quaternion.dot(prevCamQuat.current)) < 0.9999995;
274
+ // Deliberately NOT special-cased for lightning. The resolve clamps history
275
+ // to the 3x3 neighbourhood of the current frame before blending, and that
276
+ // clamp already handles a flash in both directions: dark history is pulled
277
+ // up when the bolt fires, and the bright frame is clamped away the moment
278
+ // it stops. Dropping the blend during a flash — which is what this used to
279
+ // do — throws away the temporal accumulation that turns the march's
280
+ // sub-pixel jitter into detail, and the whole deck visibly shakes.
239
281
  r.u_blend.value = moved ? Math.min(quality.temporalBlend, 0.7) : quality.temporalBlend;
240
282
  gl.setRenderTarget(destination);
241
283
  gl.render(passes.resolveScene, orthoCam);
@@ -293,6 +335,6 @@ const VolumetricCloudsPass = ({ id = '3drise-clouds', deck, cirrus, quality, sky
293
335
  useFrameRenderer(renderCompleteFrame);
294
336
  // An empty group, but a real one: it carries userData.id so findById() can reach
295
337
  // this layer, and the live handle so a controller can drive it without Redux.
296
- return _jsx("group", { ref: rootRef });
338
+ return (_jsx("group", { ref: rootRef, children: _jsx("pointLight", { ref: boltRef, visible: false, intensity: 0, distance: 0, decay: 0 }) }));
297
339
  };
298
340
  export default VolumetricCloudsPass;
@@ -1,6 +1,6 @@
1
1
  import type { MouseMoveInteractions, ObjectAnimations, SkySettings, TimeSettings } from '@3driseai/3drise-core';
2
2
  import type { ObjectReadyProps } from '../../types/objectReady';
3
- import type { CirrusLayerConfig, CloudDeckConfig, CloudsQualityConfig } from '../../types/cloudConfigs';
3
+ import type { CirrusLayerConfig, CloudDeckConfig, CloudsQualityConfig, ThunderConfig } from '../../types/cloudConfigs';
4
4
  /** Shared by every layer component. The generator hands all four the same shape. */
5
5
  export interface CloudLayerProps extends ObjectReadyProps {
6
6
  /** Scene id, so a controller can findById() the layer and drive it live. */
@@ -8,6 +8,8 @@ export interface CloudLayerProps extends ObjectReadyProps {
8
8
  deck: CloudDeckConfig;
9
9
  cirrus: CirrusLayerConfig | null;
10
10
  quality: CloudsQualityConfig;
11
+ /** Lightning. Absent or disabled means the flash path never runs. */
12
+ thunder?: ThunderConfig;
11
13
  skySettings?: SkySettings;
12
14
  timeSettings?: TimeSettings;
13
15
  sunIntensity?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAExG,oFAAoF;AACpF,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACrD,4EAA4E;IAC5E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,SAAS,CAAC,EAAE,qBAAqB,CAAC;CACrC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/volumetricClouds/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,KAAK,EAAE,iBAAiB,EAAE,eAAe,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEvH,oFAAoF;AACpF,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACrD,4EAA4E;IAC5E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,mBAAmB,CAAC;IAC7B,qEAAqE;IACrE,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,SAAS,CAAC,EAAE,qBAAqB,CAAC;CACrC"}
@@ -25,6 +25,8 @@ export { useCubeCamera } from './useCubeCamera';
25
25
  export type { UseEnvironmentProbeOptions } from './useEnvironmentProbe';
26
26
  export { useEnvironmentProbe } from './useEnvironmentProbe';
27
27
  export { useFrameRenderer } from './useFrameRenderer';
28
+ export type { ThunderDriver, ThunderState } from './useThunder';
29
+ export { createThunderDriver, useThunder } from './useThunder';
28
30
  export type { UseEnvironmentEffectsOptions } from './useEnvironmentEffects';
29
31
  export { useEnvironmentEffects } from './useEnvironmentEffects';
30
32
  export { useFrameAnimations } from './useFrameAnimations';
@@ -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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"}
@@ -17,6 +17,7 @@ export { useContinuousEffects } from './useContinuousEffects.js';
17
17
  export { useCubeCamera } from './useCubeCamera.js';
18
18
  export { useEnvironmentProbe } from './useEnvironmentProbe.js';
19
19
  export { useFrameRenderer } from './useFrameRenderer.js';
20
+ export { createThunderDriver, useThunder } from './useThunder.js';
20
21
  export { useEnvironmentEffects } from './useEnvironmentEffects.js';
21
22
  export { useFrameAnimations } from './useFrameAnimations.js';
22
23
  export { useFrameEffects } from './useFrameEffects.js';
@@ -18,6 +18,7 @@ export interface CloudLiveHandle {
18
18
  deck(key: string, value: number | boolean): void;
19
19
  cirrus(key: string, value: number | boolean): void;
20
20
  quality(key: string, value: number | boolean): void;
21
+ thunder(key: string, value: number | boolean | string): void;
21
22
  }
22
23
  /**
23
24
  * Safe before the layer mounts and after it unmounts: the handle is resolved at call
@@ -1 +1 @@
1
- {"version":3,"file":"useCloudLive.d.ts","sourceRoot":"","sources":["../../src/hooks/useCloudLive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGtC;;;;;;;;;;;;GAYG;AAEH,mFAAmF;AACnF,eAAO,MAAM,cAAc,gBAAgB,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC5B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACnD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;CACvD;AAID;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,GAAG,eAAe,CAkB/E;AAED,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"useCloudLive.d.ts","sourceRoot":"","sources":["../../src/hooks/useCloudLive.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAGtC;;;;;;;;;;;;GAYG;AAEH,mFAAmF;AACnF,eAAO,MAAM,cAAc,gBAAgB,CAAC;AAE5C,MAAM,WAAW,eAAe;IAC5B,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACjD,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACnD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;IACpD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,IAAI,CAAC;CAChE;AAID;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,GAAG,eAAe,CAmB/E;AAED,eAAe,YAAY,CAAC"}
@@ -15,7 +15,7 @@ import { findById } from '../utils/sceneQuery.js';
15
15
  */
16
16
  /** Where VolumetricCloudsPass stashes its handle on the root object's userData. */
17
17
  export const CLOUD_LIVE_KEY = '__cloudLive';
18
- const NOOP = { deck: () => { }, cirrus: () => { }, quality: () => { } };
18
+ const NOOP = { deck: () => { }, cirrus: () => { }, quality: () => { }, thunder: () => { } };
19
19
  /**
20
20
  * Safe before the layer mounts and after it unmounts: the handle is resolved at call
21
21
  * time, not at hook time, so a controller opened before the scene is ready still works
@@ -37,6 +37,7 @@ export function useCloudLive(target) {
37
37
  deck: (key, value) => resolve().deck(key, value),
38
38
  cirrus: (key, value) => resolve().cirrus(key, value),
39
39
  quality: (key, value) => resolve().quality(key, value),
40
+ thunder: (key, value) => resolve().thunder(key, value),
40
41
  };
41
42
  }, [target]);
42
43
  }