@call-me-sensei/toonlab 0.2.0 → 0.3.0

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 (205) hide show
  1. package/AGENTS.md +127 -4
  2. package/ATTRIBUTION.md +41 -3
  3. package/README.md +234 -34
  4. package/docs/characters.md +144 -0
  5. package/docs/debug-panel.md +126 -0
  6. package/docs/docs.css +589 -0
  7. package/docs/environment.md +186 -0
  8. package/docs/getting-started.md +180 -0
  9. package/docs/index.html +14 -0
  10. package/docs/lab-architecture.md +100 -0
  11. package/docs/lighting.md +825 -0
  12. package/docs/main.jsx +739 -0
  13. package/docs/mcp.md +97 -0
  14. package/docs/post-processing.md +98 -0
  15. package/docs/settings-reference.md +1878 -0
  16. package/docs/shader-constants.md +77 -0
  17. package/docs/sky.md +182 -0
  18. package/docs/style-labs.md +309 -0
  19. package/docs/texture-lab.md +135 -0
  20. package/docs/toon-shading.md +183 -0
  21. package/docs/tsl-conventions.md +167 -0
  22. package/docs/vegetation-sky.md +275 -0
  23. package/docs/water.md +430 -0
  24. package/docs/weather.md +200 -0
  25. package/docs/world-scale.md +111 -0
  26. package/mcp/server.mjs +610 -0
  27. package/mcp/style-lab-tools.mjs +371 -0
  28. package/mcp/vite-plugin.mjs +174 -0
  29. package/mcp/workspace.mjs +397 -0
  30. package/package.json +64 -5
  31. package/src/ambientfx/INTEGRATION.md +164 -0
  32. package/src/ambientfx/ambientFxPresets.js +83 -0
  33. package/src/ambientfx/ambientFxSettings.js +368 -0
  34. package/src/ambientfx/emitters.js +169 -0
  35. package/src/ambientfx/index.js +5 -0
  36. package/src/ambientfx/particleBackbone.js +493 -0
  37. package/src/ambientfx/stylizedAmbientFx.js +450 -0
  38. package/src/assetlib/ambientcg.js +117 -0
  39. package/src/assetlib/assetRef.js +91 -0
  40. package/src/assetlib/importedEntry.js +40 -0
  41. package/src/assetlib/index.js +23 -0
  42. package/src/assetlib/kaykit.js +192 -0
  43. package/src/assetlib/kaykitStaticIndex.js +700 -0
  44. package/src/assetlib/loadImported.js +143 -0
  45. package/src/assetlib/opensource3d.js +113 -0
  46. package/src/assetlib/polyhaven.js +182 -0
  47. package/src/assetlib/polypizza.js +115 -0
  48. package/src/assetlib/smithsonian.js +214 -0
  49. package/src/assetlib/sources.js +279 -0
  50. package/src/assetlib/zip.js +58 -0
  51. package/src/biome/biomeGenerator.js +385 -0
  52. package/src/biome/biomeRuntime.js +299 -0
  53. package/src/biome/index.js +2 -0
  54. package/src/buildinggen/buildingAsset.js +44 -0
  55. package/src/buildinggen/buildingGrammar.js +311 -0
  56. package/src/buildinggen/buildingMesh.js +451 -0
  57. package/src/buildinggen/buildingPresets.js +46 -0
  58. package/src/buildinggen/buildingRecipe.js +100 -0
  59. package/src/buildinggen/buildingSettings.js +238 -0
  60. package/src/buildinggen/index.js +6 -0
  61. package/src/camera/cameraDirector.js +157 -0
  62. package/src/camera/cameraGenerator.js +367 -0
  63. package/src/camera/cameraRig.js +570 -0
  64. package/src/camera/cameraSettings.js +236 -0
  65. package/src/camera/index.js +7 -0
  66. package/src/catalog/builtinEntries.js +245 -0
  67. package/src/catalog/catalog.js +210 -0
  68. package/src/catalog/index.js +3 -0
  69. package/src/catalog/manifest.js +84 -0
  70. package/src/core/generation.js +529 -0
  71. package/src/environment/environmentRigs.js +21 -1
  72. package/src/environment/environmentSettings.js +4 -0
  73. package/src/environment/environmentSunShadowPass.js +8 -0
  74. package/src/fauna/INTEGRATION.md +174 -0
  75. package/src/fauna/boids.js +861 -0
  76. package/src/fauna/faunaBodies.js +492 -0
  77. package/src/fauna/faunaPresets.js +52 -0
  78. package/src/fauna/faunaSettings.js +525 -0
  79. package/src/fauna/index.js +5 -0
  80. package/src/fauna/stylizedFauna.js +395 -0
  81. package/src/game-feel/gameFeelGenerator.js +402 -0
  82. package/src/game-feel/gameFeelRuntime.js +549 -0
  83. package/src/game-feel/index.js +2 -0
  84. package/src/index.js +17 -6
  85. package/src/lighting/colorIntensity.js +177 -0
  86. package/src/lighting/index.js +161 -0
  87. package/src/lighting/lightDescriptors.js +249 -0
  88. package/src/lighting/lightingCapabilities.js +79 -0
  89. package/src/lighting/lightingDocuments.js +247 -0
  90. package/src/lighting/lightingFixtures.js +446 -0
  91. package/src/lighting/lightingGenerator.js +449 -0
  92. package/src/lighting/lightingPresets.js +319 -0
  93. package/src/lighting/lightingRuntime.js +723 -0
  94. package/src/lighting/lightingStyle.js +386 -0
  95. package/src/lighting/lightingSystem.js +774 -0
  96. package/src/lighting/unrealExport.js +186 -0
  97. package/src/lighting/utils.js +87 -0
  98. package/src/motion/index.js +5 -0
  99. package/src/motion/motionClip.js +441 -0
  100. package/src/motion/motionController.js +628 -0
  101. package/src/motion/motionDocuments.js +225 -0
  102. package/src/motion/motionGraph.js +307 -0
  103. package/src/motion/motionSettings.js +222 -0
  104. package/src/pathgen/index.js +7 -0
  105. package/src/pathgen/pathBridge.js +232 -0
  106. package/src/pathgen/pathPresets.js +35 -0
  107. package/src/pathgen/pathRibbon.js +410 -0
  108. package/src/pathgen/pathRouter.js +380 -0
  109. package/src/pathgen/pathSettings.js +335 -0
  110. package/src/pathgen/pathTextures.js +123 -0
  111. package/src/pathgen/stylizedPaths.js +453 -0
  112. package/src/post/index.js +1 -0
  113. package/src/post/postGenerator.js +177 -0
  114. package/src/post/postProcessing.js +41 -0
  115. package/src/propgen/generatorsWave1.js +379 -0
  116. package/src/propgen/generatorsWave2.js +462 -0
  117. package/src/propgen/index.js +5 -0
  118. package/src/propgen/propAsset.js +323 -0
  119. package/src/propgen/propParts.js +170 -0
  120. package/src/propgen/propPlacement.js +459 -0
  121. package/src/propgen/propPresets.js +82 -0
  122. package/src/propgen/propSettings.js +395 -0
  123. package/src/shaders-tsl/chunks/projected-water-caustics.js +242 -0
  124. package/src/shaders-tsl/chunks/vegetation-style.js +360 -0
  125. package/src/shaders-tsl/chunks/water-shore-state.js +31 -0
  126. package/src/shaders-tsl/chunks/water-waves.js +90 -11
  127. package/src/shaders-tsl/environment.js +15 -1
  128. package/src/shaders-tsl/flower.js +279 -30
  129. package/src/shaders-tsl/grass.js +60 -33
  130. package/src/shaders-tsl/sky.js +125 -31
  131. package/src/shaders-tsl/tree-leaf.js +61 -25
  132. package/src/shaders-tsl/water-breaker.js +7 -4
  133. package/src/shaders-tsl/water-shore-state-simulation.js +523 -0
  134. package/src/shaders-tsl/water.js +439 -49
  135. package/src/shaders-tsl/woody-surface.js +154 -0
  136. package/src/sky/sceneOverrideLayers.js +10 -0
  137. package/src/sky/skyQuality.js +26 -0
  138. package/src/sky/stylizedSky.js +753 -45
  139. package/src/soundscape/index.js +4 -0
  140. package/src/soundscape/soundscapeGenerator.js +179 -0
  141. package/src/soundscape/soundscapeRuntime.js +806 -0
  142. package/src/soundscape/soundscapeSettings.js +292 -0
  143. package/src/styles/index.js +13 -0
  144. package/src/styles/styleBundle.js +325 -0
  145. package/src/stylizedTerrain.js +32 -2
  146. package/src/stylizedWorld.js +423 -20
  147. package/src/texgen/evaluateTexture.js +675 -0
  148. package/src/texgen/index.js +60 -0
  149. package/src/texgen/noise2.js +210 -0
  150. package/src/texgen/textureAi.js +436 -0
  151. package/src/texgen/textureGenerators.js +516 -0
  152. package/src/texgen/texturePresets.js +490 -0
  153. package/src/texgen/textureSettings.js +342 -0
  154. package/src/texgen/textureThree.js +59 -0
  155. package/src/vegetation/flowerSpecies.js +15 -3
  156. package/src/vegetation/grassPalettes.js +153 -0
  157. package/src/vegetation/index.js +6 -0
  158. package/src/vegetation/stylizedBush.js +2 -0
  159. package/src/vegetation/stylizedFlower.js +82 -0
  160. package/src/vegetation/stylizedFlowers.js +48 -7
  161. package/src/vegetation/stylizedForest.js +29 -1
  162. package/src/vegetation/stylizedGrass.js +291 -56
  163. package/src/vegetation/stylizedTree.js +38 -2
  164. package/src/vegetation/stylizedTreeFoliage.js +2 -1
  165. package/src/vegetation/vegetationShaders.js +1110 -0
  166. package/src/vfxgen/INTEGRATION.md +145 -0
  167. package/src/vfxgen/core/burstBackbone.js +380 -0
  168. package/src/vfxgen/core/projectileCore.js +92 -0
  169. package/src/vfxgen/core/spriteShapes.js +98 -0
  170. package/src/vfxgen/core/trailRibbon.js +272 -0
  171. package/src/vfxgen/core/vfxRandom.js +29 -0
  172. package/src/vfxgen/effects/emitHelpers.js +37 -0
  173. package/src/vfxgen/effects/magicEffects.js +162 -0
  174. package/src/vfxgen/effects/movementEffects.js +87 -0
  175. package/src/vfxgen/effects/weaponEffects.js +118 -0
  176. package/src/vfxgen/index.js +18 -0
  177. package/src/vfxgen/moves/moveController.js +146 -0
  178. package/src/vfxgen/moves/moveLibrary.js +335 -0
  179. package/src/vfxgen/vfxPresets.js +98 -0
  180. package/src/vfxgen/vfxSettings.js +384 -0
  181. package/src/vfxgen/vfxSystem.js +449 -0
  182. package/src/vfxgen/weapons/stylizedWeapons.js +137 -0
  183. package/src/villagegen/index.js +4 -0
  184. package/src/villagegen/stylizedVillage.js +490 -0
  185. package/src/villagegen/villageArchetypes.js +160 -0
  186. package/src/villagegen/villageNames.js +40 -0
  187. package/src/villagegen/villageSites.js +105 -0
  188. package/src/water/sceneOverrideLayers.js +23 -0
  189. package/src/water/water.js +5 -0
  190. package/src/water/waterBreakerSystem.js +15 -1
  191. package/src/water/waterCurrentField.js +447 -0
  192. package/src/water/waterMaterial.js +12 -0
  193. package/src/water/waterNearshorePhase.js +320 -0
  194. package/src/water/waterScenePasses.js +83 -30
  195. package/src/water/waterSettings.js +325 -13
  196. package/src/water/waterShoreMaterial.js +322 -0
  197. package/src/water/waterShoreStateField.js +605 -0
  198. package/src/water/waterSurface.js +797 -28
  199. package/src/weather/index.js +6 -0
  200. package/src/weather/weatherPrecipitation.js +221 -0
  201. package/src/weather/weatherPresets.js +258 -0
  202. package/src/weather/weatherSettings.js +269 -0
  203. package/src/weather/weatherSystem.js +871 -0
  204. package/src/worldMinimap.js +62 -0
  205. package/src/worldPresets.js +4 -1
