@woosh/meep-engine 3.60.4 → 3.60.6

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 (419) hide show
  1. package/CHANGELOG.md +2621 -0
  2. package/CONTRIBUTING.md +7 -0
  3. package/MIGRATION_2_TO_3.md +136 -0
  4. package/SECURITY.md +4 -0
  5. package/editor/EditorCameraNavigation.d.ts +2 -1
  6. package/editor/EditorCameraNavigation.d.ts.map +1 -1
  7. package/editor/EditorCameraNavigation.js +51 -57
  8. package/package.json +6 -2
  9. package/src/engine/EngineHarness.d.ts +3 -9
  10. package/src/engine/EngineHarness.d.ts.map +1 -1
  11. package/src/engine/EngineHarness.js +6 -8
  12. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts +9 -6
  13. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts.map +1 -1
  14. package/src/engine/graphics/camera/makeOrbitalCameraController.js +44 -71
  15. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts +64 -0
  16. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts.map +1 -0
  17. package/src/engine/graphics/camera/orbital/MomentumAxis.js +187 -0
  18. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts +86 -0
  19. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts.map +1 -0
  20. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.js +319 -0
  21. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts +34 -10
  22. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts.map +1 -1
  23. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +116 -30
  24. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts +1 -7
  25. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
  26. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +1 -37
  27. package/src/engine/graphics/ecs/water/Water.d.ts +8 -0
  28. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  29. package/src/engine/graphics/ecs/water/Water.js +8 -0
  30. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  31. package/src/engine/graphics3/WaterSystem.js +731 -734
  32. package/src/engine/graphics3/decal/DecalTileShader.d.ts +61 -0
  33. package/src/engine/graphics3/decal/DecalTileShader.d.ts.map +1 -0
  34. package/src/engine/graphics3/decal/DecalTileShader.js +138 -0
  35. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts +10 -4
  36. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts.map +1 -1
  37. package/src/engine/graphics3/decal/GPUDecalRenderer.js +149 -44
  38. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts +25 -0
  39. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts.map +1 -0
  40. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.js +55 -0
  41. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts +22 -0
  42. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts.map +1 -0
  43. package/src/engine/graphics3/decal/graph_gather_decal_tiles.js +70 -0
  44. package/src/engine/graphics3/decal/shader_decal_composite.d.ts +7 -5
  45. package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
  46. package/src/engine/graphics3/decal/shader_decal_composite.js +48 -44
  47. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts +12 -0
  48. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts.map +1 -0
  49. package/src/engine/graphics3/decal/shader_decal_tile_copy.js +78 -0
  50. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts +11 -0
  51. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts.map +1 -0
  52. package/src/engine/graphics3/decal/shader_gather_decal_tiles.js +80 -0
  53. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts +13 -0
  54. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts.map +1 -0
  55. package/src/engine/input/devices/mouse/MouseEventButtons.js +23 -0
  56. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts +4 -0
  57. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts.map +1 -1
  58. package/src/engine/input/ecs/controllers/KeyboardCameraController.js +9 -45
  59. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  60. package/src/shade/playground/water_refraction/README.md +5 -6
  61. package/src/shade/playground/water_refraction/index.html +1 -1
  62. package/src/shade/renderer/Renderer.d.ts +11 -0
  63. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  64. package/src/shade/renderer/Renderer.js +50 -6
  65. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts +40 -80
  66. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts.map +1 -1
  67. package/src/shade/renderer/camera/orbital/OrbitalCameraController.js +197 -147
  68. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  69. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  70. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  71. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  72. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  73. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +28 -45
  74. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  75. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +111 -119
  76. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +22 -3
  77. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
  78. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +84 -3
  79. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts +19 -0
  80. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts.map +1 -0
  81. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.js +25 -0
  82. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts +31 -0
  83. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts.map +1 -0
  84. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.js +343 -0
  85. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +15 -0
  86. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -1
  87. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +38 -0
  88. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts +17 -0
  89. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts.map +1 -0
  90. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.js +29 -0
  91. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -1
  92. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +7 -13
  93. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts +28 -59
  94. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts.map +1 -1
  95. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.js +84 -789
  96. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  97. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +1 -8
  98. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +7 -6
  99. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
  100. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +12 -11
  101. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts +2 -2
  102. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.js +2 -2
  103. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +1 -4
  104. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  105. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +1 -10
  106. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +5 -15
  107. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +1 -1
  108. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +6 -34
  109. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  110. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -7
  111. package/src/shade/renderer/hiz/HZBFootprint.d.ts +14 -0
  112. package/src/shade/renderer/hiz/HZBFootprint.d.ts.map +1 -0
  113. package/src/shade/renderer/hiz/HZBFootprint.js +16 -0
  114. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts +10 -0
  115. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts.map +1 -0
  116. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.js +11 -0
  117. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts +10 -0
  118. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts.map +1 -0
  119. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.js +11 -0
  120. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +0 -7
  121. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  122. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +405 -350
  123. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts +12 -0
  124. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts.map +1 -0
  125. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.js +27 -0
  126. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts +12 -0
  127. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts.map +1 -0
  128. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.js +27 -0
  129. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts +14 -0
  130. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts.map +1 -0
  131. package/src/shade/renderer/hiz/hzb_footprint_texels.js +34 -0
  132. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +0 -5
  133. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
  134. package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +37 -57
  135. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts +11 -0
  136. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts.map +1 -0
  137. package/src/shade/renderer/hiz/{shader_hzb_reduce_mip0_clip.js → shader_hzb_reduce_mip0.js} +120 -111
  138. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  139. package/src/shade/renderer/material/GPUMaterialManager.d.ts +11 -1
  140. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  141. package/src/shade/renderer/material/GPUMaterialManager.js +16 -8
  142. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +12 -12
  143. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  144. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +17 -118
  145. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts +7 -3
  146. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
  147. package/src/shade/renderer/postprocess/gtao/GTAO.js +26 -13
  148. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts +14 -0
  149. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  150. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +196 -68
  151. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
  152. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +42 -28
  153. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
  154. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +429 -414
  155. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts +16 -0
  156. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts.map +1 -0
  157. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.js +156 -0
  158. package/src/shade/renderer/scene/GPUSceneContext.d.ts +2 -2
  159. package/src/shade/renderer/scene/GPUSceneContext.js +5 -5
  160. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  161. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +7 -2
  162. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +0 -6
  163. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  164. package/src/shade/renderer/water/GPUWaterRenderer.js +12 -17
  165. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts +35 -0
  166. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts.map +1 -0
  167. package/src/shade/renderer/water/medium/graph_water_meshlets.js +89 -0
  168. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  169. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  170. package/src/shade/renderer/water/shader_water.js +22 -13
  171. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
  172. package/src/shade/renderer/water/shader_water_avboit.js +7 -7
  173. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +1 -1
  174. package/src/shade/renderer/water/surface/graph_water_tessellation.js +1 -1
  175. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +9 -1
  176. package/editor/REWORK_PLAN_2026_08.md +0 -692
  177. package/src/CODEC_LAYOUT_VERIFICATION.md +0 -419
  178. package/src/CORRECTNESS_HUNT_2026_07_24.md +0 -142
  179. package/src/DUPLICATION_AUDIT_2026_08_07/00_core_reuse_surface.md +0 -738
  180. package/src/DUPLICATION_AUDIT_2026_08_07/A_core_math_geom.md +0 -79
  181. package/src/DUPLICATION_AUDIT_2026_08_07/B_core_data.md +0 -93
  182. package/src/DUPLICATION_AUDIT_2026_08_07/C_gfx_render.md +0 -80
  183. package/src/DUPLICATION_AUDIT_2026_08_07/D_gfx_features.md +0 -164
  184. package/src/DUPLICATION_AUDIT_2026_08_07/E_physics.md +0 -69
  185. package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +0 -110
  186. package/src/DUPLICATION_AUDIT_2026_08_07/G_net_save.md +0 -129
  187. package/src/DUPLICATION_AUDIT_2026_08_07/H_engine_misc.md +0 -72
  188. package/src/DUPLICATION_AUDIT_2026_08_07/I_generation_view.md +0 -74
  189. package/src/DUPLICATION_AUDIT_2026_08_07/K_crosscutting.md +0 -169
  190. package/src/DUPLICATION_AUDIT_2026_08_07.md +0 -254
  191. package/src/DUPLICATION_AUDIT_REMEDIATION.md +0 -250
  192. package/src/DUPLICATION_REVIEW_2026_10_24.md +0 -1072
  193. package/src/REVIEW_2026_08_06/adv-core.md +0 -511
  194. package/src/REVIEW_2026_08_06/adv-gfx.md +0 -480
  195. package/src/REVIEW_2026_08_06/adv-view.md +0 -446
  196. package/src/REVIEW_2026_08_06/api-core.md +0 -296
  197. package/src/REVIEW_2026_08_06/api-engine.md +0 -195
  198. package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +0 -507
  199. package/src/REVIEW_2026_08_06/core-binary.md +0 -348
  200. package/src/REVIEW_2026_08_06/core-collection.md +0 -376
  201. package/src/REVIEW_2026_08_06/core-math.md +0 -221
  202. package/src/REVIEW_2026_08_06/core-process.md +0 -266
  203. package/src/REVIEW_2026_08_06/core-science.md +0 -223
  204. package/src/REVIEW_2026_08_06/engine-ai-nav.md +0 -279
  205. package/src/REVIEW_2026_08_06/engine-animation.md +0 -167
  206. package/src/REVIEW_2026_08_06/engine-asset.md +0 -166
  207. package/src/REVIEW_2026_08_06/engine-ecs.md +0 -920
  208. package/src/REVIEW_2026_08_06/engine-input.md +0 -197
  209. package/src/REVIEW_2026_08_06/engine-misc.md +0 -248
  210. package/src/REVIEW_2026_08_06/engine-terrain.md +0 -52
  211. package/src/REVIEW_2026_08_06/generation.md +0 -176
  212. package/src/REVIEW_2026_08_06/geom-2d.md +0 -434
  213. package/src/REVIEW_2026_08_06/geom-3d.md +0 -117
  214. package/src/REVIEW_2026_08_06/gfx-gi.md +0 -143
  215. package/src/REVIEW_2026_08_06/gfx-render.md +0 -740
  216. package/src/REVIEW_2026_08_06/gfx-texture.md +0 -690
  217. package/src/REVIEW_2026_08_06/prior-criticals.md +0 -49
  218. package/src/REVIEW_2026_08_06/prior-highs.md +0 -138
  219. package/src/REVIEW_2026_08_06/test-gaps.md +0 -364
  220. package/src/REVIEW_2026_08_06/view.md +0 -667
  221. package/src/REVIEW_2026_08_06.md +0 -610
  222. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +0 -542
  223. package/src/core/bvh2/bvh3/NOTES.md +0 -2
  224. package/src/core/bvh8/NOTES.md +0 -63
  225. package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +0 -243
  226. package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +0 -417
  227. package/src/core/color/COLOR_REVIEW_2026_08_28.md +0 -779
  228. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +0 -433
  229. package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +0 -486
  230. package/src/core/geom/3d/atlas/BFF_PLAN.md +0 -174
  231. package/src/core/geom/3d/atlas/REVIEW_02.md +0 -392
  232. package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +0 -146
  233. package/src/core/geom/3d/gjk/NOTES.md +0 -8
  234. package/src/core/geom/3d/topology/TOPO_MESH_RETIREMENT_PLAN.md +0 -135
  235. package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +0 -381
  236. package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +0 -684
  237. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +0 -554
  238. package/src/core/model/reactive/evaluation/PREDICATE_APPLICABILITY_PROPOSAL.md +0 -446
  239. package/src/engine/REVIEW_2026_07_03.md +0 -211
  240. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +0 -815
  241. package/src/engine/control/first-person/DESIGN.md +0 -658
  242. package/src/engine/control/first-person/DESIGN_COLLISION.md +0 -382
  243. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +0 -563
  244. package/src/engine/control/first-person/TODO.md +0 -160
  245. package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +0 -531
  246. package/src/engine/ecs/HIERARCHY_REVIEW.md +0 -717
  247. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +0 -262
  248. package/src/engine/ecs/ik/PLAN.md +0 -179
  249. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +0 -272
  250. package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +0 -199
  251. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +0 -521
  252. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +0 -463
  253. package/src/engine/graphics/ecs/camera/pp/NOTES.md +0 -48
  254. package/src/engine/graphics/render/frame_graph/CORRECTNESS_FIXES_2026_09_04.md +0 -659
  255. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +0 -235
  256. package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +0 -490
  257. package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +0 -466
  258. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +0 -717
  259. package/src/engine/input/ecs/ism/ISM_DESIGN.md +0 -1523
  260. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +0 -627
  261. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +0 -661
  262. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +0 -229
  263. package/src/engine/network/CONGESTION_CONTROL.md +0 -87
  264. package/src/engine/network/MESSAGE_TRANSPORT.md +0 -364
  265. package/src/engine/network/SMOOTHNESS_DESIGN.md +0 -400
  266. package/src/engine/physics/cloth/MEASUREMENTS.md +0 -5304
  267. package/src/engine/physics/cloth/PLAN.md +0 -3056
  268. package/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md +0 -1382
  269. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +0 -243
  270. package/src/engine/physics/fluid/solver/NOTES.md +0 -46
  271. package/src/engine/sound/SOUND_EMITTER_RETIREMENT_PLAN.md +0 -536
  272. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +0 -432
  273. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +0 -250
  274. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +0 -322
  275. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +0 -261
  276. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +0 -121
  277. package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +0 -999
  278. package/src/format/image/avif/DECISIONS.md +0 -545
  279. package/src/format/image/jpeg/NOTES.md +0 -3
  280. package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +0 -814
  281. package/src/generation/COORDINATES.md +0 -54
  282. package/src/generation/REVIEW_01_ACTION_PLAN.md +0 -628
  283. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +0 -220
  284. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +0 -172
  285. package/src/generation/foliage/CROWN_FULLNESS_BRIEF_2026_10_26.md +0 -86
  286. package/src/generation/foliage/FOLIAGE_DESIGN.md +0 -547
  287. package/src/generation/foliage/FOLIAGE_PLAN.md +0 -198
  288. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +0 -158
  289. package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +0 -521
  290. package/src/generation/foliage/REAL_TIME_TREES_BRIEF_2026_10_27.md +0 -86
  291. package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +0 -347
  292. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +0 -248
  293. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +0 -694
  294. package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +0 -552
  295. package/src/shade/RENDERER_CONTRACT.md +0 -697
  296. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +0 -263
  297. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +0 -569
  298. package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +0 -755
  299. package/src/shade/device/mock/EXTENSION_PROPOSAL_2026_08_22.md +0 -458
  300. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +0 -255
  301. package/src/shade/device/mock/REVIEW_2026_08_22.md +0 -527
  302. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +0 -894
  303. package/src/shade/device/timing/profile/SGPT_FORMAT.md +0 -345
  304. package/src/shade/renderer/NOTES.md +0 -78
  305. package/src/shade/renderer/PLAN.md +0 -8
  306. package/src/shade/renderer/animation/ADDITIVE_BLENDING_PLAN.md +0 -145
  307. package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +0 -357
  308. package/src/shade/renderer/atmosphere/NOTES.md +0 -6
  309. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts +0 -76
  310. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts.map +0 -1
  311. package/src/shade/renderer/camera/orbital/MomentumAxis.js +0 -164
  312. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts +0 -45
  313. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts.map +0 -1
  314. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.js +0 -66
  315. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +0 -98
  316. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +0 -1
  317. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +0 -184
  318. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +0 -175
  319. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +0 -1
  320. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +0 -411
  321. package/src/shade/renderer/camera/orbital/README.md +0 -81
  322. package/src/shade/renderer/camera/orbital/index.d.ts +0 -6
  323. package/src/shade/renderer/camera/orbital/index.d.ts.map +0 -1
  324. package/src/shade/renderer/camera/orbital/index.js +0 -9
  325. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +0 -964
  326. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +0 -361
  327. package/src/shade/renderer/geometry/bvh/BLAS_REFIT_BATCH_PLAN.md +0 -619
  328. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +0 -674
  329. package/src/shade/renderer/geometry/sdf/NOTES.md +0 -6
  330. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +0 -540
  331. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +0 -305
  332. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +0 -913
  333. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +0 -787
  334. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +0 -481
  335. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +0 -301
  336. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +0 -448
  337. package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +0 -385
  338. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +0 -656
  339. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +0 -308
  340. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +0 -657
  341. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +0 -551
  342. package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +0 -529
  343. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts +0 -47
  344. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts.map +0 -1
  345. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.js +0 -80
  346. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts +0 -16
  347. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts.map +0 -1
  348. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.js +0 -67
  349. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts +0 -17
  350. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts.map +0 -1
  351. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.js +0 -145
  352. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts +0 -12
  353. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts.map +0 -1
  354. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.js +0 -105
  355. package/src/shade/renderer/global_illumination/lpv/NOTES.md +0 -3
  356. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +0 -4306
  357. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +0 -410
  358. package/src/shade/renderer/global_illumination/sharc/NOTES.md +0 -8
  359. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +0 -1369
  360. package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +0 -202
  361. package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +0 -94
  362. package/src/shade/renderer/hiz/NOTES.md +0 -3
  363. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +0 -8
  364. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +0 -1
  365. package/src/shade/renderer/light/cluster/NOTES.md +0 -11
  366. package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +0 -524
  367. package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +0 -1101
  368. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts +0 -24
  369. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts.map +0 -1
  370. package/src/shade/renderer/material/resident/shader_resident_texture_means.js +0 -120
  371. package/src/shade/renderer/particles/DESIGN.md +0 -1011
  372. package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +0 -280
  373. package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +0 -453
  374. package/src/shade/renderer/path_tracer/PATH_TRACED_MEDIA_PLAN_2026_10_02.md +0 -520
  375. package/src/shade/renderer/postprocess/bloom/NOTES.md +0 -6
  376. package/src/shade/renderer/postprocess/fsr/NOTES.md +0 -4
  377. package/src/shade/renderer/postprocess/gtao/NOTES.md +0 -6
  378. package/src/shade/renderer/postprocess/nss/NOTES.md +0 -332
  379. package/src/shade/renderer/postprocess/perspective/NOTES.md +0 -3
  380. package/src/shade/renderer/postprocess/sscs/NOTES.md +0 -5
  381. package/src/shade/renderer/postprocess/ssr/NOTES.md +0 -14
  382. package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +0 -286
  383. package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +0 -39
  384. package/src/shade/renderer/postprocess/taa/NOTES.md +0 -11
  385. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +0 -78
  386. package/src/shade/renderer/postprocess/vrs/NOTES.md +0 -4
  387. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +0 -1218
  388. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +0 -600
  389. package/src/shade/renderer/restir/reservoir/NOTES.md +0 -6
  390. package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +0 -6
  391. package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +0 -391
  392. package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +0 -153
  393. package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +0 -322
  394. package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +0 -247
  395. package/src/shade/renderer/shader/chunk/fsr/NOTES.md +0 -3
  396. package/src/shade/renderer/shader/chunk/fsr/spd/NOTES.md +0 -4
  397. package/src/shade/renderer/shader/chunk/geometry/ray/NOTES.md +0 -4
  398. package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +0 -159
  399. package/src/shade/renderer/shader/chunk/mboit/NOTES.md +0 -38
  400. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/NOTES.md +0 -3
  401. package/src/shade/renderer/shader/chunk/spherical_harmonics/sampling/NOTES.md +0 -8
  402. package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +0 -927
  403. package/src/shade/renderer/shadow/contact/FINDINGS.md +0 -413
  404. package/src/shade/renderer/shadow/map/csm/NOTES.md +0 -5
  405. package/src/shade/renderer/shadow/ray/NOTES.md +0 -31
  406. package/src/shade/renderer/shadow/sdf/NOTES.md +0 -9
  407. package/src/shade/renderer/shadow/sdf/brixelizer/NOTES.md +0 -5
  408. package/src/shade/renderer/shadow/sdf/cascade/NOTES.md +0 -9
  409. package/src/shade/renderer/shadow/vsm/NOTES.md +0 -12
  410. package/src/shade/renderer/shadow/vsm/PLAN.md +0 -442
  411. package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +0 -43
  412. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +0 -2444
  413. package/src/shade/renderer/texture/mipmaps/NOTES.md +0 -3
  414. package/src/shade/renderer/volumetrics/NOTES.md +0 -1329
  415. package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +0 -336
  416. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +0 -23
  417. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +0 -1
  418. package/src/shade/renderer/water/medium/GPUWaterBodies.js +0 -75
  419. package/src/shade/wgsl/NOTES.md +0 -4
