@call-me-sensei/toonlab 0.3.1 → 0.4.20

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 (761) hide show
  1. package/NPM-LIBRARY.md +225 -0
  2. package/README.md +588 -184
  3. package/agents/PROMPTS.md +87 -0
  4. package/agents/README.md +54 -0
  5. package/agents/claude/CLAUDE.md +8 -0
  6. package/agents/codex/AGENTS.md +159 -0
  7. package/agents/cursor/toonlab.mdc +37 -0
  8. package/agents/references/anime-art-direction.md +24 -0
  9. package/agents/references/asset-sourcing-policy.md +23 -0
  10. package/agents/references/custom-gap-report.md +16 -0
  11. package/agents/references/mcp-asset-discovery.md +104 -0
  12. package/agents/references/runtime-entry-points.md +175 -0
  13. package/agents/references/style-bundles.md +71 -0
  14. package/agents/skills/claude/asset-sourcing/SKILL.md +275 -0
  15. package/agents/skills/claude/environment/SKILL.md +59 -0
  16. package/agents/skills/claude/game-dev/SKILL.md +100 -0
  17. package/agents/skills/claude/post-processing/SKILL.md +44 -0
  18. package/agents/skills/claude/rock-ground-shaders/SKILL.md +134 -0
  19. package/agents/skills/claude/rockgen/SKILL.md +30 -0
  20. package/agents/skills/claude/scene-style-application/SKILL.md +74 -0
  21. package/agents/skills/claude/style-presets/SKILL.md +101 -0
  22. package/agents/skills/claude/toon-shading/SKILL.md +44 -0
  23. package/agents/skills/claude/vegetation-sky/SKILL.md +167 -0
  24. package/agents/skills/claude/visual-verification/SKILL.md +136 -0
  25. package/agents/skills/claude/water/SKILL.md +105 -0
  26. package/agents/skills/codex/asset-sourcing/SKILL.md +275 -0
  27. package/agents/skills/codex/environment/SKILL.md +59 -0
  28. package/agents/skills/codex/game-dev/SKILL.md +100 -0
  29. package/agents/skills/codex/post-processing/SKILL.md +44 -0
  30. package/agents/skills/codex/rock-ground-shaders/SKILL.md +134 -0
  31. package/agents/skills/codex/rockgen/SKILL.md +30 -0
  32. package/agents/skills/codex/scene-style-application/SKILL.md +74 -0
  33. package/agents/skills/codex/style-presets/SKILL.md +101 -0
  34. package/agents/skills/codex/toon-shading/SKILL.md +44 -0
  35. package/agents/skills/codex/vegetation-sky/SKILL.md +167 -0
  36. package/agents/skills/codex/visual-verification/SKILL.md +136 -0
  37. package/agents/skills/codex/water/SKILL.md +105 -0
  38. package/cli/toonlab.mjs +53 -0
  39. package/compose.yaml +20 -0
  40. package/database/apply-sql.mjs +141 -0
  41. package/database/client.mjs +39 -0
  42. package/database/creation-tags.mjs +23 -0
  43. package/database/env.mjs +16 -0
  44. package/database/fal-patina.mjs +131 -0
  45. package/database/generation-service.mjs +415 -0
  46. package/database/migrations/0001_local_workspace.sql +120 -0
  47. package/database/migrations/0002_file_ownership.sql +11 -0
  48. package/database/migrations/0003_remove_autosaves_from_library.sql +7 -0
  49. package/database/migrations/0004_catalog_asset_packs.sql +39 -0
  50. package/database/migrations/0005_creation_tag_discovery.sql +1 -0
  51. package/database/migrations/0006_normalize_creation_tags.sql +28 -0
  52. package/database/migrations/0007_creation_revisions.sql +80 -0
  53. package/database/migrations/0008_creation_revision_hardening.sql +98 -0
  54. package/database/migrations/0009_creation_revision_delete_integrity.sql +11 -0
  55. package/database/migrations/0010_external_catalog_assets.sql +28 -0
  56. package/database/providers.mjs +644 -0
  57. package/database/repository.mjs +1073 -0
  58. package/database/seeds/catalog/0001_empty_official_catalog.sql +4 -0
  59. package/database/seeds/catalog/0002_2026-08.sql +19454 -0
  60. package/database/seeds/catalog/0003_2026-08-open-assets.sql +159086 -0
  61. package/database/seeds/catalog/0004_2026-08-c7-rocks.sql +39405 -0
  62. package/mcp/lab-management.mjs +629 -0
  63. package/mcp/public-catalog.mjs +168 -0
  64. package/mcp/server.mjs +1044 -63
  65. package/mcp/vite-plugin.mjs +519 -26
  66. package/mcp/workspace.mjs +26 -1
  67. package/package.json +334 -46
  68. package/scripts/generate-catalog-seed.mjs +324 -0
  69. package/scripts/setup-local.mjs +128 -0
  70. package/src/agents/index.js +7 -0
  71. package/src/agents/sceneStyleOperations.js +169 -0
  72. package/src/asset-policy/catalogLicenses.js +102 -0
  73. package/src/asset-policy/index.js +315 -0
  74. package/src/assetlib/assetRef.js +1 -1
  75. package/src/assetlib/galleryMaterialFamily.js +165 -0
  76. package/src/assetlib/index.js +6 -2
  77. package/src/assetlib/loadImported.js +15 -1
  78. package/src/assetlib/plateau.js +188 -0
  79. package/src/assetlib/plateauLandmarks.js +144 -0
  80. package/src/assetlib/plateauViewer.js +348 -0
  81. package/src/assetlib/sources.js +16 -2
  82. package/src/catalog/manifest.js +11 -1
  83. package/src/catalog/officialCatalog.js +4 -0
  84. package/src/catalog/officialCatalogAssetRuntime.js +324 -0
  85. package/src/catalog/officialCatalogLod.js +183 -0
  86. package/src/catalog/officialCatalogPlacement.js +243 -0
  87. package/src/catalog/officialCatalogProvider.js +334 -0
  88. package/src/character/animationRetarget.js +1084 -0
  89. package/src/character/characterRig.js +6 -1
  90. package/src/character/characterRuntime.js +544 -0
  91. package/src/character/groundStabilizer.js +137 -0
  92. package/src/character/index.js +8 -0
  93. package/src/character/locomotionActions.js +74 -0
  94. package/src/character/locomotionStateMachine.js +241 -0
  95. package/src/character/mannequinAsset.js +15 -0
  96. package/src/character/mannequinAssetUrl.browser.js +4 -0
  97. package/src/character/mannequinAssetUrl.node.js +3 -0
  98. package/src/character/modelLoader.js +92 -12
  99. package/src/character/walkableCharacterRuntime.js +284 -0
  100. package/src/character/waterInteractionController.js +217 -0
  101. package/src/cloud/ambientSkyBaker.js +248 -0
  102. package/src/cloud/cloudLighting.js +1114 -0
  103. package/src/cloud/cloudParams.js +819 -0
  104. package/src/cloud/cloudReprojection.js +563 -0
  105. package/src/cloud/cloudStyle.js +780 -0
  106. package/src/cloud/cloudStyleSnapshots.js +387 -0
  107. package/src/cloud/cloudVolume.js +1903 -0
  108. package/src/cloud/heroCloudRecipe.js +404 -0
  109. package/src/cloud/index.js +42 -0
  110. package/src/cloud/noise/baseShapeVolume.js +331 -0
  111. package/src/cloud/noise/cirrusMap.js +131 -0
  112. package/src/cloud/noise/curlNoise.js +289 -0
  113. package/src/cloud/noise/erosionVolume.js +188 -0
  114. package/src/cloud/noise/noiseVolume.js +202 -0
  115. package/src/cloud/noise/periodicNoise3.js +295 -0
  116. package/src/cloud/noise/weatherMap.js +470 -0
  117. package/src/cloud/paramSchema.js +458 -0
  118. package/src/collisionMetadata.js +320 -0
  119. package/src/core/systemStylePolicy.js +32 -0
  120. package/src/environment/dayCurves.js +146 -0
  121. package/src/environment/environmentGroundFieldPass.js +354 -0
  122. package/src/environment/environmentMaterialAdapter.js +144 -6
  123. package/src/environment/environmentPresets.js +486 -90
  124. package/src/environment/environmentRigs.js +17 -2
  125. package/src/environment/environmentSettings.js +37 -1
  126. package/src/environment/environmentShaderMaterials.js +37 -6
  127. package/src/environment/environmentState.js +133 -0
  128. package/src/environment/environmentSunShadowPass.js +399 -6
  129. package/src/environment/environmentTextureResolver.js +7 -0
  130. package/src/environment/index.js +51 -0
  131. package/src/environment/manufacturedMaterialContract.js +837 -0
  132. package/src/environment/manufacturedReflectionProvider.js +114 -0
  133. package/src/environment/scanAssetStylize.js +4 -4
  134. package/src/environment/surfaceMaterialModes.js +71 -0
  135. package/src/environment/toonLabEnvironmentMaterials.js +353 -0
  136. package/src/environment/toonLabMaterialPassCoupling.js +347 -0
  137. package/src/environment/toonLabNormalIntegration.js +171 -0
  138. package/src/environment/toonLabRockMaterialResolver.js +592 -0
  139. package/src/environment/toonLabSourceDefaultLit.js +444 -0
  140. package/src/environment/toonLabSourceLibrary.js +762 -0
  141. package/src/environment/toonLabSourceMaterials.js +3718 -0
  142. package/src/environment/toonLabSourceSubsurfaceLighting.js +415 -0
  143. package/src/environment/toonLabSourceTemporal.js +717 -0
  144. package/src/environment/toonLabSurfaceLighting.js +462 -0
  145. package/src/environment/toonLabTextureReadiness.js +105 -0
  146. package/src/environment/toonLabTreeMaterials.js +450 -0
  147. package/src/environment/transparentMaterialProfile.js +87 -0
  148. package/src/environment/urbanPropMaterial.js +2976 -0
  149. package/src/ground-shader/groundPrintLayer.js +375 -0
  150. package/src/ground-shader/groundShaderMaterial.js +851 -0
  151. package/src/ground-shader/groundShaderSettings.js +468 -0
  152. package/src/ground-shader/index.js +3 -0
  153. package/src/index.js +52 -22
  154. package/src/lighting/callMeSenseiLightingContract.js +163 -0
  155. package/src/lighting/index.js +14 -7
  156. package/src/lighting/lightingCapabilities.js +2 -2
  157. package/src/lighting/lightingPresets.js +6 -3
  158. package/src/lighting/lightingStyle.js +41 -6
  159. package/src/lighting/lightingSystem.js +200 -6
  160. package/src/lighting/{unrealExport.js → toonLabExport.js} +40 -41
  161. package/src/post/postProcessing.js +71 -12
  162. package/src/react/index.js +66 -0
  163. package/src/renderer/index.js +16 -0
  164. package/src/renderer/rendererConfiguration.js +250 -0
  165. package/src/renderer/styleComparison.js +985 -0
  166. package/src/rock-shader/index.js +8 -0
  167. package/src/rock-shader/rockGeometryDetail.js +701 -0
  168. package/src/rock-shader/rockMaterial.js +2586 -0
  169. package/src/rock-shader/rockRegionRuntime.js +185 -0
  170. package/src/rock-shader/rockSemanticMaterialRuntime.js +337 -0
  171. package/src/rock-shader/rockShaderRuntime.js +781 -0
  172. package/src/rock-shader/rockShaderSettings.js +1099 -0
  173. package/src/rock-shader/rockTangentIntegrity.js +136 -0
  174. package/src/rock-shader/rockTextureIntegrity.js +115 -0
  175. package/src/rockgen/export/glbExport.js +104 -14
  176. package/src/rockgen/index.js +5 -3
  177. package/src/rockgen/lod/index.js +6 -0
  178. package/src/rockgen/lod/rockLodMetrics.js +168 -0
  179. package/src/rockgen/lod/rockLodPlanner.js +372 -0
  180. package/src/rockgen/lod/rockLodPolicy.js +235 -0
  181. package/src/rockgen/lod/rockLodRuntime.js +124 -0
  182. package/src/rockgen/lod/rockLodSimplifier.js +173 -0
  183. package/src/rockgen/lod/rockLodValidation.js +113 -0
  184. package/src/rockgen/mesh/meshAttributes.js +17 -0
  185. package/src/rockgen/mesh/meshDocument.js +6 -0
  186. package/src/rockgen/rockDocument.js +376 -9
  187. package/src/rockgen/rockgenPresets.js +114 -13
  188. package/src/rockgen/rockgenSettings.js +62 -11
  189. package/src/rockgen/surface/c7GeologySurface.js +372 -0
  190. package/src/runtime/index.js +14 -0
  191. package/src/runtime/sceneCollisionRuntime.js +317 -0
  192. package/src/runtime/sceneSurfaceRuntime.js +451 -0
  193. package/src/runtime/sceneUpdateScheduler.js +203 -0
  194. package/src/shaders-tsl/anime.js +9 -2
  195. package/src/shaders-tsl/chunks/environment-ground-field.js +174 -0
  196. package/src/shaders-tsl/chunks/environment-state.js +79 -0
  197. package/src/shaders-tsl/chunks/environment-sun-shadow.js +99 -32
  198. package/src/shaders-tsl/chunks/normalized-hue.js +41 -0
  199. package/src/shaders-tsl/chunks/pass-depth-color.js +4 -2
  200. package/src/shaders-tsl/chunks/scene-depth-color-pass.js +273 -0
  201. package/src/shaders-tsl/chunks/vegetation-style.js +116 -8
  202. package/src/shaders-tsl/chunks/water-color.js +19 -5
  203. package/src/shaders-tsl/chunks/water-shore-state.js +8 -1
  204. package/src/shaders-tsl/chunks/world-noise.js +30 -0
  205. package/src/shaders-tsl/environment.js +123 -17
  206. package/src/shaders-tsl/flower.js +51 -8
  207. package/src/shaders-tsl/grass.js +194 -29
  208. package/src/shaders-tsl/post-composite.js +83 -2
  209. package/src/shaders-tsl/tree-leaf.js +107 -16
  210. package/src/shaders-tsl/water-breaker.js +18 -4
  211. package/src/shaders-tsl/water.js +51 -3
  212. package/src/shaders-tsl/woody-surface.js +59 -7
  213. package/src/sky/atmosphereDome.js +193 -0
  214. package/src/sky/atmosphereParams.js +396 -0
  215. package/src/sky/atmosphereScattering.js +593 -0
  216. package/src/sky/atmosphereSky.js +371 -0
  217. package/src/sky/cloudShadow.js +379 -0
  218. package/src/sky/godRays.js +257 -0
  219. package/src/sky/index.js +55 -1
  220. package/src/sky/nightSky.js +1190 -0
  221. package/src/sky/renderLayers.js +120 -0
  222. package/src/sky/skyColor.js +582 -0
  223. package/src/sky/skyDayCycle.js +244 -0
  224. package/src/sky/skyParams.js +661 -0
  225. package/src/sky/skyPresets.js +772 -0
  226. package/src/sky/skyQualityTiers.js +383 -0
  227. package/src/sky/skyShaderSettings.js +699 -0
  228. package/src/sky/skyStyleSnapshots.js +211 -0
  229. package/src/sky/skySystem.js +1447 -0
  230. package/src/sky/skyTimeKeyframes.js +361 -0
  231. package/src/sky/stylizedSky.js +405 -116
  232. package/src/sky/sunDriver.js +499 -0
  233. package/src/sky/timeOfDay.js +335 -0
  234. package/src/styles/animeGameProfile.js +44 -0
  235. package/src/styles/index.js +157 -0
  236. package/src/styles/manufacturedStyleLabeling.js +204 -0
  237. package/src/styles/neutralStylePresets.js +712 -0
  238. package/src/styles/sceneLayerDocuments.js +185 -0
  239. package/src/styles/sceneLookComposition.js +156 -0
  240. package/src/styles/sceneQualityApplication.js +152 -0
  241. package/src/styles/sceneQualityProfiles.js +268 -0
  242. package/src/styles/sceneStyleAudit.js +512 -0
  243. package/src/styles/sceneStyleRuntime.js +923 -0
  244. package/src/styles/styleAdapters.js +177 -0
  245. package/src/styles/styleApplication.js +369 -0
  246. package/src/styles/styleBundle.js +445 -92
  247. package/src/styles/styleBundleProvider.js +83 -0
  248. package/src/styles/styleDomains.js +21 -0
  249. package/src/styles/styleInspector.js +262 -0
  250. package/src/styles/styleMaterialContract.js +375 -0
  251. package/src/styles/styleMetadata.js +73 -0
  252. package/src/styles/styleTargetDiscovery.js +162 -0
  253. package/src/styles/styleTargetLabels.js +206 -0
  254. package/src/styles/styleTargetMaterialCoverage.js +137 -0
  255. package/src/styles/styleTransaction.js +272 -0
  256. package/src/texgen/evaluateTexture.js +30 -3
  257. package/src/texgen/textureGenerators.js +83 -35
  258. package/src/texgen/textureSettings.js +25 -8
  259. package/src/toon/toonSettings.js +100 -2
  260. package/src/vegetation/branchTree.js +587 -0
  261. package/src/vegetation/callMeSenseiGrass.js +183 -0
  262. package/src/vegetation/compiledTree.js +506 -0
  263. package/src/vegetation/contactShadowField.js +107 -0
  264. package/src/vegetation/flowerSpecies.js +10 -2
  265. package/src/vegetation/grass.js +13 -0
  266. package/src/vegetation/grassClump.js +1179 -0
  267. package/src/vegetation/importedVegetationMaterial.js +183 -0
  268. package/src/vegetation/index.js +17 -1
  269. package/src/vegetation/legacyTreePresets.js +120 -0
  270. package/src/vegetation/scatter.js +688 -3
  271. package/src/vegetation/stylizedBush.js +14 -0
  272. package/src/vegetation/stylizedFlower.js +31 -0
  273. package/src/vegetation/stylizedFlowers.js +59 -7
  274. package/src/vegetation/stylizedForest.js +455 -147
  275. package/src/vegetation/stylizedGrass.js +188 -24
  276. package/src/vegetation/stylizedTree.js +676 -54
  277. package/src/vegetation/stylizedTreeFoliage.js +1111 -38
  278. package/src/vegetation/stylizedUnderstory.js +230 -0
  279. package/src/vegetation/treeExport.js +262 -47
  280. package/src/vegetation/treeSurfaceTextures.js +665 -0
  281. package/src/vegetation/vegetationShaders.js +617 -28
  282. package/src/version.js +3 -0
  283. package/src/water/water.js +2 -0
  284. package/src/water/waterBreakerSystem.js +2 -0
  285. package/src/water/waterCurrentField.js +1 -0
  286. package/src/water/waterMaterial.js +3 -0
  287. package/src/water/waterRain.js +2 -0
  288. package/src/water/waterScenePasses.js +170 -7
  289. package/src/water/waterSettings.js +250 -50
  290. package/src/water/waterShoreMaterial.js +16 -2
  291. package/src/water/waterShoreStateField.js +1 -1
  292. package/src/water/waterSplashSystem.js +2 -0
  293. package/src/water/waterStageSettings.js +60 -0
  294. package/src/water/waterSurface.js +144 -4
  295. package/src/water/waterUnderwaterAtmosphere.js +288 -0
  296. package/src/water/waterVegetation.js +20 -4
  297. package/src/worldCollision.js +64 -9
  298. package/types/agents/index.d.ts +1 -0
  299. package/types/agents/sceneStyleOperations.d.ts +484 -0
  300. package/types/asset-policy/catalogLicenses.d.ts +7 -0
  301. package/types/asset-policy/index.d.ts +20 -0
  302. package/types/assetlib/ambientcg.d.ts +81 -0
  303. package/types/assetlib/assetRef.d.ts +26 -0
  304. package/types/assetlib/galleryMaterialFamily.d.ts +13 -0
  305. package/types/assetlib/importedEntry.d.ts +18 -0
  306. package/types/assetlib/index.d.ts +16 -0
  307. package/types/assetlib/kaykit.d.ts +112 -0
  308. package/types/assetlib/kaykitStaticIndex.d.ts +38 -0
  309. package/types/assetlib/loadImported.d.ts +56 -0
  310. package/types/assetlib/opensource3d.d.ts +55 -0
  311. package/types/assetlib/plateau.d.ts +67 -0
  312. package/types/assetlib/plateauLandmarks.d.ts +238 -0
  313. package/types/assetlib/plateauViewer.d.ts +3 -0
  314. package/types/assetlib/polyhaven.d.ts +90 -0
  315. package/types/assetlib/polypizza.d.ts +10 -0
  316. package/types/assetlib/smithsonian.d.ts +9 -0
  317. package/types/assetlib/sources.d.ts +22 -0
  318. package/types/assetlib/zip.d.ts +8 -0
  319. package/types/catalog/manifest.d.ts +26 -0
  320. package/types/catalog/officialCatalog.d.ts +4 -0
  321. package/types/catalog/officialCatalogAssetRuntime.d.ts +2 -0
  322. package/types/catalog/officialCatalogLod.d.ts +63 -0
  323. package/types/catalog/officialCatalogPlacement.d.ts +49 -0
  324. package/types/catalog/officialCatalogProvider.d.ts +7 -0
  325. package/types/character/animationRetarget.d.ts +20 -0
  326. package/types/character/characterRig.d.ts +87 -0
  327. package/types/character/characterRuntime.d.ts +5 -0
  328. package/types/character/freestyleSwimClip.d.ts +5 -0
  329. package/types/character/groundStabilizer.d.ts +55 -0
  330. package/types/character/index.d.ts +10 -0
  331. package/types/character/locomotionActions.d.ts +4 -0
  332. package/types/character/locomotionStateMachine.d.ts +62 -0
  333. package/types/character/mannequinAsset.d.ts +12 -0
  334. package/types/character/mannequinAssetUrl.node.d.ts +1 -0
  335. package/types/character/modelLoader.d.ts +7 -0
  336. package/types/character/walkableCharacterRuntime.d.ts +343 -0
  337. package/types/character/waterInteractionController.d.ts +114 -0
  338. package/types/cloud/ambientSkyBaker.d.ts +18 -0
  339. package/types/cloud/cloudLighting.d.ts +38 -0
  340. package/types/cloud/cloudParams.d.ts +18 -0
  341. package/types/cloud/cloudReprojection.d.ts +15 -0
  342. package/types/cloud/cloudStyle.d.ts +1380 -0
  343. package/types/cloud/cloudStyleSnapshots.d.ts +10 -0
  344. package/types/cloud/cloudVolume.d.ts +43 -0
  345. package/types/cloud/heroCloudRecipe.d.ts +167 -0
  346. package/types/cloud/index.d.ts +12 -0
  347. package/types/cloud/noise/baseShapeVolume.d.ts +86 -0
  348. package/types/cloud/noise/cirrusMap.d.ts +24 -0
  349. package/types/cloud/noise/curlNoise.d.ts +106 -0
  350. package/types/cloud/noise/erosionVolume.d.ts +58 -0
  351. package/types/cloud/noise/noiseVolume.d.ts +63 -0
  352. package/types/cloud/noise/periodicNoise3.d.ts +75 -0
  353. package/types/cloud/noise/weatherMap.d.ts +227 -0
  354. package/types/cloud/paramSchema.d.ts +142 -0
  355. package/types/collisionMetadata.d.ts +11 -0
  356. package/types/core/generation.d.ts +95 -0
  357. package/types/core/materialRoles.d.ts +102 -0
  358. package/types/core/presetDocuments.d.ts +25 -0
  359. package/types/core/systemStylePolicy.d.ts +4 -0
  360. package/types/environment/dayCurves.d.ts +47 -0
  361. package/types/environment/environmentAmbientProbe.d.ts +2 -0
  362. package/types/environment/environmentGroundFieldPass.d.ts +2 -0
  363. package/types/environment/environmentMaterialAdapter.d.ts +44 -0
  364. package/types/environment/environmentMaterialClassifier.d.ts +26 -0
  365. package/types/environment/environmentPlanarReflection.d.ts +3 -0
  366. package/types/environment/environmentPresets.d.ts +171 -0
  367. package/types/environment/environmentRigs.d.ts +13 -0
  368. package/types/environment/environmentSettings.d.ts +161 -0
  369. package/types/environment/environmentShaderMaterials.d.ts +14 -0
  370. package/types/environment/environmentState.d.ts +6 -0
  371. package/types/environment/environmentSunShadowPass.d.ts +2 -0
  372. package/types/environment/environmentTextureResolver.d.ts +30 -0
  373. package/types/environment/environmentTimeOfDay.d.ts +25 -0
  374. package/types/environment/environmentVertexAo.d.ts +18 -0
  375. package/types/environment/index.d.ts +27 -0
  376. package/types/environment/manufacturedMaterialContract.d.ts +129 -0
  377. package/types/environment/manufacturedReflectionProvider.d.ts +3 -0
  378. package/types/environment/scanAssetStylize.d.ts +43 -0
  379. package/types/environment/surfaceMaterialModes.d.ts +14 -0
  380. package/types/environment/toonLabEnvironmentMaterials.d.ts +139 -0
  381. package/types/environment/toonLabMaterialPassCoupling.d.ts +7 -0
  382. package/types/environment/toonLabNormalIntegration.d.ts +29 -0
  383. package/types/environment/toonLabRockMaterialResolver.d.ts +270 -0
  384. package/types/environment/toonLabSourceDefaultLit.d.ts +136 -0
  385. package/types/environment/toonLabSourceLibrary.d.ts +19 -0
  386. package/types/environment/toonLabSourceMaterials.d.ts +14 -0
  387. package/types/environment/toonLabSourceSubsurfaceLighting.d.ts +85 -0
  388. package/types/environment/toonLabSourceTemporal.d.ts +20 -0
  389. package/types/environment/toonLabSurfaceLighting.d.ts +153 -0
  390. package/types/environment/toonLabTextureReadiness.d.ts +8 -0
  391. package/types/environment/toonLabTreeMaterials.d.ts +7 -0
  392. package/types/environment/transparentMaterialProfile.d.ts +76 -0
  393. package/types/environment/urbanPropMaterial.d.ts +25 -0
  394. package/types/ground-shader/groundPrintLayer.d.ts +4 -0
  395. package/types/ground-shader/groundShaderMaterial.d.ts +11 -0
  396. package/types/ground-shader/groundShaderSettings.d.ts +90 -0
  397. package/types/ground-shader/index.d.ts +3 -0
  398. package/types/index.d.ts +1591 -0
  399. package/types/lighting/callMeSenseiLightingContract.d.ts +14 -0
  400. package/types/lighting/colorIntensity.d.ts +44 -0
  401. package/types/lighting/index.d.ts +12 -0
  402. package/types/lighting/lightDescriptors.d.ts +803 -0
  403. package/types/lighting/lightingCapabilities.d.ts +85 -0
  404. package/types/lighting/lightingDocuments.d.ts +140 -0
  405. package/types/lighting/lightingFixtures.d.ts +171 -0
  406. package/types/lighting/lightingGenerator.d.ts +403 -0
  407. package/types/lighting/lightingPresets.d.ts +264 -0
  408. package/types/lighting/lightingRuntime.d.ts +401 -0
  409. package/types/lighting/lightingStyle.d.ts +156 -0
  410. package/types/lighting/lightingSystem.d.ts +440 -0
  411. package/types/lighting/toonLabExport.d.ts +46 -0
  412. package/types/lighting/utils.d.ts +18 -0
  413. package/types/loaders/index.d.ts +1 -0
  414. package/types/post/index.d.ts +2 -0
  415. package/types/post/postGenerator.d.ts +282 -0
  416. package/types/post/postProcessing.d.ts +16 -0
  417. package/types/react/index.d.ts +1785 -0
  418. package/types/renderer/index.d.ts +2 -0
  419. package/types/renderer/rendererConfiguration.d.ts +8 -0
  420. package/types/renderer/styleComparison.d.ts +409 -0
  421. package/types/rock-shader/index.d.ts +8 -0
  422. package/types/rock-shader/rockGeometryDetail.d.ts +300 -0
  423. package/types/rock-shader/rockMaterial.d.ts +21 -0
  424. package/types/rock-shader/rockRegionRuntime.d.ts +86 -0
  425. package/types/rock-shader/rockSemanticMaterialRuntime.d.ts +29 -0
  426. package/types/rock-shader/rockShaderRuntime.d.ts +10 -0
  427. package/types/rock-shader/rockShaderSettings.d.ts +184 -0
  428. package/types/rock-shader/rockTangentIntegrity.d.ts +51 -0
  429. package/types/rock-shader/rockTextureIntegrity.d.ts +61 -0
  430. package/types/rockgen/export/glbExport.d.ts +58 -0
  431. package/types/rockgen/heightfield/heightfieldErosion.d.ts +10 -0
  432. package/types/rockgen/heightfield/heightfieldPatch.d.ts +15 -0
  433. package/types/rockgen/heightfield/stylizedErosionSim.d.ts +41 -0
  434. package/types/rockgen/index.d.ts +12 -0
  435. package/types/rockgen/lod/index.d.ts +6 -0
  436. package/types/rockgen/lod/rockLodMetrics.d.ts +62 -0
  437. package/types/rockgen/lod/rockLodPlanner.d.ts +86 -0
  438. package/types/rockgen/lod/rockLodPolicy.d.ts +76 -0
  439. package/types/rockgen/lod/rockLodRuntime.d.ts +95 -0
  440. package/types/rockgen/lod/rockLodSimplifier.d.ts +15 -0
  441. package/types/rockgen/lod/rockLodValidation.d.ts +16 -0
  442. package/types/rockgen/mesh/meshAttributes.d.ts +32 -0
  443. package/types/rockgen/mesh/meshDocument.d.ts +40 -0
  444. package/types/rockgen/mesh/surfaceNets.d.ts +42 -0
  445. package/types/rockgen/noise/cellularNoise3.d.ts +24 -0
  446. package/types/rockgen/noise/prng.d.ts +16 -0
  447. package/types/rockgen/noise/simplexNoise3.d.ts +2 -0
  448. package/types/rockgen/noise/valueNoise3.d.ts +12 -0
  449. package/types/rockgen/rockDocument.d.ts +243 -0
  450. package/types/rockgen/rockHelpers.d.ts +2 -0
  451. package/types/rockgen/rockgenPresets.d.ts +10 -0
  452. package/types/rockgen/rockgenSettings.d.ts +531 -0
  453. package/types/rockgen/sdf/fieldCompiler.d.ts +20 -0
  454. package/types/rockgen/sdf/sculptEdits.d.ts +30 -0
  455. package/types/rockgen/sdf/sdfModifiers.d.ts +19 -0
  456. package/types/rockgen/sdf/sdfOps.d.ts +8 -0
  457. package/types/rockgen/sdf/sdfPrimitives.d.ts +22 -0
  458. package/types/rockgen/surface/c7GeologySurface.d.ts +8 -0
  459. package/types/runtime/index.d.ts +3 -0
  460. package/types/runtime/sceneCollisionRuntime.d.ts +94 -0
  461. package/types/runtime/sceneSurfaceRuntime.d.ts +90 -0
  462. package/types/runtime/sceneUpdateScheduler.d.ts +28 -0
  463. package/types/shaders-tsl/anime.d.ts +9 -0
  464. package/types/shaders-tsl/chunks/character-color.d.ts +6 -0
  465. package/types/shaders-tsl/chunks/character-highlights.d.ts +12 -0
  466. package/types/shaders-tsl/chunks/character-lighting.d.ts +20 -0
  467. package/types/shaders-tsl/chunks/character-material-maps.d.ts +18 -0
  468. package/types/shaders-tsl/chunks/character-roles.d.ts +21 -0
  469. package/types/shaders-tsl/chunks/character-scene-lights.d.ts +48 -0
  470. package/types/shaders-tsl/chunks/character-shadow-color.d.ts +5 -0
  471. package/types/shaders-tsl/chunks/character-skinning.d.ts +23 -0
  472. package/types/shaders-tsl/chunks/environment-color.d.ts +9 -0
  473. package/types/shaders-tsl/chunks/environment-debug.d.ts +24 -0
  474. package/types/shaders-tsl/chunks/environment-ground-field.d.ts +40 -0
  475. package/types/shaders-tsl/chunks/environment-lighting.d.ts +22 -0
  476. package/types/shaders-tsl/chunks/environment-state.d.ts +42 -0
  477. package/types/shaders-tsl/chunks/environment-sun-shadow.d.ts +19 -0
  478. package/types/shaders-tsl/chunks/foliage-fog.d.ts +21 -0
  479. package/types/shaders-tsl/chunks/normalized-hue.d.ts +1 -0
  480. package/types/shaders-tsl/chunks/pass-depth-color.d.ts +20 -0
  481. package/types/shaders-tsl/chunks/projected-water-caustics.d.ts +24 -0
  482. package/types/shaders-tsl/chunks/scene-depth-color-pass.d.ts +39 -0
  483. package/types/shaders-tsl/chunks/stylized-cloud-shadow.d.ts +9 -0
  484. package/types/shaders-tsl/chunks/vegetation-style.d.ts +60 -0
  485. package/types/shaders-tsl/chunks/water-color.d.ts +15 -0
  486. package/types/shaders-tsl/chunks/water-common.d.ts +9 -0
  487. package/types/shaders-tsl/chunks/water-foam.d.ts +8 -0
  488. package/types/shaders-tsl/chunks/water-lighting.d.ts +9 -0
  489. package/types/shaders-tsl/chunks/water-ripple.d.ts +8 -0
  490. package/types/shaders-tsl/chunks/water-shore-state.d.ts +7 -0
  491. package/types/shaders-tsl/chunks/water-waves.d.ts +18 -0
  492. package/types/shaders-tsl/chunks/world-noise.d.ts +4 -0
  493. package/types/shaders-tsl/environment-ao-overlay.d.ts +5 -0
  494. package/types/shaders-tsl/environment.d.ts +34 -0
  495. package/types/shaders-tsl/flower.d.ts +6 -0
  496. package/types/shaders-tsl/grass.d.ts +4 -0
  497. package/types/shaders-tsl/post-composite.d.ts +25 -0
  498. package/types/shaders-tsl/sky.d.ts +4 -0
  499. package/types/shaders-tsl/tree-leaf.d.ts +2 -0
  500. package/types/shaders-tsl/water-breaker.d.ts +15 -0
  501. package/types/shaders-tsl/water-kelp.d.ts +5 -0
  502. package/types/shaders-tsl/water-rain.d.ts +10 -0
  503. package/types/shaders-tsl/water-shore-state-simulation.d.ts +12 -0
  504. package/types/shaders-tsl/water-simulation.d.ts +5 -0
  505. package/types/shaders-tsl/water-splash.d.ts +12 -0
  506. package/types/shaders-tsl/water.d.ts +22 -0
  507. package/types/shaders-tsl/woody-surface.d.ts +3 -0
  508. package/types/sky/atmosphereDome.d.ts +2 -0
  509. package/types/sky/atmosphereParams.d.ts +185 -0
  510. package/types/sky/atmosphereScattering.d.ts +11 -0
  511. package/types/sky/atmosphereSky.d.ts +2 -0
  512. package/types/sky/cloudShadow.d.ts +69 -0
  513. package/types/sky/godRays.d.ts +5 -0
  514. package/types/sky/index.d.ts +18 -0
  515. package/types/sky/nightSky.d.ts +22 -0
  516. package/types/sky/renderLayers.d.ts +59 -0
  517. package/types/sky/sceneOverrideLayers.d.ts +10 -0
  518. package/types/sky/skyColor.d.ts +704 -0
  519. package/types/sky/skyDayCycle.d.ts +86 -0
  520. package/types/sky/skyParams.d.ts +3407 -0
  521. package/types/sky/skyPresets.d.ts +160 -0
  522. package/types/sky/skyQuality.d.ts +21 -0
  523. package/types/sky/skyQualityTiers.d.ts +223 -0
  524. package/types/sky/skyShaderSettings.d.ts +152 -0
  525. package/types/sky/skyStyleSnapshots.d.ts +11 -0
  526. package/types/sky/skySystem.d.ts +3 -0
  527. package/types/sky/skyTimeKeyframes.d.ts +230 -0
  528. package/types/sky/stylizedSky.d.ts +341 -0
  529. package/types/sky/sunDriver.d.ts +15 -0
  530. package/types/sky/timeOfDay.d.ts +145 -0
  531. package/types/styles/animeGameProfile.d.ts +27 -0
  532. package/types/styles/index.d.ts +18 -0
  533. package/types/styles/manufacturedStyleLabeling.d.ts +119 -0
  534. package/types/styles/neutralStylePresets.d.ts +944 -0
  535. package/types/styles/sceneLayerDocuments.d.ts +145 -0
  536. package/types/styles/sceneLookComposition.d.ts +53 -0
  537. package/types/styles/sceneQualityApplication.d.ts +34 -0
  538. package/types/styles/sceneQualityProfiles.d.ts +13 -0
  539. package/types/styles/sceneStyleAudit.d.ts +80 -0
  540. package/types/styles/sceneStyleRuntime.d.ts +1802 -0
  541. package/types/styles/styleAdapters.d.ts +14 -0
  542. package/types/styles/styleApplication.d.ts +47 -0
  543. package/types/styles/styleBundle.d.ts +19 -0
  544. package/types/styles/styleBundleProvider.d.ts +44 -0
  545. package/types/styles/styleDomains.d.ts +18 -0
  546. package/types/styles/styleInspector.d.ts +59 -0
  547. package/types/styles/styleMaterialContract.d.ts +46 -0
  548. package/types/styles/styleMetadata.d.ts +11 -0
  549. package/types/styles/styleTargetDiscovery.d.ts +48 -0
  550. package/types/styles/styleTargetLabels.d.ts +32 -0
  551. package/types/styles/styleTargetMaterialCoverage.d.ts +20 -0
  552. package/types/styles/styleTransaction.d.ts +10 -0
  553. package/types/styles/styleTypes.d.ts +66 -0
  554. package/types/texgen/evaluateTexture.d.ts +40 -0
  555. package/types/texgen/index.d.ts +7 -0
  556. package/types/texgen/noise2.d.ts +46 -0
  557. package/types/texgen/textureAi.d.ts +6 -0
  558. package/types/texgen/textureGenerators.d.ts +261 -0
  559. package/types/texgen/texturePresets.d.ts +45 -0
  560. package/types/texgen/textureSettings.d.ts +121 -0
  561. package/types/texgen/textureThree.d.ts +13 -0
  562. package/types/toon/characterRenderPasses.d.ts +3 -0
  563. package/types/toon/index.d.ts +3 -0
  564. package/types/toon/settings/alphaSettings.d.ts +125 -0
  565. package/types/toon/settings/averageShadowSettings.d.ts +39 -0
  566. package/types/toon/settings/baseTextureSettings.d.ts +39 -0
  567. package/types/toon/settings/celShadeSettings.d.ts +37 -0
  568. package/types/toon/settings/contactShadowSettings.d.ts +30 -0
  569. package/types/toon/settings/eyeHighlightSettings.d.ts +55 -0
  570. package/types/toon/settings/faceLightingSettings.d.ts +32 -0
  571. package/types/toon/settings/furSettings.d.ts +23 -0
  572. package/types/toon/settings/glitterSettings.d.ts +43 -0
  573. package/types/toon/settings/hairHighlightSettings.d.ts +89 -0
  574. package/types/toon/settings/indirectLightSettings.d.ts +43 -0
  575. package/types/toon/settings/localLightSettings.d.ts +46 -0
  576. package/types/toon/settings/materialMapSettings.d.ts +86 -0
  577. package/types/toon/settings/outlineSettings.d.ts +125 -0
  578. package/types/toon/settings/perspectiveRemovalSettings.d.ts +14 -0
  579. package/types/toon/settings/rimLightSettings.d.ts +79 -0
  580. package/types/toon/settings/sceneShadowSettings.d.ts +32 -0
  581. package/types/toon/settings/selfShadowSettings.d.ts +44 -0
  582. package/types/toon/settings/shadowColorSettings.d.ts +77 -0
  583. package/types/toon/settings/skinToneSettings.d.ts +30 -0
  584. package/types/toon/settings/specularSettings.d.ts +96 -0
  585. package/types/toon/settings/stickerSettings.d.ts +40 -0
  586. package/types/toon/toonMaterialAdapter.d.ts +883 -0
  587. package/types/toon/toonSettings.d.ts +1182 -0
  588. package/types/vegetation/branchTree.d.ts +14 -0
  589. package/types/vegetation/callMeSenseiGrass.d.ts +8 -0
  590. package/types/vegetation/compiledTree.d.ts +75 -0
  591. package/types/vegetation/contactShadowField.d.ts +26 -0
  592. package/types/vegetation/flowerSpecies.d.ts +107 -0
  593. package/types/vegetation/grass.d.ts +4 -0
  594. package/types/vegetation/grassClump.d.ts +7 -0
  595. package/types/vegetation/grassPalettes.d.ts +29 -0
  596. package/types/vegetation/importedVegetationMaterial.d.ts +13 -0
  597. package/types/vegetation/index.d.ts +225 -0
  598. package/types/vegetation/legacyTreePresets.d.ts +22 -0
  599. package/types/vegetation/scatter.d.ts +13 -0
  600. package/types/vegetation/stylizedBush.d.ts +2 -0
  601. package/types/vegetation/stylizedFlower.d.ts +2 -0
  602. package/types/vegetation/stylizedFlowers.d.ts +8 -0
  603. package/types/vegetation/stylizedForest.d.ts +3 -0
  604. package/types/vegetation/stylizedGrass.d.ts +21 -0
  605. package/types/vegetation/stylizedTree.d.ts +20 -0
  606. package/types/vegetation/stylizedTreeFoliage.d.ts +19 -0
  607. package/types/vegetation/stylizedUnderstory.d.ts +50 -0
  608. package/types/vegetation/treeExport.d.ts +6 -0
  609. package/types/vegetation/treeSurfaceTextures.d.ts +72 -0
  610. package/types/vegetation/vegetationShaders.d.ts +74 -0
  611. package/types/version.d.ts +1 -0
  612. package/types/water/index.d.ts +1 -0
  613. package/types/water/sceneOverrideLayers.d.ts +16 -0
  614. package/types/water/water.d.ts +17 -0
  615. package/types/water/waterBreakerSystem.d.ts +46 -0
  616. package/types/water/waterCurrentField.d.ts +115 -0
  617. package/types/water/waterInteraction.d.ts +21 -0
  618. package/types/water/waterMaterial.d.ts +60 -0
  619. package/types/water/waterNearshorePhase.d.ts +5 -0
  620. package/types/water/waterRain.d.ts +17 -0
  621. package/types/water/waterRippleSimulation.d.ts +52 -0
  622. package/types/water/waterScenePasses.d.ts +70 -0
  623. package/types/water/waterSettings.d.ts +648 -0
  624. package/types/water/waterShoreMaterial.d.ts +3 -0
  625. package/types/water/waterShoreStateField.d.ts +2 -0
  626. package/types/water/waterSplashSystem.d.ts +2 -0
  627. package/types/water/waterStageSettings.d.ts +9 -0
  628. package/types/water/waterSurface.d.ts +2 -0
  629. package/types/water/waterUnderwaterAtmosphere.d.ts +103 -0
  630. package/types/water/waterVegetation.d.ts +16 -0
  631. package/types/worldCollision.d.ts +22 -0
  632. package/AGENTS.md +0 -254
  633. package/ATTRIBUTION.md +0 -78
  634. package/docs/characters.md +0 -144
  635. package/docs/debug-panel.md +0 -126
  636. package/docs/docs.css +0 -589
  637. package/docs/environment.md +0 -186
  638. package/docs/getting-started.md +0 -180
  639. package/docs/index.html +0 -14
  640. package/docs/lab-architecture.md +0 -100
  641. package/docs/lighting.md +0 -825
  642. package/docs/main.jsx +0 -752
  643. package/docs/mcp.md +0 -97
  644. package/docs/post-processing.md +0 -98
  645. package/docs/settings-reference.md +0 -1878
  646. package/docs/shader-constants.md +0 -77
  647. package/docs/sky.md +0 -182
  648. package/docs/style-labs.md +0 -309
  649. package/docs/texture-lab.md +0 -135
  650. package/docs/toon-shading.md +0 -183
  651. package/docs/tsl-conventions.md +0 -167
  652. package/docs/vegetation-sky.md +0 -275
  653. package/docs/water.md +0 -430
  654. package/docs/weather.md +0 -200
  655. package/docs/world-scale.md +0 -111
  656. package/mcp/style-lab-tools.mjs +0 -371
  657. package/src/ambientfx/INTEGRATION.md +0 -164
  658. package/src/ambientfx/ambientFxPresets.js +0 -83
  659. package/src/ambientfx/ambientFxSettings.js +0 -368
  660. package/src/ambientfx/emitters.js +0 -169
  661. package/src/ambientfx/index.js +0 -5
  662. package/src/ambientfx/particleBackbone.js +0 -493
  663. package/src/ambientfx/stylizedAmbientFx.js +0 -450
  664. package/src/biome/biomeGenerator.js +0 -385
  665. package/src/biome/biomeRuntime.js +0 -299
  666. package/src/biome/index.js +0 -2
  667. package/src/buildinggen/buildingAsset.js +0 -44
  668. package/src/buildinggen/buildingGrammar.js +0 -311
  669. package/src/buildinggen/buildingMesh.js +0 -451
  670. package/src/buildinggen/buildingPresets.js +0 -46
  671. package/src/buildinggen/buildingRecipe.js +0 -100
  672. package/src/buildinggen/buildingSettings.js +0 -238
  673. package/src/buildinggen/index.js +0 -6
  674. package/src/camera/cameraDirector.js +0 -157
  675. package/src/camera/cameraGenerator.js +0 -367
  676. package/src/camera/cameraRig.js +0 -570
  677. package/src/camera/cameraSettings.js +0 -236
  678. package/src/camera/index.js +0 -7
  679. package/src/catalog/builtinEntries.js +0 -245
  680. package/src/catalog/catalog.js +0 -210
  681. package/src/catalog/index.js +0 -3
  682. package/src/core/shaderBackend.js +0 -24
  683. package/src/debrisgen/debrisFields.js +0 -544
  684. package/src/debrisgen/debrisGenerator.js +0 -1929
  685. package/src/debrisgen/debrisPalettes.js +0 -71
  686. package/src/debrisgen/debrisPhysics.js +0 -198
  687. package/src/debrisgen/debrisPresets.js +0 -162
  688. package/src/debrisgen/debrisSettings.js +0 -333
  689. package/src/debrisgen/debrisTextures.js +0 -380
  690. package/src/debrisgen/index.js +0 -5
  691. package/src/debug/fieldValues.js +0 -95
  692. package/src/debug/index.js +0 -7
  693. package/src/debug/settingsPanel.js +0 -170
  694. package/src/fauna/INTEGRATION.md +0 -174
  695. package/src/fauna/boids.js +0 -861
  696. package/src/fauna/faunaBodies.js +0 -492
  697. package/src/fauna/faunaPresets.js +0 -52
  698. package/src/fauna/faunaSettings.js +0 -525
  699. package/src/fauna/index.js +0 -5
  700. package/src/fauna/stylizedFauna.js +0 -395
  701. package/src/game-feel/gameFeelGenerator.js +0 -402
  702. package/src/game-feel/gameFeelRuntime.js +0 -549
  703. package/src/game-feel/index.js +0 -2
  704. package/src/motion/index.js +0 -5
  705. package/src/motion/motionClip.js +0 -441
  706. package/src/motion/motionController.js +0 -628
  707. package/src/motion/motionDocuments.js +0 -225
  708. package/src/motion/motionGraph.js +0 -307
  709. package/src/motion/motionSettings.js +0 -222
  710. package/src/pathgen/index.js +0 -7
  711. package/src/pathgen/pathBridge.js +0 -232
  712. package/src/pathgen/pathPresets.js +0 -35
  713. package/src/pathgen/pathRibbon.js +0 -410
  714. package/src/pathgen/pathRouter.js +0 -380
  715. package/src/pathgen/pathSettings.js +0 -335
  716. package/src/pathgen/pathTextures.js +0 -123
  717. package/src/pathgen/stylizedPaths.js +0 -453
  718. package/src/propgen/generatorsWave1.js +0 -379
  719. package/src/propgen/generatorsWave2.js +0 -462
  720. package/src/propgen/index.js +0 -5
  721. package/src/propgen/propAsset.js +0 -323
  722. package/src/propgen/propParts.js +0 -170
  723. package/src/propgen/propPlacement.js +0 -459
  724. package/src/propgen/propPresets.js +0 -82
  725. package/src/propgen/propSettings.js +0 -395
  726. package/src/soundscape/index.js +0 -4
  727. package/src/soundscape/soundscapeGenerator.js +0 -179
  728. package/src/soundscape/soundscapeRuntime.js +0 -806
  729. package/src/soundscape/soundscapeSettings.js +0 -292
  730. package/src/stylizedTerrain.js +0 -631
  731. package/src/stylizedWorld.js +0 -903
  732. package/src/vegetation/treeRecipe.js +0 -647
  733. package/src/vfxgen/INTEGRATION.md +0 -145
  734. package/src/vfxgen/core/burstBackbone.js +0 -380
  735. package/src/vfxgen/core/projectileCore.js +0 -92
  736. package/src/vfxgen/core/spriteShapes.js +0 -98
  737. package/src/vfxgen/core/trailRibbon.js +0 -272
  738. package/src/vfxgen/core/vfxRandom.js +0 -29
  739. package/src/vfxgen/effects/emitHelpers.js +0 -37
  740. package/src/vfxgen/effects/magicEffects.js +0 -162
  741. package/src/vfxgen/effects/movementEffects.js +0 -87
  742. package/src/vfxgen/effects/weaponEffects.js +0 -118
  743. package/src/vfxgen/index.js +0 -18
  744. package/src/vfxgen/moves/moveController.js +0 -146
  745. package/src/vfxgen/moves/moveLibrary.js +0 -335
  746. package/src/vfxgen/vfxPresets.js +0 -98
  747. package/src/vfxgen/vfxSettings.js +0 -384
  748. package/src/vfxgen/vfxSystem.js +0 -449
  749. package/src/vfxgen/weapons/stylizedWeapons.js +0 -137
  750. package/src/villagegen/index.js +0 -4
  751. package/src/villagegen/stylizedVillage.js +0 -490
  752. package/src/villagegen/villageArchetypes.js +0 -160
  753. package/src/villagegen/villageNames.js +0 -40
  754. package/src/villagegen/villageSites.js +0 -105
  755. package/src/weather/index.js +0 -6
  756. package/src/weather/weatherPrecipitation.js +0 -221
  757. package/src/weather/weatherPresets.js +0 -258
  758. package/src/weather/weatherSettings.js +0 -269
  759. package/src/weather/weatherSystem.js +0 -871
  760. package/src/worldMinimap.js +0 -214
  761. package/src/worldPresets.js +0 -125