@@ -0,0 +1,275 @@
1
+ # Vegetation
2
+
3
+ Procedural stylized vegetation from
4
+ `@call-me-sensei/toonlab/vegetation`. Geometry and shading are generated;
5
+ animation runs in the vertex shaders. The runtime sky now has its own
6
+ [Sky system](sky.md) guide.
7
+
8
+ Vegetation materials use the shared TSL renderer stack: native
9
+ WebGPU by default, with `?renderer=webgl` for the WebGL2 fallback.
10
+
11
+ Geometry systems follow the same settings pattern as the rest of the library:
12
+ a `DEFAULT_*` settings object, a `create*Settings(options)` normalizer,
13
+ `*_SETTING_GROUPS` + `*_SETTING_FIELD_SCHEMA` for UIs, and a runtime
14
+ `applySettings(options)` method on the class. The IP-wide shading treatment
15
+ is a separate `VegetationShaderProfile`; it must not absorb asset identity or
16
+ the scene's current state.
17
+
18
+ Each system also has a preset registry (`register*Preset` /
19
+ `get*PresetOptions`, resolved via `preset:` in `create*Settings` and the
20
+ constructors): `default` is the baseline and `call_me_sensei` is the
21
+ studio-managed signature look, curated and updated over releases —
22
+ community presets register alongside them. For placing vegetation across
23
+ terrain (forests, meadows, slope/water masks), see the scatter helpers in
24
+ [world-scale.md](world-scale.md#distribution-helpers).
25
+
26
+ ## One vegetation shader profile
27
+
28
+ Use one versioned `VegetationShaderProfile` for an IP, not unrelated grass,
29
+ tree, and flower shader copies. The profile is dispatched by semantic material
30
+ role (`grassBlade`, `foliageCard`, `flowerPetal`, `flowerCenter`,
31
+ `woodySurface`, `herbaceousStem`), while mesh/cutout/billboard/procedural are
32
+ only technical variants. This gives specialized controls without losing one
33
+ coherent art direction.
34
+
35
+ | Scope | Owns | Does not own |
36
+ |---|---|---|
37
+ | Vegetation shader profile | shared light treatment, thin-surface response, weather response curves, and role-specific grass/foliage/flower/bark/stem shading | albedo, textures, species, geometry, current weather |
38
+ | Asset/material | purple/green/autumn albedo, texture maps, alpha cutoff, species palette | the IP's shared lighting rules |
39
+ | Scene/world | current sun/sky, cloud field, wind, wetness, snow coverage | persistent shader response coefficients |
40
+ | Instance/interaction | placement, seed, scale, bend target, local retention/response multipliers | the reusable shader definition |
41
+
42
+ The same profile therefore works unchanged for purple grass or ten differently
43
+ colored grass assets. Color remains material data; the shader defines how that
44
+ color responds to the world.
45
+
46
+ ```js
47
+ import {
48
+ StylizedGrassField,
49
+ createVegetationShaderSettings,
50
+ } from '@call-me-sensei/toonlab/vegetation';
51
+
52
+ const vegetationShader = createVegetationShaderSettings({
53
+ preset: 'call_me_sensei',
54
+ grass: { bandSoftness: 0.08 },
55
+ bark: { bandCount: 3 },
56
+ });
57
+
58
+ const purpleGrass = new StylizedGrassField({
59
+ baseColor: [0.28, 0.12, 0.48],
60
+ tipColor: [0.76, 0.38, 0.96],
61
+ placements,
62
+ vegetationShader,
63
+ });
64
+
65
+ // Host-owned current state; neither value changes the saved profile.
66
+ purpleGrass.setWind({ strength: currentWind });
67
+ purpleGrass.setSurfaceWeather({ wetness: currentWetness, snowCover: currentSnow });
68
+ ```
69
+
70
+ Vegetation Shader Lab exports the same versioned profile document consumed by
71
+ the npm runtime:
72
+
73
+ ```js
74
+ import {
75
+ createVegetationShaderPresetDocument,
76
+ parseVegetationShaderPresetDocument,
77
+ registerSerializedVegetationShaderPreset,
78
+ serializeVegetationShaderPreset,
79
+ } from '@call-me-sensei/toonlab/vegetation-shaders';
80
+
81
+ const document = createVegetationShaderPresetDocument('violet_world', {
82
+ label: 'Violet World',
83
+ settings: vegetationShader,
84
+ });
85
+ const json = serializeVegetationShaderPreset(document);
86
+ const parsed = parseVegetationShaderPresetDocument(json);
87
+ if (parsed.ok) registerSerializedVegetationShaderPreset(json, { overwrite: true });
88
+ ```
89
+
90
+ Portable documents use `toonlab/vegetation-shader-preset`.
91
+ `getVegetationShaderPresetOptions()` lists built-in and project-registered
92
+ profiles; `validateVegetationShaderPresetDocument()` validates an already
93
+ parsed object. The focused `vegetation-shaders` subpath and the main
94
+ `vegetation` barrel expose the same bindings.
95
+
96
+ `applyVegetationShader(root, profile)` updates only materials tagged with the
97
+ semantic contract and returns coverage/unsupported-uniform diagnostics.
98
+ `createStylizedWorld({ vegetationShader })` passes the profile into trees,
99
+ grass, and flowers. `world.setVegetationShader(profile)` updates live near
100
+ materials; a texture-baked far forest reports that its impostors require a
101
+ rebuild.
102
+
103
+ The labs intentionally split by responsibility:
104
+
105
+ - Grass Lab authors grass geometry, palette, planting, and grass material data.
106
+ - Tree Lab authors trees/bushes and blossoms attached to their canopies.
107
+ - Flower Lab authors standalone flower plants and fields.
108
+ - Vegetation Shader Lab authors the one cross-asset IP shader profile,
109
+ including bark/trunk and herbaceous stems.
110
+
111
+ ## Construction-time vs. runtime settings
112
+
113
+ Each class takes asset/construction settings and an optional
114
+ `vegetationShader` in the constructor. `applySettings()` remains the
115
+ compatibility path for system-specific material and construction settings;
116
+ `setVegetationShader()` applies the IP treatment, while `setWind()`,
117
+ `setSun()`, `setCloudShadow()`, and `setSurfaceWeather()` carry current world
118
+ state. Geometry-shaping settings remain construction-only.
119
+
120
+ In a composed world, `world.setSun({ direction, color, sky })` is the single
121
+ scene-light adapter. It forwards the same transient values to Grass, Flowers,
122
+ near Forest variants, Ambient FX direction, the physical directional light,
123
+ and shadow-follow logic without mutating any portable vegetation preset.
124
+ `lighting.attachWorld(world)` drives that adapter; standalone Weather uses the
125
+ same adapter and restores its captured baseline on disposal.
126
+
127
+ | Class | Live after construction | Construction-only |
128
+ |---|---|---|
129
+ | `StylizedGrassField` | asset palette through `applySettings`; current wind/sun/scene/cloud/weather through setters; IP look through `setVegetationShader` | `placements`, `bladeHeightRange`, `bladeWidthRange` (baked into instance attributes) |
130
+ | `StylizedFlowerField` | asset colors through `applySettings`; current wind/sun/cloud/weather through setters; IP look through `setVegetationShader` | placements, flower geometry |
131
+ | `StylizedTree` | current wind/sun/cloud/weather through setters; IP look through `setVegetationShader`; canopy palette re-derivation through `applySettings` | `size`, `seed`, `canopyWidth/Depth/Scale/Layout`, `leafDensity`, `leafPlacement`, trunk/skeleton topology |
132
+
133
+ ## Grass
134
+
135
+ ```js
136
+ import { StylizedGrassField } from '@call-me-sensei/toonlab/vegetation';
137
+
138
+ const grass = new StylizedGrassField({
139
+ placements: points.map((p) => ({ x: p.x, y: terrainHeight(p), z: p.z })),
140
+ windResponse: 1.35, // species flexibility relative to the current world wind
141
+ gustResponse: 0.8,
142
+ });
143
+ scene.add(grass);
144
+ grass.setPushTarget(characterObject3D); // blades bend away from the character
145
+ grass.setPushRadius(0.9); // current scene/instance interaction field
146
+ grass.setWind({ direction: [1, 0.3], speed: 1, strength: 0.25 });
147
+ grass.setCloudShadow({ strength: 0.5, coverage: 0.45 });
148
+
149
+ // per frame:
150
+ grass.update(delta);
151
+
152
+ // live asset re-tune (flat settings, see DEFAULT_GRASS_SETTINGS):
153
+ grass.applySettings({ windResponse: 1.6, gustResponse: 0.65 });
154
+ ```
155
+
156
+ One draw call for the whole field. Convenience setters mirror common groups:
157
+ `setWind`, `setSun`, `setSceneShadow({ strength, tint })` (blades darken
158
+ under tree/character shadow maps), `setCloudShadow`, `setDistanceFade({
159
+ start, end })` (collapse blades the fog has swallowed), `setPushTarget`, and
160
+ `setPushRadius`.
161
+ Backlit translucency (`backlitStrength`) gives tips a warm glow against the
162
+ sun.
163
+
164
+ Portable grass presets separate asset response from current world state.
165
+ `windResponse` and `gustResponse` belong to the species/asset; wind direction,
166
+ speed, strength, gust field, cloud-shadow field, sun/sky, push target, and push
167
+ radius belong to the active scene or instance. Constructor options and
168
+ `applySettings()` still accept those legacy runtime keys for compatibility,
169
+ but portable preset schema v2 does not serialize them. When a v1 preset is
170
+ loaded, its authored `windStrength` becomes `windResponse` relative to the
171
+ historical `0.16` default.
172
+
173
+ Grass Lab includes coordinated color palettes. A palette is asset/material
174
+ data, not a new shader: it updates `baseColor`, `tipColor`, and `shadowTint`
175
+ as one set so purple, autumn, dry, and fantasy grass retain an authored shadow
176
+ color. It does not change `shadowStrength`, asset motion response, current
177
+ weather, or the IP-wide `VegetationShaderProfile`.
178
+
179
+ ```js
180
+ import {
181
+ applyGrassColorPalette,
182
+ createGrassSettings,
183
+ serializeGrassPreset,
184
+ } from '@call-me-sensei/toonlab/vegetation';
185
+
186
+ const settings = createGrassSettings(
187
+ applyGrassColorPalette(currentSettings, 'wisteria'),
188
+ );
189
+ const json = serializeGrassPreset('violet_meadow', {
190
+ label: 'Violet Meadow',
191
+ settings,
192
+ });
193
+ ```
194
+
195
+ `GRASS_COLOR_PALETTES`, `resolveGrassColorPalette`, and
196
+ `matchGrassColorPalette` support custom UIs. Portable Grass Lab documents use
197
+ `toonlab/grass-preset`; the public API mirrors the other systems with
198
+ `createGrassPresetDocument`, `validateGrassPresetDocument`,
199
+ `parseGrassPresetDocument`, and `registerSerializedGrassPreset`. These
200
+ documents currently use schema version 2.
201
+
202
+ ## Flowers
203
+
204
+ ```js
205
+ import { StylizedFlowerField } from '@call-me-sensei/toonlab/vegetation';
206
+
207
+ const flowers = new StylizedFlowerField({ placements });
208
+ scene.add(flowers);
209
+ flowers.update(delta);
210
+ flowers.applySettings({ windStrength: 0.2 });
211
+ ```
212
+
213
+ Instanced flowers that receive scene shadows like the grass. Settings:
214
+ `DEFAULT_FLOWER_SETTINGS` / `createFlowerSettings` /
215
+ `FLOWER_SETTING_GROUPS` / `FLOWER_SETTING_FIELD_SCHEMA`.
216
+
217
+ ## Trees
218
+
219
+ ```js
220
+ import { StylizedTree, layoutTreeRow, TREE_TRUNK_STYLES } from '@call-me-sensei/toonlab/vegetation';
221
+
222
+ const tree = new StylizedTree({
223
+ size: 2, // 1 ≈ 3 m tree
224
+ seed: 7, // deterministic per-seed variation
225
+ canopyColor: { from: 0x4f8f3a, to: 0x77b34e }, // color spec: one color, list, blend, or HSL ranges
226
+ leafDensity: 0.95,
227
+ leafPlacement: 'canopy', // or 'tips' for bare-limbed silhouettes
228
+ });
229
+ scene.add(tree);
230
+ tree.update(delta);
231
+
232
+ tree.applySettings({ foliage: { windStrength: 0.4 } }); // grouped settings
233
+ tree.setCloudShadow({ strength: 0.45 });
234
+ ```
235
+
236
+ Curved trunk (`createTreeTrunkGeometry`, `TREE_TRUNK_STYLES`) + leaf-card
237
+ canopy (`stylizedTreeFoliage.js`) in one `THREE.Group`. Settings are grouped
238
+ (`DEFAULT_STYLIZED_TREE_SETTINGS`, `STYLIZED_TREE_SETTING_GROUPS`, 58
239
+ fields). `STYLIZED_TREE_EXAMPLES` + `layoutTreeRow` power the Tree Lab
240
+ (`/tree-lab/`), whose authoring scope is trees, bushes, and optional blossoms
241
+ attached to a tree canopy.
242
+
243
+ Trees are serializable: `treeRecipe.js` defines a versioned recipe document
244
+ (`recipeFromSettings` / `settingsFromRecipe` /
245
+ `validateTreeRecipeDocument` / `createPlantFromRecipe`), and
246
+ `treeExport.js` bakes a tree into plain exportable meshes
247
+ (`prepareTreeForExport`, crossed-card or baked foliage) for use outside the
248
+ library shaders. `StylizedBush` reuses the foliage system as a standalone
249
+ bush. `StylizedFlower` uses the same versioned plant recipe contract while
250
+ the Flower Lab (`/flower-lab/`) gives standalone flowers their own document
251
+ storage, preset gallery, and bloom-focused workflow.
252
+
253
+ ## Sky
254
+
255
+ Sky settings, portable preset documents, runtime ownership, and Sky Lab are
256
+ documented in [Sky system](sky.md). Sky and vegetation share current sun,
257
+ cloud-shadow, and weather inputs, but neither saved artifact owns that scene
258
+ state.
259
+
260
+ ## Shared atmosphere hooks
261
+
262
+ The outdoor systems share one procedural cloud-shadow field and the
263
+ renderer's shadow maps, so a cloud or a character shades terrain, grass,
264
+ flowers, canopies, and water together:
265
+
266
+ ```js
267
+ grass.setCloudShadow({ strength: 0.5, coverage: 0.45, scale: 0.012 });
268
+ tree.setCloudShadow({ strength: 0.5 });
269
+ water.setCloudShadow({ strength: 0.5 });
270
+ setEnvironmentCloudShadow({ strength: 0.5 }); // toonlab/environment
271
+ ```
272
+
273
+ All of these are also plain settings fields (`cloudShadowStrength`,
274
+ `cloudShadowCoverage`, `cloudShadowScale`, `cloudShadowVelocity`) on each
275
+ system.