@@ -1,694 +0,0 @@
1
- # Deep-Dive Technical Review: `meep` Foliage Generator vs. SpeedTree (v4–v10)
2
-
3
- ## 0. Status on `master` (2026-10-24)
4
-
5
- This review was written against `0dfdc29b2`. These commits have landed since.
6
-
7
- **Generator graph** (closes Item 1, and parts of Items 6 and 11):
8
- - `00807d697`: generator graph, surface roots and stubs, beam-mechanics wind joints.
9
- - `2f4465170`: dead stubs and bark knots grow from self-pruning.
10
- - `28ef51f1b`: dead stubs are shaped as their branch's base, and knots come from collars.
11
-
12
- **Tier 1, points 1–3 of §5** (closes Item 10, most of Items 3, 7 and 8):
13
- - `d415a0143`: cutout hulls fitted to the atlas, and card density derived from the shoot (Item 8).
14
- - `e72ebe14a`: plagiotropic shoots, ventral knockout and straightness (Items 3 and 7).
15
- - `f47a0516f`: leaf drop and wilt from senescence, and colour headroom for card tints (Item 10).
16
- - `f8fc614c6`: `TreeWindConfig.elastic_modulus` refitted to the new leaf sail (Item 11).
17
-
18
- **Fixes from an adversarial review of Tier 1:**
19
- - `0d7671493`: knockout holds emitted headings, and a split re-aims straightness.
20
- - `774c31a5e`: the hull's last resort holds the leaf, AO is byte-identical to before, and cards and sail share one
21
- leafy span.
22
- - `82bfadfb9`: leaves fall and dry on their own tile's pigment schedule.
23
- - `06bbbfdd5`: specs that fail when their feature is switched off.
24
-
25
- **Plagiotropism by architectural model:**
26
- - `ae56c8751`: set from each species' architectural model (Hallé, Oldeman & Tomlinson), as listed by Pfisterer
27
- (2000) and Millet, Bouchard & Édelin (1999). Spruce (Massart's model) keeps it; pine and maple (Rauh's model) lose
28
- the 0.7 the Tier 1 work had given them.
29
- - `4044ce08c`: those sources are cited in the code.
30
-
31
- The docs were brought up to date in `3bdd51a7b` and `4e142f879`.
32
-
33
- Each item below describes the current code. Its "Landed" section says where the result differs from the proposal.
34
-
35
- | Item | Status | What landed |
36
- | :--- | :--- | :--- |
37
- | **1. Branch roles & parent targeting** | **Done** | A generator graph (`branches` + `branch_rules` + `foliage_rules`) instead of the proposed `parent_level` / `role` fields. Roots, inter-whorl branches and epicormic sprouts are ordinary rules. Dead stubs and knots come from self-pruning, not from an authored role. |
38
- | **3. Spine integration** | **Mostly done** | `BranchGeneratorConfig.straightness` pulls a branch back towards its bud heading (for a split's continuing fork, the heading the split gave it). The apical curl is the existing `tip_upcurl`. Still missing: late noise. |
39
- | **6. Roots & terrain** | **Partly done** | All six woody presets have 3D surface roots on the trunk's flare-lobe crests, and the roots sink into the ground. Still missing: the skirt below `y = 0` and any slope or substrate adaptation. |
40
- | **7. Growth modifiers** | **Mostly done** | `BranchGeneratorConfig.plagiotropism` flattens lateral spines, fans buds into the horizontal plane, and emits no bud into the downward cone. It is set by architectural model: spruce (Massart) has it, the Rauh-model presets do not. Still missing: world obstacle avoidance. |
41
- | **8. Cutout hulls & card spacing** | **Mostly done** | Each atlas tile gets a fitted hull that stays inside its tile (`FoliageAtlasCutout`). Card count follows from shoot length, card size and atlas coverage. A species with `shoot_rules` (the oak) grows its twig system year by year from Buck-Sorlin & Bell's oak demography and carries one card per current-year shoot. Still missing: spine-extruded fronds. |
42
- | **10. Seasons & colour range** | **Done** | Leaves are shed with `senescence`, each once its own atlas tile has lost its chlorophyll in the pigment model, then outer and apical first. Drying folding cards roll shut and droop. Card tints can exceed 1 through the material's `diffuse_color`. The wind rig sheds the same leaves. |
43
- | **11. Wind rig** | **Partly done** | Each joint's stiffness and natural frequency come from Euler–Bernoulli beam mechanics, with the foliage sail taken from the derived leaf area. The number of joints is derived from how the tree bends (`deflection_tolerance`, in metres), and `max_joints` is only a safety net. Drag is quadratic. One `elastic_modulus` holds the oak's bough sway; against their sway before the derived sail, other presets' boughs moved from 0.18x (pine) to 4.2x (palm). Each segment bends under its own load too, so a one-unit twig sways. Still missing: removing `uv1`, and shared skinning-cache clones. |
44
- | 2, 4, 5, 9, 12 | Open | No change in behaviour. Their file links and line anchors point at the current code. |
45
-
46
- **Known gaps in what landed (measured):**
47
- - The ventral knockout is the least-sourced part of plagiotropism. No *Picea*-specific source was found for whether
48
- the underside buds of its branches stay dormant. On spruce it barely acts, since its buds are already distichous.
49
- - Contact projection of a child's first segment can still deflect it into the downward cone, at most 1% of children
50
- in the specs.
51
- - Cards about to fall are nearly shut, valid slivers. Cross and tri-star cards do not wilt.
52
-
53
- **Corrections to the original review.** Every file link resolves on master, and the line ranges were checked to show
54
- the code they name. Three identifiers the review presented as existing engine code never existed:
55
- - `BinaryBVH` is now the engine's [`BVH`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/bvh2/bvh3/BVH.js).
56
- - `evaluate_leaf_sdf` is now `evaluate_leaflet`.
57
- - `compute_golden_ranks` is now the `ranks` that `foliage_collect_attachments` computes.
58
-
59
- Species names such as `ScotsPine`, and functions the review proposes (`branch_fork_triangulate`,
60
- `build_spine_fronds`, `gravitropism_crown_delta`), are not meant to exist yet.
61
-
62
- ## 1. Philosophy, API & Architectural Paradigm
63
-
64
- Comparing [`src/generation/foliage`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/index.js) against **SpeedTree** (IDV / Unity, versions v4 through v10) requires separating **botanical and geometric algorithms** (which `meep` can directly benefit from) from **DCC artist-authoring workflows and legacy vertex-shader workarounds** (which are non-goals or superseded in `meep`).
65
-
66
- ```mermaid
67
- flowchart LR
68
- subgraph ST["SpeedTree (v5–v10): Interactive Artist DCC + Legacy Vertex-Shader SDK"]
69
- direction TB
70
- ST_DAG["Interactive Generator DAG<br/>(Tree -> Branch -> Frond -> Batched Leaf / Zone)"]
71
- ST_ART["Manual Artist Authoring<br/>(2D UI Curves, Freehand Brushes, Guide Splines)"]
72
- ST_BAKE["Offline Compiler / Baker<br/>(3D Sub-Branch Cluster Atlases, Vertex AO)"]
73
- ST_SDK["Custom Foliage Shaders & Vertex Factory<br/>(Packed UV Wind & Custom Subsurface Shading)"]
74
- ST_DAG --> ST_ART --> ST_BAKE --> ST_SDK
75
- end
76
-
77
- subgraph MEEP["meep Foliage: Autonomous Procedural Pipeline + GPU Skinning Cache"]
78
- direction TB
79
- M_CFG["Compact Declarative Config<br/>(TreeSpeciesConfig / TreePreset)"]
80
- M_SKEL["Stage 1: Autonomous Skeleton<br/>(Space Colonization + Pipe Model + BVH Avoidance)"]
81
- M_MESH["Stage 2: Mesh & StandardShadeMaterial<br/>(Manifold Bark + Cutout Cards + Procedural PBR)"]
82
- M_CACHE["Stage 3: Northlight-Style GPU Skinning Cache<br/>(FoliageWindRig -> GPUMeshSkinningContext -> Meshlets & BLAS)"]
83
- M_CFG --> M_SKEL --> M_MESH --> M_CACHE
84
- end
85
- ```
86
-
87
- ### 1.1 SpeedTree's Philosophy: Artist-Directed DCC Authoring & Custom Runtime Shaders
88
- Across its evolution—from **SpeedTreeRT v1–v4** (2002–2006) through the **SpeedTree v5–v7** Modeler/Compiler/SDK split (2009–2015) to **SpeedTree v8–v10** (2018–2025)—SpeedTree was designed around four assumptions:
89
-
90
- 1. **Human Artists in the Loop:**
91
- SpeedTree is first and foremost an interactive desktop DCC application. Procedural rules are meant to get a tree roughly $80\%$ of the way there, after which a human environment artist manually shapes the asset using **2D UI Property Curves** (`Parent Curve` $\times$ `Profile Curve`), **Hand-Drawn Bézier Splines**, **Freehand Mode Brushes** (v9/v10), and **Photogrammetry Mesh Converters** (v8/v9).
92
- 2. **Composable Generator DAG:**
93
- Instead of a fixed sequence of branch levels, the **Generation Editor** is a Directed Acyclic Graph (DAG) rooted at a `Tree` node. Any `Branch` generator can spawn child `Branch` nodes (boughs, twigs, structural roots, dead lower stubs, epicormic trunk sprouts), `Cap` calluses, `Frond` ribbons, or `Batched Leaf` clouds.
94
- 3. **Hierarchical Complexity Compilation (3D Sub-Branches $\rightarrow$ 2D Baked Cluster Atlases):**
95
- Rendering individual leaves on 4 levels of thin 3D twigs blows out both triangle counts and $2\times 2$ pixel quad overdraw. SpeedTree solves this by modeling high-poly 3D twig-and-leaf sub-branches and baking them (`Export Material`) into orthographic PBR **Branch Cluster Atlases**. A runtime game tree then places 150–400 folded cluster cards on Level 1/2 branches to represent $500,000$ triangles of detail in $3,000\text{–}8,000$ triangles.
96
- 4. **Era-Specific Vertex-Shader Wind & Custom Foliage Materials:**
97
- Because SpeedTree's runtime architecture was designed in the DirectX 9–11 era (before visibility buffers, GPU compute skinning caches, and hardware ray tracing), it avoided skeletal bone rigs by packing branch/leaf anchor pivots and wind weights into `TEXCOORD0..TEXCOORD7` and deforming vertices on-the-fly in a custom vertex shader (`SpeedTreeWind`), paired with a dedicated two-sided foliage shading model.
98
-
99
- ---
100
-
101
- ### 1.2 `meep`'s Philosophy: Autonomous Proceduralism, `StandardShadeMaterial` & GPU Skinning Caches
102
- By contrast, `meep`'s foliage generator ([`FOLIAGE_DESIGN.md`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/FOLIAGE_DESIGN.md)) is built for a modern WebGPU engine (`Shade`) with three foundational architectural tenets that deliberately diverge from SpeedTree:
103
-
104
- 1. **Autonomous Procedural Generation (Not an Artist Authoring Suite):**
105
- `meep` is designed to generate botanically convincing trees **autonomously at runtime** from compact declarative configs ([`TreeSpeciesConfig`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/config/TreeSpeciesConfig.js) / [`TreePreset`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/config/TreePreset.js)) with zero external binary assets. Instead of relying on an artist manually painting guide splines or tweaking dozens of UI curves, `meep` derives natural form from first-principles biological and physical solvers:
106
- - **Weber-Penn Envelopes + Runions Space Colonization** ([`PointHashGrid3`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/3d/hash-grid/PointHashGrid3.js))
107
- - **Leonardo/Murray Pipe-Model Area Conservation** ([`tree_skeleton_compute_pipe_radii.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js))
108
- - **3D Capsule-BVH Self-Avoidance & Bud Probing** ([`BVH`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/bvh2/bvh3/BVH.js) in [`tree_skeleton_grow.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js#L1038-L1126))
109
- - **Self-Pruning History**: dead stubs and healed-over knots follow from where a crown rule once grew children ([`tree_skeleton_grow.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js#L700-L717))
110
- - **Euler–Bernoulli Wind Joints**: each joint's compliance comes from its span's bending flexibility and drag, and its natural frequency from its branch's first mode ([`tree_skeleton_compute_joint_mechanics.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js))
111
- - **Leaf Density From Sight-Line Coverage**: a shoot carries just enough cards that a line of sight through its foliage sleeve meets one leaf on average, from card size, insertion angle and the atlas's measured coverage ([`foliage_card_density.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/foliage_card_density.js))
112
- - **Biochemical Ontogeny & 3-Stage Autumn Senescence** ([`make_foliage_material.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/make_foliage_material.js#L145-L267)), with leaves shed and wilted from where the pigment model loses its chlorophyll ([`foliage_senescence.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/foliage_senescence.js))
113
- Exposing tweakable parameters is a welcome bonus where it costs little to nothing in the design, but interactive manual authoring is explicitly **not** a goal.
114
- 2. **Northlight-Style GPU Skinning Cache Over Legacy Vertex-Shader Wind:**
115
- Vertex-animated foliage (SpeedTree's packed `TEXCOORD` vertex shader) is legacy technology. In a modern renderer built on meshlet visibility buffers, temporal upscaling (TAAU), and hardware ray tracing (BVH/BLAS), deforming vertices transiently inside a raster vertex shader is an architectural dead-end: ray-traced shadows and reflections cannot see vertex-shader deformations, meshlet bounding spheres become invalid for frustum/Hi-Z culling, and every pass must re-evaluate the vertex math.
116
- Following recent advancements in **GPU Skinning Caches** (as pioneered by Remedy's **Northlight Engine** in *Alan Wake 2*), `meep` treats foliage wind as **true GPU compute skinning**:
117
- - [`shader_foliage_wind_apply.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/animation/foliage/shader_foliage_wind_apply.js) samples `meep`'s live 3D [`GPUSceneWind`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/wind/GPUSceneWind.js) fluid cascade stack and integrates a stateful 2nd-order aeroelastic harmonic oscillator with Strouhal vortex shedding ([`chunk_foliage_wind_step.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.js)) into standard Dual-Quaternion bone poses.
118
- - [`GPUMeshSkinningContext.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js) and [`shader_meshlet_apply_skinning.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/animation/skinning/shader_meshlet_apply_skinning.js) deform the meshlet vertex/normal/tangent buffers into a persistent **GPU skinning cache**, write `prev_positions` for exact TAAU motion vectors, run a 4-stage GPU meshlet bounds reduction (`shader_meshlet_bounds_reduce` $\rightarrow$ `shader_skinned_mesh_bounds_refresh`), and refit hardware ray-tracing acceleration structures (`GPUBLASRefitBatch`).
119
- - Every downstream consumer—visibility buffer rasterization, cascaded shadow maps, Hi-Z occlusion culling, and ray tracing—consumes the skinned meshlets uniformly with zero foliage-specific shader permutations.
120
- 3. **Strict Compatibility with [`StandardShadeMaterial`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/material/StandardShadeMaterial.js):**
121
- From its inception, the foliage generator was designed to output standard [`StandardShadeMaterial`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/material/StandardShadeMaterial.js) instances (`albedo_texture`, `normal_texture`, `orm_texture`, plus `StandardAttributes.Color` vertex tint/AO) without requiring custom foliage G-buffer layouts or custom deferred shading models. While the generator can synthesize rich internal maps during the generation process (such as the lamina height field that [`make_foliage_material.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/make_foliage_material.js#L290-L299) folds into ORM occlusion and the normal map, or the per-tile hull and leaf coverage it reports in `FoliageAtlasCutout` that can be routed out or baked into the generated textures), the final runtime material strictly adheres to `StandardShadeMaterial`.
122
-
123
- ---
124
-
125
- ## 2. Historical Timeline of SpeedTree (Unwinding Algorithmic Stepping Stones)
126
-
127
- Unwinding how SpeedTree evolved from v1 to v10 allows us to separate **high-leverage procedural geometry/texture algorithms** that fit `meep`'s autonomous pipeline from **DCC authoring features and legacy shader tricks** that `meep` should skip.
128
-
129
- | Era | Versions | Key Features Introduced | Relevance to `meep` (`src/generation/foliage`) |
130
- | :--- | :--- | :--- | :--- |
131
- | **Gen 1 (2002–2006)** | **SpeedTreeRT v1–v4** | Rigid spline tubes; intersecting branch bases with alpha collar skirts (`v4`); camera-facing leaf `Fins`; discrete 3D LODs swapping to azimuthal billboards. | **Superseded by `meep`:** `meep` already uses RMF frames, integer-zippered manifold rings, and conformal apothem collar projection. |
132
- | **Gen 2 (2009–2015)** | **SpeedTree v5–v7** | Arbitrary **Generator DAG** (roots, stubs, sprouts, fronds); **Conformal Collar Welding** (`v6`) + **Light Seam Reduction** (`v7`); **Cutout Editor** minimum-area hulls (`v7`); **3D Sub-Branch Cluster Baking** (`Export Material`); packed vertex-shader wind. | **High Algorithmic Value (Geometry & Baking):** DAG parent targeting, minimum-area cutout hulls, and 3D-to-2D branch cluster atlas baking are directly applicable to `meep`. Vertex-shader wind is superseded by `meep`'s GPU skinning cache. |
133
- | **Gen 3 (2018–2025+)** | **SpeedTree v8–v10** | Full PBR textures; **True Spine Bifurcation** trouser junctions (`v8/v9`); **Season** slider + leaf drop (`v8`); **Hemi-Octahedral Impostors** (`v8+`); Photogrammetry Mesh Converter (`v9`); Freehand Mode brushes (`v9`); Physics Vines (`v10`). | **Selective Algorithmic Value:** Symmetric trouser-junction bifurcations, seasonal abscission/wilt, plagiotropic planar forces, and octahedral impostors fit `meep` cleanly; Freehand/Photogrammetry DCC tools are non-goals. |
134
-
135
- ---
136
-
137
- ## 3. Executive Feature & Capability Gap Matrix
138
-
139
- All gaps below are evaluated strictly from the perspective of **`meep`'s autonomous generator**, **`StandardShadeMaterial`**, and **`Shade`'s GPU skinning cache**.
140
-
141
- | Domain | SpeedTree Mechanism | `meep` (`src/generation/foliage`) Current State | Gap Severity | `meep`-Native Upgrade Path |
142
- | :--- | :--- | :--- | :--- | :--- |
143
- | **1. Branch Hierarchy & Structural Roles** | Generator DAG where any branch/frond/root/stub/sprout generator can attach to any parent generator. | **Done.** [`TreeSpeciesConfig`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/config/TreeSpeciesConfig.js#L45-L68): `branches: BranchGeneratorConfig[]` joined by `branch_rules: BranchSpawnRule[]` (`source < target`, so acyclic) and `foliage_rules: FoliageSpawnRule[]`. Roots (`root`), inter-whorl branches and epicormic sprouts are rules. Dead stubs and knots come from `self_pruning`. | **Closed** | — |
144
- | **2. Spatial Parameter Modulation** | 2D `(Parent Curve x Profile Curve)` modulation across crown height and branch arc length. | 3 [`AnimationCurve`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/engine/animation/curve/AnimationCurve.js) slots: `length_profile` and `insertion_angle_profile` per rule, `radius_profile` per generator. `gravitropism` and `gnarl_strength` are scalars. | **Medium** | Add lightweight crown-height / local-$t$ modulation for `gravitropism` (drooping lower boughs vs. ascending upper crown) and `gnarl_strength`. |
145
- | **3. Autonomous Spine Integration** | Early noise + Straightness restoring force + Late noise + binormal `Curl` pitch. | `curl_noise_3d` perturbs the tangent at each step (early noise), alongside sympodial nodal kinking and the apical `tip_upcurl`, in [`tree_skeleton_grow.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js#L920-L956). `straightness` pulls a branch back towards its bud heading. There is no late noise. | **Low** | ~~Add `straightness`~~ (done). Remaining: post-march RMF `late_noise`. |
146
- | **4. Bifurcation (Co-Dominant Forks)** | Symmetric Y-saddle (trouser junction) splitting parent loop into two daughter loops across a crotch web. | [`tree_skeleton_grow.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js#L1479-L1633) deflects the parent as Fork 0 and queues Fork 1 as an interior side-child (`parent_attach_t < 1.0`). [`tree_mesh_build_bark.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_bark.js#L754) then pinches Fork 1 asymmetrically and sockets it into the side of Fork 0 like a collar. | **Medium-High** | Terminate parent at `s_split` on co-dominant forks and zipper the parent ring into both daughters via a symmetric 2-vertex crotch saddle (`branch_fork_triangulate`). |
147
- | **5. Lateral Branch Collar Joins** | Conformal collar projection + normal bending + collar texture transition + optional manifold quad union. | [`branch_collar_project.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/branch_collar_project.js) sockets child inside parent apothem, blends normals & skin weights, warps parent $U$, and matches `v_start = parent_v_attach`. | **Low-Medium** | Bake subtle bark-crevice AO darkening at the collar ring (`i = 0`) into `vertex_color`; optionally use [`bt_mesh_bridge_islands`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/3d/topology/struct/binary/io/bt_mesh_bridge_islands.js) for manifold hero trunk unions. |
148
- | **6. Roots & Terrain Adaptation** | 3D structural root spines + buttress flare lobes + terrain/rock surface crawling & flattening. | **Partly done.** Cross-sectional `flare_lobes` at the trunk base ([`tree_mesh_build_bark.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_bark.js#L569-L635)), plus 3D surface roots (`BranchGeneratorConfig.root`) planted on the lobe crests by `PhyllotaxisMode.FlareLobes`. The roots creep along `y = 0` and sink into it ([`tree_skeleton_grow.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js#L1364-L1399)). The trunk is still cut flat at `y = 0`, and nothing adapts to slope. | **Medium** | Extend trunk base skirt below $y = 0$; crawl optional heightfield / [`BVH`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/bvh2/bvh3/BVH.js) / SDF. |
149
- | **7. Growth Forces & Biological Pruning** | `Planar` flattening (plagiotropism), `Knockout` angle culling, `Interior` self-shading pruning, obstacle avoidance. | 9 Weber-Penn envelopes, Space Colonization, and capsule-BVH self-avoidance. Self-shading pruning of the stem is in (`self_pruning`, see Item 1). `plagiotropism` flattens lateral spines into pads, fans buds into the horizontal plane and knocks out ventral buds. Spruce, the presets' Massart-model species, forms tiers. There is no world obstacle avoidance. | **Low-Medium** | ~~Plagiotropism and ventral knockout~~ (done, on `BranchGeneratorConfig`). Remaining: optional SDF/BVH obstacle fields. |
150
- | **8. Cutout Hulls, Card Spacing & Fronds** | Minimum-area polygon cutouts (`Fold`, `Curl`) + shoot-length-proportional spacing + spine-extruded `Frond` strips. | **Partly done.** `CutoutHull` cards draw each tile's fitted hull ([`foliage_atlas_cutout.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/foliage_atlas_cutout.js)). Card count follows the carrier's leafy length through a derived density ([`foliage_card_density.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/foliage_card_density.js)). `RibbedFrond` is still a rigid cantilever. | **Medium** | ~~Fitted per-tile hulls; card count by shoot length~~ (done). Remaining: extrude fronds along terminal `TreeSkeleton` spines. |
151
- | **9. Branch Cluster Atlas Baking** | Bakes 3D sub-branches (woody twigs + dozens of 3D-oriented leaves/needles) into PBR cluster atlases. | [`foliage_leaf_silhouette.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/foliage_leaf_silhouette.js#L155-L232) draws a single straight vertical stem (`lu = 0`) with 5–9 flat 2D SDF leaflets per variant tile. | **Critical** | Upgrade `make_foliage_material.js` to a depth-buffered, multi-twig + 3D-tilted leaf/needle cluster baker outputting directly to `StandardShadeMaterial`. |
152
- | **10. Seasonality, Abscission & Color Range** | Seasonal pigment shift + progressive leaf abscission (drop) & senescent curl. | [`make_foliage_material.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/make_foliage_material.js#L145-L267) has biochemical ontogeny & 3-stage senescence pigments, **Done:** progressive abscission and wilt driven by `senescence`, and tint headroom through the material's `diffuse_color`. | **Closed** | — |
153
- | **11. GPU Skinning Cache & Wind Rig** | Legacy stateless vertex-shader wind (no skinning cache, no ray-tracing BLAS support). | **Superior foundation:** a 3D fluid-coupled `FoliageWindRig` and a Northlight-style `GPUMeshSkinningContext` skinning cache. Each joint's stiffness and frequency come from beam mechanics, and joints go wherever the wind visibly bends the tree, outer twigs included. Two gaps remain: the mesh builders write dead data into lightmap `uv1`, and `obtain_clone` is strictly 1-to-1 per entity. | **Medium** | Remove dead `uv1` writes from bark/foliage mesh builders; support shared archetype skinning cache clones in `GPUMeshSkinningContext`. |
154
- | **12. LODs, Mip Coverage & Virtual Geometry** | Mipmap alpha coverage preservation + smooth LOD transitions + Hemi-Octahedral Impostors. | Static `LOD0..LOD3` in [`TreeAsset`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/asset/TreeAsset.js); [`place_tree`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/asset/place_tree.js#L56-L66) spawns a single static LOD; standard mip box-filtering thins distant alpha cutouts; no `VirtualGeometry` or impostor stage. | **High** | Preserve alpha coverage across mip levels in `make_foliage_material.js`; add runtime LOD switching; feed `bark_geometry` into [`vgeo_build`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/geometry/virtual/build/vgeo_build.js); optional octahedral impostor via [`src/core/geom/3d/octahedra/`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/3d/octahedra/). |
155
-
156
- ---
157
-
158
- ## 4. Deep-Dive Itemized Review, Historical Unwinding & `meep` Upgrades
159
-
160
- ---
161
-
162
- ### Item 1: Structural Branch Roles & Parent Targeting vs. Strict `L - 1 -> L` Array
163
-
164
- #### How SpeedTree Works (Historical Unwinding)
165
- In **SpeedTreeRT v1–v4**, trees had a rigid linear hierarchy (`Trunk -> Branches -> Sub-Branches -> Leaves`). By **SpeedTree v5**, it became clear that a strictly sequential level array cannot represent common botanical structures even in purely procedural trees:
166
- - **Mature Broadleaf Trees (`EnglishOak`, `EuropeanBeech`):** Have **Structural Surface Roots** emerging at the trunk base (`Level 0`), **Dead Lower Stubs** (short broken limbs with callus caps and zero leaves in the lower shaded third of the trunk), **Primary Canopy Boughs** in the upper crown, and **Epicormic Sprouts** (small leafy shoots sprouting directly from the main trunk or primary boughs, skipping intermediate levels).
167
- - **Conifers (`ScotsPine`, `NorwaySpruce`, `SilverFir`):** Exhibit **Whorled Primary Boughs** at annual growth nodes alongside smaller **Inter-Whorl Branches** distributed spirally along the internode segments of the exact same trunk (`Level 0`).
168
- - **Palms & Cycads:** Spawn **Fronds** and **Old Petiole Stubs** directly from the apex of `Level 0`.
169
-
170
- #### State in `meep` before `00807d697`
171
- `TreeSpeciesConfig` configured branching as `levels: BranchLevelConfig[]`, at most 4 levels. `tree_skeleton_grow.js` looped over `level = 1 .. num_levels - 1` and attached the branches of `levels[L]` only to parents with `branch_level === L - 1`. `foliage_collect_attachments.js` chose carriers by `b_level >= min_level` alone. `TreeSkeleton` itself was already a general tree, since `branch_parent` can point at any branch.
172
-
173
- #### Current State in `meep` (Done: `00807d697`, `2f4465170`, `28ef51f1b`)
174
- The fixed level list is replaced by a generator graph in [`TreeSpeciesConfig.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/config/TreeSpeciesConfig.js#L45-L68):
175
- - **Generators.** `branches: BranchGeneratorConfig[]` says how each kind of branch is shaped. `branches[0]` is the trunk.
176
- - **Branch rules.** `branch_rules: BranchSpawnRule[]` says which generator spawns which, and how:
177
- - where along the parent (`attach_min` / `attach_max`) and how many (`count`);
178
- - with what phyllotaxis, insertion angle and `length_profile`;
179
- - whether the child kinks its stem (`parent_kink`);
180
- - whether the crown envelope shapes it (`crown_envelope`).
181
-
182
- Every rule has `source < target`, so the graph is acyclic. One generator can spawn several kinds of children, and several generators can spawn the same kind. A generator's outgoing rules are walked in a canonical order (by target, then by `hash()`), so the order rules are listed in does not change the tree.
183
- - **Foliage rules.** `foliage_rules: FoliageSpawnRule[]` says which generators carry leaves, and how many.
184
- - **Skeleton record.** [`TreeSkeleton.branch_generator`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/TreeSkeleton.js#L167) records which generator grew each branch.
185
-
186
- The four roles this item asked for are covered as follows:
187
- 1. **3D Structural Roots.** A generator with `root: true`, spawned by a trunk rule with `PhyllotaxisMode.FlareLobes`, puts one root on each crest of the trunk's buttress lobes. `flare_lobe_phase_offset` keeps the roots in phase with the lobes. A root creeps along `y = 0` while it sinks into the ground, with its centreline at $y = r(t) - 2 r_{\text{base}} t$. Roots add no pipe-model area to the stem, carry no leaves and never get a wind joint. Children on a flare crest are capped at $R \sin(\pi / N)$ so that $N$ of them fit side by side. Oak, Pine, Birch, Willow, Maple and Spruce all have roots.
188
- 2. **Conifer Inter-Whorl Branches.** Pine and Spruce each have a second trunk rule: short laterals that spiral along the internodes between whorls. They carry the same twig generator as the whorl boughs.
189
- 3. **Dead Lower Stubs.** These are not an authored role, and no preset sets a number of them. A crown rule's bare stretch below its living children (`attach_min`) is where the stem once grew children too: the same node layout (`rule_node_u` / `rule_node_phi`) continued down the stem, so a conifer's dead branches come in whorls.
190
- - **Age and size.** A branch that died at site $t$ has age $(t_{\text{lo}} - t) / t_{\text{lo}}$, and its radius is $(1 - \text{age})$ of a living branch's there.
191
- - **Length kept.** It keeps $(1 - \texttt{self\_pruning}) - \text{age}$ of its length.
192
- - **Scars.** A stub that no longer clears the bark has been grown over and becomes a scar ([`TreeSkeleton.add_scar`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/TreeSkeleton.js#L282)). The bark builder renders each scar as a knot: the branch's collar outliving it as a callus rim. Its amplitude is `parent_collar_bulge * (0.55 + 0.75 * r_ratio)` ([`tree_mesh_build_bark.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_bark.js#L281-L300)). `knot_count` and `knot_strength` are gone.
193
- - **Dead stubs.** A dead branch (`branch_dead`) grows nothing, carries no leaves, conducts no sap (no pipe-model area) and ends in a flat break. It is shaped as the base of the branch it was: shape envelopes are read at its position along that whole branch, and per-step amounts use that branch's segmentation.
194
- - **Per preset.** The outcome follows from each preset's `self_pruning`:
195
-
196
- | Preset | `self_pruning` | What it keeps |
197
- | :--- | :--- | :--- |
198
- | Oak | 0.7 | one dead limb under the crown |
199
- | Maple | 0.5 | a dead pair |
200
- | Pine | 0.55 | a few thin dead branches |
201
- | Spruce | 0.2 | a few thin dead branches |
202
- | Birch | 0.85 | none |
203
- | Willow | 0.75 | none |
204
-
205
- A palm's dropped fronds ring its trunk as scars.
206
- 4. **Epicormic Sprouts.** Oak spawns leafy water sprouts (generator 4) from two rules. One is on the bole and has `crown_envelope: false`. The other is on the boughs.
207
-
208
- **How this differs from the proposal.** There is no `role` enum: `root` is the only role that changes how a branch grows. There is no `dead_stub` role, because stubs follow from growth history and `self_pruning`. The per-level `foliage_enabled` flag became `foliage_rules`.
209
-
210
- **Still open.** A species' stubs do not vary from seed to seed, because their sites and lengths follow from the rule layout. The broken end is a flat cut, not a jagged one.
211
-
212
- ---
213
-
214
- ### Item 2: Autonomous Spatial Modulation Across Crown Height & Branch Arc Length
215
-
216
- #### How SpeedTree Works vs. What Autonomous Generation Actually Needs
217
- SpeedTree exposes a 2D UI curve editor (`Parent Curve` $\times$ `Profile Curve`) on nearly every parameter so artists can hand-sculpt curves. In an autonomous generator like `meep`, ubiquitous manual curve editors are unnecessary overhead—however, **two specific biological gradients** depend on evaluating a property as a function of **normalized crown height ($u_{\text{crown}} \in [0, 1]$)** or **local branch progression ($v_{\text{local}} \in [0, 1]$)**:
218
- 1. **Gravitropism Gradient Across the Crown ($u_{\text{crown}}$):** On conifers (`NorwaySpruce`, `CedarOfLebanon`, `ScotsPine`) and mature broadleaf trees, lower boughs ($u_{\text{crown}} \approx 0$) droop downward under age and shade (`gravitropism > 0`), middle boughs spread horizontally (`gravitropism` $\approx 0$), and upper crown shoots ($u_{\text{crown}} \to 1$) reach steeply skyward (`gravitropism < 0`). A single constant scalar `gravitropism` per level cannot express this inversion.
219
- 2. **Local Gnarl / Curvature Ramp Along a Branch ($v_{\text{local}}$):** Real limbs emerge straight and stiff near the high-moment collar weld ($v_{\text{local}} \in [0, 0.2]$) and become progressively more gnarled and contorted toward their thinner distal tips ($v_{\text{local}} \in [0.5, 1.0]$).
220
-
221
- #### Current State in `meep`
222
- [`BranchSpawnRule.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/config/BranchSpawnRule.js#L79-L85) provides [`AnimationCurve`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/engine/animation/curve/AnimationCurve.js) slots for `length_profile` ($u_{\text{parent}}$) and `insertion_angle_profile` ($u_{\text{parent}}$). [`BranchGeneratorConfig.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/config/BranchGeneratorConfig.js#L59) provides `radius_profile` ($v_{\text{local}}$). `gravitropism` and `gnarl_strength` are single scalars on the generator.
223
-
224
- #### Evolutionary Path for `meep`
225
- Without adding heavyweight curve objects everywhere, allow `gravitropism` in [`BranchGeneratorConfig`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/config/BranchGeneratorConfig.js) to specify an optional `gravitropism_crown_delta` (linearly interpolating gravitropism from base to top of the crown envelope) and modulate `gnarl_strength` by $\text{smoothstep}(0.05, 0.35, t_{\text{local}})$ near branch bases so lateral collar welds remain clean even on heavily gnarled oaks and pines.
226
-
227
- ---
228
-
229
- ### Item 3: Autonomous Spine Integration (Heading Restoring Force, Late Noise & Apical Curl)
230
-
231
- #### How SpeedTree Works
232
- During procedural spine marching, SpeedTree separates three distinct geometric mechanisms:
233
- 1. **Early Noise + Straightness Restoring Force:** Early noise perturbs the integration tangent $\hat{\mathbf{t}}_i$ at each step, creating sweeping organic bends, while **Straightness** applies a proportional restoring pull back toward the branch's initial target heading $\hat{\mathbf{d}}_0$ so noisy branches do not wander completely out of their crown sector or loop back into the trunk.
234
- 2. **Late Noise:** Displaces spine vertices *perpendicular* to the integrated curve (along the RMF normal/binormal frame) after the trajectory is solved, adding high-frequency rustic character without altering where the branch tip lands.
235
- 3. **Apical Curl (Binormal Pitch):** Rotates the growth tangent around the branch's horizontal binormal $\hat{\mathbf{b}} = \text{normalize}(\hat{\mathbf{t}} \times \mathbf{Y}_{\text{up}})$ near $v \in [0.7, 1.0]$, producing the characteristic upturned tips ("ski-jump" bough ends) of conifers and cedars or the coiled tips of fern fronds.
236
-
237
- #### Current State in `meep`
238
- Inspecting [`tree_skeleton_grow.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js#L920-L956):
239
- - `meep` adds `gnarl_strength * curl_noise_3d(...)` directly to the unit tangent `(dx, dy, dz)` and re-normalizes at every step. This is pure **Early Noise**.
240
- - It is paired with sympodial nodal kinking (`nodal_kink_strength`, `internode_zigzag`).
241
- - The per-step scale is $\sqrt{6 / N_{\text{shape}}}$. $N_{\text{shape}}$ is the segmentation of the whole branch, so a dead stub bends as that branch's base did.
242
- - The apical upturn already exists as `BranchGeneratorConfig.tip_upcurl`.
243
- - Right after the gnarl (step 4b), `straightness` adds a restoring term towards the initial bud heading $\hat{\mathbf{d}}_0$, so a high `gnarl_strength` no longer has to carry a branch out of its phyllotactic sector. The same step pulls a plagiotropic lateral towards the horizontal (Item 7).
244
- - Early and late noise are still not separated.
245
-
246
- #### Landed (Tier 1, point 2)
247
- - **Straightness.** `straightness` lives on `BranchGeneratorConfig`, because it shapes a branch. Each step adds
248
- $\lambda(\hat{\mathbf{d}}_0 - \hat{\mathbf{d}}_i)$, with $\hat{\mathbf{d}}_0$ the heading the bud gave the branch,
249
- after the gnarl.
250
- - **Measured.** With `gnarl_strength` 0.6 on oak's boughs, the mean start-to-tip heading change falls from 72° to
251
- 54° at `straightness` 1. No preset sets it.
252
- - **Splits.** A split re-aims the fork that continues the branch at the heading the split deflected it to, as the
253
- other forks aim along their own. Before `0d7671493`, straightness pulled it back to the bough's bud heading.
254
- - **Apical curl.** This is the existing `tip_upcurl`; no second curl was added.
255
- - **Late noise.** Not built.
256
-
257
- #### Evolutionary Path for `meep`
258
- In the per-step spine march of [`tree_skeleton_grow.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js#L734):
259
- 1. ~~**Add `straightness` ($\in [0, 1]$)**~~: done, as described above. The original proposal: blend a restoring pull $\lambda_{\text{straight}}(\hat{\mathbf{d}}_0 - \hat{\mathbf{d}}_i)$ at each segment step so branches can exhibit strong mid-span gnarl while still arriving near their intended canopy region.
260
- 2. **Add `late_noise`:** Displace spine vertices along the RMF normal and binormal after the march. This adds rustic character without moving the tip.
261
-
262
- ---
263
-
264
- ### Item 4: Bifurcation (Co-Dominant Splitting Topology)
265
-
266
- #### How SpeedTree Works (Historical Unwinding)
267
- - **SpeedTree v4–v7:** Lacked true spine bifurcation; forks were approximated by spawning a thick lateral child branch on the side of a continuing parent tube, which caused asymmetric pinching at the fork.
268
- - **SpeedTree v8–v10:** Introduced topological **Bifurcation (`Split`)**. When a branch splits into co-dominant forks, the parent cylinder widens into an oval/figure-8 cross-section along the split plane and partitions into two symmetric daughter rings bridged across a central crotch saddle web, obeying pipe-model area conservation ($r_p^\alpha = r_0^\alpha + r_1^\alpha$).
269
-
270
- ```mermaid
271
- flowchart TD
272
- subgraph MEEP_SPLIT["Current meep Bifurcation (tree_skeleton_grow.js L1486–1615)"]
273
- P0["Parent Branch b<br/>(Deflects by fork0_deflect & continues as Fork 0)"]
274
- D1["Fork 1 (Queued as Child Branch at t_curr < 1.0)<br/>is_split_fork = true, base_radius = 0.78 * r_curr"]
275
- COLLAR["tree_mesh_build_bark runs branch_collar_project on Fork 1<br/>Pinched to 0.78 * R_p * cos(pi/M_p) & socketed into side of Fork 0"]
276
- P0 --> D1 --> COLLAR
277
- end
278
-
279
- subgraph ST_SPLIT["Proposed Symmetric Saddle Bifurcation (Trouser Junction)"]
280
- SP0["Parent Ring M_p vertices at s_split<br/>(Widened into Oval along fork plane)"]
281
- BRIDGE["2 Saddle Bridge Triangles<br/>Across Crotch Ridge"]
282
- SD1["Fork 0 Base Ring<br/>(M_0 = M_p/2 + 2 vertices)"]
283
- SD2["Fork 1 Base Ring<br/>(M_1 = M_p/2 + 2 vertices)"]
284
- SP0 --> BRIDGE
285
- BRIDGE --> SD1
286
- BRIDGE --> SD2
287
- end
288
- ```
289
-
290
- #### Current State in `meep`
291
- Tracing how [`tree_skeleton_grow.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js#L1479-L1633) and [`tree_mesh_build_bark.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_bark.js#L754) construct a split reveals a topological asymmetry:
292
- 1. In [`tree_skeleton_grow.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js#L1479-L1633), when `split_probability` triggers at an interior segment $s \in [0.25 N_{\text{seg}}, 0.75 N_{\text{seg}}]$, the parent branch is **not** terminated. Instead, the parent spine deflects by `fork0_deflect` (`split_ang * 0.22` on the trunk, `split_ang * 0.5` on limbs) and continues growing to $N_{\text{seg}}$ as **Fork 0**, while **Fork 1..N-1** are queued as child branches attached at interior `parent_attach_t: t_curr` with `base_radius: r_curr * 0.78` and `is_split_fork: true`.
293
- 2. Although [`tree_skeleton_compute_pipe_radii.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js) accumulates pipe-model cross-sectional area from both Fork 0 and Fork 1 into the parent segment upstream of `t_curr`, [`tree_mesh_build_bark.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_bark.js#L754) treats Fork 1 identically to a lateral side-branch.
294
- 3. Consequently, **Fork 0** is meshed as one continuous dominant tube, whereas **Fork 1** is passed through [`branch_collar_project.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/branch_collar_project.js#L74-L193), which shrinks Fork 1's base ring to the parent's inscribed polygon apothem $0.78 R_p \cos(\pi/M_p)$ ($\approx 0.675 R_p$ for $M_p = 6$) and sockets it laterally into the side of Fork 0 while raising a side collar boss on Fork 0.
295
- 4. **Result:** Co-dominant dichotomous forks in `meep` are topologically asymmetric (one continuous tube + one pinched lateral branch socketed into its side) rather than a symmetric Y-saddle where two co-equal limbs divide from a shared crotch ridge.
296
-
297
- #### Evolutionary Path for `meep`
298
- We do not need general 3D mesh booleans to build watertight bifurcations:
299
- 1. **Symmetric Terminal Split in `TreeSkeleton`:** When a branch undergoes a co-dominant bifurcation at step `s_split`, terminate the parent branch segment range at `s_split` (`has_terminal_split = true`, suppressing `branch_apex_triangulate`) and spawn **both** Fork 0 and Fork 1 as daughter branches at `t_attach = 1.0` with symmetric deflection angles, suppressing `branch_collar_project` on both daughters.
300
- 2. **Analytic Trouser / Saddle Ring Partition (`branch_fork_triangulate`):**
301
- - On the final ring of the parent branch before the split, apply `oval_eccentricity` aligned with the split plane $\hat{\mathbf{e}}_{\text{split}} = \text{normalize}(\mathbf{d}_1 - \mathbf{d}_0)$ so the parent cross-section widens smoothly along the fork plane.
302
- - Partition the parent's top ring of $M_p$ vertices into two half-arcs ($M_p/2 + 1$ vertices for Fork 0, $M_p/2 + 1$ vertices for Fork 1) sharing 2 saddle-bridge vertices across the crotch ridge $\hat{\mathbf{b}}_{\text{crotch}} = \text{normalize}(\mathbf{d}_0 \times \mathbf{d}_1)$, and use [`branch_ring_triangulate`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/branch_ring_triangulate.js#L23-L60) to zipper each half-arc+saddle loop directly to Fork 0's and Fork 1's ring `i = 0`.
303
- - This produces a **100% watertight, manifold, zero-T-junction Y-fork** with continuous bark $V$-coordinates and zero internal intersecting faces.
304
-
305
- ---
306
-
307
- ### Item 5: Lateral Branch Welding & Procedural Collar Transitions
308
-
309
- #### Current State in `meep` (Already a Strongpoint)
310
- For lateral side-branches (where a smaller limb emerges from a continuing trunk or bough), `meep`'s implementation in [`branch_collar_project.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/branch_collar_project.js#L44-L205) and [`tree_mesh_build_bark.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_bark.js#L586-L719) is already well ahead of early SpeedTree versions:
311
- - **Parent Boss Swelling & Grain Deflection:** [`tree_mesh_build_bark.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_bark.js#L586-L719) pre-collects all child attachments on a parent branch and displaces parent vertices outward with an anisotropic Gaussian collar boss (`parent_collar_bulge`), while deflecting the parent's $U$ texture coordinate (`u_warp`) around the emerging limb like wood fibers parting around a knot.
312
- - **Axial $V$-Coordinate Continuity:** [`tree_mesh_build_bark.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_bark.js#L420-L427) initializes the child branch's starting $V$ coordinate at ring `i = 0` to `v_start = parent_v_attach`.
313
- - **Inscribed Apothem Socketing + Normal & Skinning Transfer:** [`branch_collar_project.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/branch_collar_project.js#L74-L193) seats the child's flared `i = 0` ring onto the parent's inscribed polygon apothem ($R_{\text{seat}} = 0.78 R_p \cos(\pi/M_p)(1 - \text{flute\_amp})$), blends the child's vertex normals toward the parent's radial normal (`normal_blend = 0.85` at $i=0$, `0.35` at $i=1$), and copies the parent frustum's 4 skinning joints/weights onto ring `i = 0` so the collar never tears under GPU compute skinning.
314
-
315
- #### Evolutionary Path for `meep` (Strictly Within `StandardShadeMaterial` & Geometry Generation)
316
- Without modifying `StandardShadeMaterial` or adding secondary UVs:
317
- 1. **Collar Crevice AO Darkening in `vertex_color`:** In real trees, the bark ridge at a branch collar is compressed and darkened by crevice occlusion and rough suberin tissue. Multiplying a subtle collar-crevice AO factor ($\sim 0.65\text{–}0.75$ at ring $i = 0$, recovering to $1.0$ at $i = 1$) into the bark `vertex_color` in [`tree_mesh_build_bark.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_bark.js) naturally masks the transition between parent vertical furrows and child circumferential UVs using `StandardShadeMaterial`'s existing `albedo * s.vertex_color` modulation.
318
- 2. **Optional Manifold Topological Bridge for Hero `LOD0` Trunks:** Where a 100% manifold outer shell without internal socketed triangles is desired on `level <= 1` trunks, `meep`'s existing [`BinaryTopology`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/3d/topology/struct/binary/BinaryTopology.js) and [`bt_mesh_bridge_islands.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/3d/topology/struct/binary/io/bt_mesh_bridge_islands.js) can remove the occluded parent quad faces under a large bough collar and bridge the boundary loop directly to the child's `i = 0` ring.
319
-
320
- ---
321
-
322
- ### Item 6: 3D Structural Roots, Buttressing & Substrate Adaptation
323
-
324
- #### How SpeedTree Works
325
- SpeedTree combines **Trunk Base Flare (`Flare` + `Lobes`)** with **3D Root Generators** that emerge from the bottom of the trunk (`Start Angle > 0.6`) and optionally conform to terrain heightfields or rock meshes (`Mesh Force` attract/obstruct), flattening their underside cross-sections against the substrate.
326
-
327
- #### Current State in `meep` (Step 2 done: `00807d697`)
328
- [`tree_mesh_build_bark.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_bark.js#L569-L635) implements **Trunk Base Flare** (`flare_lobes`, `flare_amplitude`, `flare_height_ratio`, `flare_sharpness`, `flute_amplitude`) on the trunk. Since `00807d697`, structural surface roots also grow from it:
329
- - **Placement.** A generator with `BranchGeneratorConfig.root` is spawned by a trunk rule with `PhyllotaxisMode.FlareLobes`, which puts one root on each lobe crest. `flare_lobe_phase_offset` keeps the roots in phase with the bark builder's lobes, so each root continues a buttress ridge.
330
- - **Shape.** [`tree_skeleton_grow.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js#L1364-L1399) keeps the root on the ground plane while it sinks. Its centreline is at $y = r(t) - 2 r_{\text{base}} t$: it rests on the ground at the trunk and is under the ground by about halfway out.
331
- - **Thickness.** Children on a flare crest are capped at $R \sin(\pi / N)$, so that $N$ of them fit side by side inside the stem.
332
- - **What roots skip.** Roots add no pipe-model area, carry no leaves, never self-prune and never get a wind joint.
333
- - **Presets.** `make_surface_roots` / `make_surface_roots_rule` give Oak, Pine, Birch, Willow, Maple and Spruce one root per lobe.
334
-
335
- Two gaps remain:
336
- 1. The trunk base still ends at a flat horizontal plane (`y = 0`). This can leave a visible gap under the downhill side when a tree is placed on sloped terrain.
337
- 2. The roots know only the plane `y = 0`, not the terrain.
338
-
339
- #### Evolutionary Path for `meep`
340
- 1. **Step 1 (Root Skirt Extension Below `y = 0`):** Extend the trunk base ring slightly below `y = 0` ($y \in [-0.35 R_{\text{base}}, 0]$) so trees placed on uneven slopes never float on their downhill side.
341
- 2. ~~**Step 2 (Phase-Locked 3D Root Spines)**~~: done, as described above.
342
- 3. **Step 3 (Optional Substrate Query via Heightfield / [`BVH`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/bvh2/bvh3/BVH.js) / SDF):** When an optional `substrate` query is supplied to `generate_tree`, project root tangents along the surface normal plane and flatten the lower half of root cross-sectional rings (`dot(ring_dir, -n_surface) > 0`) against the ground.
343
-
344
- ---
345
-
346
- ### Item 7: Botanical Growth Modifiers (Plagiotropism, Ventral Knockout & Obstacle Avoidance)
347
-
348
- #### How SpeedTree Works
349
- SpeedTree shapes secondary and tertiary branching using directional/planar forces and pruning filters:
350
- - **`Planar` Force (Botanical Plagiotropism):** Flattens lateral branches and twigs onto horizontal or gently tilted planes—essential for the layered horizontal foliage pads of conifers (`ScotsPine`, `CedarOfLebanon`), `JapaneseMaple`, and `CornelianCherry`.
351
- - **`Knockout` Angle Pruning:** Deletes lateral buds whose initial growth direction points into a forbidden downward cone (`Ventral Knockout`), preventing twigs from growing straight down out of the shaded underside of horizontal boughs.
352
- - **Obstacle Forces:** Deflects or prunes branches against world geometry (walls, cliffs, neighbouring structures).
353
-
354
- #### Current State in `meep`
355
- `meep` shapes crowns in four ways:
356
- - 9 [`CrownEnvelopeType`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/config/CrownEnvelopeType.js)s, Runions Space Colonization, and scope-local capsule [`BVH`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/bvh2/bvh3/BVH.js) self-avoidance.
357
- - Shade-driven self-pruning of the stem below the living crown (`self_pruning`, see Item 1).
358
- - **Plagiotropism.** A lateral with `BranchGeneratorConfig.plagiotropism` grows towards the horizontal (step 4b of the
359
- [spine march](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js#L920-L956)).
360
- At [bud emission](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js#L1791-L1849)
361
- it fans its buds into its horizontal plane. Buds pointing into the downward cone of half-angle
362
- `plagiotropism * pi / 2` do not break. The spruce preset forms horizontal foliage tiers this way.
363
- - **Not yet:** nothing avoids world geometry.
364
-
365
- #### Landed (Tier 1, point 2)
366
- Point 1 below is done, with these differences from the proposal:
367
- - **One field, not two.** `plagiotropism` is on `BranchGeneratorConfig`, not `BranchSpawnRule`. Dorsiventrality is a
368
- property of the shoot, so it shapes the parent's own spine (pulled towards the horizontal) and decides where that
369
- parent's buds go.
370
- - **Knockout is derived.** There is no `ventral_knockout` field. On a dorsiventral parent, a bud whose own heading
371
- points into the downward cone of half-angle `plagiotropism * pi / 2` does not break. The test runs before the
372
- surviving buds are fanned into the plane of the parent's tangent and the horizontal across it.
373
- - **Replaces a hidden rule.** It replaces an undocumented emission rule keyed on the child's gravitropism, which biased
374
- every lateral's buds upward and off its underside. Its pad effect was small (oak 0.750 with it, 0.789 without), but
375
- its heading effect was not. Measured over 12 seeds without it:
376
- - oak: twigs more than 30° below the horizontal 1.4% → 3.8%;
377
- - birch: 0.6% → 1.2%.
378
- That bias had no botanical basis: Rauh-model branches (oak, birch, maple, pine) are orthotropic and branch
379
- radially, and the positional bias reported for some of them is slight hypotony, lower-side laterals favoured
380
- (Millet, Bouchard & Édelin 1999). It is not reinstated.
381
- - **Knockout covers emitted headings.** Fanning, or a turn for clearance, can no longer carry a bud into the cone
382
- (`0d7671493`). Contact projection of a first segment can still deflect a child afterwards, by at most 1% of
383
- children in the specs.
384
- - **Set by architectural model, not by look.** The source is Hallé, Oldeman & Tomlinson's architectural models, as listed by Pfisterer (2000, *Mitt. Biol. Bundesanst.* 370) and Millet, Bouchard & Édelin (1999, *Écoscience* 6: 187–203).
385
- - **Massart's model** (*Picea*): tiers of plagiotropic branches. Spruce sets 0.7 on its laterals.
386
- - **Rauh's model** (*Pinus*, *Acer*, *Quercus*, *Betula*): orthotropic branches built like the trunk. Pine, maple,
387
- oak and birch set none. Pine's tiers come from its annual whorls, not from plagiotropy.
388
- - The first cut of this work also set pine and maple to 0.7. That was reverted when the sources were checked.
389
- - **Measured** on spruce, averaged over seeds 1, 7 and 1337:
390
-
391
- | Measure | Without | With |
392
- | :--- | :--- | :--- |
393
- | pad thickness (vertical over horizontal spread of a bough's cards) | 0.42 | 0.25 |
394
- | crown height in empty tier gaps | 0.27 | 0.41 |
395
-
396
- Forced onto pine at 1.0, the knockout starts costing twigs (cards −8%). 0.7 is where the pads have flattened
397
- without losing any.
398
-
399
- Point 2, obstacle avoidance, is still open.
400
-
401
- #### Evolutionary Path for `meep`
402
- 1. ~~**Add `plagiotropism` and `ventral_knockout`**~~: done as one generator field, with knockout derived from it (see "Landed"). The original proposal: **Add `plagiotropism` ($\in [0, 1]$) and `ventral_knockout` ($\in [0, 1]$) to [`BranchSpawnRule`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/config/BranchSpawnRule.js):**
403
- - `plagiotropism`: Projects a child branch's initial bud direction and step tangents toward the horizontal fan plane spanned by the parent tangent $\hat{\mathbf{t}}_p$ and $\hat{\mathbf{t}}_p \times \mathbf{Y}_{\text{up}}$. This ~6-line vector projection in [`tree_skeleton_grow.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js) immediately gives `CedarOfLebanon`, `ScotsPine`, and `JapaneseMaple` authentic layered horizontal foliage pads.
404
- - `ventral_knockout`: Suppresses or rolls any lateral bud whose initial direction has $\hat{\mathbf{d}}_{\text{bud}} \cdot \mathbf{Y}_{\text{up}} < -\cos(\theta_{\text{knockout}})$.
405
- 2. **Optional World Obstacle Avoidance Using `meep`'s Existing SDFs & [`BVH`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/bvh2/bvh3/BVH.js):**
406
- Leveraging [`src/core/geom/3d/shape/sdf/`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/3d/shape/sdf/) and [`BVH`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/bvh2/bvh3/BVH.js), allow callers to pass optional obstacle volumes into `tree_skeleton_grow` alongside the existing self-avoidance BVH.
407
-
408
- ---
409
-
410
- ### Item 8: Optimal Cutout Hulls, Shoot-Proportional Card Spacing & Spine-Deformed Fronds
411
-
412
- #### How SpeedTree Works
413
- To minimize alpha-test pixel waste (`discard` in $2\times 2$ pixel quads) while preserving 3D volume:
414
- 1. SpeedTree's **Cutout Editor** fits a tight minimum-area $k$-vertex polygon around the non-transparent silhouette of each atlas sub-tile, split across a central midrib so the card can fold into a V-trough (`Fold`) and arch longitudinally (`Curl`).
415
- 2. Leaf/cluster count per branch scales proportionally with the branch's arc length (`Steps / Proportional`) so short shoots do not accumulate excessive overlapping cards.
416
- 3. The **`Frond` generator** extrudes ribbon strips directly along 3D curved skeleton spines.
417
-
418
- #### Current State in `meep`
419
- 1. **Fitted `CutoutHull` cards.** [`make_foliage_material.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/make_foliage_material.js) fits each variant tile's hull while it synthesizes the alpha ([`foliage_atlas_cutout_fit_tile`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/foliage_atlas_cutout.js#L26)), and reports the hulls in a [`FoliageAtlasCutout`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/FoliageAtlasCutout.js).
420
- - **Fitting.** Each covered texel row contributes the outer corners of its first and last texel with any alpha.
421
- [`convex_hull_monotone_2d`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/2d/convex-hull/convex_hull_monotone_2d.js)
422
- hulls those points.
423
- [`convex_hull_fixed_count_2d_relaxation`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js)
424
- reduces the hull to 6 vertices inside the tile, inset by half a texel, using its new `bounds` box.
425
- - **The card.** [`tree_mesh_build_foliage.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_foliage.js#L385-L421)
426
- fans the 6 vertices around a midrib vertex, turns each half about the midrib by the fold angle, and arches the card
427
- along its length.
428
- 2. **Card density follows the shoot.** [`foliage_collect_attachments.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/foliage_collect_attachments.js#L174-L182) gives each carrier its leafy length times [`foliage_cards_per_metre`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/foliage_card_density.js#L73) cards, rounded with a per-branch dither.
429
- - **The density** is the leaf that puts one leaf on every line of sight through the shoot's foliage sleeve, divided
430
- by the leaf each card carries (card size × measured atlas coverage × planes).
431
- - **Wind.** The joint mechanics use the same leaf area as the foliage's sail.
432
- - **No dead carriers.** Dead branches carry no cards.
433
- 3. **Cantilevered `RibbedFrond`:** `RibbedFrond` in [`tree_mesh_build_foliage.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_foliage.js#L349-L384) is a rigid cantilevered card with a fixed quadratic sag (`-0.14 * y_norm^2`) rather than following a skeleton spine.
434
-
435
- #### Landed (Tier 1, point 1)
436
- Points 1 and 2 below are done, with these differences from the proposal:
437
- - **Hulls.**
438
- - `make_foliage_material` fits each tile's hull while it synthesizes the atlas, and returns it in a
439
- `FoliageAtlasCutout`. `TreeAsset.foliage_cutout` keeps it, and the mesh builder takes it.
440
- - The hull holds every texel with any alpha, so there is no 0.1 threshold.
441
- - Clamping corners into the tile was measured to cut drawn texels (154 of 30,876 on maple). Instead, the relaxation
442
- solver gained a `bounds` box, and an unbounded fit is clipped to the tile when the greedy pass gets stuck. With
443
- that, no drawn texel lies outside its hull.
444
- - The midrib vertex sits on `u = anchor_u` at the hull's mean height, and the fold turns each half about it.
445
- - `OctagonalCutoutHull` is now `CutoutHull`.
446
- - **Density.** There is no reference length `L_ref`. The cards hold enough leaf that a line of sight through the
447
- shoot's foliage sleeve meets one leaf on average, which gives `pi sin(alpha) / (W s phi P)` cards per metre (see
448
- `FOLIAGE_DESIGN.md` §6.1). This uses the measured atlas coverage phi, and replaces `count` and `terminal_count`.
449
- Measured at seed 1337, 5b96446cc against now (with all of Tier 1), the card count changes per preset: oak 1013 →
450
- 842, pine 1584 → 694, spruce 1296 → 1191, maple 847 → 439, willow 682 → 1455. Pine's tri-star cards each stand up three planes of a tile with 0.17 leaf
451
- coverage, so it needs fewer of them. The wind rig's leaf drag uses the same leaf area.
452
-
453
- Point 3, spine-extruded fronds, is still open.
454
-
455
- #### Landed: Leaves on Annual Shoots
456
- The oak's cards were a median 0.90 m, each standing in for twigs the skeleton never grew. Each moved as one plate, so
457
- wind displaced large patches of the crown together. Now
458
- [`tree_skeleton_grow_shoots`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.js)
459
- grows the twig system on the generators named in `TreeSpeciesConfig.shoot_rules`, year by year, from Buck-Sorlin &
460
- Bell's oak demography (Forestry 73(1), 2000; Bot. J. Linn. Soc. 127, 1998):
461
- - **Outgrowth.** Each year a living axis extends its terminal bud. Last year's unit bursts its subapical and median
462
- buds.
463
- - **Lengths.** Unit lengths are drawn from the paper's distributions.
464
- - **Shedding.** `vigour / 2.65` of each year's shoots are kept.
465
- - **Leaves.** `foliage_collect_attachments` puts one card on each current-year unit
466
- (`TreeSkeleton.branch_current_growth_t`), drawing its leaves as a `rosette`.
467
-
468
- On the oak, 2,261 cards of about 0.17 m replace 842, on 2,158 current shoots, and the rig takes 5,703 joints where it
469
- took 447. See `ANNUAL_SHOOTS_BRIEF_2026_10_25.md` for the measurements, including the crown's lower opacity (side 0.49
470
- against 0.64).
471
-
472
- #### Evolutionary Path for `meep`
473
- 1. ~~**Per-variant cutout generation**~~: done (see "Landed"). The original proposal: **Wire [`convex_hull_fixed_count_2d_relaxation`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js) into Per-Variant Cutout Generation:**
474
- For each variant tile in the [`pack_max_rectangles`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/packing/max-rect/pack_max_rectangles.js) atlas, compute the 2D convex hull of opaque texels ($\alpha > 0.1$) via [`convex_hull_monotone_2d`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/2d/convex-hull/convex_hull_monotone_2d.js), reduce it to a 6-vertex bounding polygon via [`convex_hull_fixed_count_2d_relaxation`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js), clamp the resulting exterior vertices to the tile's padded UV box $[\epsilon, 1-\epsilon]^2$ (so ray-intersection hull vertices never bleed into adjacent atlas tiles), and fan the 6 perimeter vertices around the interior midrib vertex `v3 = (0.5, 0.52)` to preserve 3D V-trough folding (`lift`) and longitudinal arch (`camber`).
475
- 2. ~~**Shoot-proportional card count**~~: done, derived rather than scaled by a reference length (see "Landed"). The original proposal: **Scale `FoliageSpawnRule.count` by Shoot Arc Length (`b_len`) in `foliage_collect_attachments.js`:**
476
- Multiply lateral card count by $\text{clamp}(b_{\text{len}} / L_{\text{ref}}, 0.25, 1.5)$ so internode card density remains uniform across short and long twigs.
477
- 3. **Spine-Extruded Fronds:** Add a `build_spine_fronds` path in `tree_mesh_build_foliage.js` that extrudes a folded V-strip directly along the Hermite segments and RMF frames (`spine_u`, `spine_v`) of terminal `TreeSkeleton` branches.
478
-
479
- ---
480
-
481
- ### Item 9: Hierarchical 3D-to-2D Branch Cluster Atlas Synthesis (The #1 Visual & Performance Multiplier)
482
-
483
- #### Why This is the Single Biggest Visual Gap Between `meep` and SpeedTree
484
- Inspecting [`make_foliage_material.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/make_foliage_material.js#L145-L267) highlights both a major strength and the primary visual bottleneck of `meep`'s current canopy generation:
485
- - **What `make_foliage_material.js` already does well:** It packs $N_{\text{variants}}$ (4–8) tiles into an atlas using [`pack_max_rectangles`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/packing/max-rect/pack_max_rectangles.js) and varies **ontogenetic maturity** (`mu_k` $\in [0, 1]$ from juvenile apical flush on variant 0 to mature shaded basal leaves on variant $N-1$, modulating `juvenile_color_shift`, `juvenile_anthocyanin`, `ontogeny_shape_variation`, and `ontogeny_vein_contrast`).
486
- - **The Structural Bottleneck (`foliage_variant_leaflets`):** Every variant tile is synthesized by drawing a **perfectly straight vertical central line** (`stem_mask` along `lu = 0`) and placing 5 to 9 flat 2D SDF leaflets (`evaluate_leaflet`) symmetrically left and right in a single flat plane.
487
- - As a result, every tree species in `meep`—whether an `EnglishOak`, a `ScotsPine`, a `SilverBirch`, or a `WeepingWillow`—is constructed by attaching hundreds of small cards (`0.38m`–`0.55m`) textured with a **flat pinnate compound leaf stamp** onto thin `Level 2` and `Level 3` 3D cylinder twigs.
488
- - This creates two problems:
489
- 1. **Botanical Silhouette & Normal Flatness:** Oaks, birches, maples, beeches, and pines do not have straight pinnate compound leaves; they have forked woody branchlets carrying dozens of overlapping leaves or needle fascicles pitched and rolled at varied 3D angles.
490
- 2. **Polygon & Sub-Pixel Aliasing Overhead:** To make a crown look dense with small individual leaf stamps, `meep` must generate hundreds of thin `Level 2` and `Level 3` 3D bark tubes (`min_radius = 0.008m`–`0.015m`) that sub-pixel alias at medium camera distances and inflate triangle counts.
491
-
492
- #### How SpeedTree Solves This (`Export Material` / Branch Cluster Baking)
493
- In SpeedTree (v6–v10), a runtime tree only models `Level 0` (Trunk), `Level 1` (Primary Boughs), and `Level 2` (Secondary Limbs) as 3D tubular bark meshes. `Level 3` (Branchlets), `Level 4` (Twigs/Petioles), and `Level 5` (Individual 3D Leaves/Needles) are **generated as a 3D miniature sub-branch hierarchy** and **orthographically baked into the Foliage Atlas** (`Albedo+Alpha`, `Normal`, `ORM`).
494
-
495
- ```mermaid
496
- flowchart LR
497
- subgraph SUB["1. Procedural 3D Sub-Branch Cluster (In-Memory)"]
498
- B1["Main Twig Spine<br/>(Curved + Forked + Bark Textured)"]
499
- B2["2–4 Sub-Twigs & Buds<br/>(Phyllotactic Branching)"]
500
- L3["20–60 Oriented 3D Leaf/Needle Splats<br/>(Cambered, Folded, Pitch/Roll Varied)"]
501
- B1 --> B2 --> L3
502
- end
503
-
504
- subgraph BAKE["2. Tile-Local Float Z-Buffer Baker (make_foliage_material.js)"]
505
- ALB["Albedo + Alpha<br/>(Edge-Dilated RGB, Bark + Leaf Pigment)"]
506
- NRM["Tangent-Space Normal<br/>(3D Twig Cylinder + 3D Tilted Leaf Normals)"]
507
- ORM["ORM Texture<br/>(Inter-Leaf Depth AO + Roughness)"]
508
- end
509
-
510
- subgraph CARD["3. StandardShadeMaterial Cutout Card on Game Tree"]
511
- HULL["Tight 6+1 Vert Cutout Hull<br/>+ 3D V-Fold & Longitudinal Camber"]
512
- end
513
-
514
- SUB --> BAKE --> CARD
515
- ```
516
-
517
- #### Evolutionary Path for `meep`: Procedural 3D-to-2D Branch Cluster Synthesis into `StandardShadeMaterial`
518
- Without changing a single line of `StandardShadeMaterial` or `Shade`, `make_foliage_material.js` can be upgraded from a flat 2D pinnate leaf stamp to a **depth-buffered 3D Branch Cluster Baker**:
519
- 1. **Curved & Branched Woody Stem Network per Tile:** Instead of a straight line along `lu = 0`, grow a miniature 2-level sympodial twig network in tile space: a primary curved stem from `(0, -0.92)` to `(0, 0.85)` that spawns $3\text{–}6$ secondary lateral sub-twigs at species-appropriate insertion angles and phyllotaxis (`Alternate`, `Opposite`, `Fascicle/Needle-Bundle` for pine/cedar, `Pendulous Tress` for willow), shaded with the species' [`BarkMaterialConfig`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/config/BarkMaterialConfig.js) color, cylindrical normal profile, and roughness.
520
- 2. **Depth-Sorted 3D Leaf/Needle Splats (`Z-Buffer` Compositing):** Along the primary and secondary twigs, splat $15\text{–}45$ individual leaves (or $80\text{–}150$ pine needles in fascicle bundles for `ScotsPine` / `CedarOfLebanon`) using a per-tile float Z-buffer:
521
- - True depth ordering $z \in [-1, 1]$ and **inter-leaf drop-shadow / depth ambient occlusion** ($\text{AO}_{\text{cluster}}$ baked into `orm_bytes[i]` and `albedo`) where upper leaves overlap lower leaves or stems.
522
- - 3D tilted leaf normals ($\mathbf{n}_{\text{leaf}} = \mathbf{R}_{\text{pitch,roll}} \cdot \mathbf{n}_{\text{camber}}$) encoded directly into `normal_bytes`, so a single V-folded card catches directional sunlight across dozens of differently-angled leaves using `StandardShadeMaterial`'s standard normal-mapped BRDF.
523
-
524
- ---
525
-
526
- ### Item 10: Material Synthesis Within `StandardShadeMaterial`, Seasonal Abscission & Vertex Color Normalization
527
-
528
- #### Architectural Boundary: Fitting `StandardShadeMaterial`
529
- `meep`'s generator is designed to output standard [`StandardShadeMaterial`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/material/StandardShadeMaterial.js) instances (`transmission_factor = 0.0`, standard PBR `albedo`, `normal`, and `orm` textures, plus vertex color tint/AO). Any internal botanical properties computed during texture synthesis (such as the lamina height field that [`make_foliage_material.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/make_foliage_material.js#L290-L299) folds into ORM occlusion and the normal map, or the per-tile hull and leaf coverage it reports in `FoliageAtlasCutout`) remain generator-side data that can either be routed out by callers if needed later or folded into the synthesized `StandardShadeMaterial` textures (`albedo` / `orm` ambient & roughness channels).
530
-
531
- Within that clean `StandardShadeMaterial` contract, [`make_foliage_material.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/make_foliage_material.js#L212-L266) and [`foliage_collect_attachments.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/foliage_collect_attachments.js#L511-L536) implement two things:
532
- - a 3-stage biochemical autumn pigment model: `senescence` $\in [0, 1]$ drives chlorophyll degradation $\rightarrow$
533
- `carotenoid_density` gold $\rightarrow$ `anthocyanin_potential` crimson $\rightarrow$ `tannin_oxidation` brown;
534
- - leaf abscission and dryness from the same `senescence`
535
- ([`foliage_senescence.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/foliage_senescence.js)).
536
-
537
- The per-card `tints` (with `tint_scale`) are carried into vertex colours, and those are preserved through [`tree_mesh_apply_canopy_ao.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_apply_canopy_ao.js#L76-L80) (`preserve_existing_color: true`).
538
-
539
- #### Landed (Tier 1, point 3)
540
- Both upgrades below are done, with these differences from the proposal:
541
- - **Abscission onset is derived.** It is not an authored $[0.5, 1]$ window. Each leaf waits for its own atlas tile.
542
- - **The onset.** The pigment model ages each tile at its own pace, and its exposed lamina is bare of chlorophyll at
543
- $\sigma_0(\mu)$: 0.66 for mature tiles, up to 0.82 for mid-maturity ones (`foliage_variant_abscission_onset`).
544
- - **The threshold.** After that, a card's threshold in $[\sigma_0(\mu), 1]$ comes from its exposure order: sun
545
- exposure combined with apical position on its shoot.
546
- - **History.** `f47a0516f` used one onset of 1/1.36 for every tile. It dried 404 of 444 maple leaves at senescence
547
- 0.7 while their tiles were still green; `82bfadfb9` fixed it.
548
- - **Measured.** On maple (seed 5), 33% of cards are left at 0.9 and none at 0.97. The survivors are the shaded
549
- interior and the basal leaves.
550
- - The joint mechanics shed the same leaves, so a bare maple's summed joint compliance falls by more than 20%.
551
- - **Wilt is the turgor-loss limit.** It is not a tuned increment. A card's dryness, rising from its tile's onset to its
552
- fall, takes it towards a leaf with no turgor: fold towards 90°, arch to 0, droop to 1.
553
- - It falls before it arrives. Just before, it is a valid sliver.
554
- - Only folding cards wilt (`FoldedVCard`, `RibbedFrond`, `CutoutHull`); `CrossCard` and `TriStarCluster` have
555
- no fold.
556
- - **Colour headroom goes through the material.** The texture is not rebaked. Card tints are computed in
557
- `foliage_collect_attachments` and are no longer clamped to 1; about half of all tint channels exceed it.
558
- - Vertex colours carry `tint / tint_scale`, with `tint_scale` the largest channel (about 1.1).
559
- - The synthesized material's `diffuse_color`, the shader's `albedo_color`, carries `tint_scale` back. This is exact
560
- and needs no renderer change.
561
- - A caller's own material is left alone, and its tints stay clamped.
562
- - The tint model's coefficients are unchanged; no new colour maths was added.
563
-
564
- #### Original Proposal (both done, see "Landed")
565
- 1. ~~**Seasonal Abscission (Leaf Drop) & 3D Geometric Wilt/Curl**~~:
566
- Before Tier 1, when `senescence` approaches $1.0$, [`make_foliage_material.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/make_foliage_material.js) shifts leaf pigment to brown tannin, but the tree retains $100\%$ of its summer leaf card count and card geometry.
567
- - **Upgrade:** In [`foliage_collect_attachments.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/foliage_collect_attachments.js), apply a deterministic abscission retention curve as `senescence` increases in $[0.5, 1.0]$ (shedding outer/apical leaves first to expose bare late-autumn/winter branch structure), and in [`tree_mesh_build_foliage.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_foliage.js#L278-L285), progressively increase 3D card `fold_angle` and `camber_droop` with `senescence` to simulate dry leaf curling and shriveling.
568
- 2. ~~**Avoiding the `unorm8` Vertex Color Darkening Ceiling**~~:
569
- Before Tier 1, in `tree_mesh_build_foliage.js`, per-card color multipliers `r_col, g_col, b_col` start at `1.0 + c_jit` and were clamped to $[0.68, 1]$, on top of the $[0, 1]$ saturation when encoded into `unorm8x3` (`StandardAttributes.Color` via [`encode_colors_to_u32.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/geometry/encode_colors_to_u32.js#L16-L28)) before being multiplied by canopy AO in [`tree_mesh_apply_canopy_ao.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_apply_canopy_ao.js). Because `unorm8` cannot represent values $> 1.0$, `out.albedo = albedo * s.vertex_color` can only *darken* the synthesized texture.
570
- - **Upgrade:** Bake the mean baseline brightness $+10\%$ higher into `albedo_bytes` in `make_foliage_material.js` and anchor sunlit apical cards at `1.0` in `tree_mesh_build_foliage.js` so `vertex_color` modulation spans the full dynamic range without darkening the crown.
571
-
572
- ---
573
-
574
- ### Item 11: GPU Skinning Cache Architecture (`GPUMeshSkinningContext` + `FoliageWindRig`)
575
-
576
- #### Why `meep`'s GPU Skinning Cache Supersedes SpeedTree's Vertex-Shader Wind
577
- SpeedTree's stateless vertex-shader wind (`SpeedTreeWind`) was designed for a rendering era where geometry only needed to be deformed once during rasterization. In a modern engine like `Shade`, vertex-shader-only deformation breaks visibility-buffer meshlet culling, temporal motion vectors, and hardware ray-traced BLAS refitting.
578
-
579
- `meep` instead uses a **Northlight-style GPU Skinning Cache** architecture:
580
- 1. **3D Fluid-Coupled Aeroelastic Solver:** [`shader_foliage_wind_apply.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/animation/foliage/shader_foliage_wind_apply.js) samples the 3D [`GPUSceneWind`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/wind/GPUSceneWind.js) fluid cascade stack at each bone's world position and advances a stateful 2nd-order damped harmonic oscillator with Strouhal vortex shedding ([`chunk_foliage_wind_step.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.js)).
581
- 2. **Unified Compute Skinning Cache & Bounds/BLAS Pipeline:** [`GPUMeshSkinningContext.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js) runs [`shader_meshlet_apply_skinning.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/animation/skinning/shader_meshlet_apply_skinning.js) to deform meshlet vertices into the skinning cache, writes `prev_positions` for TAAU motion vectors, executes the 4-stage GPU meshlet/entity bounds refresh (`shader_meshlet_bounds_reduce` $\rightarrow$ `shader_skinned_mesh_bounds_refresh`), and dispatches `GPUBLASRefitBatch`.
582
-
583
- #### Landed: Joint Stiffness From Beam Mechanics (`00807d697`)
584
- A joint's sway used to come from its branching level, through `TreeWindConfig.trunk_compliance` / `branch_compliance` / `natural_frequency`. Bare stubs, which have no sail, swayed like leafy boughs. Now each joint's parameters come from the wood:
585
- - **Beam elements.** [`tree_skeleton_compute_segment_mechanics`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js#L81) treats each skeleton segment as an Euler–Bernoulli beam element. It carries the drag of its bark ($C_d = 1.2$) and leaf cards ($C_d = 0.4$), and the mass of green wood and fresh leaves. A lateral loads the parent segment it hangs from.
586
- - **Joint parameters.** [`tree_skeleton_compute_joint_mechanics`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js) integrates the drag moment over the flexibility $dx / (E I)$ of the span each joint rotates. That gives the joint's compliance. Its natural frequency is its branch's first mode: the single-degree-of-freedom $\sqrt{K / J}$ of the whole branch under its own weight, with everything it carries ([`tree_skeleton_compute_branch_frequency`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js)). Every joint on a branch shares it and the branch's phase, so the branch sways as one piece however many joints it has.
587
- - **Material.** One `TreeWindConfig.elastic_modulus` replaces the per-level knobs. It was 2.42e8 Pa effective, and was
588
- refitted to 3.33e7 when the foliage sail became the derived leaf area (Item 8), so the oak's boughs keep their sway.
589
- It was refitted again, to 4.55e7, when each segment began to bend under its own drag and weight and the oak grew its
590
- twig layer.
591
- - **Joint selection.** Superseded by a derived joint count (next section).
592
- - **Drag law.** [`chunk_foliage_wind_step`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.js) drags with the dynamic pressure, deflection $0.5 \cdot \text{compliance} \cdot v^2$.
593
-
594
- #### Landed: Joint Count Derived From the Tree
595
- The rig used to fill a fixed budget of 32 joints. Now [`tree_skeleton_assign_skin_joints`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.js) places joints where the rig would otherwise hide visible sway:
596
- - **Bends.** Each segment bends by its share of its branch's bend in the wind the wood is fitted to (`TREE_WIND_REFERENCE_SPEED`, 6.5 m/s). Bends are taken as the rig shows them: `tree_wind_bend_limit` saturates them, as `chunk_foliage_wind_step` does.
597
- - **Hidden sway.** A branch without a joint loses its bending, and a bend $\theta$ moves what the segment carries by up to $\theta \cdot \text{reach}$. A joint rotates its whole span about one pivot, so a bend at distance $x$ along the span lands $\theta x$ off. Walking each branch from its base, a joint goes wherever either error would pass the tolerance.
598
- - **Tolerance.** One distance in metres, `TreeWindConfig.deflection_tolerance` (default 0.01, a chosen number). Stiff or bare wood takes few joints and slender leafy wood many, and a tall tree, whose bends move more, takes more than a small one.
599
- - **Counts (seed 1337, 1 cm).** Oak 447, pine 517, birch 185, willow 514, maple 311, spruce 416, palm 65, shrub 46 and fern 26. With the oak's twig layer and the self-load (Item 8, "Leaves on Annual Shoots"): oak 5,703, pine 544, birch 185, willow 513, maple 332, spruce 435, palm 65, shrub 54 and fern 24. Oak takes 234 at 4 cm and 609 at 2.5 mm. With wood 10x stiffer it takes 187, and at 100x it takes 1, which leaves no joint that moves.
600
- - **Cap.** `max_joints` defaults to 16,384 and only catches a runaway skeleton. Past it, the joints that keep the least sway are dropped. 16,384 is a chosen number above every preset's skeleton node count, the oak's 9,860 included.
601
- - **Sway is shared out, not added.** A branch's joint compliances sum to its own bend however many joints it gets, so `elastic_modulus` keeps its fit.
602
- - **Seams.** Skinning has 4 weights per vertex. Where a child branch or a leaf card sits on a frustum whose rings hold more than 4 joints between them, each joint past the fourth now hands its weight to the kept joint nearest it in the joint tree. In a steady 6.5 m/s pose, the widest seam the bark specs find went from 1.05 to 0.74 mm, and on leaf cards from 0.81 to 0.39 mm. The specs bound it by `deflection_tolerance`.
603
-
604
- #### Cleaning Up Generator Baggage & Advancing the Skinning Cache Pipeline
605
- Inspecting the boundary between `src/generation/foliage` and `GPUMeshSkinningContext` reveals three clean improvements that reinforce this architecture:
606
-
607
- 1. **Remove Dead `uv1` Writes from [`tree_mesh_build_bark.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_bark.js#L796-L797) and [`tree_mesh_build_foliage.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_foliage.js#L204-L205):**
608
- Both mesh builders still allocate `StandardAttributes.TextureCoordinates1` (`uv1`) and fill it with `[sway_weight, wind_phase]`. In `Shade`, `uv1` is reserved for lightmaps, and `shader_meshlet_apply_skinning.js` never reads it. Removing those dead `uv1` writes from both builders saves per-vertex attribute storage and leaves `uv1` for lightmapping alone.
609
- 2. ~~**Deeper Skeletal Rig Granularity for Outer Limbs & Fronds**~~: done, with the count derived rather than raised (see "Landed: Joint Count Derived From the Tree"). The original proposal:
610
- [`tree_skeleton_assign_skin_joints.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.js#L36) still caps the joints at `TreeWindConfig.max_joints = 32`. The budget now goes to the boughs that sway most, but all distal `Level 2`/`Level 3` shoots and foliage cards still move rigidly with their parent bough's joint. Because `GPUMeshSkinningContext` and `shader_foliage_wind_apply.js` operate on arbitrary joint counts per rig (`FoliageWindRig.joint_count`), raising `max_joints` (e.g., to `64–128` for hero `LOD0` trees) and assigning joints to distal sub-branch clusters allows outer canopy shoots and spine-extruded fronds to exhibit independent high-frequency aeroelastic oscillation and vortex shedding directly through the standard Dual-Quaternion skinning cache.
611
- 3. **Shared Skinning Cache Archetype Pooling for Large Forests:**
612
- In [`GPUMeshSkinningContext.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js#L410-L429), `obtain_clone(entity, geometry)` currently allocates a 1-to-1 skinning cache entry per `SkinnedMesh` entity. For large forests ($1,000+$ trees), allowing multiple mid/far-field `SkinnedMesh` instances bound to the same archetype `(skin_id, source_geometry)` to reference a shared ref-counted skinning cache clone lets `shader_meshlet_apply_skinning`, meshlet bounds reduction, and `GPUBLASRefitBatch` run once per animated archetype ($K = 4\text{–}8$ per species) while every instance still benefits from hardware-accelerated meshlet culling, shadows, and ray tracing.
613
-
614
- ---
615
-
616
- ### Item 12: LOD Pipeline, Mipmap Alpha Coverage, `VirtualGeometry` & Octahedral Impostors
617
-
618
- #### Historical Unwinding of SpeedTree LODs
619
- 1. **Discrete 3D Thinning + Compensatory Leaf Scaling:** Dropping smaller twigs and culling a fraction of leaf cards while scaling surviving cards up to preserve optical canopy density.
620
- - *Already in `meep`:* [`tree_mesh_build_foliage.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_foliage.js#L63-L77) and [`TreeLODConfig.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/config/TreeLODConfig.js#L43) already implement golden-ratio rank filtering (each card's `ranks` entry from [`foliage_collect_attachments.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/foliage_collect_attachments.js#L496), kept while below `foliage_keep_ratio`) and compensatory area scaling (`Math.pow(keep_ratio, -area_compensation_exponent)`).
621
- 2. **Mipmap Alpha Coverage Preservation (Castano 2010 / SpeedTree):** Scaling alpha values in higher mip levels of `albedo_texture` so the fraction of texels above the alpha test threshold ($0.5$) stays constant with distance, preventing distant alpha-tested canopies from thinning out.
622
- 3. **Hemi-Octahedral Impostors (v8–v10):** Baking an $M \times M$ upper-hemisphere octahedral atlas for horizon trees ($d > 100\text{ m}$).
623
-
624
- #### Current State in `meep`
625
- 1. **Static Spawn-Time LOD Selection:** [`generate_tree.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/asset/generate_tree.js#L88-L106) builds `LOD0..LOD3`, but [`place_tree.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/asset/place_tree.js#L56-L66) selects a single `const lod_index = opts.lod ?? 0` at placement time.
626
- 2. **Mipmap Coverage Loss:** [`make_foliage_material.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/make_foliage_material.js#L98-L120) dilates leaf RGB into transparent background pixels (which prevents dark bilinear fringes), but standard mipmap box filtering averages $A = 0$ background pixels with $A = 1$ leaf pixels, causing distant trees to lose canopy volume at high mip levels.
627
- 3. **Unused Engine Primitives (`VirtualGeometry` & Octahedral Math):**
628
- - `meep` has a full Nanite-style cluster DAG builder in [`vgeo_build.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/geometry/virtual/build/vgeo_build.js) that can simplify opaque `bark_geometry`.
629
- - `meep` already provides `y`-pole octahedral parameterization in [`octahedral_direction_to_uv.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/3d/octahedra/octahedral_direction_to_uv.js) and [`octahedral_uv_to_direction.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/3d/octahedra/octahedral_uv_to_direction.js).
630
-
631
- #### Evolutionary Path for `meep`
632
- 1. **Step 1 (Mipmap Alpha Coverage Preservation in `make_foliage_material.js`):**
633
- Generate custom coverage-preserving mip levels for the foliage `albedo_texture` (searching via 8-step binary search per mip level for the alpha multiplier $s_m$ that preserves the $LOD_0$ coverage fraction above $\alpha = 0.5$). This works 100% within `StandardShadeMaterial` and [`viz_rasterization_alpha_tested_pass_descriptor.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.js).
634
- 2. **Step 2 (Runtime Distance LOD Switching for `TreeAsset.lods`):**
635
- Allow placed trees to switch across `TreeAsset.lods[0..3]` based on camera distance / screen-space projected sphere radius.
636
- 3. **Step 3 (`VirtualGeometry` Bark + Octahedral Impostor Baking):**
637
- Optionally feed static/distant `bark_geometry` into [`vgeo_build.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/geometry/virtual/build/vgeo_build.js), and use [`octahedral_uv_to_direction`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/3d/octahedra/octahedral_uv_to_direction.js) to bake multi-view impostor atlases into a standard `StandardShadeMaterial` card for extreme horizon distances.
638
-
639
- ---
640
-
641
- ## 5. Summary Prioritized Roadmap for `meep`
642
-
643
- ```mermaid
644
- flowchart TD
645
- subgraph T1["Tier 1: Immediate Generator Wins (Zero Engine/Material Changes)"]
646
- direction LR
647
- T1_A["1. DONE: Fitted Cutout Hulls<br/>& Derived Card Density"]
648
- T1_B["2. DONE: Plagiotropism (Planar Tiers),<br/>Derived Ventral Knockout & Straightness"]
649
- T1_C["3. DONE: Seasonal Abscission, Wilt<br/>& Tint Headroom"]
650
- T1_D["4. Remove Dead uv1 Writes & Preserve<br/>Mipmap Alpha Coverage"]
651
- end
652
-
653
- subgraph T2["Tier 2: Major Visual & Topological Generator Upgrades"]
654
- direction LR
655
- T2_A["5. Procedural 3D-to-2D Branch Cluster<br/>Baker in make_foliage_material.js"]
656
- T2_B["6. Watertight Symmetric Trouser-Saddle<br/>Bifurcation (branch_fork_triangulate)"]
657
- T2_C["7. DONE: Generator Graph<br/>(3D Roots, Sprouts, Self-Pruned Stubs, Inter-Whorls)"]
658
- T2_D["8. Spine-Extruded Fronds Along<br/>Terminal TreeSkeleton Branches"]
659
- end
660
-
661
- subgraph T3["Tier 3: Forest Scale & Environment Integration"]
662
- direction LR
663
- T3_A["9. Deeper Aeroelastic Rig Granularity &<br/>Shared Skinning Cache Archetype Pool"]
664
- T3_B["10. Substrate/Obstacle BVH & SDF<br/>Root Crawling & Canopy Avoidance"]
665
- T3_C["11. Runtime LOD Switching, VirtualGeometry<br/>Bark & Octahedral Horizon Impostors"]
666
- end
667
-
668
- T1 --> T2 --> T3
669
- ```
670
-
671
- ### Tier 1: Immediate Generator Wins (Zero Renderer or Material Changes)
672
- 1. **Done:** fitted, tile-bounded hulls and a derived card density (see Item 8, "Landed"). The original proposal follows. **Replace Hardcoded `OCTAGON_HULL_UV` with [`convex_hull_fixed_count_2d_relaxation`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js) & Scale Card Count by Shoot Length:**
673
- Automatically fit tile-clamped 6-vertex exterior hulls (fanned around interior midrib vertex `v3`) to each variant tile in [`make_foliage_material.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/make_foliage_material.js), and scale `FoliageSpawnRule.count` by shoot arc length `b_len` in [`foliage_collect_attachments.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/foliage_collect_attachments.js#L174-L182) to slash alpha-test overdraw.
674
- 2. **Done:** `plagiotropism`, with ventral knockout derived from it, and `straightness`; `tip_upcurl` is the existing apical curl (see Items 3 and 7, "Landed"). The original proposal follows. **Add `plagiotropism` (Horizontal Pad Flattening), `ventral_knockout`, `straightness`, and `tip_curl` to [`tree_skeleton_grow.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/skeleton/tree_skeleton_grow.js):**
675
- Transforms conifer, cedar, and maple silhouettes into authentic horizontal foliage tiers, culls downward-growing underside twigs, prevents noisy branches from wandering off-heading, and adds upturned bough tips.
676
- 3. **Done:** abscission, wilt and tint headroom (see Item 10, "Landed"). The original proposal follows. **Add Seasonal Abscission (Leaf Drop), Senescent 3D Wilt/Curl & Vertex Color Normalization:**
677
- Couple `senescence` $\in [0, 1]$ in [`foliage_collect_attachments.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/foliage_collect_attachments.js) and [`tree_mesh_build_foliage.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_foliage.js) to progressive leaf shedding and dry card curling, and normalize vertex color tint so `unorm8` clamping does not darken the crown.
678
- 4. **Remove Dead `uv1` Attribute Writes & Add Mipmap Alpha Coverage Preservation:**
679
- Stop writing unused `[sway_weight, wind_phase]` data into lightmap channel `uv1` (`StandardAttributes.TextureCoordinates1`) in [`tree_mesh_build_bark.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_bark.js#L796-L797) and [`tree_mesh_build_foliage.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/mesh/tree_mesh_build_foliage.js#L204-L205), and preserve alpha coverage across mipmap levels of `albedo_texture`.
680
-
681
- ### Tier 2: Major Visual & Topological Generator Upgrades
682
- 5. **Upgrade [`make_foliage_material.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/generation/foliage/material/make_foliage_material.js) to a Procedural 3D-to-2D Branch Cluster Baker:**
683
- Replace the straight-line 5-leaflet SDF stamp with a depth-buffered, multi-twig + 3D-tilted leaf/needle cluster baker with inter-leaf depth AO and bark-textured stems outputting directly to `StandardShadeMaterial`.
684
- 6. **Watertight Trouser-Saddle Bifurcation (`branch_fork_triangulate`):**
685
- Replace the asymmetric side-collar split (`is_split_fork` attached at `t_curr < 1.0`) with a symmetric Y-saddle trouser triangulation across a 2-vertex crotch bridge.
686
- 7. ~~**Structural Branch Roles**~~: **done** (`00807d697`, `2f4465170`, `28ef51f1b`) as a generator graph (`branches` + `branch_rules` + `foliage_rules`). It grows **3D structural surface roots** on the `flare_lobes` crests, **conifer inter-whorl branches** and **epicormic trunk sprouts**. **Dead lower stubs** and **bark knots** follow from `self_pruning`. See Item 1.
687
- 8. **Spine-Extruded Fronds Along Terminal `TreeSkeleton` Branches:**
688
- Extrude `RibbedFrond` strips directly along terminal skeleton spines (`spine_u`, `spine_v`) so palms, ferns, and weeping willow tresses bend organically under gravity and skeletal wind.
689
-
690
- ### Tier 3: Forest Scale & Environment Integration
691
- 9. **Deeper Aeroelastic Rig Granularity & Shared Skinning Cache Archetype Pooling:**
692
- Joint stiffness, frequency and the number of joints now come from beam mechanics (Item 11), so distal twigs animate through `FoliageWindRig`. What remains is to support shared ref-counted `(skin_id, source_geometry)` skinning cache clones in [`GPUMeshSkinningContext.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js) for large forests.
693
- 10. **Substrate & Obstacle Crawling/Avoidance** (surface roots exist and creep along `y = 0`, see Item 6) **via [`BVH`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/bvh2/bvh3/BVH.js), [`bt_mesh_find_nearest_face`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/3d/topology/struct/binary/query/bt_mesh_find_nearest_face.js), and [`src/core/geom/3d/shape/sdf/`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/3d/shape/sdf/).**
694
- 11. **Runtime LOD Switching, [`vgeo_build.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/geometry/virtual/build/vgeo_build.js) Bark Integration & Octahedral Horizon Impostors (via [`src/core/geom/3d/octahedra/`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/core/geom/3d/octahedra/)).**