@3driseai/3drise-viewer 0.1.7 → 0.1.8

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 (259) hide show
  1. package/dist/components/Clouds.d.ts.map +1 -1
  2. package/dist/components/Clouds.js +0 -1
  3. package/dist/components/CloudsGenerator.d.ts +32 -0
  4. package/dist/components/CloudsGenerator.d.ts.map +1 -0
  5. package/dist/components/CloudsGenerator.js +58 -0
  6. package/dist/components/EnvironmentManager.d.ts +47 -5
  7. package/dist/components/EnvironmentManager.d.ts.map +1 -1
  8. package/dist/components/EnvironmentManager.js +35 -66
  9. package/dist/components/HdrEnvironment.d.ts +20 -0
  10. package/dist/components/HdrEnvironment.d.ts.map +1 -0
  11. package/dist/components/HdrEnvironment.js +44 -0
  12. package/dist/components/LandscapeBuilder.d.ts +23 -0
  13. package/dist/components/LandscapeBuilder.d.ts.map +1 -0
  14. package/dist/components/LandscapeBuilder.js +25 -0
  15. package/dist/components/LandscapeObject.d.ts +24 -0
  16. package/dist/components/LandscapeObject.d.ts.map +1 -0
  17. package/dist/components/LandscapeObject.js +27 -0
  18. package/dist/components/ObjectNode.d.ts.map +1 -1
  19. package/dist/components/ObjectNode.js +10 -0
  20. package/dist/components/OceanBuilder.d.ts +35 -0
  21. package/dist/components/OceanBuilder.d.ts.map +1 -0
  22. package/dist/components/OceanBuilder.js +53 -0
  23. package/dist/components/SceneBuilder.d.ts.map +1 -1
  24. package/dist/components/SkySystem.d.ts +27 -6
  25. package/dist/components/SkySystem.d.ts.map +1 -1
  26. package/dist/components/SkySystem.js +6 -5
  27. package/dist/components/SunLight.d.ts.map +1 -1
  28. package/dist/components/SunLight.js +4 -1
  29. package/dist/components/TerrainBuilder.d.ts +30 -0
  30. package/dist/components/TerrainBuilder.d.ts.map +1 -0
  31. package/dist/components/TerrainBuilder.js +44 -0
  32. package/dist/components/index.d.ts +17 -1
  33. package/dist/components/index.d.ts.map +1 -1
  34. package/dist/components/index.js +10 -0
  35. package/dist/components/landscape/LandscapeMesh.d.ts +18 -0
  36. package/dist/components/landscape/LandscapeMesh.d.ts.map +1 -0
  37. package/dist/components/landscape/LandscapeMesh.js +278 -0
  38. package/dist/components/landscape/index.d.ts +3 -0
  39. package/dist/components/landscape/index.d.ts.map +1 -0
  40. package/dist/components/landscape/index.js +1 -0
  41. package/dist/components/landscape/types.d.ts +13 -0
  42. package/dist/components/landscape/types.d.ts.map +1 -0
  43. package/dist/components/landscape/types.js +1 -0
  44. package/dist/components/terrain/Canyon.d.ts +23 -0
  45. package/dist/components/terrain/Canyon.d.ts.map +1 -0
  46. package/dist/components/terrain/Canyon.js +29 -0
  47. package/dist/components/terrain/Dunes.d.ts +22 -0
  48. package/dist/components/terrain/Dunes.d.ts.map +1 -0
  49. package/dist/components/terrain/Dunes.js +25 -0
  50. package/dist/components/terrain/Hills.d.ts +17 -0
  51. package/dist/components/terrain/Hills.d.ts.map +1 -0
  52. package/dist/components/terrain/Hills.js +20 -0
  53. package/dist/components/terrain/Mountains.d.ts +19 -0
  54. package/dist/components/terrain/Mountains.d.ts.map +1 -0
  55. package/dist/components/terrain/Mountains.js +22 -0
  56. package/dist/components/terrain/TerrainSurface.d.ts +22 -0
  57. package/dist/components/terrain/TerrainSurface.d.ts.map +1 -0
  58. package/dist/components/terrain/TerrainSurface.js +94 -0
  59. package/dist/components/terrain/index.d.ts +7 -0
  60. package/dist/components/terrain/index.d.ts.map +1 -0
  61. package/dist/components/terrain/index.js +7 -0
  62. package/dist/components/terrain/types.d.ts +17 -0
  63. package/dist/components/terrain/types.d.ts.map +1 -0
  64. package/dist/components/terrain/types.js +1 -0
  65. package/dist/components/volumetricClouds/Cirrus.d.ts +14 -0
  66. package/dist/components/volumetricClouds/Cirrus.d.ts.map +1 -0
  67. package/dist/components/volumetricClouds/Cirrus.js +13 -0
  68. package/dist/components/volumetricClouds/Cumulonimbus.d.ts +17 -0
  69. package/dist/components/volumetricClouds/Cumulonimbus.d.ts.map +1 -0
  70. package/dist/components/volumetricClouds/Cumulonimbus.js +20 -0
  71. package/dist/components/volumetricClouds/Cumulus.d.ts +14 -0
  72. package/dist/components/volumetricClouds/Cumulus.d.ts.map +1 -0
  73. package/dist/components/volumetricClouds/Cumulus.js +17 -0
  74. package/dist/components/volumetricClouds/Stratocumulus.d.ts +12 -0
  75. package/dist/components/volumetricClouds/Stratocumulus.d.ts.map +1 -0
  76. package/dist/components/volumetricClouds/Stratocumulus.js +16 -0
  77. package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts +42 -0
  78. package/dist/components/volumetricClouds/VolumetricCloudsPass.d.ts.map +1 -0
  79. package/dist/components/volumetricClouds/VolumetricCloudsPass.js +298 -0
  80. package/dist/components/volumetricClouds/index.d.ts +8 -0
  81. package/dist/components/volumetricClouds/index.d.ts.map +1 -0
  82. package/dist/components/volumetricClouds/index.js +7 -0
  83. package/dist/components/volumetricClouds/types.d.ts +17 -0
  84. package/dist/components/volumetricClouds/types.d.ts.map +1 -0
  85. package/dist/components/volumetricClouds/types.js +1 -0
  86. package/dist/components/water/Host.d.ts +12 -0
  87. package/dist/components/water/Host.d.ts.map +1 -0
  88. package/dist/components/water/Host.js +12 -0
  89. package/dist/components/water/Lake.d.ts +18 -0
  90. package/dist/components/water/Lake.d.ts.map +1 -0
  91. package/dist/components/water/Lake.js +21 -0
  92. package/dist/components/water/OceanSurface.d.ts +27 -0
  93. package/dist/components/water/OceanSurface.d.ts.map +1 -0
  94. package/dist/components/water/OceanSurface.js +60 -0
  95. package/dist/components/water/Sea.d.ts +18 -0
  96. package/dist/components/water/Sea.d.ts.map +1 -0
  97. package/dist/components/water/Sea.js +17 -0
  98. package/dist/components/water/Shore.d.ts +16 -0
  99. package/dist/components/water/Shore.d.ts.map +1 -0
  100. package/dist/components/water/Shore.js +15 -0
  101. package/dist/components/water/Storm.d.ts +14 -0
  102. package/dist/components/water/Storm.d.ts.map +1 -0
  103. package/dist/components/water/Storm.js +13 -0
  104. package/dist/components/water/WaterBody.d.ts +31 -0
  105. package/dist/components/water/WaterBody.d.ts.map +1 -0
  106. package/dist/components/water/WaterBody.js +76 -0
  107. package/dist/components/water/index.d.ts +9 -0
  108. package/dist/components/water/index.d.ts.map +1 -0
  109. package/dist/components/water/index.js +11 -0
  110. package/dist/components/water/types.d.ts +20 -0
  111. package/dist/components/water/types.d.ts.map +1 -0
  112. package/dist/components/water/types.js +1 -0
  113. package/dist/constants.d.ts.map +1 -1
  114. package/dist/constants.js +9 -0
  115. package/dist/hooks/index.d.ts +24 -1
  116. package/dist/hooks/index.d.ts.map +1 -1
  117. package/dist/hooks/index.js +12 -0
  118. package/dist/hooks/useClipmap.d.ts +71 -0
  119. package/dist/hooks/useClipmap.d.ts.map +1 -0
  120. package/dist/hooks/useClipmap.js +81 -0
  121. package/dist/hooks/useCloudLive.d.ts +29 -0
  122. package/dist/hooks/useCloudLive.d.ts.map +1 -0
  123. package/dist/hooks/useCloudLive.js +43 -0
  124. package/dist/hooks/useCloudNoise.d.ts +28 -0
  125. package/dist/hooks/useCloudNoise.d.ts.map +1 -0
  126. package/dist/hooks/useCloudNoise.js +128 -0
  127. package/dist/hooks/useCloudSun.d.ts +49 -0
  128. package/dist/hooks/useCloudSun.d.ts.map +1 -0
  129. package/dist/hooks/useCloudSun.js +84 -0
  130. package/dist/hooks/useCubeCamera.d.ts +27 -9
  131. package/dist/hooks/useCubeCamera.d.ts.map +1 -1
  132. package/dist/hooks/useCubeCamera.js +28 -70
  133. package/dist/hooks/useEnvironmentProbe.d.ts +32 -0
  134. package/dist/hooks/useEnvironmentProbe.d.ts.map +1 -0
  135. package/dist/hooks/useEnvironmentProbe.js +35 -0
  136. package/dist/hooks/useFrameRenderer.d.ts +15 -0
  137. package/dist/hooks/useFrameRenderer.d.ts.map +1 -0
  138. package/dist/hooks/useFrameRenderer.js +23 -0
  139. package/dist/hooks/useLandscapeLive.d.ts +29 -0
  140. package/dist/hooks/useLandscapeLive.d.ts.map +1 -0
  141. package/dist/hooks/useLandscapeLive.js +41 -0
  142. package/dist/hooks/useLandscapeMaps.d.ts +32 -0
  143. package/dist/hooks/useLandscapeMaps.d.ts.map +1 -0
  144. package/dist/hooks/useLandscapeMaps.js +138 -0
  145. package/dist/hooks/useOceanLive.d.ts +29 -0
  146. package/dist/hooks/useOceanLive.d.ts.map +1 -0
  147. package/dist/hooks/useOceanLive.js +38 -0
  148. package/dist/hooks/useOceanMaterial.d.ts +39 -0
  149. package/dist/hooks/useOceanMaterial.d.ts.map +1 -0
  150. package/dist/hooks/useOceanMaterial.js +65 -0
  151. package/dist/hooks/useTerrainClipmap.d.ts +12 -0
  152. package/dist/hooks/useTerrainClipmap.d.ts.map +1 -0
  153. package/dist/hooks/useTerrainClipmap.js +10 -0
  154. package/dist/hooks/useTerrainLive.d.ts +34 -0
  155. package/dist/hooks/useTerrainLive.d.ts.map +1 -0
  156. package/dist/hooks/useTerrainLive.js +45 -0
  157. package/dist/index.d.ts +26 -0
  158. package/dist/index.d.ts.map +1 -1
  159. package/dist/index.js +16 -0
  160. package/dist/presets/landscapePresets.d.ts +60 -0
  161. package/dist/presets/landscapePresets.d.ts.map +1 -0
  162. package/dist/presets/landscapePresets.js +194 -0
  163. package/dist/presets/landscapeTypes.d.ts +195 -0
  164. package/dist/presets/landscapeTypes.d.ts.map +1 -0
  165. package/dist/presets/landscapeTypes.js +315 -0
  166. package/dist/presets/oceanSurfacePresets.d.ts +33 -0
  167. package/dist/presets/oceanSurfacePresets.d.ts.map +1 -0
  168. package/dist/presets/oceanSurfacePresets.js +245 -0
  169. package/dist/presets/terrainPresets.d.ts +28 -0
  170. package/dist/presets/terrainPresets.d.ts.map +1 -0
  171. package/dist/presets/terrainPresets.js +293 -0
  172. package/dist/presets/volumetricCloudPresets.d.ts +38 -0
  173. package/dist/presets/volumetricCloudPresets.d.ts.map +1 -0
  174. package/dist/presets/volumetricCloudPresets.js +480 -0
  175. package/dist/shaders/clouds/CirrusMaterial.d.ts +84 -0
  176. package/dist/shaders/clouds/CirrusMaterial.d.ts.map +1 -0
  177. package/dist/shaders/clouds/CirrusMaterial.js +167 -0
  178. package/dist/shaders/clouds/CloudCompositeMaterial.d.ts +20 -0
  179. package/dist/shaders/clouds/CloudCompositeMaterial.d.ts.map +1 -0
  180. package/dist/shaders/clouds/CloudCompositeMaterial.js +82 -0
  181. package/dist/shaders/clouds/CloudResolveMaterial.d.ts +22 -0
  182. package/dist/shaders/clouds/CloudResolveMaterial.d.ts.map +1 -0
  183. package/dist/shaders/clouds/CloudResolveMaterial.js +77 -0
  184. package/dist/shaders/clouds/CloudVolumeMaterial.d.ts +143 -0
  185. package/dist/shaders/clouds/CloudVolumeMaterial.d.ts.map +1 -0
  186. package/dist/shaders/clouds/CloudVolumeMaterial.js +249 -0
  187. package/dist/shaders/clouds/SkyBackgroundMaterial.d.ts +21 -0
  188. package/dist/shaders/clouds/SkyBackgroundMaterial.d.ts.map +1 -0
  189. package/dist/shaders/clouds/SkyBackgroundMaterial.js +42 -0
  190. package/dist/shaders/glsl/cloudCore.glsl.d.ts +24 -0
  191. package/dist/shaders/glsl/cloudCore.glsl.d.ts.map +1 -0
  192. package/dist/shaders/glsl/cloudCore.glsl.js +348 -0
  193. package/dist/shaders/glsl/landscapeCore.glsl.d.ts +49 -0
  194. package/dist/shaders/glsl/landscapeCore.glsl.d.ts.map +1 -0
  195. package/dist/shaders/glsl/landscapeCore.glsl.js +518 -0
  196. package/dist/shaders/glsl/noiseBake.glsl.d.ts +30 -0
  197. package/dist/shaders/glsl/noiseBake.glsl.d.ts.map +1 -0
  198. package/dist/shaders/glsl/noiseBake.glsl.js +164 -0
  199. package/dist/shaders/glsl/oceanCore.glsl.d.ts +52 -0
  200. package/dist/shaders/glsl/oceanCore.glsl.d.ts.map +1 -0
  201. package/dist/shaders/glsl/oceanCore.glsl.js +421 -0
  202. package/dist/shaders/glsl/terrainCore.glsl.d.ts +78 -0
  203. package/dist/shaders/glsl/terrainCore.glsl.d.ts.map +1 -0
  204. package/dist/shaders/glsl/terrainCore.glsl.js +625 -0
  205. package/dist/shaders/landscape/LandscapeMaterial.d.ts +73 -0
  206. package/dist/shaders/landscape/LandscapeMaterial.d.ts.map +1 -0
  207. package/dist/shaders/landscape/LandscapeMaterial.js +136 -0
  208. package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts +57 -0
  209. package/dist/shaders/ocean/OceanSurfaceMaterial.d.ts.map +1 -0
  210. package/dist/shaders/ocean/OceanSurfaceMaterial.js +268 -0
  211. package/dist/shaders/terrain/TerrainMaterial.d.ts +80 -0
  212. package/dist/shaders/terrain/TerrainMaterial.d.ts.map +1 -0
  213. package/dist/shaders/terrain/TerrainMaterial.js +291 -0
  214. package/dist/types/cloudConfigs.d.ts +244 -0
  215. package/dist/types/cloudConfigs.d.ts.map +1 -0
  216. package/dist/types/cloudConfigs.js +282 -0
  217. package/dist/types/index.d.ts +8 -0
  218. package/dist/types/index.d.ts.map +1 -1
  219. package/dist/types/index.js +4 -1
  220. package/dist/types/landscapeConfigs.d.ts +218 -0
  221. package/dist/types/landscapeConfigs.d.ts.map +1 -0
  222. package/dist/types/landscapeConfigs.js +256 -0
  223. package/dist/types/oceanConfigs.d.ts +290 -0
  224. package/dist/types/oceanConfigs.d.ts.map +1 -0
  225. package/dist/types/oceanConfigs.js +380 -0
  226. package/dist/types/terrainConfigs.d.ts +251 -0
  227. package/dist/types/terrainConfigs.d.ts.map +1 -0
  228. package/dist/types/terrainConfigs.js +292 -0
  229. package/dist/utils/cloudUniforms.d.ts +14 -0
  230. package/dist/utils/cloudUniforms.d.ts.map +1 -0
  231. package/dist/utils/cloudUniforms.js +122 -0
  232. package/dist/utils/frameRenderer.d.ts +33 -0
  233. package/dist/utils/frameRenderer.d.ts.map +1 -0
  234. package/dist/utils/frameRenderer.js +24 -0
  235. package/dist/utils/handleCloudsAnimations.d.ts +16 -0
  236. package/dist/utils/handleCloudsAnimations.d.ts.map +1 -0
  237. package/dist/utils/handleCloudsAnimations.js +64 -0
  238. package/dist/utils/landscapeGeometry.d.ts +61 -0
  239. package/dist/utils/landscapeGeometry.d.ts.map +1 -0
  240. package/dist/utils/landscapeGeometry.js +126 -0
  241. package/dist/utils/landscapeHeight.d.ts +44 -0
  242. package/dist/utils/landscapeHeight.d.ts.map +1 -0
  243. package/dist/utils/landscapeHeight.js +65 -0
  244. package/dist/utils/landscapeTextures.d.ts +94 -0
  245. package/dist/utils/landscapeTextures.d.ts.map +1 -0
  246. package/dist/utils/landscapeTextures.js +290 -0
  247. package/dist/utils/landscapeUniforms.d.ts +20 -0
  248. package/dist/utils/landscapeUniforms.d.ts.map +1 -0
  249. package/dist/utils/landscapeUniforms.js +61 -0
  250. package/dist/utils/oceanUniforms.d.ts +47 -0
  251. package/dist/utils/oceanUniforms.d.ts.map +1 -0
  252. package/dist/utils/oceanUniforms.js +216 -0
  253. package/dist/utils/rtin.d.ts +63 -0
  254. package/dist/utils/rtin.d.ts.map +1 -0
  255. package/dist/utils/rtin.js +202 -0
  256. package/dist/utils/terrainUniforms.d.ts +14 -0
  257. package/dist/utils/terrainUniforms.d.ts.map +1 -0
  258. package/dist/utils/terrainUniforms.js +196 -0
  259. package/package.json +2 -2
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Config shapes for the procedural terrain system that lives in this package.
3
+ *
4
+ * Declared locally rather than in `@3driseai/3drise-core`, alongside
5
+ * `cloudConfigs.ts` and `gridConfigs.ts`, because the material and the renderer
6
+ * are here and nothing outside the viewer needs to construct these by hand.
7
+ *
8
+ * Core's `TerrainSettings` is the retired flat shape (`visible` +
9
+ * `displacementScale`) and is deliberately left alone: a saved project still
10
+ * carries it, and `normalizeTerrain` below is what turns one into nothing rather
11
+ * than into a mountain range the scene was never authored with.
12
+ *
13
+ * A terrain is ONE landform model with per-type shaping, not four renderers —
14
+ * the same way three of the four cloud types share one marcher. What separates
15
+ * mountains from dunes is the operator applied to the fBm and the numbers around
16
+ * it, so the type is a config field the shader branches on.
17
+ */
18
+ // -----------------------------------------------------------------------------
19
+ // Defaults
20
+ // -----------------------------------------------------------------------------
21
+ const surfaceBase = {
22
+ elevation: 1200,
23
+ seaLevel: 0,
24
+ featureSize: 2600,
25
+ octaves: 9,
26
+ lacunarity: 2.06,
27
+ gain: 0.52,
28
+ ridgeSharpness: 0.62,
29
+ warpStrength: 0.28,
30
+ warpSize: 0.6,
31
+ erosion: 0.7,
32
+ terraces: 0,
33
+ terraceSharpness: 0.6,
34
+ bearing: 78,
35
+ duneWavelength: 320,
36
+ duneAsymmetry: 0.6,
37
+ plateau: 0,
38
+ valleyDepth: 0,
39
+ valleyWidth: 0.25,
40
+ lowColor: '#4a4636',
41
+ midColor: '#6b6248',
42
+ rockColor: '#6a6259',
43
+ peakColor: '#eef1f6',
44
+ slopeRockStart: 0.35,
45
+ slopeRockEnd: 0.62,
46
+ peakLevel: 0.62,
47
+ peakBlend: 0.12,
48
+ peakSlopeFalloff: 1.4,
49
+ macroVariation: 0.22,
50
+ macroSize: 2400,
51
+ detailStrength: 0.45,
52
+ detailSize: 9,
53
+ roughness: 0.82,
54
+ specular: 0.06,
55
+ ambient: 1,
56
+ bounce: 0.35,
57
+ sunShadow: 1,
58
+ shadowSoftness: 12,
59
+ aerialPerspective: 0.00007,
60
+ };
61
+ export const defaultMountainsConfig = {
62
+ ...surfaceBase,
63
+ type: 'terrain',
64
+ terrainType: 'mountains',
65
+ preset: '',
66
+ enabled: true,
67
+ };
68
+ export const defaultHillsConfig = {
69
+ ...surfaceBase,
70
+ type: 'terrain',
71
+ terrainType: 'hills',
72
+ preset: '',
73
+ enabled: true,
74
+ elevation: 300,
75
+ featureSize: 2200,
76
+ octaves: 8,
77
+ gain: 0.46,
78
+ ridgeSharpness: 0.05,
79
+ warpStrength: 0.35,
80
+ erosion: 0.45,
81
+ lowColor: '#3f5326',
82
+ midColor: '#55663a',
83
+ rockColor: '#7a7266',
84
+ peakColor: '#8d9a6a',
85
+ slopeRockStart: 0.5,
86
+ slopeRockEnd: 0.78,
87
+ peakLevel: 0.78,
88
+ peakBlend: 0.2,
89
+ macroVariation: 0.3,
90
+ macroSize: 1400,
91
+ detailStrength: 0.5,
92
+ detailSize: 6,
93
+ roughness: 0.9,
94
+ specular: 0.03,
95
+ aerialPerspective: 0.00009,
96
+ };
97
+ export const defaultDunesConfig = {
98
+ ...surfaceBase,
99
+ type: 'terrain',
100
+ terrainType: 'dunes',
101
+ preset: '',
102
+ enabled: true,
103
+ elevation: 150,
104
+ featureSize: 3000,
105
+ octaves: 6,
106
+ gain: 0.42,
107
+ ridgeSharpness: 0.15,
108
+ warpStrength: 0.2,
109
+ warpSize: 0.8,
110
+ erosion: 0.2,
111
+ duneWavelength: 340,
112
+ duneAsymmetry: 0.62,
113
+ lowColor: '#b08a53',
114
+ midColor: '#d6b077',
115
+ rockColor: '#9c7a4c',
116
+ peakColor: '#f0dcb4',
117
+ slopeRockStart: 0.62,
118
+ slopeRockEnd: 0.9,
119
+ peakLevel: 0.7,
120
+ peakBlend: 0.24,
121
+ peakSlopeFalloff: 0.6,
122
+ macroVariation: 0.14,
123
+ macroSize: 3600,
124
+ detailStrength: 0.3,
125
+ detailSize: 3.5,
126
+ roughness: 0.55,
127
+ specular: 0.16,
128
+ ambient: 1.1,
129
+ bounce: 0.55,
130
+ shadowSoftness: 22,
131
+ aerialPerspective: 0.00008,
132
+ };
133
+ export const defaultCanyonConfig = {
134
+ ...surfaceBase,
135
+ type: 'terrain',
136
+ terrainType: 'canyon',
137
+ preset: '',
138
+ enabled: true,
139
+ elevation: 700,
140
+ featureSize: 2600,
141
+ octaves: 8,
142
+ gain: 0.48,
143
+ ridgeSharpness: 0.3,
144
+ warpStrength: 0.18,
145
+ erosion: 0.85,
146
+ terraces: 14,
147
+ terraceSharpness: 0.72,
148
+ plateau: 0.55,
149
+ valleyDepth: 0.8,
150
+ valleyWidth: 0.22,
151
+ lowColor: '#7a4a30',
152
+ midColor: '#a4643c',
153
+ rockColor: '#c07a4a',
154
+ peakColor: '#d9a877',
155
+ slopeRockStart: 0.28,
156
+ slopeRockEnd: 0.5,
157
+ peakLevel: 0.72,
158
+ peakBlend: 0.08,
159
+ peakSlopeFalloff: 0.9,
160
+ macroVariation: 0.26,
161
+ macroSize: 1800,
162
+ detailStrength: 0.4,
163
+ detailSize: 7,
164
+ roughness: 0.86,
165
+ specular: 0.05,
166
+ shadowSoftness: 8,
167
+ aerialPerspective: 0.000075,
168
+ };
169
+ export const defaultTerrainQuality = {
170
+ levels: 9,
171
+ segments: 128,
172
+ cellSize: 2,
173
+ curvature: 1 / (2 * 6371000),
174
+ shadowSteps: 12,
175
+ shadowDistance: 5000,
176
+ detailFadeDistance: 1200,
177
+ receiveShadows: true,
178
+ exposure: 1,
179
+ wireframe: false,
180
+ };
181
+ /** Per-type defaults, for the controller's type switcher. */
182
+ export const TERRAIN_DEFAULTS = {
183
+ mountains: defaultMountainsConfig,
184
+ dunes: defaultDunesConfig,
185
+ hills: defaultHillsConfig,
186
+ canyon: defaultCanyonConfig,
187
+ };
188
+ export const TERRAIN_SCHEMA = [
189
+ { key: 'elevation', label: 'Elevation', group: 'form', min: 5, max: 6000, step: 5, unit: 'm', description: 'Peak height above sea level. Every height-keyed splat threshold is a fraction of this, so raising it does not move the snow line.' },
190
+ { key: 'seaLevel', label: 'Sea level', group: 'form', min: -2000, max: 2000, step: 5, unit: 'm', description: 'World Y the terrain is built around — where flat ground sits, and where a placed object meets it.' },
191
+ { key: 'featureSize', label: 'Feature size', group: 'form', min: 200, max: 40000, step: 50, unit: 'm', description: 'Horizontal size of the primary landform. The one knob that decides whether this reads as a mountain range or a gravel pile.' },
192
+ { key: 'octaves', label: 'Octaves', group: 'form', min: 3, max: 12, step: 1, description: 'fBm detail levels. Past ~10 the extra octaves are finer than the closest clipmap cell and only cost; distant rings drop them automatically.' },
193
+ { key: 'lacunarity', label: 'Lacunarity', group: 'form', min: 1.7, max: 2.6, step: 0.01, advanced: true, description: 'Frequency step per octave. Slightly off 2.0 breaks the grid alignment that otherwise shows as a faint square lattice.' },
194
+ { key: 'gain', label: 'Gain', group: 'form', min: 0.25, max: 0.72, step: 0.005, description: 'Amplitude step per octave. Below 0.5 smooth and rolling, above it jagged and fractal.' },
195
+ { key: 'ridgeSharpness', label: 'Ridge sharpness', group: 'form', min: 0, max: 1, step: 0.005, description: '0 gives rounded billow hills, 1 knife ridges. The strongest single cue between a mountain and a dune field.' },
196
+ { key: 'warpStrength', label: 'Domain warp', group: 'form', min: 0, max: 1, step: 0.005, description: 'Bends ridge lines into curved, branching shapes. At 0 the silhouette reads as noise rather than landscape.' },
197
+ { key: 'warpSize', label: 'Warp size', group: 'form', min: 0.1, max: 2, step: 0.01, advanced: true, description: 'Scale of the warp field relative to feature size. Above ~1 it drifts the terrain instead of bending it.' },
198
+ { key: 'erosion', label: 'Erosion', group: 'form', min: 0, max: 1, step: 0.005, description: 'Damps octaves where slope is already steep — flattens valley floors, sharpens flanks. The cheapest approximation of erosion there is.' },
199
+ { key: 'terraces', label: 'Strata', group: 'form', min: 0, max: 40, step: 1, types: ['canyon', 'mountains'], description: 'Sedimentary banding step count. 0 is off. Most of what makes a mesa read as a mesa.' },
200
+ { key: 'terraceSharpness', label: 'Strata hardness', group: 'form', min: 0, max: 1, step: 0.01, types: ['canyon', 'mountains'], description: '0 is a smooth ramp between bands, 1 a near-vertical riser.' },
201
+ { key: 'plateau', label: 'Plateau', group: 'form', min: 0, max: 1, step: 0.005, types: ['canyon'], description: 'Fraction of the height range flattened into mesa tops.' },
202
+ { key: 'valleyDepth', label: 'Incision depth', group: 'form', min: 0, max: 1.5, step: 0.005, types: ['canyon'], description: 'Depth of the carved channel network as a fraction of elevation. At 0 the mesas have nothing between them.' },
203
+ { key: 'valleyWidth', label: 'Incision width', group: 'form', min: 0.03, max: 1, step: 0.005, types: ['canyon'], description: 'Narrow cuts slot canyons; wide ones cut broad washes.' },
204
+ { key: 'bearing', label: 'Wind bearing', group: 'form', min: 0, max: 360, step: 1, unit: 'deg', types: ['dunes'], description: 'Dunes are transverse to the wind, so this rotates the whole crest train.' },
205
+ { key: 'duneWavelength', label: 'Dune wavelength', group: 'form', min: 40, max: 2000, step: 5, unit: 'm', types: ['dunes'], description: 'Crest-to-crest distance of the dune train.' },
206
+ { key: 'duneAsymmetry', label: 'Slip face', group: 'form', min: 0, max: 1, step: 0.005, types: ['dunes'], description: 'Lee-slope steepening. At 0 the dunes are sine waves; real ones have a long windward ramp and a short face at the angle of repose.' },
207
+ { key: 'slopeRockStart', label: 'Rock from slope', group: 'surface', min: 0, max: 1, step: 0.005, description: 'Slope at which rock starts showing through. Splatting rock by slope rather than height is what makes a cliff read as a cliff at any altitude.' },
208
+ { key: 'slopeRockEnd', label: 'Bare rock at slope', group: 'surface', min: 0, max: 1, step: 0.005, description: 'Slope at which the surface is fully bare rock.' },
209
+ { key: 'peakLevel', label: 'Peak line', group: 'surface', min: 0, max: 1, step: 0.005, description: 'Height fraction where the peak layer (snow, salt, bleached stone) begins.' },
210
+ { key: 'peakBlend', label: 'Peak blend', group: 'surface', min: 0.01, max: 0.5, step: 0.005, description: 'Width of that transition. A hard line is physically right for temperature but reads as a decal.' },
211
+ { key: 'peakSlopeFalloff', label: 'Peak slope falloff', group: 'surface', min: 0, max: 3, step: 0.01, description: 'Peak coverage lost per unit slope. Snow does not sit on a vertical face; without this a summit looks dipped in paint.' },
212
+ { key: 'macroVariation', label: 'Macro variation', group: 'surface', min: 0, max: 1, step: 0.005, description: 'Large-scale albedo break-up. Without it a splat layer is one flat colour across kilometres and reads as untextured.' },
213
+ { key: 'macroSize', label: 'Macro size', group: 'surface', min: 200, max: 12000, step: 50, unit: 'm', description: 'Size of that variation.' },
214
+ { key: 'detailStrength', label: 'Detail bump', group: 'surface', min: 0, max: 1.5, step: 0.005, description: 'High-frequency normal detail added per fragment — bumps far below the mesh resolution.' },
215
+ { key: 'detailSize', label: 'Detail size', group: 'surface', min: 0.5, max: 60, step: 0.25, unit: 'm', description: 'Size of that detail. Below about a metre it aliases before it fades.' },
216
+ { key: 'roughness', label: 'Roughness', group: 'surface', min: 0.05, max: 1, step: 0.005, description: 'Widens the specular lobe. Rock is nearly matte; wet sand and snow are not.' },
217
+ { key: 'specular', label: 'Specular', group: 'surface', min: 0, max: 1, step: 0.005, description: 'Specular strength. The grazing sheen on sand at low sun comes from here.' },
218
+ { key: 'ambient', label: 'Ambient', group: 'lighting', min: 0, max: 3, step: 0.01, description: 'Sky-dome fill, taken from the same atmosphere the sky and clouds use, so it darkens and warms as the sun sets instead of freezing.' },
219
+ { key: 'bounce', label: 'Ground bounce', group: 'lighting', min: 0, max: 2, step: 0.01, description: 'Fill on downward-facing surfaces, tinted by the low colour. Keeps overhangs and north faces off pure black.' },
220
+ { key: 'sunShadow', label: 'Self shadow', group: 'lighting', min: 0, max: 1, step: 0.01, description: 'Strength of the analytic shadow marched down the sun vector. This is what puts a mountain shadow in its own valley, with no shadow-map resolution to run out of.' },
221
+ { key: 'shadowSoftness', label: 'Shadow softness', group: 'lighting', min: 1, max: 60, step: 0.5, description: 'Penumbra width of that shadow. Larger reads as a hazier day.' },
222
+ { key: 'aerialPerspective', label: 'Aerial perspective', group: 'lighting', min: 0, max: 0.0004, step: 0.000002, unit: '1/m', description: 'Rate distant terrain fades into the sky behind it. The main cue for how large the landscape reads, and what makes the horizon a horizon rather than a cut-out.' },
223
+ ];
224
+ export const TERRAIN_QUALITY_SCHEMA = [
225
+ { key: 'levels', label: 'Clipmap levels', group: 'quality', min: 2, max: 12, step: 1, description: 'Each ring doubles its cell size, so visible radius is roughly cellSize x segments x 2^(levels-1). 9 levels of 192 at 2 m reaches ~98 km, which is past where haze has dissolved the ground.' },
226
+ { key: 'segments', label: 'Ring resolution', group: 'quality', min: 32, max: 320, step: 8, description: 'Grid resolution per ring side, and the one knob that sets how polygonal the terrain looks: a clipmap triangle subtends about 2/segments radians whatever the distance, so 192 is roughly 12 px at 1080p. Vertex cost is levels x segments^2 x 0.75, since every ring above the first is hollow.' },
227
+ { key: 'cellSize', label: 'Cell size', group: 'quality', min: 0.25, max: 32, step: 0.25, unit: 'm', description: 'Finest cell, at the camera. Lower it for a walkable scene, raise it for a flyover.' },
228
+ { key: 'shadowSteps', label: 'Shadow steps', group: 'quality', min: 0, max: 48, step: 1, description: 'Steps in the analytic sun-shadow march, nearest the camera. 0 disables terrain self-shadowing entirely, which is the single biggest thing you can turn off; below ~12 long shadows at low sun start to leak.' },
229
+ { key: 'shadowDistance', label: 'Shadow distance', group: 'quality', min: 0, max: 40000, step: 100, unit: 'm', description: 'Range over which the self-shadow fades out. The march runs per vertex, so lowering this drops whole clipmap rings out of it — the cheapest quality dial there is after turning shadows off.' },
230
+ { key: 'detailFadeDistance', label: 'Detail fade distance', group: 'quality', min: 50, max: 8000, step: 25, unit: 'm', description: 'Distance over which fragment-stage bump fades out. Removes far-field shimmer and buys back most of its own cost.' },
231
+ { key: 'curvature', label: 'Planetary curvature', group: 'quality', min: 0, max: 0.0000012, step: 0.00000001, advanced: true, description: '1/(2R). Drops the surface with the square of distance so it meets a real horizon. Zero gives a flat world, which at these extents looks wrong long before it looks flat.' },
232
+ { key: 'exposure', label: 'Exposure', group: 'quality', min: 0.2, max: 4, step: 0.01, description: 'Radiance scale, so terrain matches the sky and clouds whether or not the cloud composite is what tonemaps the frame.' },
233
+ ];
234
+ export const defaultProceduralTerrainSettings = {
235
+ id: '3drise-terrain',
236
+ type: 'terrain',
237
+ config: { ...defaultHillsConfig, enabled: false },
238
+ quality: { ...defaultTerrainQuality },
239
+ };
240
+ // =============================================================================
241
+ // Normalisation
242
+ // =============================================================================
243
+ //
244
+ // A published scene loads whatever was in the database the day it was saved, and
245
+ // a scene saved before this system existed carries core's flat TerrainSettings
246
+ // (`visible` + `displacementScale`) under the same key. Reading that straight
247
+ // into the renderer is how an embed dies: the clipmap sizes its rings from
248
+ // `quality.segments` on its first frame.
249
+ //
250
+ // Each block merges over its own defaults SEPARATELY, not through one merge over
251
+ // the settings object, so a quality edit does not hand the surface a new config
252
+ // object and rebuild the clipmap geometry.
253
+ const TERRAIN_TYPES = ['mountains', 'dunes', 'hills', 'canyon'];
254
+ const isRecord = (v) => typeof v === 'object' && v !== null;
255
+ /**
256
+ * Surface block merged over its type's defaults, or null when there is nothing to
257
+ * render — including the retired flat shape, which has no `config` and must draw
258
+ * nothing rather than a landscape the project was never authored with.
259
+ *
260
+ * An unknown or missing `terrainType` falls back to hills rather than rendering
261
+ * nothing: a scene that says `enabled: true` should show ground.
262
+ */
263
+ export function normalizeTerrain(raw) {
264
+ if (!isRecord(raw))
265
+ return null;
266
+ const terrainType = TERRAIN_TYPES.includes(raw.terrainType)
267
+ ? raw.terrainType
268
+ : 'hills';
269
+ return {
270
+ ...TERRAIN_DEFAULTS[terrainType],
271
+ ...raw,
272
+ type: 'terrain',
273
+ terrainType,
274
+ };
275
+ }
276
+ export function normalizeTerrainQuality(raw) {
277
+ return { ...defaultTerrainQuality, ...(isRecord(raw) ? raw : {}) };
278
+ }
279
+ /**
280
+ * A whole settings blob, from a project of any age. The flat legacy shape has no
281
+ * `config`, so it normalises to a disabled terrain rather than to a default one.
282
+ */
283
+ export function normalizeTerrainSettings(raw) {
284
+ const source = isRecord(raw) ? raw : {};
285
+ const config = normalizeTerrain(source.config);
286
+ return {
287
+ id: typeof source.id === 'string' ? source.id : defaultProceduralTerrainSettings.id,
288
+ type: 'terrain',
289
+ config: config ?? { ...defaultHillsConfig, enabled: false },
290
+ quality: normalizeTerrainQuality(source.quality),
291
+ };
292
+ }
@@ -0,0 +1,14 @@
1
+ import * as THREE from 'three';
2
+ import type { CloudDeckConfig, CirrusLayerConfig, CloudsQualityConfig } from '../types/cloudConfigs';
3
+ import type { CloudSunState } from '../hooks/useCloudSun';
4
+ export declare function applyDeckUniforms(material: THREE.ShaderMaterial, deck: CloudDeckConfig, quality: CloudsQualityConfig): void;
5
+ export declare function applyCirrusUniforms(material: THREE.ShaderMaterial, cirrus: CirrusLayerConfig, quality: CloudsQualityConfig): void;
6
+ /** Sun and atmosphere. Every cloud material and the sky background share these. */
7
+ export declare function applySunUniforms(material: THREE.ShaderMaterial, sun: CloudSunState, intensity: number): void;
8
+ /**
9
+ * Camera basis for the ray reconstruction. `invProj` is passed in rather than read
10
+ * off the camera because the cloud pass uses a sub-pixel jittered projection that
11
+ * the scene pass must not see.
12
+ */
13
+ export declare function applyCameraUniforms(material: THREE.ShaderMaterial, camera: THREE.PerspectiveCamera, invProj: THREE.Matrix4, width: number, height: number): void;
14
+ //# sourceMappingURL=cloudUniforms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudUniforms.d.ts","sourceRoot":"","sources":["../../src/utils/cloudUniforms.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACrG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA0B1D,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,KAAK,CAAC,cAAc,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI,CA0C3H;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,cAAc,EAAE,MAAM,EAAE,iBAAiB,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAkBjI;AAED,mFAAmF;AACnF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,cAAc,EAAE,GAAG,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAY5G;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,KAAK,CAAC,cAAc,EAAE,MAAM,EAAE,KAAK,CAAC,iBAAiB,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAUhK"}
@@ -0,0 +1,122 @@
1
+ import * as THREE from 'three';
2
+ /**
3
+ * Config to uniform mapping for the cloud materials.
4
+ *
5
+ * The config speaks in the units a person thinks in — "600 m features", "wind
6
+ * bearing 78 degrees" — and the shader wants reciprocals and direction vectors.
7
+ * Doing that conversion here rather than storing shader-space numbers means the
8
+ * settings panel, the presets and the AI agent all read in world units.
9
+ *
10
+ * These mutate the material in place and are called every frame. A 50-uniform
11
+ * shader driven through React props would re-render the tree once per frame.
12
+ */
13
+ const _dir = new THREE.Vector2();
14
+ function bearingToVector(degrees, out) {
15
+ const a = THREE.MathUtils.degToRad(degrees);
16
+ return out.set(Math.sin(a), Math.cos(a)).normalize();
17
+ }
18
+ /** Guard against a zero or negative size producing an infinite scale. */
19
+ function inverse(size, fallback) {
20
+ return size > 1e-6 ? 1 / size : 1 / fallback;
21
+ }
22
+ export function applyDeckUniforms(material, deck, quality) {
23
+ const u = material.uniforms;
24
+ if (!u)
25
+ return;
26
+ u.u_coverage.value = deck.coverage;
27
+ u.u_density.value = deck.density;
28
+ u.u_cloudType.value = deck.profile;
29
+ u.u_layerBottom.value = deck.baseAltitude;
30
+ u.u_layerTop.value = Math.max(deck.topAltitude, deck.baseAltitude + 50);
31
+ u.u_baseScale.value = inverse(deck.featureSize, 2600);
32
+ u.u_detailScale.value = inverse(deck.detailSize, 400);
33
+ u.u_detailStrength.value = deck.detailStrength;
34
+ u.u_curlStrength.value = deck.curlStrength;
35
+ u.u_weatherScale.value = inverse(deck.weatherCellSize, 24000);
36
+ u.u_shear.value = deck.shear;
37
+ u.u_anvil.value = deck.anvil;
38
+ u.u_precip.value = deck.precipitation;
39
+ u.u_windDir.value.copy(bearingToVector(deck.windBearing, _dir));
40
+ u.u_windSpeed.value = deck.windSpeed;
41
+ u.u_rise.value = deck.rise;
42
+ u.u_churn.value = deck.churn;
43
+ u.u_evolution.value = deck.evolution;
44
+ u.u_sigmaT.value = deck.extinction;
45
+ u.u_g1.value = deck.forwardLobe;
46
+ u.u_g2.value = deck.backLobe;
47
+ u.u_msExtinction.value = deck.msExtinction;
48
+ u.u_msEnergy.value = deck.msEnergy;
49
+ u.u_msPhase.value = deck.msPhase;
50
+ u.u_powder.value = deck.powder;
51
+ u.u_silver.value = deck.silverLining;
52
+ u.u_ambient.value = deck.ambient;
53
+ u.u_fogDensity.value = deck.aerialPerspective;
54
+ u.u_steps.value = Math.round(quality.steps);
55
+ u.u_lightSteps.value = Math.round(quality.lightSteps);
56
+ u.u_lightStep.value = quality.lightStep;
57
+ u.u_stepGrowth.value = quality.stepGrowth;
58
+ u.u_maxSpan.value = quality.maxSpan;
59
+ u.u_detailFade.value = inverse(quality.detailFadeDistance, 16000);
60
+ u.u_curvature.value = quality.curvature;
61
+ }
62
+ export function applyCirrusUniforms(material, cirrus, quality) {
63
+ const u = material.uniforms;
64
+ if (!u)
65
+ return;
66
+ u.u_altitude.value = cirrus.altitude;
67
+ u.u_thickness.value = cirrus.thickness;
68
+ u.u_coverage.value = cirrus.coverage;
69
+ u.u_opticalDepth.value = cirrus.opticalDepth;
70
+ u.u_featureScale.value = inverse(cirrus.featureSize, 44000);
71
+ u.u_anisotropy.value = cirrus.anisotropy;
72
+ u.u_windDir.value.copy(bearingToVector(cirrus.windBearing, _dir));
73
+ u.u_windSpeed.value = cirrus.windSpeed;
74
+ u.u_halo.value = cirrus.halo;
75
+ u.u_g1.value = cirrus.forwardLobe;
76
+ u.u_g2.value = cirrus.secondaryLobe;
77
+ u.u_ambient.value = cirrus.ambient;
78
+ u.u_fogDensity.value = cirrus.aerialPerspective;
79
+ u.u_curvature.value = quality.curvature;
80
+ }
81
+ /** Sun and atmosphere. Every cloud material and the sky background share these. */
82
+ export function applySunUniforms(material, sun, intensity) {
83
+ const u = material.uniforms;
84
+ if (!u)
85
+ return;
86
+ if (u.u_sunDir)
87
+ u.u_sunDir.value.copy(sun.direction);
88
+ if (u.u_sunColor)
89
+ u.u_sunColor.value.copy(sun.color);
90
+ if (u.u_skyAmbient)
91
+ u.u_skyAmbient.value.copy(sun.skyAmbient);
92
+ if (u.u_groundAmbient)
93
+ u.u_groundAmbient.value.copy(sun.groundAmbient);
94
+ if (u.u_sunIntensity)
95
+ u.u_sunIntensity.value = intensity;
96
+ if (u.u_turbidity)
97
+ u.u_turbidity.value = sun.turbidity;
98
+ if (u.u_rayleigh)
99
+ u.u_rayleigh.value = sun.rayleigh;
100
+ if (u.u_mieCoefficient)
101
+ u.u_mieCoefficient.value = sun.mieCoefficient;
102
+ if (u.u_mieG)
103
+ u.u_mieG.value = sun.mieG;
104
+ }
105
+ const _fwd = new THREE.Vector3();
106
+ /**
107
+ * Camera basis for the ray reconstruction. `invProj` is passed in rather than read
108
+ * off the camera because the cloud pass uses a sub-pixel jittered projection that
109
+ * the scene pass must not see.
110
+ */
111
+ export function applyCameraUniforms(material, camera, invProj, width, height) {
112
+ const u = material.uniforms;
113
+ if (!u)
114
+ return;
115
+ u.u_camPos.value.copy(camera.position);
116
+ u.u_camWorld.value.copy(camera.matrixWorld);
117
+ u.u_invProj.value.copy(invProj);
118
+ u.u_camFwd.value.copy(_fwd.set(0, 0, -1).applyQuaternion(camera.quaternion).normalize());
119
+ u.u_near.value = camera.near;
120
+ u.u_far.value = camera.far;
121
+ u.u_resolution.value.set(width, height);
122
+ }
@@ -0,0 +1,33 @@
1
+ import type * as THREE from 'three';
2
+ /**
3
+ * Who is allowed to say what a finished frame looks like.
4
+ *
5
+ * Most of the scene is the scene graph, so `gl.render(scene, camera)` is the whole
6
+ * picture. A full-screen pass breaks that. VolumetricCloudsPass runs at
7
+ * `useFrame(…, 1)`, which takes rendering away from R3F: it draws the scene into an
8
+ * HDR target, marches the clouds at half resolution, resolves them temporally and
9
+ * composites the result to the canvas. The clouds exist only in that composite —
10
+ * there is no cloud geometry in the scene graph to find.
11
+ *
12
+ * So anything that renders a frame for its own purposes — a screenshot, a thumbnail,
13
+ * an export — must not call `gl.render(scene, camera)` directly. It gets everything
14
+ * except the clouds, which is worse than failing, because it looks like it worked.
15
+ *
16
+ * The registry is the same shape as `useCloudLive`: the pass publishes a handle, the
17
+ * consumer resolves it at call time and falls back to plain rendering when nothing
18
+ * has taken the frame over. Keyed on the renderer (like the cloud-noise cache) rather
19
+ * than React context, so a capture component mounted anywhere inside the Canvas
20
+ * finds it without being a descendant of the environment tree.
21
+ */
22
+ /** Produce one complete frame to the currently bound target. */
23
+ export type FrameRenderer = (camera: THREE.Camera) => void;
24
+ /** Claim the frame. Returns the release function; call it on unmount. */
25
+ export declare function registerFrameRenderer(gl: THREE.WebGLRenderer, renderer: FrameRenderer): () => void;
26
+ /** True when a full-screen pass owns the frame, so `gl.render` alone is incomplete. */
27
+ export declare function hasFrameRenderer(gl: THREE.WebGLRenderer): boolean;
28
+ /**
29
+ * Render one complete frame. Use this instead of `gl.render(scene, camera)` anywhere
30
+ * you need the canvas to hold a finished image — screenshots, thumbnails, exports.
31
+ */
32
+ export declare function renderFrame(gl: THREE.WebGLRenderer, scene: THREE.Scene, camera: THREE.Camera): void;
33
+ //# sourceMappingURL=frameRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frameRenderer.d.ts","sourceRoot":"","sources":["../../src/utils/frameRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,OAAO,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,gEAAgE;AAChE,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC;AAI3D,yEAAyE;AACzE,wBAAgB,qBAAqB,CACjC,EAAE,EAAE,KAAK,CAAC,aAAa,EACvB,QAAQ,EAAE,aAAa,GACxB,MAAM,IAAI,CAKZ;AAED,uFAAuF;AACvF,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,KAAK,CAAC,aAAa,GAAG,OAAO,CAEjE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACvB,EAAE,EAAE,KAAK,CAAC,aAAa,EACvB,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,MAAM,EAAE,KAAK,CAAC,MAAM,GACrB,IAAI,CAIN"}
@@ -0,0 +1,24 @@
1
+ const registry = new WeakMap();
2
+ /** Claim the frame. Returns the release function; call it on unmount. */
3
+ export function registerFrameRenderer(gl, renderer) {
4
+ registry.set(gl, renderer);
5
+ return () => {
6
+ if (registry.get(gl) === renderer)
7
+ registry.delete(gl);
8
+ };
9
+ }
10
+ /** True when a full-screen pass owns the frame, so `gl.render` alone is incomplete. */
11
+ export function hasFrameRenderer(gl) {
12
+ return registry.has(gl);
13
+ }
14
+ /**
15
+ * Render one complete frame. Use this instead of `gl.render(scene, camera)` anywhere
16
+ * you need the canvas to hold a finished image — screenshots, thumbnails, exports.
17
+ */
18
+ export function renderFrame(gl, scene, camera) {
19
+ const owner = registry.get(gl);
20
+ if (owner)
21
+ owner(camera);
22
+ else
23
+ gl.render(scene, camera);
24
+ }
@@ -0,0 +1,16 @@
1
+ import type { AnimationOptions, MouseMoveProperty } from '@3driseai/3drise-core';
2
+ import type { CloudDeckConfig } from '../types/cloudConfigs';
3
+ export type CloudPropertyOverride = Partial<Record<string, number>>;
4
+ /** Cache of the value a property started at, so `from`-less keyframes have an origin. */
5
+ export type CloudStartValues = Record<string, number>;
6
+ export declare function applyCloudsKeyframeAnimations(animations: AnimationOptions[] | undefined, startValues: CloudStartValues, deck: CloudDeckConfig, override: CloudPropertyOverride, currentTime: number): void;
7
+ export declare function applyCloudsMouseMove(properties: MouseMoveProperty[] | undefined, deck: CloudDeckConfig, override: CloudPropertyOverride, pointer: {
8
+ x: number;
9
+ y: number;
10
+ }): void;
11
+ /**
12
+ * Merge the frame's overrides into a deck config. Returns `deck` untouched when
13
+ * nothing is animating, so the common case allocates nothing.
14
+ */
15
+ export declare function resolveDeckConfig(deck: CloudDeckConfig, override: CloudPropertyOverride): CloudDeckConfig;
16
+ //# sourceMappingURL=handleCloudsAnimations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handleCloudsAnimations.d.ts","sourceRoot":"","sources":["../../src/utils/handleCloudsAnimations.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAmB7D,MAAM,MAAM,qBAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEpE,yFAAyF;AACzF,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEtD,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,gBAAgB,EAAE,GAAG,SAAS,EAAE,WAAW,EAAE,gBAAgB,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAiB1M;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,iBAAiB,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,qBAAqB,EAAE,OAAO,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUjL;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,eAAe,EAAE,QAAQ,EAAE,qBAAqB,GAAG,eAAe,CAOzG"}
@@ -0,0 +1,64 @@
1
+ import { calculateTimeProgress, applyEasing, gsapEasingMap, interpolateValue, interpolateMouseMoveProperty, } from '@3driseai/3drise-core';
2
+ import { CLOUD_ANIMATABLE_PROPERTIES } from '../types/cloudConfigs.js';
3
+ /**
4
+ * The `clouds` animation and mouse-move domains, applied to a deck config.
5
+ *
6
+ * Same shape as the legacy Clouds.tsx helpers — keyframes first, then mouse-move
7
+ * on top of the keyframed value — but over the whole animatable property set
8
+ * rather than just `speed`.
9
+ *
10
+ * Only scalars that can be interpolated per frame without rebuilding anything are
11
+ * eligible. Altitudes and feature sizes are excluded on purpose: the vertical
12
+ * profile is measured as a fraction of base-to-top, so animating an altitude
13
+ * restretches the entire density field and the cloud appears to pump rather than
14
+ * move.
15
+ */
16
+ const ANIMATABLE = new Set(CLOUD_ANIMATABLE_PROPERTIES);
17
+ export function applyCloudsKeyframeAnimations(animations, startValues, deck, override, currentTime) {
18
+ if (!animations?.length)
19
+ return;
20
+ for (const anim of animations) {
21
+ const { property, to, duration, ease, loop = false, yoyo = false, active } = anim;
22
+ if (!active || to === undefined || !ANIMATABLE.has(property))
23
+ continue;
24
+ let from = anim.from;
25
+ if (from === undefined) {
26
+ from = startValues[property] ??= deck[property];
27
+ }
28
+ let p = calculateTimeProgress(currentTime, duration, yoyo, loop);
29
+ if (ease) {
30
+ const fn = gsapEasingMap[ease] || ease;
31
+ p = applyEasing(fn, p);
32
+ }
33
+ override[property] = interpolateValue(property, from, to, p);
34
+ }
35
+ }
36
+ export function applyCloudsMouseMove(properties, deck, override, pointer) {
37
+ if (!properties?.length)
38
+ return;
39
+ for (const { property, enabled, propertySettings } of properties) {
40
+ if (!enabled || !ANIMATABLE.has(property))
41
+ continue;
42
+ const { axis = 'both', sensitivity = 1, inverted = false, min, max } = propertySettings || {};
43
+ // Layer on top of the keyframed value when there is one, so the two compose
44
+ // instead of the pointer snapping back to the config every frame.
45
+ const base = override[property] ?? deck[property];
46
+ override[property] = interpolateMouseMoveProperty(base, min, max, pointer, axis, sensitivity, inverted);
47
+ }
48
+ }
49
+ /**
50
+ * Merge the frame's overrides into a deck config. Returns `deck` untouched when
51
+ * nothing is animating, so the common case allocates nothing.
52
+ */
53
+ export function resolveDeckConfig(deck, override) {
54
+ let dirty = false;
55
+ for (const k in override) {
56
+ if (override[k] !== undefined) {
57
+ dirty = true;
58
+ break;
59
+ }
60
+ }
61
+ if (!dirty)
62
+ return deck;
63
+ return { ...deck, ...override };
64
+ }
@@ -0,0 +1,61 @@
1
+ import * as THREE from 'three';
2
+ import { type RtinTile } from './rtin';
3
+ import type { DecodedHeightmap } from './landscapeTextures';
4
+ /**
5
+ * Heightmap to drawable geometry.
6
+ *
7
+ * Two decisions worth knowing:
8
+ *
9
+ * **Y stays zero in the buffer.** The mesh carries XZ and UV only; the height is
10
+ * applied in the vertex shader from the heightmap texture. That keeps
11
+ * `elevationScale` and `smoothness` live-draggable without re-running RTIN, and
12
+ * it is what lets the depth material displace identically for shadow casting.
13
+ * The cost is that object-space bounds describe a flat plate, which is why the
14
+ * per-chunk bounding boxes below are built by hand from the heightmap's own
15
+ * min/max rather than from the vertex buffer.
16
+ *
17
+ * **The tile is chunked.** One tile is one draw call in the reference, with
18
+ * culling disabled. Here the index buffer is split into an N x N grid over ONE
19
+ * shared vertex buffer: each chunk gets real bounds and culls independently, and
20
+ * because neighbouring chunks share vertices exactly there is no crack risk. The
21
+ * shared buffer is also why disposal is centralised — disposing every chunk
22
+ * geometry would free the same attribute N^2 times.
23
+ */
24
+ export interface LandscapeChunk {
25
+ geometry: THREE.BufferGeometry;
26
+ /** Normalised height range of the vertices this chunk references, so the
27
+ * bounding box can be rebuilt when the elevation scale changes without
28
+ * touching the geometry. */
29
+ minH01: number;
30
+ maxH01: number;
31
+ }
32
+ export interface LandscapeGeometry {
33
+ chunks: LandscapeChunk[];
34
+ /** Shared across every chunk. Disposed once. */
35
+ position: THREE.BufferAttribute;
36
+ uv: THREE.BufferAttribute;
37
+ vertexCount: number;
38
+ triangleCount: number;
39
+ /** World size the XZ coordinates were built for. */
40
+ size: number;
41
+ dispose(): void;
42
+ }
43
+ export interface BuildLandscapeGeometryOptions {
44
+ /** World units across the tile. */
45
+ size: number;
46
+ /** N x N culling chunks. */
47
+ chunks: number;
48
+ /** RTIN budget in NORMALISED height units — world error divided by the
49
+ * elevation scale. Keeping the error map normalised is what lets a change
50
+ * of elevation scale re-run `getMesh` instead of rebuilding the map. */
51
+ maxError: number;
52
+ }
53
+ /** The error map depends only on the heightfield, so it is built once per
54
+ * decoded heightmap and reused for every error budget. */
55
+ export declare function rtinTileFor(height: DecodedHeightmap): RtinTile;
56
+ export declare function buildLandscapeGeometry(height: DecodedHeightmap, options: BuildLandscapeGeometryOptions): LandscapeGeometry;
57
+ /** Rewrite the vertical extent of every chunk's bounds. Called whenever the
58
+ * elevation scale or bias changes; without it a raised landscape culls against
59
+ * the flat plate it was built as and disappears when the camera tilts. */
60
+ export declare function setLandscapeBounds(geometry: LandscapeGeometry, scale: number, bias: number): void;
61
+ //# sourceMappingURL=landscapeGeometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"landscapeGeometry.d.ts","sourceRoot":"","sources":["../../src/utils/landscapeGeometry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAC5C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAA;AAE3D;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,WAAW,cAAc;IAC3B,QAAQ,EAAE,KAAK,CAAC,cAAc,CAAA;IAC9B;;iCAE6B;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,gDAAgD;IAChD,QAAQ,EAAE,KAAK,CAAC,eAAe,CAAA;IAC/B,EAAE,EAAE,KAAK,CAAC,eAAe,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,CAAA;IACrB,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,IAAI,IAAI,CAAA;CAClB;AAED,MAAM,WAAW,6BAA6B;IAC1C,mCAAmC;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAA;IACd;;6EAEyE;IACzE,QAAQ,EAAE,MAAM,CAAA;CACnB;AAID;2DAC2D;AAC3D,wBAAgB,WAAW,CAAC,MAAM,EAAE,gBAAgB,GAAG,QAAQ,CAM9D;AAED,wBAAgB,sBAAsB,CAClC,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,6BAA6B,GACvC,iBAAiB,CAiGnB;AAED;;2EAE2E;AAC3E,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAYjG"}