@@ -0,0 +1,1114 @@
1
+ // Cloud scattering, as composable TSL nodes: Beer-Lambert extinction, Nubis'
2
+ // max-combined deep-light and silver-lining terms, the powder edge deficit,
3
+ // skylight and ground-bounce fill, the base darkening pair, and the moonlit rim.
4
+ //
5
+ // Sources, per docs/sky-cloud-parameters.md's runtime boundary — this is
6
+ // written from the published literature, not from the reference product:
7
+ //
8
+ // Schneider & Vos, "Nubis: Authoring Real-Time Volumetric Cloudscapes with
9
+ // the Decima Engine" (SIGGRAPH 2017), slides 80 and 85 — the two HG lobes
10
+ // and two Beer-Lambert curves are combined with max(), not summed.
11
+ // Schneider, "The Real-Time Volumetric Cloudscapes of Horizon Zero Dawn"
12
+ // (SIGGRAPH 2015) — the powder / dark-edge approximation and density field.
13
+ // Hillaire, "Physically Based and Unified Volumetric Rendering in Frostbite"
14
+ // (SIGGRAPH 2015) and "A Scalable and Production Ready Sky and Atmosphere
15
+ // Rendering Technique" (EGSR 2020) — the energy-conserving segment
16
+ // integration the marcher uses.
17
+ //
18
+ // Everything here is an expression builder: no `toVar`, no `Loop`, no stack
19
+ // requirement, so a headless test can build any single term on its own. The one
20
+ // exception is `createCloudLightingModel().inScatterNode`, which is a laid-out
21
+ // `Fn` so the 128 primary samples share one GPU function instead of inlining
22
+ // 128 copies of the whole model.
23
+ //
24
+ // Units. `extinction` is sigma_t in 1/m — `shape.density` times the normalized
25
+ // density field. Slab distances are metres. Optical depths are dimensionless.
26
+
27
+ import {
28
+ clamp,
29
+ exp,
30
+ float,
31
+ Fn,
32
+ max,
33
+ mix,
34
+ saturate,
35
+ smoothstep,
36
+ sqrt,
37
+ vec3,
38
+ vec4,
39
+ } from 'three/tsl';
40
+
41
+ import { henyeyGreensteinPhaseNode } from '../sky/atmosphereScattering.js';
42
+
43
+ /** Dual-HG droplet phase constants. */
44
+ export const CLOUD_PHASE_FORWARD_G = 0.8;
45
+ export const CLOUD_PHASE_BACKWARD_G = -0.2;
46
+ export const CLOUD_PHASE_BLEND = 0.5;
47
+
48
+ /** Three-octave multiple-scattering falloffs. */
49
+ export const CLOUD_MULTISCATTER_EXTINCTION = 0.5;
50
+ export const CLOUD_MULTISCATTER_SCATTER = 0.5;
51
+ export const CLOUD_MULTISCATTER_ECCENTRICITY = 0.5;
52
+
53
+ // Backward-compatible diagnostics names. They now report the reference model,
54
+ // not the discarded max-combined Nubis approximation.
55
+ export const CLOUD_PHASE_BASE_G = CLOUD_PHASE_FORWARD_G;
56
+ export const CLOUD_PHASE_SILVER_INTENSITY = 0;
57
+ export const CLOUD_PHASE_SILVER_SPREAD = 0;
58
+ export const CLOUD_DEEP_EXTINCTION_SCALE = CLOUD_MULTISCATTER_EXTINCTION;
59
+ export const CLOUD_DEEP_CONTRIBUTION = CLOUD_MULTISCATTER_SCATTER;
60
+
61
+ /**
62
+ * Powder exponent. Nubis' approximation of the near-surface deficit of
63
+ * multiply-scattered light is `1 - exp(-2 d)`; this is that 2.
64
+ */
65
+ export const CLOUD_POWDER_EXPONENT = 2;
66
+
67
+ /**
68
+ * Normalisation that turns `1 - exp(-2 x)` into a pure edge term.
69
+ *
70
+ * Nubis writes the expression against a density sample in its own units; over a
71
+ * field normalised to [0, 1] it tops out at `1 - exp(-2)` = 0.8647, so a solid
72
+ * core loses 13.5% of its direct light at `powderStrength` 1 and more above it.
73
+ * That is a global absorption, and `lighting.scatteringAlbedo` already owns
74
+ * global absorption — the parameter here documents only "darkens the thin outer
75
+ * edges". Dividing by the value at full occupancy keeps the shape of the fit and
76
+ * pins a fully surrounded sample to exactly 1 at every strength.
77
+ */
78
+ /**
79
+ * Representative path, in metres, the moon rim term attenuates over.
80
+ *
81
+ * The rim is an edge term, so what it needs is "how thin is the cloud here",
82
+ * and the cheapest honest answer is Beer-Lambert over a fixed short path: a
83
+ * wisp at sigma 0.002 keeps three quarters of the moonlight, a core at 0.03
84
+ * keeps one percent. Marching toward the moon instead would double the light
85
+ * march for a term that is only ever a few percent of the image.
86
+ */
87
+ export const CLOUD_MOON_RIM_PATH = 150;
88
+
89
+ /** Lambertian bounce normalisation, folded into the ground-bounce term. */
90
+ const INV_PI = 1 / Math.PI;
91
+ const CLOUD_LUMINANCE = vec3(0.2126, 0.7152, 0.0722);
92
+
93
+ // Laid-out function names have to be unique inside one shader, and a name is a
94
+ // GPU identifier rather than a label, so a second cloud material built in the
95
+ // same program cannot reuse this one's.
96
+ let lightingModelId = 0;
97
+
98
+ /** Beer-Lambert transmittance for an optical depth. */
99
+ export function beerLambertNode(opticalDepth) {
100
+ return exp(max(float(opticalDepth), 0).negate());
101
+ }
102
+
103
+ /**
104
+ * Nubis powder / dark-edge term: `1 - exp(-2 x)`, raised to `strength`.
105
+ *
106
+ * Beer-Lambert alone makes a thin sunlit edge the *brightest* part of a cloud,
107
+ * because little light was absorbed there — which is exactly backwards. In a
108
+ * real cloud a point near the surface has few neighbours to scatter light in
109
+ * from, so the multiply-scattered field is starved there and the edge reads
110
+ * darker than the body. This is the standard approximation of that deficit.
111
+ *
112
+ * `occupancy` is **how much cloud surrounds the sample**, in [0, 1]:
113
+ * `createCloudDensityField`'s third channel, which is the density field with the
114
+ * shell's own height envelope divided out. Both of the obvious alternatives are
115
+ * wrong in a way that shows up in the render:
116
+ *
117
+ * - The light-march optical depth makes a sunlit top black, because a top with
118
+ * clear sky above it has a light depth of zero and `1 - exp(0)` is zero.
119
+ * - The plain normalized density carries the cumulus taper
120
+ * (`saturate((1 - h) / 0.7)`) and the two edge fades, so it falls
121
+ * monotonically with height whatever the cloud is actually doing there. That
122
+ * turns the term into a sunlit-top darkening ramp — measured 0.865 at the
123
+ * h <= 0.3 plateau against 0.133 at h = 0.95, a 6.5x penalty on exactly the
124
+ * tops the spec wants brilliant — and it dims solid cores too, since the
125
+ * envelope caps the density they can reach.
126
+ *
127
+ * The envelope is the shell's vertical profile, not the local cloud boundary,
128
+ * so dividing it out leaves the quantity the term is defined on: the horizontal
129
+ * occupancy of the cloud field. A wisp is thin at any height and stays dark; a
130
+ * tower's crown is surrounded by cloud and is not darkened relative to its
131
+ * middle.
132
+ *
133
+ * `strength` is an exponent rather than a mix weight, so 0 removes the term
134
+ * exactly (`x^0 = 1`), 1 is the published expression, and larger values
135
+ * over-darken without ever leaving [0, 1] — and because the base is normalised to
136
+ * 1 at full occupancy, a solid core is untouched at *every* strength. A
137
+ * `mix(1, powder, strength)` would have clamped everything above 1 to the same
138
+ * image. The reference publishes a default of 1.0 and no range, so none is
139
+ * asserted here.
140
+ */
141
+ export function powderNode(occupancy, strength) {
142
+ const local = saturate(float(occupancy));
143
+ const powder = exp(local.mul(-CLOUD_POWDER_EXPONENT)).oneMinus();
144
+ return mix(float(1), powder, max(float(strength), 0));
145
+ }
146
+
147
+ /**
148
+ * Nubis' max-combined phase function (2017 slide 80).
149
+ *
150
+ * The broad g=0.6 lobe keeps clouds readable away from the sun. A narrow
151
+ * g=(0.99 - spread) lobe supplies the silver lining, and max() prevents that
152
+ * highlight from adding energy over the whole body as a blend or sum would.
153
+ */
154
+ export function cloudPhaseNode(cosTheta) {
155
+ return mix(
156
+ henyeyGreensteinPhaseNode(cosTheta, float(CLOUD_PHASE_FORWARD_G)),
157
+ henyeyGreensteinPhaseNode(cosTheta, float(CLOUD_PHASE_BACKWARD_G)),
158
+ float(CLOUD_PHASE_BLEND),
159
+ );
160
+ }
161
+
162
+ /**
163
+ * Nubis' deep-light approximation (2017 slide 85), made view-dependent as the
164
+ * accompanying text specifies.
165
+ *
166
+ * Looking into the sun (cos=1) uses physical single scattering. Looking away
167
+ * (cos=-1) may use the dimmer, quarter-depth curve that stands in for light
168
+ * scattered deeper into the cloud. The linear angle ramp is the published code
169
+ * example also reproduced by the open Meteoros implementation.
170
+ */
171
+ export function cloudDirectionalAttenuationNode({ cosTheta, lightOpticalDepth }) {
172
+ void cosTheta;
173
+ return beerLambertNode(max(float(lightOpticalDepth), 0));
174
+ }
175
+
176
+ /** Phase, deep-light visibility and powder deficit for the directional sun. */
177
+ export function cloudDirectionalScatteringNode({
178
+ cosTheta,
179
+ lightOpticalDepth,
180
+ occupancy,
181
+ powderStrength,
182
+ }) {
183
+ const depth = max(float(lightOpticalDepth), 0);
184
+ let eccentricity = 1;
185
+ let extinction = 1;
186
+ let scatter = 1;
187
+ let energy = float(0);
188
+ for (let octave = 0; octave < 3; octave += 1) {
189
+ const phase = mix(
190
+ henyeyGreensteinPhaseNode(
191
+ cosTheta,
192
+ float(CLOUD_PHASE_FORWARD_G * eccentricity),
193
+ ),
194
+ henyeyGreensteinPhaseNode(
195
+ cosTheta,
196
+ float(CLOUD_PHASE_BACKWARD_G * eccentricity),
197
+ ),
198
+ float(CLOUD_PHASE_BLEND),
199
+ );
200
+ energy = energy.add(
201
+ exp(depth.mul(-extinction)).mul(scatter).mul(phase),
202
+ );
203
+ eccentricity *= CLOUD_MULTISCATTER_ECCENTRICITY;
204
+ extinction *= CLOUD_MULTISCATTER_EXTINCTION;
205
+ scatter *= CLOUD_MULTISCATTER_SCATTER;
206
+ }
207
+ return energy.mul(powderNode(occupancy, powderStrength));
208
+ }
209
+
210
+ /**
211
+ * Direct-beam transmittance for cloud shadows.
212
+ *
213
+ * Multiple scattering is radiance arriving from other directions; it fills the
214
+ * cloud image but cannot make the unobstructed solar beam reappear on a ground
215
+ * receiver. Shadow transmission is therefore plain Beer-Lambert.
216
+ */
217
+ export function cloudSunTransmittanceNode({ lightOpticalDepth }) {
218
+ return beerLambertNode(lightOpticalDepth);
219
+ }
220
+
221
+ /**
222
+ * Fraction of the sphere around a cloud sample that the ground fills.
223
+ *
224
+ * A sample at cloud altitude sees the ground below its own horizon, which is half
225
+ * the sphere to within the horizon dip (1.7 degrees at 2.8 km). The same one-half
226
+ * is implicit in the multiple-scattering bake, whose ground term fires on the
227
+ * directions that intersect the planet and is then averaged over the whole
228
+ * sphere. Using it here is what makes the two ground estimates cancel below,
229
+ * rather than a fitted number.
230
+ */
231
+ export const CLOUD_GROUND_HEMISPHERE_FRACTION = 0.5;
232
+
233
+ /**
234
+ * Radiance arriving at a cloud sample from the lit ground, before the cloud
235
+ * below it attenuates anything: a Lambertian re-emission of the direct beam that
236
+ * reached the ground, over the half-sphere the ground fills.
237
+ *
238
+ * This is the same construction Hillaire's multiple-scattering bake uses for its
239
+ * own ground term, which is what lets it serve two purposes — estimating the
240
+ * ground light the table's tap already contains, and adding the cloud's own.
241
+ * Checked against a re-bake with `groundAlbedo` zeroed: the estimate lands within
242
+ * 5% of the measured ground share of the tap at every sun angle (1.049 / 1.008 /
243
+ * 0.937 of it in R/G/B at zenith, 1.045 / 0.997 / 0.908 at 10 degrees).
244
+ *
245
+ * `groundIrradiance` is the *direct* beam at the ground and nothing else. The
246
+ * sky-lit part of the ground is already inside the table's own
247
+ * multiple-scattering boost.
248
+ */
249
+ export function cloudGroundRadianceNode({ groundIrradiance, albedo }) {
250
+ return albedo.mul(groundIrradiance).mul(INV_PI * CLOUD_GROUND_HEMISPHERE_FRACTION);
251
+ }
252
+
253
+ /**
254
+ * Skylight fill at a sample: the sky's share of the ambient bath, attenuated by
255
+ * the cloud above it, scaled by `lighting.ambientIntensity`.
256
+ *
257
+ * `skyRadiance` is the multiple-scattering table's tap, and that tap is a
258
+ * **sphere average** — the bake integrates every direction, including the ones
259
+ * that end on the lit ground, so it already carries a ground bounce taken at
260
+ * `atmosphere.groundAlbedo`. Measured at 2.8 km with the sun at zenith, 63% /
261
+ * 51% / 33% of the R/G/B of the tap *is* that ground bounce.
262
+ *
263
+ * `groundInTap` is that share, and subtracting it is what leaves this term the
264
+ * sky alone. Three things follow, all of which the reference's own docs require:
265
+ * `atmosphere.groundAlbedo` cancels out of the cloud — it is documented "sky dome
266
+ * only", and the fill now moves by at most 2.2% when it is driven from 0.18 to 0,
267
+ * against 14% before; `lighting.ambientIntensity`, documented as the *skylight*
268
+ * fill, no longer dials the ground; and at `ambientIntensity` 1 the two terms sum
269
+ * back to exactly the tap, so the bath is neither gained nor lost by the split.
270
+ *
271
+ * Checked against a ground-free re-bake of the same table: the remainder is
272
+ * 0.916 / 0.991 / 1.031 of it in R/G/B with the sun at zenith, and
273
+ * 0.990 / 1.000 / 1.004 at 10 degrees.
274
+ */
275
+ export function cloudAmbientNode({
276
+ skyRadiance,
277
+ groundInTap,
278
+ ambientIntensity,
279
+ multipleScattering = 0,
280
+ extinction,
281
+ slabAbove,
282
+ }) {
283
+ // This is an already integrated hemispherical bath. Treating the local
284
+ // extinction as constant through the whole remaining shell double-counts
285
+ // self-shadow and makes a dense core black; the directional light march owns
286
+ // cloud self-shadow until there is a real ambient-direction march.
287
+ void extinction;
288
+ void slabAbove;
289
+ void multipleScattering;
290
+ const skyOnly = max(skyRadiance.sub(groundInTap), vec3(0));
291
+ return skyOnly.mul(max(float(ambientIntensity), 0));
292
+ }
293
+
294
+ /**
295
+ * Ground bounce on a cloud underside: the ground's radiance at
296
+ * `lighting.groundBounceAlbedo`, attenuated by the cloud below the sample.
297
+ *
298
+ * The ground now enters the fill exactly once — here. `cloudAmbientNode` has
299
+ * already taken the table's own copy back out, so `groundBounceAlbedo` is the
300
+ * only albedo that decides how much light a cloud underside receives, which is
301
+ * what the parameter documents. It also means the two halves of the bath are
302
+ * attenuated along the paths they actually travel: sky light through the slab
303
+ * above the sample, ground light through the slab below it. Before, the whole
304
+ * sphere average rode the slab above and a second full bounce rode the slab
305
+ * below, which counted the ground twice and — because ground light is the
306
+ * spectrally flat term — flattened the fill toward grey (B/R 0.84 against a
307
+ * measured 1.04 for the true bath; 1.21 after).
308
+ */
309
+ export function cloudGroundBounceNode({
310
+ groundIrradiance,
311
+ groundBounceAlbedo,
312
+ extinction,
313
+ slabBelow,
314
+ }) {
315
+ // As above, a single local extinction value is not a valid integral through
316
+ // the heterogeneous volume. The sun light march supplies the directional
317
+ // depth; keep the low-frequency bounce as a fill rather than extinguishing it
318
+ // through a fictitious solid slab.
319
+ void extinction;
320
+ void slabBelow;
321
+ return cloudGroundRadianceNode({ albedo: groundBounceAlbedo, groundIrradiance });
322
+ }
323
+
324
+ /**
325
+ * The base-darkening pair as a multiplier on the lit terms.
326
+ *
327
+ * 1 above `baseShadowHeight`, falling to `1 - baseShadowStrength` at the floor
328
+ * of the shell. `baseShadowStrength` 1 therefore shades the bottom to black,
329
+ * which is what "shades them all the way down to the floor of the shell" means,
330
+ * and a larger height spreads the same amount of shading over more of the cloud
331
+ * so it reads softer.
332
+ */
333
+ export function cloudBaseShadowNode({ heightFraction, baseShadowStrength, baseShadowHeight }) {
334
+ const verticalProbability = mix(
335
+ float(0.15),
336
+ float(1),
337
+ smoothstep(
338
+ float(0),
339
+ max(float(baseShadowHeight), 1e-3),
340
+ saturate(float(heightFraction)),
341
+ ),
342
+ );
343
+ return mix(float(1), verticalProbability, saturate(float(baseShadowStrength)));
344
+ }
345
+
346
+ /** Height-varying sky and ground ambient fill. */
347
+ export function cloudSkyAmbientNode({
348
+ heightFraction,
349
+ zenithRadiance,
350
+ horizonRadiance,
351
+ groundBounceRadiance,
352
+ ambientIntensity,
353
+ }) {
354
+ const height = saturate(float(heightFraction));
355
+ const baseSky = mix(zenithRadiance, horizonRadiance, float(0.35));
356
+ const skyAmbient = mix(baseSky, zenithRadiance, sqrt(height));
357
+ const ground = groundBounceRadiance.mul(height.oneMinus());
358
+ return skyAmbient.add(ground).mul(max(float(ambientIntensity), 0));
359
+ }
360
+
361
+ /**
362
+ * Moonlight on cloud edges.
363
+ *
364
+ * Scaled by `lighting.moonGain`, by the moon's lit fraction
365
+ * (`moonPhaseIllumination` — a sliver must not light a sky like a full moon),
366
+ * and by how night it is, so the term is gone by day. `moonRadiance` carries
367
+ * `moonColor * moonIntensity`.
368
+ */
369
+ export function cloudMoonRimNode({
370
+ cosTheta,
371
+ extinction,
372
+ moonRadiance,
373
+ moonGain,
374
+ moonIllumination,
375
+ nightFactor,
376
+ path = CLOUD_MOON_RIM_PATH,
377
+ }) {
378
+ const rim = beerLambertNode(max(float(extinction), 0).mul(path));
379
+ return moonRadiance
380
+ .mul(cloudPhaseNode(cosTheta))
381
+ .mul(rim)
382
+ .mul(max(float(moonGain), 0))
383
+ .mul(saturate(float(moonIllumination)))
384
+ .mul(saturate(float(nightFactor)));
385
+ }
386
+
387
+ /**
388
+ * Directional moonlight through the same cloud depth model as sunlight.
389
+ *
390
+ * The old night path only supplied a local edge rim, so the moon could outline
391
+ * a cloud but could not reveal lobes or self-shadowing inside it. This term is
392
+ * fed by a moon-facing light march and is multiplied by `nightFactor`; the
393
+ * caller skips that second light march entirely while the sky is not dark.
394
+ */
395
+ export function cloudMoonDirectionalNode({
396
+ cosTheta,
397
+ lightOpticalDepth,
398
+ moonRadiance,
399
+ moonGain,
400
+ moonIllumination,
401
+ nightFactor,
402
+ occupancy,
403
+ powderStrength,
404
+ }) {
405
+ return moonRadiance
406
+ .mul(cloudDirectionalScatteringNode({
407
+ cosTheta,
408
+ lightOpticalDepth,
409
+ occupancy,
410
+ powderStrength,
411
+ }))
412
+ .mul(max(float(moonGain), 0))
413
+ .mul(saturate(float(moonIllumination)))
414
+ .mul(saturate(float(nightFactor)));
415
+ }
416
+
417
+ /**
418
+ * Optional three-tone remap over physically calculated cloud radiance.
419
+ *
420
+ * The physical luminance selects the authored shadow, body and highlight
421
+ * colours. It is compressed into 0..1 only for choosing a band; output remains
422
+ * linear HDR radiance, so atmosphere, exposure and bloom still operate in the
423
+ * same space as V1. Both switches are uniforms. A disabled master or module
424
+ * blends by exactly zero and leaves the physical value unchanged.
425
+ */
426
+ export function applyCloudToneNode(radiance, style = null) {
427
+ const physical = max(vec3(radiance), vec3(0));
428
+ if (!style?.enabled || !style?.tone?.enabled) return physical;
429
+
430
+ const tone = style.tone;
431
+ const luminance = max(physical.dot(CLOUD_LUMINANCE), 0).toVar();
432
+ const signal = luminance.div(luminance.add(1)).toVar();
433
+ const width = max(tone.softness, 1e-4).toVar();
434
+ const shadowToMid = smoothstep(
435
+ tone.shadowPoint.sub(width),
436
+ tone.shadowPoint.add(width),
437
+ signal,
438
+ ).toVar();
439
+ const midToLight = smoothstep(
440
+ tone.lightPoint.sub(width),
441
+ tone.lightPoint.add(width),
442
+ signal,
443
+ ).toVar();
444
+ const palette = mix(
445
+ mix(tone.shadowColor, tone.midColor, shadowToMid),
446
+ tone.lightColor,
447
+ midToLight,
448
+ ).toVar();
449
+ const paletteLuminance = max(palette.dot(CLOUD_LUMINANCE), 1e-4).toVar();
450
+ const compressed = max(luminance, tone.shadowLift)
451
+ .div(float(1).add(luminance.mul(max(tone.highlightCompression, 0))))
452
+ .mul(max(tone.brightness, 0))
453
+ .toVar();
454
+ const styled = palette.mul(compressed.div(paletteLuminance)).toVar();
455
+ const amount = saturate(style.enabled.mul(tone.enabled).mul(style.amount));
456
+ return mix(physical, styled, amount);
457
+ }
458
+
459
+ /**
460
+ * Adds the cool skylight art direction to shadowed cloud regions only.
461
+ *
462
+ * The physical pre-tone luminance selects the shadow mask. The authored colour
463
+ * is normalized back to the already-styled luminance before blending, so this
464
+ * module changes hue without flattening the light march or lifting the back of
465
+ * every cloud to a constant colour.
466
+ */
467
+ export function applyCloudBlueShadowNode(radiance, physicalRadiance, style = null) {
468
+ const styled = max(vec3(radiance), vec3(0));
469
+ if (!style?.enabled || !style?.blueShadow?.enabled) return styled;
470
+
471
+ const source = max(vec3(physicalRadiance), vec3(0));
472
+ const blueShadow = style.blueShadow;
473
+ const sourceLuminance = max(source.dot(CLOUD_LUMINANCE), 0).toVar();
474
+ const signal = sourceLuminance.div(sourceLuminance.add(1)).toVar();
475
+ const width = max(blueShadow.softness, 1e-4).toVar();
476
+ const shadowMask = smoothstep(
477
+ blueShadow.range.sub(width),
478
+ blueShadow.range.add(width),
479
+ signal,
480
+ ).oneMinus().toVar();
481
+ const styledLuminance = max(styled.dot(CLOUD_LUMINANCE), 0).toVar();
482
+ const blueLuminance = max(blueShadow.color.dot(CLOUD_LUMINANCE), 1e-4).toVar();
483
+ const tinted = blueShadow.color.mul(styledLuminance.div(blueLuminance)).toVar();
484
+ const amount = saturate(
485
+ style.enabled
486
+ .mul(blueShadow.enabled)
487
+ .mul(style.amount)
488
+ .mul(blueShadow.amount)
489
+ .mul(shadowMask),
490
+ );
491
+ return mix(styled, tinted, amount);
492
+ }
493
+
494
+ /**
495
+ * Applies the per-sample daytime style modules in a stable, documented order.
496
+ *
497
+ * `daylightAmount` lets the shared clock remove the daytime remap before the
498
+ * night palette is applied. Full night then starts from the physically
499
+ * moonlit, self-shadowed volume instead of a blue daytime tone ramp. A value of
500
+ * one preserves the established V2.6 result exactly.
501
+ */
502
+ export function applyCloudStyleNode(radiance, style = null, daylightAmount = 1) {
503
+ const physical = max(vec3(radiance), vec3(0));
504
+ const toned = applyCloudToneNode(physical, style);
505
+ const styled = applyCloudBlueShadowNode(toned, physical, style);
506
+ return mix(physical, styled, saturate(float(daylightAmount)));
507
+ }
508
+
509
+ /**
510
+ * Turns the accumulated cloud underside into a pale painted wash.
511
+ *
512
+ * This runs once after the volume march rather than once per density sample.
513
+ * Working on the resolved cloud colour lets `detail` compress small lighting
514
+ * variations across the whole visible body. The blue-shadow range selects the
515
+ * same underside region, but this module has its own switch and still works
516
+ * when the blue hue module is bypassed.
517
+ */
518
+ export function applyCloudShadowWashNode(premultipliedRadiance, alpha, style = null) {
519
+ const original = max(vec3(premultipliedRadiance), vec3(0));
520
+ if (!style?.enabled || !style?.shadowWash?.enabled) return original;
521
+
522
+ const wash = style.shadowWash;
523
+ const safeAlpha = max(float(alpha), 1e-4).toVar();
524
+ const body = original.div(safeAlpha).toVar();
525
+ const luminance = max(body.dot(CLOUD_LUMINANCE), 0).toVar();
526
+ const signal = luminance.div(luminance.add(1)).toVar();
527
+ const range = style?.blueShadow?.range ?? float(0.38);
528
+ const width = max(wash.blend, 1e-4).toVar();
529
+ const shadowMask = smoothstep(
530
+ range.sub(width),
531
+ range.add(width),
532
+ signal,
533
+ ).oneMinus().toVar();
534
+ const washedLuminance = mix(
535
+ max(wash.lift, 0),
536
+ luminance,
537
+ saturate(wash.detail),
538
+ ).toVar();
539
+ const washedBody = body
540
+ .mul(washedLuminance.div(max(luminance, 1e-4)))
541
+ .toVar();
542
+ const amount = saturate(
543
+ style.enabled
544
+ .mul(wash.enabled)
545
+ .mul(style.amount)
546
+ .mul(shadowMask),
547
+ );
548
+ return mix(original, washedBody.mul(safeAlpha), amount);
549
+ }
550
+
551
+ /**
552
+ * Keeps the physical cloud edge while allowing a painted interior.
553
+ *
554
+ * Cloud opacity remains entirely owned by the volume march. This function only
555
+ * blends between the resolved physical colour and the shadow-washed colour,
556
+ * using resolved opacity as an interior mask. Thin wisps and the outer contour
557
+ * therefore retain their physical shading and silhouette.
558
+ */
559
+ export function applyCloudInnerPaintNode(
560
+ premultipliedRadiance,
561
+ alpha,
562
+ style = null,
563
+ daylightAmount = 1,
564
+ ) {
565
+ const original = max(vec3(premultipliedRadiance), vec3(0));
566
+ const painted = applyCloudShadowWashNode(original, alpha, style);
567
+ if (!style?.enabled || !style?.innerPaint?.enabled) return painted;
568
+
569
+ const inner = style.innerPaint;
570
+ const edgeStart = saturate(inner.edgeKeep).toVar();
571
+ const edgeWidth = max(inner.edgeBlend, 1e-4).toVar();
572
+ const interiorMask = smoothstep(
573
+ edgeStart,
574
+ edgeStart.add(edgeWidth),
575
+ saturate(float(alpha)),
576
+ ).toVar();
577
+ const amount = saturate(
578
+ style.enabled
579
+ .mul(inner.enabled)
580
+ .mul(inner.amount)
581
+ .mul(saturate(float(daylightAmount)))
582
+ .mul(interiorMask),
583
+ );
584
+ return mix(original, painted, amount);
585
+ }
586
+
587
+ /**
588
+ * Broadens the clean white region across sun-reachable upper cloud samples.
589
+ *
590
+ * `sunlitHeight` is accumulated by the physical volume march from the existing
591
+ * height fraction and light optical depth. It changes no density or opacity.
592
+ * The final blend reuses the V2.4 resolved-opacity boundary so the physical
593
+ * contour and thin wisps remain untouched while only the opaque interior is
594
+ * simplified toward the authored warm white.
595
+ */
596
+ export function applyCloudWhiteTopNode(
597
+ premultipliedRadiance,
598
+ alpha,
599
+ sunlitHeight,
600
+ style = null,
601
+ ) {
602
+ const original = max(vec3(premultipliedRadiance), vec3(0));
603
+ if (!style?.enabled || !style?.whiteTop?.enabled) return original;
604
+
605
+ const white = style.whiteTop;
606
+ const safeAlpha = max(float(alpha), 1e-4).toVar();
607
+ const body = original.div(safeAlpha).toVar();
608
+ const start = saturate(white.area).oneMinus().toVar();
609
+ const width = max(white.softness, 1e-4).toVar();
610
+ const topMask = smoothstep(
611
+ start.sub(width),
612
+ start.add(width),
613
+ saturate(float(sunlitHeight)),
614
+ ).toVar();
615
+
616
+ const edgeStart = saturate(style.innerPaint.edgeKeep).toVar();
617
+ const edgeWidth = max(style.innerPaint.edgeBlend, 1e-4).toVar();
618
+ const interiorMask = smoothstep(
619
+ edgeStart,
620
+ edgeStart.add(edgeWidth),
621
+ saturate(float(alpha)),
622
+ ).toVar();
623
+
624
+ const bodyLuminance = max(body.dot(CLOUD_LUMINANCE), 0).toVar();
625
+ const whiteLuminance = max(white.color.dot(CLOUD_LUMINANCE), 1e-4).toVar();
626
+ const paintedLuminance = mix(
627
+ whiteLuminance,
628
+ bodyLuminance,
629
+ saturate(white.detail),
630
+ ).toVar();
631
+ const paintedBody = white.color
632
+ .mul(paintedLuminance.div(whiteLuminance))
633
+ .toVar();
634
+ const amount = saturate(
635
+ style.enabled
636
+ .mul(white.enabled)
637
+ .mul(style.amount)
638
+ .mul(white.amount)
639
+ .mul(topMask)
640
+ .mul(interiorMask),
641
+ );
642
+ return mix(original, paintedBody.mul(safeAlpha), amount);
643
+ }
644
+
645
+ /**
646
+ * Restores directional sunlight value variation after the white-top paint.
647
+ *
648
+ * White Top deliberately simplifies the upper cloud into one authored hue.
649
+ * This stage uses both the physical in-scatter luminance and Beer-Lambert sun
650
+ * reach from the existing light march to shade that hue. An aerial view then
651
+ * recovers sun-facing crowns and shadowed folds without changing density,
652
+ * opacity, or the approved top colour. The fixed value range keeps the
653
+ * authored white top bright while retaining the light march's local variation.
654
+ */
655
+ export function applyCloudTopLightNode(
656
+ premultipliedRadiance,
657
+ physicalLight,
658
+ sunlight,
659
+ alpha,
660
+ sunlitHeight,
661
+ daylight,
662
+ surfaceLightAmount = 0,
663
+ surfaceSunFacing = 0.5,
664
+ style = null,
665
+ ) {
666
+ const original = max(vec3(premultipliedRadiance), vec3(0));
667
+ if (!style?.enabled || !style?.topLight?.enabled) return original;
668
+
669
+ const safeAlpha = max(float(alpha), 1e-4).toVar();
670
+ const body = original.div(safeAlpha).toVar();
671
+ const physicalSignal = smoothstep(
672
+ 0.08,
673
+ 0.9,
674
+ max(float(physicalLight), 0),
675
+ ).toVar();
676
+ const lightSignal = sqrt(saturate(float(sunlight))).mul(mix(
677
+ 0.4,
678
+ 1,
679
+ physicalSignal,
680
+ )).toVar();
681
+ const exteriorAmount = saturate(float(surfaceLightAmount)).toVar();
682
+ const exteriorSignal = smoothstep(
683
+ 0.15,
684
+ 0.9,
685
+ saturate(float(surfaceSunFacing)),
686
+ ).mul(mix(0.7, 1, sqrt(saturate(float(sunlight))))).toVar();
687
+ const resolvedSignal = mix(lightSignal, exteriorSignal, exteriorAmount).toVar();
688
+ const shadowValue = mix(0.65, 0.55, exteriorAmount).toVar();
689
+ // Exterior shaping is carried by the shaded turn, not clipped pin-light
690
+ // highlights on distant wisps. Keep the bright end close to the V2.8 white.
691
+ const highlightValue = mix(1.25, 1.3, exteriorAmount).toVar();
692
+ const lightRatio = mix(shadowValue, highlightValue, resolvedSignal).toVar();
693
+ const relitBody = body.mul(lightRatio).toVar();
694
+
695
+ const white = style.whiteTop;
696
+ const start = saturate(white.area).oneMinus().toVar();
697
+ const width = max(white.softness, 1e-4).toVar();
698
+ const topMask = smoothstep(
699
+ start.sub(width),
700
+ start.add(width),
701
+ saturate(float(sunlitHeight)),
702
+ ).toVar();
703
+ const edgeStart = saturate(style.innerPaint.edgeKeep).toVar();
704
+ const edgeWidth = max(style.innerPaint.edgeBlend, 1e-4).toVar();
705
+ const interiorMask = smoothstep(
706
+ edgeStart,
707
+ edgeStart.add(edgeWidth),
708
+ saturate(float(alpha)),
709
+ ).toVar();
710
+ const amount = saturate(
711
+ style.enabled
712
+ .mul(style.topLight.enabled)
713
+ .mul(style.amount)
714
+ .mul(style.topLight.amount)
715
+ .mul(saturate(float(daylight)))
716
+ .mul(topMask)
717
+ .mul(interiorMask),
718
+ );
719
+ return mix(original, relitBody.mul(safeAlpha), amount);
720
+ }
721
+
722
+ /**
723
+ * Adds a restrained cool tint to the shadow and middle regions while leaving
724
+ * the existing warm white top intact.
725
+ *
726
+ * The physical march still owns opacity and the outer contour. This final
727
+ * colour stage reuses the same sunlit-height descriptor, White Top boundary,
728
+ * and V2.4 interior mask. It therefore changes only the readable lower colour
729
+ * regions inside opaque daytime clouds.
730
+ */
731
+ export function applyCloudLightBlendNode(
732
+ premultipliedRadiance,
733
+ alpha,
734
+ sunlitHeight,
735
+ daylight,
736
+ style = null,
737
+ ) {
738
+ const original = max(vec3(premultipliedRadiance), vec3(0));
739
+ if (!style?.enabled || !style?.lightBlend?.enabled) return original;
740
+
741
+ const blend = style.lightBlend;
742
+ const safeAlpha = max(float(alpha), 1e-4).toVar();
743
+ const body = original.div(safeAlpha).toVar();
744
+ const daylightAmount = saturate(float(daylight)).toVar();
745
+ const signal = saturate(float(sunlitHeight).mul(daylightAmount)).toVar();
746
+ const center = saturate(blend.balance).toVar();
747
+ const width = max(blend.softness, 1e-4).toVar();
748
+ const bottomToMiddle = smoothstep(
749
+ center.sub(width),
750
+ center.add(width),
751
+ signal,
752
+ ).toVar();
753
+
754
+ // Match the V2.5 selector exactly. Its bright upper region passes through
755
+ // this stage instead of being repainted by a second palette.
756
+ const topStart = saturate(style.whiteTop.area).oneMinus().toVar();
757
+ const topWidth = max(style.whiteTop.softness, 1e-4).toVar();
758
+ const keepWhiteTop = smoothstep(
759
+ topStart.sub(topWidth),
760
+ topStart.add(topWidth),
761
+ signal,
762
+ ).toVar();
763
+ const palette = mix(
764
+ blend.bottomColor,
765
+ blend.middleColor,
766
+ bottomToMiddle,
767
+ ).toVar();
768
+
769
+ const edgeStart = saturate(style.innerPaint.edgeKeep).toVar();
770
+ const edgeWidth = max(style.innerPaint.edgeBlend, 1e-4).toVar();
771
+ const interiorMask = smoothstep(
772
+ edgeStart,
773
+ edgeStart.add(edgeWidth),
774
+ saturate(float(alpha)),
775
+ ).toVar();
776
+
777
+ const bodyLuminance = max(body.dot(CLOUD_LUMINANCE), 0).toVar();
778
+ const paletteLuminance = max(palette.dot(CLOUD_LUMINANCE), 1e-4).toVar();
779
+ const tintedBody = palette.mul(bodyLuminance.div(paletteLuminance)).toVar();
780
+ const paintedBody = mix(
781
+ tintedBody,
782
+ body,
783
+ saturate(blend.detail),
784
+ ).toVar();
785
+ const amount = saturate(
786
+ style.enabled
787
+ .mul(blend.enabled)
788
+ .mul(style.amount)
789
+ .mul(blend.amount)
790
+ .mul(daylightAmount)
791
+ .mul(interiorMask)
792
+ .mul(keepWhiteTop.oneMinus()),
793
+ );
794
+ return mix(original, paintedBody.mul(safeAlpha), amount);
795
+ }
796
+
797
+ /**
798
+ * Tints the resolved cloud interior in the morning, evening, and night from the
799
+ * shared sky clock. Afternoon receives an exact zero blend, so V2.6 remains
800
+ * the day result rather than becoming another palette input.
801
+ *
802
+ * The physical march still owns opacity and the outer contour. Density and
803
+ * alpha remain untouched. The V2.4 interior mask only softens the
804
+ * colour grade slightly at the contour; time colour must still reach wisps so
805
+ * they cannot remain daytime cyan or white after the clock changes.
806
+ */
807
+ export function applyCloudTimePaletteNode(
808
+ premultipliedRadiance,
809
+ alpha,
810
+ sunlitHeight,
811
+ morningLight,
812
+ eveningLight,
813
+ nightness,
814
+ style = null,
815
+ ) {
816
+ const original = max(vec3(premultipliedRadiance), vec3(0));
817
+ if (!style?.enabled || !style?.timePalette?.enabled) return original;
818
+
819
+ const timePalette = style.timePalette;
820
+ const safeAlpha = max(float(alpha), 1e-4).toVar();
821
+ const body = original.div(safeAlpha).toVar();
822
+ const night = saturate(float(nightness)).toVar();
823
+ const morning = saturate(float(morningLight)).toVar();
824
+ const evening = saturate(float(eveningLight)).toVar();
825
+ const eveningSide = evening.div(max(morning.add(evening), 1e-4)).toVar();
826
+
827
+ const bodyLuminance = max(body.dot(CLOUD_LUMINANCE), 0).toVar();
828
+ const bodySignal = bodyLuminance.div(bodyLuminance.add(1)).toVar();
829
+ const compressedNightSignal = bodySignal.mul(bodySignal).toVar();
830
+ const nightSignal = mix(
831
+ bodySignal,
832
+ compressedNightSignal,
833
+ saturate(timePalette.nightContrast),
834
+ ).toVar();
835
+ // The marcher exposes a sunlight-weighted height boosted for the daytime
836
+ // white-top module. Bring it back to a normalized shell height here, then
837
+ // combine it with resolved opacity. This creates broad top/body/edge value
838
+ // regions at night even when the physical moon contribution is too uniform
839
+ // to describe the cloud on its own. It never changes density or alpha.
840
+ const heightSignal = saturate(float(sunlitHeight).mul(0.2)).toVar();
841
+ const topSignal = smoothstep(0.12, 0.78, heightSignal).toVar();
842
+ const depthSignal = smoothstep(0.08, 0.85, saturate(float(alpha))).toVar();
843
+ const edgeSignal = depthSignal.oneMinus().toVar();
844
+ const nightValue = nightSignal
845
+ .mul(1.2)
846
+ .add(topSignal.mul(0.012))
847
+ .add(edgeSignal.mul(0.006))
848
+ .add(0.008)
849
+ .toVar();
850
+ const warmBand = smoothstep(
851
+ 0.01,
852
+ 0.18,
853
+ max(bodySignal, heightSignal.mul(0.18)),
854
+ ).toVar();
855
+ const nightBand = smoothstep(0.015, 0.08, nightValue).toVar();
856
+ const morningColor = mix(
857
+ timePalette.morningBottom,
858
+ timePalette.morningTop,
859
+ warmBand,
860
+ ).toVar();
861
+ const eveningColor = mix(
862
+ timePalette.eveningBottom,
863
+ timePalette.eveningTop,
864
+ warmBand,
865
+ ).toVar();
866
+ const nightColor = mix(
867
+ timePalette.nightBottom,
868
+ timePalette.nightTop,
869
+ nightBand,
870
+ ).toVar();
871
+ const warmColor = mix(morningColor, eveningColor, eveningSide).toVar();
872
+ const palette = mix(warmColor, nightColor, night).toVar();
873
+
874
+ const edgeStart = saturate(style.innerPaint.edgeKeep).toVar();
875
+ const edgeWidth = max(style.innerPaint.edgeBlend, 1e-4).toVar();
876
+ const interiorMask = smoothstep(
877
+ edgeStart,
878
+ edgeStart.add(edgeWidth),
879
+ saturate(float(alpha)),
880
+ ).toVar();
881
+ const contourColor = mix(float(0.9), float(1), interiorMask).toVar();
882
+
883
+ const warmBrightness = mix(
884
+ timePalette.morningBrightness,
885
+ timePalette.eveningBrightness,
886
+ eveningSide,
887
+ ).toVar();
888
+ const brightness = mix(
889
+ warmBrightness,
890
+ timePalette.nightBrightness,
891
+ night,
892
+ ).toVar();
893
+ const shapedLuminance = mix(bodySignal, nightValue, night).toVar();
894
+ const styledLuminance = shapedLuminance.mul(max(brightness, 0)).toVar();
895
+ const paletteLuminance = max(palette.dot(CLOUD_LUMINANCE), 1e-4).toVar();
896
+ const tintedBody = palette.mul(styledLuminance.div(paletteLuminance)).toVar();
897
+ const warmDetail = mix(
898
+ timePalette.morningDetail,
899
+ timePalette.eveningDetail,
900
+ eveningSide,
901
+ ).toVar();
902
+ const retainedDetail = saturate(
903
+ mix(warmDetail, timePalette.nightDetail, night),
904
+ ).toVar();
905
+ // Detail means the original volumetric lighting, including its value
906
+ // structure. The earlier draft normalized this branch back to the painted
907
+ // luminance, so it restored hue but erased the self-shadowing developers
908
+ // expected the control to preserve.
909
+ const paintedBody = mix(
910
+ tintedBody,
911
+ body,
912
+ retainedDetail,
913
+ ).toVar();
914
+ const timeAmount = max(
915
+ max(
916
+ morning.mul(timePalette.morningEnabled).mul(timePalette.morningAmount),
917
+ evening.mul(timePalette.eveningEnabled).mul(timePalette.eveningAmount),
918
+ ),
919
+ night.mul(timePalette.nightEnabled).mul(timePalette.nightAmount),
920
+ ).toVar();
921
+ const amount = saturate(
922
+ style.enabled
923
+ .mul(timePalette.enabled)
924
+ .mul(timeAmount)
925
+ .mul(contourColor),
926
+ ).toVar();
927
+ // Keep afternoon on the exact V2.6 result. A conditional return is stronger
928
+ // than evaluating the time colour and trusting a zero mix to cancel it;
929
+ // inactive time calculations cannot perturb or poison the day value.
930
+ return timeAmount.greaterThan(1e-5).select(
931
+ mix(original, paintedBody.mul(safeAlpha), amount),
932
+ original,
933
+ );
934
+ }
935
+
936
+ /**
937
+ * Binds the scattering model to one set of live parameter groups.
938
+ *
939
+ * `lighting` is a `CloudLighting` group, `atmosphere` an atmosphere param group
940
+ * (`multipleScattering` and `groundAlbedo` are read — the latter only to cancel
941
+ * it out of the fill, see `cloudAmbientNode`), and `timeOfDay` is optional —
942
+ * without it the moon terms resolve to zero rather than to a full moon.
943
+ *
944
+ * Returns `inScatterNode`, a laid-out TSL function. RGB is the styled radiance
945
+ * scattered toward the eye from one cubic metre of cloud, with
946
+ * `scatteringAlbedo` already applied. Alpha preserves the physical luminance
947
+ * from before any style module, so final-pixel paint can restore lighting value
948
+ * without a second light march. The marcher's job is then the segment integral:
949
+ * `radiance += transmittance * (1 - exp(-sigma dt)) * inScatter`, which is the
950
+ * analytically integrated form for a constant medium over the segment.
951
+ */
952
+ export function createCloudLightingModel({
953
+ lighting,
954
+ atmosphere,
955
+ style = null,
956
+ timeOfDay = null,
957
+ name = 'cloudInScatter',
958
+ } = {}) {
959
+ if (!lighting?.scatteringAlbedo || !lighting?.powderStrength) {
960
+ throw new TypeError('createCloudLightingModel needs a cloud lighting param group.');
961
+ }
962
+ // `groundAlbedo` as well as `multipleScattering`: the fill has to know which
963
+ // albedo the skylight table was baked with to avoid counting the ground twice.
964
+ if (!atmosphere?.multipleScattering || !atmosphere?.groundAlbedo) {
965
+ throw new TypeError('createCloudLightingModel needs an atmosphere param group.');
966
+ }
967
+
968
+ // Absent clock: no moon, rather than a full one. `float(0)` is a constant node
969
+ // the compiler folds away, so the moon terms cost nothing when unused.
970
+ const moonIllumination = timeOfDay?.moonPhaseIllumination ?? float(0);
971
+ const nightFactor = timeOfDay?.skyDarkness ?? float(0);
972
+
973
+ lightingModelId += 1;
974
+ const functionName = `${name}${lightingModelId}`;
975
+
976
+ const inScatterNode = Fn(([
977
+ heightFraction,
978
+ occupancy,
979
+ extinction,
980
+ lightOpticalDepth,
981
+ moonLightOpticalDepth,
982
+ slabAbove,
983
+ slabBelow,
984
+ cosSun,
985
+ cosMoon,
986
+ sunRadiance,
987
+ zenithRadiance,
988
+ horizonRadiance,
989
+ groundBounceRadiance,
990
+ moonRadiance,
991
+ ]) => {
992
+ const baseShadow = cloudBaseShadowNode({
993
+ baseShadowHeight: lighting.baseShadowHeight,
994
+ baseShadowStrength: lighting.baseShadowStrength,
995
+ heightFraction,
996
+ });
997
+
998
+ const direct = sunRadiance.mul(cloudDirectionalScatteringNode({
999
+ cosTheta: cosSun,
1000
+ lightOpticalDepth,
1001
+ occupancy,
1002
+ powderStrength: lighting.powderStrength,
1003
+ }));
1004
+
1005
+ const ambient = cloudSkyAmbientNode({
1006
+ ambientIntensity: lighting.ambientIntensity,
1007
+ groundBounceRadiance,
1008
+ heightFraction,
1009
+ horizonRadiance,
1010
+ zenithRadiance,
1011
+ });
1012
+
1013
+ const moonDirectional = cloudMoonDirectionalNode({
1014
+ cosTheta: cosMoon,
1015
+ lightOpticalDepth: moonLightOpticalDepth,
1016
+ moonGain: lighting.moonGain,
1017
+ moonIllumination,
1018
+ moonRadiance,
1019
+ nightFactor,
1020
+ occupancy,
1021
+ powderStrength: lighting.powderStrength,
1022
+ });
1023
+ const moonRim = cloudMoonRimNode({
1024
+ cosTheta: cosMoon,
1025
+ extinction,
1026
+ moonGain: lighting.moonGain,
1027
+ moonIllumination,
1028
+ moonRadiance,
1029
+ nightFactor,
1030
+ });
1031
+ const moon = moonDirectional.add(moonRim.mul(0.35));
1032
+
1033
+ void slabAbove;
1034
+ void slabBelow;
1035
+ const lit = direct.add(moon).mul(baseShadow).add(ambient);
1036
+ const physical = max(lit.mul(saturate(lighting.scatteringAlbedo)), vec3(0));
1037
+ const styled = applyCloudStyleNode(physical, style, nightFactor.oneMinus());
1038
+ return vec4(styled, max(physical.dot(CLOUD_LUMINANCE), 0));
1039
+ }).setLayout({
1040
+ name: functionName,
1041
+ type: 'vec4',
1042
+ inputs: [
1043
+ { name: 'heightFraction', type: 'float' },
1044
+ { name: 'occupancy', type: 'float' },
1045
+ { name: 'extinction', type: 'float' },
1046
+ { name: 'lightOpticalDepth', type: 'float' },
1047
+ { name: 'moonLightOpticalDepth', type: 'float' },
1048
+ { name: 'slabAbove', type: 'float' },
1049
+ { name: 'slabBelow', type: 'float' },
1050
+ { name: 'cosSun', type: 'float' },
1051
+ { name: 'cosMoon', type: 'float' },
1052
+ { name: 'sunRadiance', type: 'vec3' },
1053
+ { name: 'zenithRadiance', type: 'vec3' },
1054
+ { name: 'horizonRadiance', type: 'vec3' },
1055
+ { name: 'groundBounceRadiance', type: 'vec3' },
1056
+ { name: 'moonRadiance', type: 'vec3' },
1057
+ ],
1058
+ });
1059
+
1060
+ return {
1061
+ functionName,
1062
+ inScatterNode,
1063
+ lighting,
1064
+ atmosphere,
1065
+ style,
1066
+ timeOfDay,
1067
+
1068
+ /**
1069
+ * Sun transmittance through the cloud, 0..1 — what the shadow bake needs.
1070
+ *
1071
+ * View-independent and normalised, per `cloudSunTransmittanceNode`. The
1072
+ * bake's own job is still to return 1 outside its footprint.
1073
+ */
1074
+ sunTransmittanceNode({ lightOpticalDepth }) {
1075
+ return cloudSunTransmittanceNode({ lightOpticalDepth });
1076
+ },
1077
+
1078
+ /**
1079
+ * The phase-weighted, powdered Nubis directional term — the key light's
1080
+ * contribution to radiance scattered toward `cosTheta`, which is what the
1081
+ * env-map bake needs and what the marcher multiplies `sunRadiance` by.
1082
+ *
1083
+ * Not a transmittance and not in [0, 1]: it carries the max-combined broad
1084
+ * and silver-lining phase. Use `sunTransmittanceNode` for anything that has
1085
+ * to shadow.
1086
+ */
1087
+ phaseVisibilityNode({ cosTheta, occupancy, lightOpticalDepth }) {
1088
+ return cloudDirectionalScatteringNode({
1089
+ cosTheta,
1090
+ lightOpticalDepth,
1091
+ occupancy,
1092
+ powderStrength: lighting.powderStrength,
1093
+ });
1094
+ },
1095
+
1096
+ /** Fixed phase terms exposed for diagnostics and verification. */
1097
+ phaseConstants: Object.freeze({
1098
+ backwardG: CLOUD_PHASE_BACKWARD_G,
1099
+ phaseBlend: CLOUD_PHASE_BLEND,
1100
+ forwardG: CLOUD_PHASE_FORWARD_G,
1101
+ msEccentricity: CLOUD_MULTISCATTER_ECCENTRICITY,
1102
+ msExtinction: CLOUD_MULTISCATTER_EXTINCTION,
1103
+ msScatter: CLOUD_MULTISCATTER_SCATTER,
1104
+ }),
1105
+ nubis: Object.freeze({
1106
+ backwardG: CLOUD_PHASE_BACKWARD_G,
1107
+ phaseBlend: CLOUD_PHASE_BLEND,
1108
+ forwardG: CLOUD_PHASE_FORWARD_G,
1109
+ msEccentricity: CLOUD_MULTISCATTER_ECCENTRICITY,
1110
+ msExtinction: CLOUD_MULTISCATTER_EXTINCTION,
1111
+ msScatter: CLOUD_MULTISCATTER_SCATTER,
1112
+ }),
1113
+ };
1114
+ }