@woosh/meep-engine 3.58.0 → 3.59.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (609) hide show
  1. package/editor/particles/effect/ParticleEffectDocument.d.ts +162 -43
  2. package/editor/particles/effect/ParticleEffectDocument.d.ts.map +1 -1
  3. package/editor/particles/effect/ParticleEffectDocument.js +450 -43
  4. package/editor/particles/effect/ParticleReferenceSimulation.d.ts +12 -3
  5. package/editor/particles/effect/ParticleReferenceSimulation.d.ts.map +1 -1
  6. package/editor/particles/effect/ParticleReferenceSimulation.js +78 -23
  7. package/editor/particles/effect/make_starter_particle_effect.js +17 -17
  8. package/editor/view/particles/effect/ParticleEmitterInspectorView.d.ts +3 -3
  9. package/editor/view/particles/effect/ParticleEmitterInspectorView.d.ts.map +1 -1
  10. package/editor/view/particles/effect/ParticleEmitterInspectorView.js +224 -67
  11. package/editor/view/particles/effect/ParticleGraphEditorView.d.ts.map +1 -1
  12. package/editor/view/particles/effect/ParticleGraphEditorView.js +44 -11
  13. package/editor/view/particles/effect/ParticleNodeParametersView.d.ts +2 -1
  14. package/editor/view/particles/effect/ParticleNodeParametersView.d.ts.map +1 -1
  15. package/editor/view/particles/effect/ParticleNodeParametersView.js +46 -16
  16. package/editor/view/particles/effect/ParticlePreviewView.js +2 -2
  17. package/editor/view/particles/effect/particle-editor.css +77 -68
  18. package/package.json +1 -1
  19. package/src/engine/Engine.d.ts.map +1 -1
  20. package/src/engine/Engine.js +2 -2
  21. package/src/engine/ecs/EntityManager.d.ts +29 -5
  22. package/src/engine/ecs/EntityManager.d.ts.map +1 -1
  23. package/src/engine/ecs/EntityManager.js +37 -1
  24. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  25. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +4 -0
  26. package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts +74 -17
  27. package/src/engine/graphics/ecs/particles/ParticleEffect.d.ts.map +1 -1
  28. package/src/engine/graphics/ecs/particles/ParticleEffect.js +156 -25
  29. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.d.ts +13 -3
  30. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.d.ts.map +1 -1
  31. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationAdapter.js +59 -13
  32. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_1_2.d.ts +3 -3
  33. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_1_2.js +9 -9
  34. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_2_3.d.ts +15 -0
  35. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_2_3.d.ts.map +1 -0
  36. package/src/engine/graphics/ecs/particles/ParticleEffectSerializationUpgrader_2_3.js +78 -0
  37. package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts +2 -0
  38. package/src/engine/graphics/ecs/trail3d/Trail3D.d.ts.map +1 -1
  39. package/src/engine/graphics/ecs/trail3d/Trail3D.js +2 -0
  40. package/src/engine/graphics/ecs/trail3d/seed_trail_stroke.js +1 -1
  41. package/src/engine/graphics/ecs/trail3d/seed_trail_tube.js +1 -1
  42. package/src/engine/graphics/trail/tube/TubeX.d.ts +5 -3
  43. package/src/engine/graphics/trail/tube/TubeX.d.ts.map +1 -1
  44. package/src/engine/graphics/trail/tube/TubeX.js +5 -3
  45. package/src/engine/graphics/trail/tube/tube_attributes_spec.d.ts +3 -2
  46. package/src/engine/graphics/trail/tube/tube_attributes_spec.d.ts.map +1 -1
  47. package/src/engine/graphics/trail/tube/tube_attributes_spec.js +9 -8
  48. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts +65 -4
  49. package/src/engine/graphics3/GPUParticleEmitterSystem.d.ts.map +1 -1
  50. package/src/engine/graphics3/GPUParticleEmitterSystem.js +1351 -904
  51. package/src/engine/graphics3/trail/trail_tube_write_geometry.d.ts +1 -1
  52. package/src/engine/graphics3/trail/trail_tube_write_geometry.js +13 -13
  53. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  54. package/src/generation/foliage/FOLIAGE_DESIGN.md +26 -5
  55. package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +35 -0
  56. package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +2 -1
  57. package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +552 -0
  58. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts.map +1 -1
  59. package/src/generation/foliage/analysis/tree_crown_opacity.js +2 -1
  60. package/src/generation/foliage/analysis/tree_render_cost.d.ts +5 -3
  61. package/src/generation/foliage/analysis/tree_render_cost.d.ts.map +1 -1
  62. package/src/generation/foliage/analysis/tree_render_cost.js +8 -7
  63. package/src/generation/foliage/asset/TreeAsset.d.ts +17 -0
  64. package/src/generation/foliage/asset/TreeAsset.d.ts.map +1 -1
  65. package/src/generation/foliage/asset/TreeAsset.js +20 -0
  66. package/src/generation/foliage/asset/TreeSpeciesCache.d.ts +69 -0
  67. package/src/generation/foliage/asset/TreeSpeciesCache.d.ts.map +1 -0
  68. package/src/generation/foliage/asset/TreeSpeciesCache.js +147 -0
  69. package/src/generation/foliage/asset/generate_tree.d.ts +10 -0
  70. package/src/generation/foliage/asset/generate_tree.d.ts.map +1 -1
  71. package/src/generation/foliage/asset/generate_tree.js +57 -29
  72. package/src/generation/foliage/asset/place_tree.d.ts +2 -1
  73. package/src/generation/foliage/asset/place_tree.d.ts.map +1 -1
  74. package/src/generation/foliage/asset/place_tree.js +2 -1
  75. package/src/generation/foliage/asset/tree_lod_plan.d.ts +4 -2
  76. package/src/generation/foliage/asset/tree_lod_plan.d.ts.map +1 -1
  77. package/src/generation/foliage/asset/tree_lod_plan.js +12 -14
  78. package/src/generation/foliage/asset/tree_shoot_instances.d.ts +119 -0
  79. package/src/generation/foliage/asset/tree_shoot_instances.d.ts.map +1 -0
  80. package/src/generation/foliage/asset/tree_shoot_instances.js +410 -0
  81. package/src/generation/foliage/asset/tree_shoot_prototypes.d.ts +155 -0
  82. package/src/generation/foliage/asset/tree_shoot_prototypes.d.ts.map +1 -0
  83. package/src/generation/foliage/asset/tree_shoot_prototypes.js +251 -0
  84. package/src/generation/foliage/config/TreeGrowth.d.ts +10 -0
  85. package/src/generation/foliage/config/TreeGrowth.d.ts.map +1 -0
  86. package/src/generation/foliage/config/TreeGrowth.js +18 -0
  87. package/src/generation/foliage/config/TreeLODConfig.d.ts +6 -0
  88. package/src/generation/foliage/config/TreeLODConfig.d.ts.map +1 -1
  89. package/src/generation/foliage/config/TreeLODConfig.js +7 -0
  90. package/src/generation/foliage/index.d.ts +3 -0
  91. package/src/generation/foliage/index.js +3 -0
  92. package/src/generation/foliage/material/foliage_tile.d.ts +6 -6
  93. package/src/generation/foliage/material/foliage_tile.js +3 -3
  94. package/src/generation/foliage/material/tree_cluster_atlas.d.ts +44 -0
  95. package/src/generation/foliage/material/tree_cluster_atlas.d.ts.map +1 -0
  96. package/src/generation/foliage/material/tree_cluster_atlas.js +37 -0
  97. package/src/generation/foliage/mesh/foliage_collect_attachments.js +2 -2
  98. package/src/generation/foliage/mesh/foliage_scale_spread.d.ts +14 -0
  99. package/src/generation/foliage/mesh/foliage_scale_spread.d.ts.map +1 -0
  100. package/src/generation/foliage/mesh/foliage_scale_spread.js +15 -0
  101. package/src/generation/foliage/mesh/tree_cluster_representatives.d.ts +8 -7
  102. package/src/generation/foliage/mesh/tree_cluster_representatives.d.ts.map +1 -1
  103. package/src/generation/foliage/mesh/tree_cluster_representatives.js +85 -40
  104. package/src/generation/foliage/mesh/tree_clusters.d.ts +26 -5
  105. package/src/generation/foliage/mesh/tree_clusters.d.ts.map +1 -1
  106. package/src/generation/foliage/mesh/tree_clusters.js +52 -39
  107. package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
  108. package/src/generation/foliage/mesh/tree_mesh_build_bark.js +32 -54
  109. package/src/generation/foliage/presets/make_tree_species_preset.d.ts +6 -1
  110. package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
  111. package/src/generation/foliage/presets/make_tree_species_preset.js +157 -3
  112. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts +19 -0
  113. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts.map +1 -1
  114. package/src/generation/foliage/skeleton/TreeSkeleton.js +41 -0
  115. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts +5 -0
  116. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts.map +1 -1
  117. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js +8 -1
  118. package/src/generation/foliage/skeleton/tree_skeleton_copy_branches.d.ts +70 -0
  119. package/src/generation/foliage/skeleton/tree_skeleton_copy_branches.d.ts.map +1 -0
  120. package/src/generation/foliage/skeleton/tree_skeleton_copy_branches.js +171 -0
  121. package/src/generation/foliage/skeleton/tree_skeleton_extend_branch.d.ts +17 -0
  122. package/src/generation/foliage/skeleton/tree_skeleton_extend_branch.d.ts.map +1 -0
  123. package/src/generation/foliage/skeleton/tree_skeleton_extend_branch.js +79 -0
  124. package/src/generation/foliage/skeleton/tree_skeleton_fit_crown_frame.d.ts +12 -0
  125. package/src/generation/foliage/skeleton/tree_skeleton_fit_crown_frame.d.ts.map +1 -0
  126. package/src/generation/foliage/skeleton/tree_skeleton_fit_crown_frame.js +56 -0
  127. package/src/generation/foliage/skeleton/tree_skeleton_floor_girth.d.ts +11 -0
  128. package/src/generation/foliage/skeleton/tree_skeleton_floor_girth.d.ts.map +1 -0
  129. package/src/generation/foliage/skeleton/tree_skeleton_floor_girth.js +38 -0
  130. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts +4 -11
  131. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
  132. package/src/generation/foliage/skeleton/tree_skeleton_grow.js +8 -2034
  133. package/src/generation/foliage/skeleton/tree_skeleton_grow_framework.d.ts +22 -0
  134. package/src/generation/foliage/skeleton/tree_skeleton_grow_framework.d.ts.map +1 -0
  135. package/src/generation/foliage/skeleton/tree_skeleton_grow_framework.js +2050 -0
  136. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts +10 -0
  137. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts.map +1 -1
  138. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.js +27 -56
  139. package/src/shade/descriptor/pipeline/render/DepthStencilState.d.ts +4 -0
  140. package/src/shade/descriptor/pipeline/render/DepthStencilState.d.ts.map +1 -1
  141. package/src/shade/descriptor/pipeline/render/DepthStencilState.js +170 -144
  142. package/src/shade/descriptor/pipeline/render/MultisampleState.d.ts +4 -0
  143. package/src/shade/descriptor/pipeline/render/MultisampleState.d.ts.map +1 -1
  144. package/src/shade/descriptor/pipeline/render/MultisampleState.js +78 -65
  145. package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.d.ts.map +1 -1
  146. package/src/shade/descriptor/pipeline/render/RenderPipelineDescriptor.js +176 -172
  147. package/src/shade/descriptor/pipeline/render/StencilFaceState.d.ts +4 -0
  148. package/src/shade/descriptor/pipeline/render/StencilFaceState.d.ts.map +1 -1
  149. package/src/shade/descriptor/pipeline/render/StencilFaceState.js +107 -88
  150. package/src/shade/playground/particle_ecs/README.md +9 -8
  151. package/src/shade/playground/particle_ecs/bonfire_editor.js +3 -3
  152. package/src/shade/playground/particle_ecs/bonfire_effects.d.ts +6 -6
  153. package/src/shade/playground/particle_ecs/bonfire_effects.js +6 -6
  154. package/src/shade/playground/particle_editor/README.md +14 -11
  155. package/src/shade/playground/particle_system/particle_prototype.js +18 -18
  156. package/src/shade/playground/particle_system/particle_scene.js +13 -13
  157. package/src/shade/playground/probe_clipmap/README.md +42 -0
  158. package/src/shade/playground/probe_clipmap/index.html +178 -0
  159. package/src/shade/playground/probe_clipmap/main.d.ts +8 -0
  160. package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -0
  161. package/src/shade/playground/probe_clipmap/main.js +360 -0
  162. package/src/shade/renderer/Renderer.d.ts +3 -1
  163. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  164. package/src/shade/renderer/Renderer.js +94 -38
  165. package/src/shade/renderer/extension/ViewTextures.d.ts +2 -1
  166. package/src/shade/renderer/extension/ViewTextures.d.ts.map +1 -1
  167. package/src/shade/renderer/extension/ViewTextures.js +2 -1
  168. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  169. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  170. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  171. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  172. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  173. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts +34 -12
  174. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.d.ts.map +1 -1
  175. package/src/shade/renderer/geometry/virtual/runtime/GPUVirtualGeometryRuntime.js +56 -15
  176. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts +2 -2
  177. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.d.ts.map +1 -1
  178. package/src/shade/renderer/geometry/virtual/runtime/VGeoFeedbackLoop.js +13 -26
  179. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +25 -2
  180. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -1
  181. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +54 -32
  182. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_VERDICT.d.ts +14 -0
  183. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_VERDICT.d.ts.map +1 -0
  184. package/src/shade/renderer/geometry/virtual/runtime/cut/VGEO_CUT_VERDICT.js +37 -0
  185. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.d.ts.map +1 -1
  186. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_arena.js +16 -0
  187. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_claim.d.ts.map +1 -1
  188. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_claim.js +2 -6
  189. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_descent.d.ts +131 -0
  190. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_descent.d.ts.map +1 -0
  191. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_descent.js +467 -0
  192. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_instance.d.ts +24 -0
  193. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_instance.d.ts.map +1 -0
  194. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_instance.js +111 -0
  195. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_rule.d.ts +42 -0
  196. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_rule.d.ts.map +1 -0
  197. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_rule.js +404 -0
  198. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_stat.d.ts +16 -0
  199. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_stat.d.ts.map +1 -0
  200. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_stat.js +23 -0
  201. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_want.d.ts +17 -0
  202. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_want.d.ts.map +1 -0
  203. package/src/shade/renderer/geometry/virtual/runtime/cut/chunk_vgeo_cut_want.js +65 -0
  204. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.d.ts.map +1 -1
  205. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_collect.js +14 -70
  206. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.d.ts.map +1 -1
  207. package/src/shade/renderer/geometry/virtual/runtime/cut/shader_vgeo_cut_traverse.js +13 -773
  208. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_cut_descent.d.ts +55 -0
  209. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_cut_descent.d.ts.map +1 -0
  210. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_cut_descent.js +248 -0
  211. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  212. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +15 -174
  213. package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_probe_meta_pick2.d.ts.map +1 -1
  214. package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_probe_meta_pick2.js +8 -24
  215. package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_sample_forward_indirect.d.ts.map +1 -1
  216. package/src/shade/renderer/global_illumination/brick4/gpu/draw/chunk_brick4_sample_forward_indirect.js +1 -25
  217. package/src/shade/renderer/global_illumination/lpv/deprecated/chunk_lpv_get_visibility_mask.d.ts.map +1 -1
  218. package/src/shade/renderer/global_illumination/lpv/deprecated/chunk_lpv_get_visibility_mask.js +5 -23
  219. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +25 -4
  220. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  221. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +126 -8
  222. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +832 -4
  223. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.d.ts +7 -0
  224. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.d.ts.map +1 -1
  225. package/src/shade/renderer/global_illumination/probe_clipmap/brick/BRICK_CLIPMAP.js +8 -0
  226. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts +16 -0
  227. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts.map +1 -1
  228. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.js +9 -0
  229. package/src/shade/renderer/global_illumination/probe_clipmap/brick/{mesh/chunk_mesh_brick_object.d.ts → chunk_brick_object.d.ts} +8 -8
  230. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_object.d.ts.map +1 -0
  231. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_object.js +42 -0
  232. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_provider.d.ts +45 -0
  233. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_provider.d.ts.map +1 -0
  234. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_provider.js +93 -0
  235. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK_INSTANCE_STRUCT.d.ts +0 -7
  236. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK_INSTANCE_STRUCT.d.ts.map +1 -1
  237. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/MESH_BRICK_INSTANCE_STRUCT.js +0 -8
  238. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts +2 -4
  239. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts.map +1 -1
  240. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.js +5 -8
  241. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_provider.d.ts.map +1 -1
  242. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/shader_mesh_brick_provider.js +13 -22
  243. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGEO_BRICK.d.ts +99 -0
  244. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGEO_BRICK.d.ts.map +1 -0
  245. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGEO_BRICK.js +139 -0
  246. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGeoBrickProvider.d.ts +65 -0
  247. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGeoBrickProvider.d.ts.map +1 -0
  248. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/VGeoBrickProvider.js +393 -0
  249. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_box.d.ts +17 -0
  250. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_box.d.ts.map +1 -0
  251. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_box.js +36 -0
  252. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_pair.d.ts +29 -0
  253. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_pair.d.ts.map +1 -0
  254. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_pair.js +108 -0
  255. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_texel.d.ts +31 -0
  256. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_texel.d.ts.map +1 -0
  257. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_texel.js +113 -0
  258. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_triangle.d.ts +36 -0
  259. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_triangle.d.ts.map +1 -0
  260. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/chunk_vgeo_brick_triangle.js +85 -0
  261. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_distance.d.ts +23 -0
  262. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_distance.d.ts.map +1 -0
  263. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_distance.js +273 -0
  264. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_gather.d.ts +13 -0
  265. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_gather.d.ts.map +1 -0
  266. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_gather.js +151 -0
  267. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_traverse.d.ts +13 -0
  268. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_traverse.d.ts.map +1 -0
  269. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_traverse.js +133 -0
  270. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_wait.d.ts +22 -0
  271. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_wait.d.ts.map +1 -0
  272. package/src/shade/renderer/global_illumination/probe_clipmap/brick/vgeo/shader_vgeo_brick_wait.js +135 -0
  273. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +20 -6
  274. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  275. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +152 -10
  276. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +7 -0
  277. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
  278. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +8 -0
  279. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +14 -2
  280. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
  281. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +50 -5
  282. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_cage.d.ts +19 -0
  283. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_cage.d.ts.map +1 -0
  284. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_cage.js +40 -0
  285. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts +72 -0
  286. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.d.ts.map +1 -0
  287. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_pick.js +343 -0
  288. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts +29 -0
  289. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -0
  290. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +188 -0
  291. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts +26 -0
  292. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts.map +1 -0
  293. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.js +132 -0
  294. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts +4 -0
  295. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts.map +1 -1
  296. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js +26 -3
  297. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.d.ts +3 -0
  298. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.d.ts.map +1 -1
  299. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_admit.js +8 -1
  300. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_diffuse.d.ts +12 -0
  301. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_diffuse.d.ts.map +1 -0
  302. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_diffuse.js +101 -0
  303. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts +1 -1
  304. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.js +1 -1
  305. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.d.ts +15 -0
  306. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.d.ts.map +1 -0
  307. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_indirect_lighting.js +175 -0
  308. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.d.ts +26 -0
  309. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.d.ts.map +1 -0
  310. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.js +210 -0
  311. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.d.ts +3 -3
  312. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.js +3 -3
  313. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts +2 -1
  314. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  315. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +5 -1
  316. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
  317. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +3 -10
  318. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts +5 -9
  319. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts.map +1 -1
  320. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.js +9 -110
  321. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_hits.d.ts +27 -0
  322. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_hits.d.ts.map +1 -0
  323. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_hits.js +110 -0
  324. package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.d.ts +13 -0
  325. package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.d.ts.map +1 -1
  326. package/src/shade/renderer/light/world_cluster/chunk_world_light_cluster_lookup.js +40 -0
  327. package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.d.ts +11 -6
  328. package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.d.ts.map +1 -1
  329. package/src/shade/renderer/light/world_cluster/graph_build_world_light_clusters.js +15 -8
  330. package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.d.ts +9 -2
  331. package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.d.ts.map +1 -1
  332. package/src/shade/renderer/light/world_cluster/shader_world_cluster_assign_lights.js +25 -11
  333. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  334. package/src/shade/renderer/particles/DESIGN.md +151 -42
  335. package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +283 -0
  336. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +10 -2
  337. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  338. package/src/shade/renderer/particles/GPUParticleSystem.js +46 -8
  339. package/src/shade/renderer/particles/ParticleConstants.d.ts +23 -6
  340. package/src/shade/renderer/particles/ParticleConstants.d.ts.map +1 -1
  341. package/src/shade/renderer/particles/ParticleConstants.js +25 -6
  342. package/src/shade/renderer/particles/bounds/chunk_particle_bounds.js +5 -5
  343. package/src/shade/renderer/particles/bounds/shader_particle_bounds.js +187 -187
  344. package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.d.ts +20 -9
  345. package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.d.ts.map +1 -1
  346. package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.js +36 -10
  347. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts +8 -7
  348. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.d.ts.map +1 -1
  349. package/src/shade/renderer/particles/data/PARTICLE_EMITTER_STRUCT.js +25 -16
  350. package/src/shade/renderer/particles/data/PARTICLE_FIELD_BINDING.d.ts +51 -0
  351. package/src/shade/renderer/particles/data/PARTICLE_FIELD_BINDING.d.ts.map +1 -0
  352. package/src/shade/renderer/particles/data/PARTICLE_FIELD_BINDING.js +56 -0
  353. package/src/shade/renderer/particles/data/particle_emitter_record.d.ts.map +1 -1
  354. package/src/shade/renderer/particles/data/particle_emitter_record.js +2 -0
  355. package/src/shade/renderer/particles/graph/ParticleGroupBuilder.d.ts +1 -1
  356. package/src/shade/renderer/particles/graph/ParticleGroupBuilder.js +1 -1
  357. package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts +22 -11
  358. package/src/shade/renderer/particles/graph/ParticleNodeDescription.d.ts.map +1 -1
  359. package/src/shade/renderer/particles/graph/ParticleNodeDescription.js +14 -11
  360. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts +4 -4
  361. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.d.ts.map +1 -1
  362. package/src/shade/renderer/particles/graph/ParticleNodeRegistry.js +59 -24
  363. package/src/shade/renderer/particles/graph/ParticleValueType.d.ts +3 -3
  364. package/src/shade/renderer/particles/graph/ParticleValueType.js +287 -287
  365. package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts +13 -6
  366. package/src/shade/renderer/particles/graph/compile_particle_graph.d.ts.map +1 -1
  367. package/src/shade/renderer/particles/graph/compile_particle_graph.js +46 -27
  368. package/src/shade/renderer/particles/graph/infer_particle_graph_types.d.ts +8 -2
  369. package/src/shade/renderer/particles/graph/infer_particle_graph_types.d.ts.map +1 -1
  370. package/src/shade/renderer/particles/graph/infer_particle_graph_types.js +240 -234
  371. package/src/shade/renderer/particles/graph/make_particle_group.d.ts +1 -1
  372. package/src/shade/renderer/particles/graph/make_particle_group.js +1 -1
  373. package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts +3 -2
  374. package/src/shade/renderer/particles/graph/particle_graph_authoring.d.ts.map +1 -1
  375. package/src/shade/renderer/particles/graph/particle_graph_authoring.js +3 -2
  376. package/src/shade/renderer/particles/graph/particle_graph_distributions.js +170 -170
  377. package/src/shade/renderer/particles/graph/particle_graph_json.d.ts +25 -16
  378. package/src/shade/renderer/particles/graph/particle_graph_json.d.ts.map +1 -1
  379. package/src/shade/renderer/particles/graph/particle_graph_json.js +16 -2
  380. package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts +29 -15
  381. package/src/shade/renderer/particles/graph/particle_node_parameters.d.ts.map +1 -1
  382. package/src/shade/renderer/particles/graph/particle_node_parameters.js +54 -22
  383. package/src/shade/renderer/particles/graph/particle_node_presentation.d.ts.map +1 -1
  384. package/src/shade/renderer/particles/graph/particle_node_presentation.js +18 -8
  385. package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts +9 -2
  386. package/src/shade/renderer/particles/graph/validate_particle_graph.d.ts.map +1 -1
  387. package/src/shade/renderer/particles/graph/validate_particle_graph.js +70 -32
  388. package/src/shade/renderer/particles/graph_particles.d.ts +9 -4
  389. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  390. package/src/shade/renderer/particles/graph_particles.js +27 -4
  391. package/src/shade/renderer/particles/isa/InstructionStream.d.ts +7 -6
  392. package/src/shade/renderer/particles/isa/InstructionStream.d.ts.map +1 -1
  393. package/src/shade/renderer/particles/isa/InstructionStream.js +17 -16
  394. package/src/shade/renderer/particles/isa/ParticleAssembler.d.ts +17 -0
  395. package/src/shade/renderer/particles/isa/ParticleAssembler.d.ts.map +1 -1
  396. package/src/shade/renderer/particles/isa/ParticleAssembler.js +35 -0
  397. package/src/shade/renderer/particles/isa/ParticleProgram.d.ts +26 -6
  398. package/src/shade/renderer/particles/isa/ParticleProgram.d.ts.map +1 -1
  399. package/src/shade/renderer/particles/isa/ParticleProgram.js +61 -9
  400. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts +55 -4
  401. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts.map +1 -1
  402. package/src/shade/renderer/particles/isa/ParticleVMISA.js +79 -10
  403. package/src/shade/renderer/particles/isa/particle_assembly.d.ts +20 -6
  404. package/src/shade/renderer/particles/isa/particle_assembly.d.ts.map +1 -1
  405. package/src/shade/renderer/particles/isa/particle_assembly.js +136 -25
  406. package/src/shade/renderer/particles/isa/particle_link_global_fields.d.ts +20 -0
  407. package/src/shade/renderer/particles/isa/particle_link_global_fields.d.ts.map +1 -0
  408. package/src/shade/renderer/particles/isa/particle_link_global_fields.js +46 -0
  409. package/src/shade/renderer/particles/isa/validate_particle_program.js +8 -8
  410. package/src/shade/renderer/particles/layout/ParticleLayout.d.ts +62 -28
  411. package/src/shade/renderer/particles/layout/ParticleLayout.d.ts.map +1 -1
  412. package/src/shade/renderer/particles/layout/ParticleLayout.js +102 -62
  413. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.d.ts.map +1 -1
  414. package/src/shade/renderer/particles/optimizer/dag/optimize_particle_program_vector.js +2 -0
  415. package/src/shade/renderer/particles/optimizer/dag/particle_vector_groups.js +1 -1
  416. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lift.js +4 -3
  417. package/src/shade/renderer/particles/optimizer/dag/particle_vector_lower.js +2 -2
  418. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.d.ts +3 -3
  419. package/src/shade/renderer/particles/optimizer/dag/particle_vector_pack.js +11 -11
  420. package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts +4 -4
  421. package/src/shade/renderer/particles/optimizer/optimize_particle_program.d.ts.map +1 -1
  422. package/src/shade/renderer/particles/optimizer/optimize_particle_program.js +5 -4
  423. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.d.ts +1 -1
  424. package/src/shade/renderer/particles/optimizer/particle_integer_bounds.js +1 -1
  425. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts +4 -4
  426. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.d.ts.map +1 -1
  427. package/src/shade/renderer/particles/optimizer/particle_program_equivalence.js +13 -11
  428. package/src/shade/renderer/particles/optimizer/particle_program_fuzz.js +7 -7
  429. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts +3 -2
  430. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
  431. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +5 -4
  432. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.d.ts.map +1 -1
  433. package/src/shade/renderer/particles/optimizer/pass_dedup_constants.d.ts.map +1 -1
  434. package/src/shade/renderer/particles/optimizer/pass_eliminate_dead_code.d.ts.map +1 -1
  435. package/src/shade/renderer/particles/optimizer/pass_eliminate_dead_code.js +51 -51
  436. package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
  437. package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +5 -5
  438. package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts.map +1 -1
  439. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.d.ts.map +1 -1
  440. package/src/shade/renderer/particles/optimizer/pass_pack_registers.d.ts.map +1 -1
  441. package/src/shade/renderer/particles/optimizer/pass_peephole.d.ts.map +1 -1
  442. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.d.ts.map +1 -1
  443. package/src/shade/renderer/particles/optimizer/pass_schedule.d.ts.map +1 -1
  444. package/src/shade/renderer/particles/optimizer/pass_schedule.js +2 -2
  445. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.d.ts.map +1 -1
  446. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.js +5 -4
  447. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts +93 -22
  448. package/src/shade/renderer/particles/runtime/EmitterRegistry.d.ts.map +1 -1
  449. package/src/shade/renderer/particles/runtime/EmitterRegistry.js +336 -29
  450. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts +43 -3
  451. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.d.ts.map +1 -1
  452. package/src/shade/renderer/particles/runtime/GPUParticleEmitterContext.js +43 -3
  453. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts +56 -26
  454. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
  455. package/src/shade/renderer/particles/runtime/ParticleEmitter.js +89 -33
  456. package/src/shade/renderer/particles/runtime/ParticleGlobalFields.d.ts +85 -0
  457. package/src/shade/renderer/particles/runtime/ParticleGlobalFields.d.ts.map +1 -0
  458. package/src/shade/renderer/particles/runtime/ParticleGlobalFields.js +221 -0
  459. package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts +143 -18
  460. package/src/shade/renderer/particles/runtime/ProgramHeap.d.ts.map +1 -1
  461. package/src/shade/renderer/particles/runtime/ProgramHeap.js +378 -28
  462. package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts +19 -7
  463. package/src/shade/renderer/particles/runtime/create_particle_effect.d.ts.map +1 -1
  464. package/src/shade/renderer/particles/runtime/create_particle_effect.js +22 -9
  465. package/src/shade/renderer/particles/shaders/chunk_particle_billboard_vertex.js +8 -8
  466. package/src/shade/renderer/particles/shaders/chunk_particle_render_math.js +1 -1
  467. package/src/shade/renderer/particles/shaders/chunk_particle_setup_context.d.ts +3 -0
  468. package/src/shade/renderer/particles/shaders/chunk_particle_setup_context.d.ts.map +1 -1
  469. package/src/shade/renderer/particles/shaders/chunk_particle_setup_context.js +4 -0
  470. package/src/shade/renderer/particles/shaders/shader_particle_field_bind.d.ts +30 -0
  471. package/src/shade/renderer/particles/shaders/shader_particle_field_bind.d.ts.map +1 -0
  472. package/src/shade/renderer/particles/shaders/shader_particle_field_bind.js +121 -0
  473. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.d.ts.map +1 -1
  474. package/src/shade/renderer/particles/vm/PARTICLE_VM_CONTEXT_STRUCT.js +3 -1
  475. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +12 -4
  476. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
  477. package/src/shade/renderer/particles/vm/ParticleVMReference.js +48 -11
  478. package/src/shade/renderer/particles/vm/chunk_particle_vm.d.ts.map +1 -1
  479. package/src/shade/renderer/particles/vm/chunk_particle_vm.js +36 -14
  480. package/src/shade/renderer/postprocess/PostProcess.d.ts.map +1 -1
  481. package/src/shade/renderer/postprocess/PostProcess.js +2 -1
  482. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts +31 -19
  483. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
  484. package/src/shade/renderer/postprocess/gtao/GTAO.js +44 -30
  485. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  486. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +16 -2
  487. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  488. package/src/shade/renderer/postprocess/nss/NSS.d.ts.map +1 -1
  489. package/src/shade/renderer/postprocess/nss/NSS.js +4 -3
  490. package/src/shade/renderer/postprocess/ssr/SSR.d.ts +7 -1
  491. package/src/shade/renderer/postprocess/ssr/SSR.d.ts.map +1 -1
  492. package/src/shade/renderer/postprocess/ssr/SSR.js +16 -0
  493. package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_add_hit_irradiance.d.ts +20 -2
  494. package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_add_hit_irradiance.d.ts.map +1 -1
  495. package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_add_hit_irradiance.js +53 -3
  496. package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_sample_radiance.d.ts +10 -2
  497. package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_sample_radiance.d.ts.map +1 -1
  498. package/src/shade/renderer/postprocess/ssr/resolve/chunk_ssr_sample_radiance.js +31 -3
  499. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.d.ts.map +1 -1
  500. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.js +17 -11
  501. package/src/shade/renderer/postprocess/taa/TAA.d.ts +4 -2
  502. package/src/shade/renderer/postprocess/taa/TAA.d.ts.map +1 -1
  503. package/src/shade/renderer/postprocess/taa/TAA.js +6 -1
  504. package/src/shade/renderer/postprocess/taa/chunk_fsr2_compute_depth_clip.d.ts.map +1 -1
  505. package/src/shade/renderer/postprocess/taa/chunk_fsr2_compute_depth_clip.js +10 -5
  506. package/src/shade/renderer/postprocess/taa/shader_taa.d.ts.map +1 -1
  507. package/src/shade/renderer/postprocess/taa/shader_taa.js +15 -12
  508. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts.map +1 -1
  509. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.js +26 -17
  510. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect.d.ts +4 -3
  511. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect.d.ts.map +1 -1
  512. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect.js +6 -4
  513. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.d.ts +12 -0
  514. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.d.ts.map +1 -0
  515. package/src/shade/renderer/rasterize/forward/chunk_forward_sample_indirect_probe_clipmap.js +57 -0
  516. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +4 -2
  517. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  518. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +4 -2
  519. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts +8 -2
  520. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  521. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +28 -15
  522. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw.d.ts +2 -1
  523. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw.d.ts.map +1 -1
  524. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw.js +19 -3
  525. package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.d.ts.map +1 -1
  526. package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.js +4 -2
  527. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts +3 -1
  528. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts.map +1 -1
  529. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +27 -14
  530. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.d.ts +2 -1
  531. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.d.ts.map +1 -1
  532. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.js +19 -3
  533. package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_bounds.d.ts +2 -8
  534. package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_bounds.d.ts.map +1 -1
  535. package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_bounds.js +25 -52
  536. package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_positions.d.ts +15 -0
  537. package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_positions.d.ts.map +1 -0
  538. package/src/shade/renderer/shader/chunk/geometry/meshlet/chunk_read_meshlet_triangle_positions.js +52 -0
  539. package/src/shade/renderer/shader/chunk/geometry/triangle/TRIANGLE_POSITIONS_STRUCT.d.ts +7 -0
  540. package/src/shade/renderer/shader/chunk/geometry/triangle/TRIANGLE_POSITIONS_STRUCT.d.ts.map +1 -0
  541. package/src/shade/renderer/shader/chunk/geometry/triangle/TRIANGLE_POSITIONS_STRUCT.js +12 -0
  542. package/src/shade/renderer/shader/chunk/grid/chunk_index_to_grid2d_reciprocal.d.ts +22 -0
  543. package/src/shade/renderer/shader/chunk/grid/chunk_index_to_grid2d_reciprocal.d.ts.map +1 -0
  544. package/src/shade/renderer/shader/chunk/grid/chunk_index_to_grid2d_reciprocal.js +37 -0
  545. package/src/shade/renderer/shader/chunk/light/lpv/depth/chunk_lpv_mask_weights_by_visibility.d.ts.map +1 -1
  546. package/src/shade/renderer/shader/chunk/light/lpv/depth/chunk_lpv_mask_weights_by_visibility.js +26 -60
  547. package/src/shade/renderer/shader/chunk/light/probe/chunk_probe_visibility_weight.d.ts +23 -0
  548. package/src/shade/renderer/shader/chunk/light/probe/chunk_probe_visibility_weight.d.ts.map +1 -0
  549. package/src/shade/renderer/shader/chunk/light/probe/chunk_probe_visibility_weight.js +54 -0
  550. package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.d.ts +25 -0
  551. package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.d.ts.map +1 -0
  552. package/src/shade/renderer/shader/chunk/math/chunk_f16_round_stochastic.js +43 -0
  553. package/src/shade/renderer/shader/chunk/random/chunk_jitter_from_vectors.d.ts +14 -0
  554. package/src/shade/renderer/shader/chunk/random/chunk_jitter_from_vectors.d.ts.map +1 -0
  555. package/src/shade/renderer/shader/chunk/random/chunk_jitter_from_vectors.js +37 -0
  556. package/src/shade/renderer/shader/chunk/random/reservoir/chunk_pick2_wrs_mat2x4.d.ts +27 -0
  557. package/src/shade/renderer/shader/chunk/random/reservoir/chunk_pick2_wrs_mat2x4.d.ts.map +1 -0
  558. package/src/shade/renderer/shader/chunk/random/reservoir/chunk_pick2_wrs_mat2x4.js +61 -0
  559. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/chunk_resolve_irradiance_sh_to_specular.d.ts +21 -0
  560. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/chunk_resolve_irradiance_sh_to_specular.d.ts.map +1 -0
  561. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/chunk_resolve_irradiance_sh_to_specular.js +41 -0
  562. package/src/shade/renderer/texture/util/texture_fill_rectangle.d.ts.map +1 -1
  563. package/src/shade/renderer/texture/util/texture_fill_rectangle.js +282 -267
  564. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +8 -4
  565. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  566. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +36 -36
  567. package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts +6 -1
  568. package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.d.ts.map +1 -1
  569. package/src/shade/renderer/volumetrics/irradiance_clipmap/GPUIrradianceClipmap.js +498 -484
  570. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts +15 -2
  571. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.d.ts.map +1 -1
  572. package/src/shade/renderer/volumetrics/irradiance_clipmap/chunk_irradiance_clipmap_gi_sample.js +57 -3
  573. package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.d.ts.map +1 -1
  574. package/src/shade/renderer/volumetrics/irradiance_clipmap/shader_irradiance_clipmap_build.js +197 -191
  575. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +4 -4
  576. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +2 -1
  577. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  578. package/src/shade/renderer/water/GPUWaterRenderer.js +5 -1
  579. package/src/shade/renderer/water/chunk_water_gi.d.ts +13 -3
  580. package/src/shade/renderer/water/chunk_water_gi.d.ts.map +1 -1
  581. package/src/shade/renderer/water/chunk_water_gi.js +47 -5
  582. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  583. package/src/shade/renderer/water/shader_water.d.ts +3 -2
  584. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  585. package/src/shade/renderer/water/shader_water.js +9 -3
  586. package/src/shade/renderer/geometry/sdf/SDF_BUILD_SETTINGS_STRUCT.d.ts +0 -3
  587. package/src/shade/renderer/geometry/sdf/SDF_BUILD_SETTINGS_STRUCT.d.ts.map +0 -1
  588. package/src/shade/renderer/geometry/sdf/SFD_BUILD_WORKGROUP_SIZE.d.ts +0 -2
  589. package/src/shade/renderer/geometry/sdf/SFD_BUILD_WORKGROUP_SIZE.d.ts.map +0 -1
  590. package/src/shade/renderer/geometry/sdf/chunk_blas_query_sdf.d.ts +0 -8
  591. package/src/shade/renderer/geometry/sdf/chunk_blas_query_sdf.d.ts.map +0 -1
  592. package/src/shade/renderer/geometry/sdf/chunk_blas_query_volume_sign.d.ts +0 -3
  593. package/src/shade/renderer/geometry/sdf/chunk_blas_query_volume_sign.d.ts.map +0 -1
  594. package/src/shade/renderer/geometry/sdf/shader_build_sdf.d.ts +0 -3
  595. package/src/shade/renderer/geometry/sdf/shader_build_sdf.d.ts.map +0 -1
  596. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_object.d.ts.map +0 -1
  597. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_object.js +0 -42
  598. package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts +0 -31
  599. package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts.map +0 -1
  600. package/src/shade/renderer/shadow/vsm/VSMMoverTracker.d.ts +0 -42
  601. package/src/shade/renderer/shadow/vsm/VSMMoverTracker.d.ts.map +0 -1
  602. package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.d.ts +0 -54
  603. package/src/shade/renderer/shadow/vsm/VSM_MOVER_LAYOUT.d.ts.map +0 -1
  604. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.d.ts +0 -14
  605. package/src/shade/renderer/shadow/vsm/shader/chunk_vsm_append_mover.d.ts.map +0 -1
  606. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.d.ts +0 -30
  607. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_movers.d.ts.map +0 -1
  608. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.d.ts +0 -23
  609. package/src/shade/renderer/shadow/vsm/shader/shader_vsm_skinned_movers.d.ts.map +0 -1
@@ -0,0 +1,552 @@
1
+ # Two growth front ends on one pipeline (2026-10-28)
2
+
3
+ Alex, 2026-10-28: the botanical generator is very slow. Can we keep it for beautiful, highly detailed trees, and add a
4
+ graph generator for real-time ones? Only if the two share most of their code.
5
+
6
+ They can. Both front ends grow a `TreeSkeleton` and its leaves, and everything after that point is shared. This brief
7
+ covers three things: the contract both front ends fill, how the graph's presets get their density, and how the graph
8
+ tree's cards come from a botanical prototype grown once per species.
9
+
10
+ ## Measured (master b8c61d89e, seed 1337)
11
+
12
+ ### Where the code sits
13
+
14
+ Source lines, specs excluded:
15
+
16
+ | part | lines | what |
17
+ | :--- | ---: | :--- |
18
+ | shared | ~14k | `TreeSkeleton`, pipe radii, joint mechanics, rig, bark mesh, attachments, clusters, cards, representatives, atlas, LOD plan, cost gate, wind, materials, analysis |
19
+ | botany only | ~2.9k | `shoot_systems_simulate`, `ShootLightField`, `ShootWoodHash`, `ShootFrameworkHash`, `ShootGirth`, `shoot_demography`, `shoot_geometry`, `tree_skeleton_grow_shoots`; `ShootSystemRule`, `ShootGrowthConfig`, `ShootBudZone` |
20
+ | graph only | ~2.7k | the rule part of `tree_skeleton_grow`; `BranchSpawnRule`, `BranchGeneratorConfig`, `FoliageSpawnRule`, `crown_envelope_evaluate` |
21
+
22
+ The graph front end exists already. Each tree grows its framework with it, then `tree_skeleton_grow_shoots` grows
23
+ the twigs on top. The palm and the fern use the graph alone, and so does any preset whose `shoot_rules` is empty.
24
+
25
+ ### What each front end costs
26
+
27
+ Times are for the whole asset, every LOD built.
28
+
29
+ | preset | nodes, botany → graph | leaves, botany → graph | whole asset, botany → graph |
30
+ | :--- | :--- | :--- | :--- |
31
+ | oak | 9,856 → 766 | 30,017 → 6,714 | 4.3 → 2.0 s |
32
+ | pine | 78,275 → 18 | 14,082 → 10 | 9.4 → 0.9 s |
33
+ | birch | 48,695 → 401 | 53,174 → 4,510 | 6.4 → 0.9 s |
34
+ | willow | 64,234 → 723 | 129,056 → 23,634 | 12.5 → 1.5 s |
35
+ | maple | 10,854 → 604 | 20,862 → 5,838 | 4.6 → 1.3 s |
36
+ | spruce | 109,725 → 690 | 116,185 → 18,377 | 7.9 → 1.5 s |
37
+ | shrub | 7,131 → 84 | 12,863 → 471 | 1.2 → 0.6 s |
38
+
39
+ The graph-only trees are bare. The presets' framework rules were thinned for the shoots to fill. The pine has no graph
40
+ framework at all: since S1 (4a3a41928) it grows from its seed.
41
+
42
+ ### Where a graph-only tree spends its time
43
+
44
+ | preset | atlas and LOD0 cards | bark and leaf materials | everything else |
45
+ | :--- | ---: | ---: | ---: |
46
+ | oak | 1.09 s | 0.28 s | ~0.3 s |
47
+ | willow | 0.92 s | 0.33 s | ~0.4 s |
48
+ | spruce | 1.49 s | 0.38 s | ~0.3 s |
49
+ | maple | 0.71 s | 0.64 s | ~0.3 s |
50
+ | birch | 0.38 s | 0.52 s | ~0.1 s |
51
+
52
+ The atlas and the materials depend on the species, not the tree, yet every tree computes them again.
53
+
54
+ ### Which wood the LODs draw
55
+
56
+ The botanical trees, with framework branches (grown by the graph) counted apart from shoot branches (grown by
57
+ `tree_skeleton_grow_shoots`):
58
+
59
+ | preset | LOD0 error | framework drawn at LOD0 | shoots drawn at LOD0 | shoot orders drawn | shoots drawn at LOD1 |
60
+ | :--- | ---: | ---: | ---: | ---: | ---: |
61
+ | oak | 2.0 cm | 115 / 117 | 33 / 2,515 (1.3%) | 2 | 0 |
62
+ | pine | 2.8 cm | 1 / 5 | 252 / 9,225 (2.7%) | 3 | 252 |
63
+ | birch | 2.8 cm | 44 / 54 | 131 / 16,851 (0.8%) | 3 | 50 |
64
+ | willow | 4.0 cm | 76 / 83 | 121 / 21,464 (0.6%) | 2 | 121 |
65
+ | maple | 2.8 cm | 79 / 86 | 1 / 4,331 (0.02%) | 1 | 0 |
66
+ | spruce | 2.8 cm | 116 / 151 | 35 / 31,720 (0.1%) | 2 | 3 |
67
+ | shrub | 2.8 cm | 12 / 17 | 31 / 2,416 (1.3%) | 3 | 31 |
68
+
69
+ - At least 97% of the simulated shoots are never drawn as wood at any LOD; they end up inside cluster cards.
70
+ - The graph's framework is nearly all of LOD0's wood.
71
+ - The exceptions are the pine and shrub, whose framework is shoots, and the birch and willow, which draw 121–131
72
+ shoots up to three orders deep.
73
+
74
+ ## The design
75
+
76
+ **One pipeline, two front ends.**
77
+ - The botanical front end is today's generator, unchanged, per-tree bake included. It serves hero trees.
78
+ - The graph front end grows only the framework. On each terminal carrier it hangs a prototype: the species' shoot
79
+ system, grown once by the botanical front end. The prototype supplies the carrier's drawn twigs, its cluster cards
80
+ and their tiles.
81
+ - Each species is grown botanically once, and every tree of that species shares the result.
82
+ - Everything downstream of the skeleton is shared. A shared spec runs it on both front ends.
83
+
84
+ ### Reuse map
85
+
86
+ | piece | graph front end | botanical front end |
87
+ | :--- | :--- | :--- |
88
+ | framework: `tree_skeleton_grow` (graph rules, roots, flare, self-pruning, scars) | unchanged | unchanged |
89
+ | `tree_skeleton_compute_pipe_radii`, joint mechanics, `tree_skeleton_assign_skin_joints` / `_bind_` | unchanged | unchanged |
90
+ | `tree_skeleton_grow_shoots`, `shoot_systems_simulate` | run once per species, on the prototype's carrier | per tree, unchanged |
91
+ | `tree_mesh_compute_branch_rings`, `tree_mesh_build_bark` | unchanged, over framework plus grafted prototype wood | unchanged |
92
+ | `tree_clusters`, `tree_cluster_cards`, `_press`, `_tiles`, `_atlas_pack`, `_bake` | run on the prototype, once per species | per tree, unchanged |
93
+ | `tree_cluster_representatives` | its cover chosen over the prototypes | per tree, unchanged |
94
+ | `tree_mesh_build_clusters` | placement from prototype instances (changed) | unchanged |
95
+ | `tree_lod_plan` | counts prototype instances at each candidate error (changed) | unchanged |
96
+ | `foliage_collect_attachments` | a carrier with a prototype has no leaves of its own (changed) | unchanged |
97
+ | `make_bark_material`, `make_foliage_material` | cached per species (new cache, same code) | per tree, unchanged |
98
+ | `tree_render_cost`, `TREE_RENDER_COST_CEILING` | same gate | same gate |
99
+ | new | the prototype (grow, cut, bake, cache), carrier spacing from its sleeve, the graft | none |
100
+
101
+ ## The skeleton contract
102
+
103
+ Downstream reads each field below. Today's writers:
104
+
105
+ | field | read by | graph writes | shoots write |
106
+ | :--- | :--- | :---: | :---: |
107
+ | nodes, segments, frames, radii, `t_norm`, `arc_s`, branch chain, parent, `attach_t`, length, base radius | everything | yes | yes |
108
+ | `branch_generator` | attachments (`foliage_rules[].source`), bark (`species.branches[g]`), rig (`root`), mechanics, pipe radii | yes | yes (rule target) |
109
+ | `branch_level` | rig bend limit, bark, attachments, girth | yes | yes |
110
+ | `branch_dead` | attachments, bark, mechanics, pipe radii | yes (self-pruning) | yes (burial) |
111
+ | `branch_unit_offset` / `_count`, `unit_start_t` | attachments (leaves per annual unit), mechanics, `foliage_unit_cards` | no | yes |
112
+ | scars | bark knots, bark material | yes | no |
113
+ | `crown_center`, `crown_radii` | attachments, cards, AO, bark, senescence | yes | yes, every season (G0 review: one law since, `tree_skeleton_fit_crown_frame`) |
114
+ | `branch_phase_hash` | attachments, bark, unit cards | yes | yes |
115
+ | joints, `joint_rotation` | rig, bind | (written by the rig, after growth) | (written by the rig, after growth) |
116
+
117
+ The contract is already nearly symmetric:
118
+ - Annual units are the one field only the shoots write.
119
+ - `foliage_collect_attachments` already has a branch for a carrier without units: it derives the carrier's leaf count
120
+ from the card density.
121
+
122
+ The graph front end adds one record: which carriers hang a prototype, which prototype, at what scale and turn. That
123
+ record is new data on the skeleton, not a new branch kind.
124
+
125
+ **The contract spec** generates every preset with each front end. On each tree it runs the gates every tree must pass:
126
+ - the cost gate;
127
+ - the bark seam and skinning spec;
128
+ - every leaf or card bound to at most 4 joints;
129
+ - the crown-density measure against the botanical tree's.
130
+
131
+ It loops over the front ends inside plain `test()`s, so a field one front end forgets fails there instead of degrading
132
+ quietly.
133
+
134
+ ## Forks
135
+
136
+ ### G-F1: where the graph stops
137
+
138
+ **(a) At the framework (mine).** The graph grows its rules' branches. Shoots start where the prototype hangs.
139
+ - Measured: LOD0 draws 89–98% of the framework on the oak, maple, willow and spruce, and 0.02–1.3% of the shoots.
140
+ - The shoots LOD0 does draw (up to 252 on the pine) come from the prototype's own drawn wood (G-F2).
141
+
142
+ **(b) At the LOD0 error.** The graph keeps growing branches until they thin past the error.
143
+ - This needs graph rules for orders the presets never authored, the twig orders the shoots now grow.
144
+ - It brings back authored densities for exactly the part botany was brought in to derive.
145
+
146
+ ### G-F2: what a prototype carries onto its carrier
147
+
148
+ **(a) Its drawn wood plus its cuts, at every error on the ladder (mine).**
149
+ - Every LOD error the plan can choose is a √2 step from 1 cm. For each step, the prototype stores:
150
+ - the wood it draws (shoots thicker than that error, a few branches);
151
+ - the clusters cut there.
152
+ - When the plan picks an error, each carrier gets the prototype's wood at that error, grafted into the skeleton, plus
153
+ the prototype's cards at that error. Rig, bark and seams then run on that wood as on any other.
154
+ - `tree_lod_plan` searches the same errors. A prototype's triangles at each error are precomputed, so the plan's cost
155
+ per candidate does not grow with the shoots.
156
+
157
+ **(b) One cluster card per carrier.** This loses LOD0's drawn shoots: 252 on the pine, 121–131 on the birch and
158
+ willow. They are the twig wood these trees show up close.
159
+
160
+ ### G-F3: how the graph presets get their density
161
+
162
+ **(a) From the prototype's sleeve (mine).** This was fork 2 of `CROWN_FULLNESS_BRIEF_2026_10_26.md`, never built.
163
+ - A carrier's shoot system has a measurable reach. The prototype gives it once per species.
164
+ - Terminal carriers are spaced so their sleeves tile the crown envelope, the way card density was derived from the
165
+ leaf sleeve (`foliage_cards_per_metre`).
166
+ - The terminal rule's `count` becomes an outcome. The scaffold above it keeps today's authored rules, the same ones
167
+ the botanical presets use for their framework.
168
+
169
+ **(b) Fitted from a botanical tree.** Grow the species' botanical tree once and measure laterals per metre at each
170
+ order. This costs a whole botanical tree per species, and it fits the graph to one seed's outcome.
171
+
172
+ **(c) Authored per preset.** Rejected before: "no rule like Oak gets 3 stubs".
173
+
174
+ ### G-F4: what a prototype is grown on, and in what light
175
+
176
+ **(a) A framework terminal carrier of the species' median length, in open light, for the preset's `age` (mine).**
177
+ - A few prototypes per species, as few as keep the carriers' lengths within the scaling the leaves allow. This is the
178
+ representatives' rule one level up: a prototype drawn on a carrier is scaled by their length ratio, and that scale
179
+ must stay within the tree's own leaf-size spread (p10..p90 of `attachments.scales`).
180
+ - With no simulated neighbours, the crown's own shading is lost. The botanical crown sheds shaded shoots; the graph
181
+ crown keeps them.
182
+ - Open light is what the presets mostly see anyway: 60–100% of candidates are in saturating light (crown fullness
183
+ brief).
184
+
185
+ **(b) Sun and shade prototypes, picked by depth in the crown.** Twice the prototypes. Build it only if (a)'s crown
186
+ density measures outside the botanical tree's.
187
+
188
+ ### G-F5: the pine and the shrub
189
+
190
+ These two have no graph framework: the pine's was removed by S1, and the shrub's is 17 branches with the shoots doing
191
+ the rest.
192
+
193
+ **(a) Restore the pine's framework rules from 4a3a41928^ (mine).** For the shrub, keep its 17-branch framework and let
194
+ the prototypes do the rest. The botanical pine stays on S1.
195
+
196
+ **(b) Grow their framework from a botanical run.** Same objection as G-F3 (b).
197
+
198
+ ### G-F6: how callers choose
199
+
200
+ **(a) An explicit option on `generate_tree`, `growth: TreeGrowth.Graph | TreeGrowth.Botanical`, with Graph as the
201
+ default (mine).** Trees are real-time assets first. A hero tree asks for Botanical.
202
+
203
+ **(b) A separate entry point per front end.** This duplicates the asset assembly that both front ends share.
204
+
205
+ ### G-F7: the self-organizing plan's S6
206
+
207
+ S6 removes the graph's crown machinery. With two front ends, the graph is a product, so **S6 is dropped (mine)**.
208
+ S2–S5 stay parked as before, only within the cost gate.
209
+
210
+ ## Decisions (2026-10-28)
211
+
212
+ Alex took my picks on G-F1 to G-F7. One change of timing: `growth` defaults to Botanical until G3. Until then the
213
+ graph trees are bare, and every caller that passes no `growth` (the playground, `place_tree`) would get them.
214
+
215
+ ## Stages
216
+
217
+ Each stage gives the cost gate, crown density against the botanical tree, and time per tree, for every preset.
218
+
219
+ | stage | what | done when |
220
+ | :--- | :--- | :--- |
221
+ | G0 | The contract spec over both front ends; materials cached per species; `growth` option; the pine's framework rules restored | Both front ends pass every shared gate; the graph trees are still bare |
222
+ | G1 | The prototype: a single carrier grown by `tree_skeleton_grow_shoots`, cut and baked at every error, cached by the species hash | Its cost, sleeve and leaf area measured per species |
223
+ | G2 | Carrier spacing from the sleeve (G-F3 a) | Graph crowns' FIA side density within the botanical tree's |
224
+ | G3 | Prototypes on carriers: graft, cards, one atlas per species (G-F2 a, G-F4 a) | Every gate green on both front ends; a graph tree, once its species is cached, no slower than today's graph-only tree without its atlas and materials (0.1–0.4 s) |
225
+ | G4 | Docs: FOLIAGE_DESIGN §7, CHANGELOG, the parked plan's S6 struck | |
226
+
227
+ Not in scope: runtime LOD switching, impostors, more skinning influences.
228
+
229
+ ## G0 landed
230
+
231
+ - **Two front ends.** `TreeGrowth.Graph` / `TreeGrowth.Botanical`, passed as `generate_tree`'s `growth`.
232
+ - `tree_skeleton_grow_framework` is the generator graph alone: the old `tree_skeleton_grow` up to the pipe model.
233
+ - `tree_skeleton_grow` is that framework, then `tree_skeleton_grow_shoots`.
234
+ - **The contract, measured on every preset (seed 1337).** The botanical tree's first branches are the graph tree:
235
+ - every node in the same place, on the same branch;
236
+ - every branch from the same generator, on the same parent;
237
+ - no annual units on the graph tree.
238
+ - **Girth is the one difference.** The shoots thicken the framework they grow on: a botanical node is up to 1.33x
239
+ (maple) to 8.8x (birch) the graph tree's radius. The pine's is 50x, as its graph framework is only its seed.
240
+ A prototype's leaf has to reach the framework's pipe model for the graph tree's wood to match (G3).
241
+ - **The pine's graph framework.** `make_tree_species_preset(preset, overrides, growth)` gives the pine for
242
+ `TreeGrowth.Graph` the framework it had at 4a3a41928^: an 11.2 m stem, 32 whorl boughs, 14 inter-whorl branches,
243
+ twigs on both, and needles on all four. It is 10.68 m tall against the seed-grown pine's 10.76 m, less than a year's
244
+ leader growth apart.
245
+ - **Materials per species.** A `TreeSpeciesCache` passed to `generate_tree` shares each material between the
246
+ trees whose species make it alike.
247
+ - The bark material is keyed on `bark_material`, the leaf atlas on `foliage` and `foliage_material`. The atlas
248
+ is made from a species holding those two alone, so the key is everything it can read. The graph and the
249
+ seed-grown pine share both.
250
+ - Each is made when a tree first asks for it, so a tree drawn with the caller's own materials makes none.
251
+ - Each tree clones the leaf material, so its own leaves' tint scale stays its own.
252
+ - **Changed for the botanical front end too:** a tree's bark no longer changes with its seed: every bark has the
253
+ same noise (`make_bark_material`'s own seed). The leaf atlas never depended on the seed (0 texels differ between
254
+ seeds 1 and 2 on the maple, oak and pine). This follows from sharing materials per species, but none of G-F1 to
255
+ G-F7 decided it. Per-seed bark would cost a cache entry per seed.
256
+ - **Specs.**
257
+ - The cost gate, the bark-moves-with-its-rig spec and the each-LOD-on-its-own-rig spec now run on both front ends.
258
+ - New specs: the framework contract, `growth` picking the front end and the species, the graph pine, and the cache.
259
+ - **Two spec assumptions failed on graph trees; both are the rules working, not defects.**
260
+ - The graph oak's LOD2 (11.3 cm) needs no joint: its wood, with less leaf to catch the wind, nowhere bends past
261
+ the error. Its rig is the root alone, so it has no wind rig.
262
+ - The graph shrub's LOD2 (seed 7) draws 5 branches, 6 ring pairs. The bark spec's guard against checking nothing
263
+ is now that every drawn branch at every LOD is examined, and 30 ring pairs per tree.
264
+ - The per-LOD rig test now requires a wind rig exactly when the LOD has a joint beyond the root.
265
+ - **Every preset fits the ceiling on both front ends** (seed 1337, LOD0/1/2 triangles per m², joints per m²):
266
+
267
+ | preset | graph | botanical |
268
+ | :--- | :--- | :--- |
269
+ | oak | 662/363/64, 10.1 | 565/293/70, 10.3 |
270
+ | pine | 587/287/73, 13.2 | 218/218/43, 4.0 |
271
+ | birch | 626/318/89, 9.7 | 444/233/73, 10.7 |
272
+ | willow | 633/348/72, 16.4 | 397/397/60, 8.2 |
273
+ | maple | 736/308/89, 9.2 | 560/396/59, 5.5 |
274
+ | spruce | 658/334/87, 14.7 | 502/313/61, 11.1 |
275
+ | shrub | 452/313/87, 13.2 | 312/312/77, 10.8 |
276
+
277
+ The palm and the fern have no shoot rules and are the same on both.
278
+
279
+ - **Crown density and time per tree** (seed 1337; FIA side and below density at LOD0; time to every LOD's bark and cards
280
+ built, with the species' materials made / already in the cache):
281
+
282
+ | preset | graph density, side / below | graph time | botanical density, side / below | botanical time |
283
+ | :--- | :--- | :--- | :--- | :--- |
284
+ | oak | 0.37 / 0.36 | 1.56 / 1.10 s | 0.46 / 0.46 | 4.35 / 4.16 s |
285
+ | pine | 0.30 / 0.29 | 1.77 / 1.17 s | 0.25 / 0.31 | 14.20 / 13.29 s |
286
+ | birch | 0.24 / 0.31 | 1.10 / 0.60 s | 0.52 / 0.72 | 7.28 / 6.90 s |
287
+ | willow | 0.38 / 0.23 | 1.92 / 1.49 s | 0.71 / 0.68 | 17.31 / 15.35 s |
288
+ | maple | 0.37 / 0.33 | 1.89 / 1.01 s | 0.43 / 0.43 | 6.79 / 5.88 s |
289
+ | spruce | 0.21 / 0.21 | 1.41 / 0.89 s | 0.25 / 0.40 | 11.76 / 11.42 s |
290
+ | shrub | 0.38 / 0.28 | 0.42 / 0.06 s | 0.64 / 0.58 | 1.69 / 1.44 s |
291
+
292
+ - The graph trees fall short of the botanical trees' density everywhere except the pine. The pine's graph framework
293
+ carries needles on the stem, boughs, inter-whorl branches and twigs, and is denser from the side than the
294
+ seed-grown pine.
295
+ - With its materials cached, a graph tree's remaining time is mostly its own atlas bake, which G3 replaces with the
296
+ species' prototype tiles.
297
+ - **Review (independent, adversarial).** It found no defect in the botanical skeleton or geometry. Fixed:
298
+ - species materials were made even for a tree drawn with the caller's own;
299
+ - the cache was keyed on the whole config, so the two pines and differently sized crowns made the same atlas twice;
300
+ - the bark was seeded by a hash that leaves out some of its fields;
301
+ - the restored pine framework carried `radial_segments_*` keys, which L1 removed;
302
+ - two spec guards had been weakened for the botanical trees as well;
303
+ - the pine preset's comment and `place_tree`'s docs were stale.
304
+ - `growth` is asserted to be a `TreeGrowth`.
305
+ - Left as they are: `growth` and `cache` reach `generate_tree` only through an options object, not with a
306
+ preset name or a `TreeSpeciesConfig` instance, as `seed` and the custom materials do.
307
+
308
+ ## Reuse review (2026-10-28)
309
+
310
+ Alex asked for an adversarial review of G0 focused on sharing before G1. Fixed in G0:
311
+
312
+ - **One crown frame law.** The framework set the frame from the authored envelope; the shoot simulation rewrote it
313
+ every season from its own box. Graph and botanical trees disagreed by up to 2.8 m (willow's centre). Both now end
314
+ on `tree_skeleton_fit_crown_frame`: the box of every living branch a shoot rule grows on or grows. A species
315
+ without shoot rules keeps its envelope's. The graph oak's centre is now 5.09 m, as the botanical oak's (the
316
+ envelope gave 6.60). The botanical frame moves slightly, since it now includes the last season's growth.
317
+ - **The graph pine is the seed-grown pine's generators, overridden, with its shoot system.**
318
+ - Its stem and boughs are the seed-grown pine's, given the framework's length and shape. Its roots and twig
319
+ system are the seed-grown pine's own objects.
320
+ - It has the conifer shoot rules on boughs, inter-whorl branches and twigs again. The first restore had dropped
321
+ them, and G1 grows its prototypes from them.
322
+ - Its generator numbering still differs from the seed-grown pine's (inter-whorl at 2, roots at 4), since a shoot
323
+ rule's target must follow every carrier.
324
+ - **The cache is core's `HashMap`**, keyed on the configs' own `hash`/`equals`. A spec now checks every preset's
325
+ cached atlas and bark against the whole species' materials.
326
+ - **The contract spec checks the frame law on both front ends, and that what died in the framework died in both.**
327
+
328
+ For G3, measured or read, not settled:
329
+
330
+ - **Grafting per error breaks the one-skeleton LOD contract** (`tree_lod_plan` nests every LOD's joints on one
331
+ skeleton). Grafting a prototype's finest wood once and letting `tree_mesh_compute_branch_rings` cull it per error
332
+ reuses the planner instead of storing wood per error.
333
+ - **A prototype's leaves are lit and tinted for its own crown frame** (facing, maturity, sun, tint) and its cards face
334
+ away from its own centre. Drawn on a host they need the host's frame.
335
+ - **The host's rig must carry the prototype's leaf load**, or the graph rig stays as under-loaded as G0's (the graph
336
+ oak's LOD2 has no joint).
337
+ - **The texture gate charges each tree for its whole atlas**, while the atlas becomes the species'.
338
+ - **Girth:** the graph's wood comes from the pipe pass, the botanical from `ShootGirth`. A graft must not add a third
339
+ law.
340
+ - **The botanical tree is the degenerate case of G3:** its own single prototype, placed once. One path for both
341
+ instead of a fork in `generate_tree`'s cluster block.
342
+ - **Species-level cutout work still runs per call** (`foliage_atlas_cutout` in the simulation and the joint
343
+ mechanics: 9-72 ms each, once per rig).
344
+
345
+ ## G1 landed
346
+
347
+ `tree_shoot_prototypes(species, leaf_material, cutout)`, cached by `TreeSpeciesCache.prototypes`, keyed on the whole
348
+ species but its seed.
349
+
350
+ - **Where they grow.**
351
+ - The species' graph framework is grown once, at seed 0.
352
+ - Each prototype is grown in place on one of the framework's carriers (`tree_skeleton_grow_shoots_on`). So it is as
353
+ old as that carrier is in the tree, kept out of the framework's wood, and lit by its own leaves alone.
354
+ - **It stays where it grew.** Every prototype, its carrier and its shoots, is copied where it grew
355
+ (`tree_skeleton_copy_branches`) into one skeleton, the sheet. The sheet is given the framework's crown frame, so its
356
+ leaves are collected, cut and baked as the tree's own would be: the same gravity, height and crown.
357
+ - **Which.**
358
+ - For each generator the shoot rules grow on, the median carrier is grown first. Its leaves' spread
359
+ (`foliage_scale_spread`: p10/p50 and p90/p50 of their sizes, which the representatives also use) bounds how far a
360
+ prototype may be scaled.
361
+ - Prototypes are then added, each the longest carrier whose scaled reach still meets where the last one stopped,
362
+ until they reach without a gap from the shortest carrier to the longest.
363
+ - `length` is the carrier's length in the framework, which a host carrier is scaled against.
364
+ - **Cut.**
365
+ - The sheet is cut at every error from 1 cm in `TREE_LOD_ERROR_STEP` steps (the plan's, now exported) to the first
366
+ error that draws no wood.
367
+ - It goes through the same atlas path a tree's own LODs take: `tree_cluster_atlas`, now shared by `generate_tree`,
368
+ with each error's rings planned once.
369
+ - The texture budget is the ceiling over the prototypes' side areas together.
370
+ - `tree_clusters` hangs a whole tree's cut from that tree's own root, so the sheet, which holds a tree per prototype,
371
+ is cut per prototype. For a single tree that is branch 0's root, as before.
372
+ - **The representatives' greedy was quadratic in cuts.**
373
+ - Every pick scored every candidate against every cut. The sheet's 10-14 errors made that 85% of the time: the
374
+ willow's prototypes took 414 s.
375
+ - It now counts each candidate's undrawn cuts in its size window with a Fenwick tree a LOD. Only the tied candidates
376
+ sum their unlikeness, over their window, in cut order.
377
+ - On the same inputs the picks, texels and placements are identical to the bit (oak, shrub, maple, pine, the shrub's
378
+ prototypes).
379
+ - The pine's representatives went from 46.4 s to 6.3 s, and the maple's from 2.3 s to 0.55 s. That speeds up every
380
+ tree's own bake too.
381
+ - **Measured** (seed 1337 species, graph pine; the time is once per species, the atlas bake included):
382
+
383
+ | species | prototypes | time | tiles | errors | sleeve p90, median (range) | leaf per carrier metre, median | other seeds' carriers out of reach |
384
+ | :--- | ---: | ---: | ---: | ---: | :--- | :--- | :--- |
385
+ | oak | 19 | 10.9 s | 14 | 12 | 0.25 m (0.02-0.97) | 1.10 m²/m | 38 / 450, worst 5.7x |
386
+ | pine | 27 | 16.3 s | 9 | 14 | 0.26 m (0.00-1.16) | 0.18 m²/m | 32 / 553, worst 5.4x |
387
+ | birch | 18 | 16.5 s | 20 | 10 | 0.40 m (0.00-1.13) | 2.03 m²/m | 9 / 166, worst 1.6x |
388
+ | willow | 14 | 39.6 s | 24 | 12 | 0.63 m (0.00-1.48) | 4.10 m²/m | 30 / 248, worst 2.2x |
389
+ | maple | 16 | 7.8 s | 13 | 12 | 0.14 m (0.01-0.41) | 0.93 m²/m | 13 / 298, worst 2.2x |
390
+ | spruce | 27 | 17.6 s | 23 | 14 | 0.15 m (0.00-0.47) | 0.23 m²/m | 45 / 554, worst 4.8x |
391
+ | shrub | 6 | 1.6 s | 23 | 10 | 0.68 m (0.13-1.20) | 7.33 m²/m | 16 / 52, worst 1.8x |
392
+
393
+ - The sleeve is the 90th-percentile distance of a prototype's leaves from its carrier. A sleeve of 0.00 is a carrier
394
+ on which no shoot grew; its own annual units carry its leaves.
395
+ - "Out of reach" counts the carriers of seeds 1, 7, 4242 and 1337 that no prototype reaches within the leaves'
396
+ spread. The cover is gapless across seed 0's range, so these are carriers shorter or longer than any seed 0 grew.
397
+ G3 has to draw them with the nearest prototype, scaled past the spread.
398
+ - The leaves' size spread is narrow: p10/p50 0.82-0.87, p90/p50 1.11-1.18. Only the spruce's stem is wider, at
399
+ 0.54-2.25. The carriers' lengths span 6x (oak's boughs) to 100x (spruce's twigs).
400
+ - **Review (independent, adversarial).** Fixed:
401
+ - **The first version lifted each prototype into its carrier's frame.** That turned its leaves' gravity and sky with
402
+ the carrier: the oak's mean leaf up·Y fell from 0.70 in place to 0.29. All its prototypes were then fitted under one
403
+ crown frame stacked at the origin. Both made the atlas from leaves no tree grows.
404
+ - **A gapped cover** left 8-17% of other seeds' oak carriers out of reach.
405
+ - **Grown lengths:** `length` was the carrier's grown length, extension included, up to 11x the framework's on the
406
+ pine.
407
+ - **Copied levels and frame:** copies were re-levelled from their first branch, and a lateral's first node was hung
408
+ from the start of its parent's segment, not the node it hung from. The new round-trip spec caught the second.
409
+ - **Duplicated code:** the percentile law and the error step were copies, now shared; the rings were planned twice.
410
+ - **Weak specs:** a round trip blind to anything untransformed, a cover spec that only restated the greedy, and no
411
+ check that a prototype keeps the leaves it grew. Now the specs check:
412
+ - the sheet's wood is the in-place wood, node for node;
413
+ - its crown is the framework's;
414
+ - its leaves hang on the same branches at the same points;
415
+ - the cover is gapless and has no prototype to spare.
416
+ - A card's turn, size and small offset round its shoot come from the tree's one random stream, in collection order.
417
+ So a prototype's leaves match the in-place ones in where they hang and in their sun, not card for card.
418
+
419
+ ### G-F8: how many prototypes (new, from G1's measurement)
420
+
421
+ **(a) Keep G-F4's rule (mine).**
422
+ - It is per-species work, cached, and no tree pays for it: 1.6-39.6 s once per species.
423
+ - It keeps leaves at their own size: the alternative, scaling one prototype across a carrier range 6-100x long, would
424
+ draw the oak's bough leaves from a third to twice their size (its boughs run 0.62-3.90 m about a 1.9 m median).
425
+
426
+ **(b) Fewer prototypes, drawn at true size on the carriers nearest their length.** No leaf is scaled, but a host
427
+ carrier longer than its prototype is drawn bare past the prototype's reach, and a shorter one overhangs. That density
428
+ loss would only show at G3.
429
+
430
+ **G-F8 decided (mine, Alex left it to me, 2026-10-28): (a).** Each species grows its prototypes once, and the
431
+ leaves keep their size.
432
+
433
+ ## G3 landed: prototypes drawn on a graph tree's carriers
434
+
435
+ Alex, 2026-10-28: the botanical generator is for hero pieces, big meshes that look and move beautifully at LOD0. The
436
+ graph generator is the daily driver, for most trees. Keep the blast radius to the generator, and build for the long
437
+ term.
438
+
439
+ **How a graph tree draws its prototypes** (`tree_shoot_instances`):
440
+ - **Choice.** Every living carrier takes the prototype of its generator nearest its length in ratio.
441
+ - **Scaled by the ladder.** That ratio is drawn as the nearest power of the error ladder's step (√2): within ±19%,
442
+ so with the species' leaf spread, at 1, as the prototype grew.
443
+ - Wood, girth, leaves and cards scale alike, by `TREE_LOD_ERROR_STEP` to the instance's `shift`.
444
+ - At the tree's error, the tree draws as wood exactly what the prototype's cuts, `shift` steps finer, leave to
445
+ wood. A host error divided by such a scale is again a step of the ladder.
446
+ - **Turned about the vertical only**, so up stays up, as the prototype's leaves were lit and baked.
447
+ - **The tree's own framework stays**, so a seed still varies the tree. Each carrier keeps its course and takes:
448
+ - the prototype's growth past its framework's tip (`tree_skeleton_extend_branch`, the shoot simulation's own
449
+ extension, now shared), turned to continue from the tree's carrier's tip;
450
+ - its annual units;
451
+ - its girth.
452
+ - **The wood any LOD can draw** (what the finest error draws) is grafted onto the carrier
453
+ (`tree_skeleton_copy_branch`, which carries one branch through a placement). Each shoot system lands on the tree's
454
+ carrier where it hangs on the prototype's. The rig, the bark mesher and the LOD plan take it as the tree's own, so
455
+ the one-skeleton contract holds and the LODs' joints nest.
456
+ - **Its girth holds together** (`tree_skeleton_floor_girth`): no branch is thinner than what grows from it, and none
457
+ thickens toward its tip. It only raises.
458
+ - **Everything else is the prototype's** (`tree_shoot_instance_cards`):
459
+ - Each card's tile lies where the prototype's did, from the place on the tree where it hangs.
460
+ - It is skinned as the nearest drawn wood holds it (`tree_cluster_hang`, from `tree_clusters`).
461
+ - It is drawn from the species' atlas through the same `tree_mesh_build_clusters`.
462
+ - Per tree there is no leaf collection, no cutting, no representatives and no bake.
463
+ - **The skeleton contract gains three records:**
464
+ - `branch_instance`: the leaf collector leaves an instance's branches to its prototype;
465
+ - `segment_carried_leaf_area` and `segment_carried_reach`: the shoot systems no LOD draws as wood, weighed by the
466
+ mechanics' own law (`leaf_area`, now reported). The wind's mechanics load the segment each hangs from.
467
+ - **The LOD plan, the side area and the cost:**
468
+ - The LOD plan counts the instances' cards (`tree_lod_plan`'s `cards`).
469
+ - The grown side area includes every leaf the prototypes draw, those on a carrier where the carrier runs
470
+ (`tree_grown_side_area`'s `carried`).
471
+ - `TreeAsset.side_area` holds it once, and `tree_render_cost` reads it.
472
+ - **What the asset records.** `TreeAsset.shoot_prototypes` and `shoot_instances` record what a graph tree draws.
473
+ `tree_crown_opacity` measures a graph tree's leaves from them.
474
+ - **Caching.**
475
+ - Without a cache, every call shares `TREE_SPECIES_CACHE`: a species' prototypes grow once in a program, and
476
+ `clear()` lets them go.
477
+ - A caller's own leaf material bakes the prototypes from it, cached per species and material.
478
+ - A caller's own species goes through `generate_tree({ species, growth })`.
479
+
480
+ **Measured** (seed 7 trees, the species already cached; LOD0/1/2 triangles per m² and LOD0 joints per m²). The machine
481
+ ran 30-45% slower than for the G1 numbers, the botanical trees included:
482
+
483
+ | preset | graph side density / botanical | graph tree / botanical tree | triangles per m² | joints per m² | texture B/m² |
484
+ | :--- | :--- | :--- | :--- | :--- | ---: |
485
+ | oak | 0.51 / 0.46 | 0.88 s / 2.9 s | 606/323/93 | 11.4 | 51,945 |
486
+ | pine | 0.34 / 0.25 | 2.60 s / 9.6 s | 342/342/83 | 5.3 | 45,018 |
487
+ | birch | 0.64 / 0.52 | 1.92 s / 7.2 s | 388/388/54 | 9.3 | 65,931 |
488
+ | willow | 0.74 / 0.69 | 3.55 s / 11.9 s | 371/371/93 | 7.7 | 55,993 |
489
+ | maple | 0.40 / 0.43 | 0.57 s / 5.2 s | 703/371/66 | 7.6 | 23,884 |
490
+ | spruce | 0.23 / 0.25 | 2.22 s / 10.9 s | 518/301/86 | 13.7 | 29,311 |
491
+ | shrub | 0.65 / 0.66 | 0.21 s / 1.4 s | 390/390/57 | 13.6 | 170,215 |
492
+
493
+ - Every graph tree fits the ceiling. The palm and the fern have no shoot rules and are grown as before.
494
+ - The first tree of a species also grows its prototypes: 1.8 s (shrub) to 44 s (willow).
495
+ - **The review's measures, on oak 7, birch 1337, willow 7, pine 7, spruce 7 and maple 7:**
496
+ - Carriers thicker than their parents: none (were up to 12x).
497
+ - Wood drawn while its parent is not: none (were up to 14).
498
+ - Instance wood drawn unlike its prototype's cuts: 4 of about 196,000 checks, each where the girth floor thickened
499
+ a carrier to hold what grows from it.
500
+ - The pine's carriers bend p50 5.7°, p90 10.8° where their growth carries on, against 5.4° and 9.9° on the
501
+ prototype (were 33-40° p50, up to 143°).
502
+ - **Per tree, the time is the LOD plan** over the grafted wood, whose drawable shoots run to 9,214 branches on the
503
+ willow. The botanical tree pays the same plan cost. Measured, not argued: G3's done-when, 0.1-0.4 s a tree, is not
504
+ met above the shrub. It assumed a tree of framework alone. The plan's cost is shared with the botanical front end,
505
+ and so is its fix.
506
+ - **Looked at** (the playground, LOD0, before the review): the oak, the pine and the willow draw their prototypes
507
+ along their boughs.
508
+
509
+ **Review (independent, adversarial), fixed:**
510
+ - **Girth.** Carriers took their prototype's girth unscaled, up to 12x their parent's: wood floated, and cards fell
511
+ out of step with the wood. Fixed by the ladder-scaled girth and the girth floor.
512
+ - **Extensions** were translated, not turned: 33-40° bends at the junction.
513
+ - **No default cache.** Every caller without one regrew the species' prototypes, 12-43 s each time.
514
+ - **The config form.** `generate_tree(config)` grew any config by the graph, and the botanical pine's seed-grown
515
+ config became one seed-0 prototype. Now documented, with the `species` option for choosing.
516
+ - **Cards were placed relative to the wood that held them.** When they walked up to it, they moved by up to 1.55 m
517
+ and popped between LODs.
518
+ - **Leaves on a carrier** were placed along the prototype's course, not the tree's.
519
+ - **The carried reach** was counted from a segment's middle twice.
520
+ - **Duplicated code:** the placement transform and the point on a chain (now `tree_branch_placement_apply` and
521
+ `shoot_locate_on_chain`).
522
+ - **Specs** that only restated their code, or ran on one tree.
523
+
524
+ **Open, measured:**
525
+ - **Other seeds' carriers.** Those shorter or longer than any of seed 0's are drawn with the nearest prototype at
526
+ their ladder scale, past the leaves' spread. That is 2-31% of carriers, up to 5.7x (G1).
527
+ - **Shoot angles.** A shoot leaves the tree's carrier at the angle it left the prototype's, which follows its own
528
+ course: a p50 of 20° off the tree's local course (review, oak).
529
+
530
+ ## G2 dropped (measured)
531
+
532
+ G2 was to space a graph tree's carriers by its prototypes' sleeves until its crown filled. It isn't needed:
533
+ - A graph tree's framework is the botanical tree's own, node for node (the G0 contract).
534
+ - Its prototypes fill that framework as the botany does: its side density is within -0.03 to +0.14 of the botanical
535
+ tree's (above).
536
+ - Respacing the carriers would make its framework differ from the botanical tree's, and break that contract, for
537
+ density it already has.
538
+
539
+ ## G4 landed
540
+
541
+ - `generate_tree` grows by the generator graph unless asked otherwise. A preset's name is grown that way too.
542
+ `make_tree_species_preset` still describes the botanical species unless asked for the graph's (only the pine
543
+ differs).
544
+ - Specs of per-leaf behaviour (seasons, tints, the leaf-area measure) ask for the botanical tree, which holds its own
545
+ leaves.
546
+ - The self-organizing framework plan's S6 is struck (G-F7).
547
+
548
+ ## Not measured yet
549
+
550
+ - The cost of growing a prototype. Its upper bound is the species' whole botanical grow (0.3–5.6 s), once per
551
+ species. G1 measures it.
552
+ - Whether open-light prototypes keep the crown's density (G-F4). G2 measures it.
@@ -1 +1 @@
1
- {"version":3,"file":"tree_crown_opacity.d.ts","sourceRoot":"","sources":["../../../../../src/generation/foliage/analysis/tree_crown_opacity.js"],"names":[],"mappings":"AAoBA;;;;;;;;;;;;;;;;;GAiBG;AACH,0CAVW,OAAO,uBAAuB,EAAE,SAAS;IAExB,GAAG,GAApB,MAAM;IACW,gBAAgB,GAAjC,MAAM;IACW,UAAU,GAA3B,MAAM;IACW,WAAW,GAA5B,MAAM;IACW,kBAAkB,GAAnC,MAAM;SACN,YAAY,GACV,YAAY,CAqBxB;6BAxD4B,mBAAmB"}
1
+ {"version":3,"file":"tree_crown_opacity.d.ts","sourceRoot":"","sources":["../../../../../src/generation/foliage/analysis/tree_crown_opacity.js"],"names":[],"mappings":"AAqBA;;;;;;;;;;;;;;;;;GAiBG;AACH,0CAVW,OAAO,uBAAuB,EAAE,SAAS;IAExB,GAAG,GAApB,MAAM;IACW,gBAAgB,GAAjC,MAAM;IACW,UAAU,GAA3B,MAAM;IACW,WAAW,GAA5B,MAAM;IACW,kBAAkB,GAAnC,MAAM;SACN,YAAY,GACV,YAAY,CAqBxB;6BAzD4B,mBAAmB"}
@@ -12,7 +12,8 @@ import { foliage_card_reach } from "../skeleton/foliage_card_density.js";
12
12
  * @returns {number}
13
13
  */
14
14
  function median_card_length(asset) {
15
- const attachments = asset.attachments;
15
+ // a tree grown by its generator graph draws its prototypes' leaves
16
+ const attachments = asset.shoot_prototypes !== null ? asset.shoot_prototypes.attachments : asset.attachments;
16
17
  assert.greaterThan(attachments.count, 0, 'a leafless tree has no card length: pass microhole_radius');
17
18
  const scales = attachments.scales.slice(0, attachments.count).sort();
18
19
  return foliage_card_reach(foliage_tile_layout(asset.config), scales[scales.length >> 1]);
@@ -16,12 +16,14 @@ export function tree_envelope_side_area(position_arrays: Array<ArrayLike<number>
16
16
  * @param {import("../skeleton/TreeSkeleton.js").TreeSkeleton} skeleton
17
17
  * @param {import("../../../shade/renderer/geometry/Geometry.js").Geometry|null} leaves every leaf's card
18
18
  * (`tree_mesh_build_foliage`), `null` for a leafless tree
19
+ * @param {Float32Array|null} [carried] the cards of the leaves it draws but does not hold, its shoot prototypes'
20
+ * (`tree_shoot_instance_leaves`): positions
19
21
  * @returns {number}
20
22
  */
21
- export function tree_grown_side_area(skeleton: import("../skeleton/TreeSkeleton.js").TreeSkeleton, leaves: import("../../../shade/renderer/geometry/Geometry.js").Geometry | null): number;
23
+ export function tree_grown_side_area(skeleton: import("../skeleton/TreeSkeleton.js").TreeSkeleton, leaves: import("../../../shade/renderer/geometry/Geometry.js").Geometry | null, carried?: Float32Array | null): number;
22
24
  /**
23
25
  * @typedef {Object} TreeRenderCost
24
- * @property {number} side_area m^2, `tree_grown_side_area`: what the tree grew shows from the side
26
+ * @property {number} side_area m^2, `tree_grown_side_area`: what the tree grew shows from the side (`TreeAsset.side_area`)
25
27
  * @property {number[]} triangles bark and foliage triangles of each LOD
26
28
  * @property {number[]} triangle_density each LOD's triangles per m^2 of `side_area`
27
29
  * @property {number[]} joints each LOD's wind joints
@@ -57,7 +59,7 @@ export const TREE_RENDER_COST_CEILING: {
57
59
  };
58
60
  export type TreeRenderCost = {
59
61
  /**
60
- * m^2, `tree_grown_side_area`: what the tree grew shows from the side
62
+ * m^2, `tree_grown_side_area`: what the tree grew shows from the side (`TreeAsset.side_area`)
61
63
  */
62
64
  side_area: number;
63
65
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"tree_render_cost.d.ts","sourceRoot":"","sources":["../../../../../src/generation/foliage/analysis/tree_render_cost.js"],"names":[],"mappings":"AAKA;;;;;;;;;GASG;AACH,yDAJW,MAAM,UAAU,MAAM,CAAC,CAAC,WACxB,MAAM,GACJ,MAAM,CA8ClB;AAiBD;;;;;;;;GAQG;AACH,+CALW,OAAO,6BAA6B,EAAE,YAAY,UAClD,OAAO,8CAA8C,EAAE,QAAQ,GAAC,IAAI,GAElE,MAAM,CAYlB;AAaD;;;;;;;;;GASG;AAEH;;;;;;GAMG;AACH,wCAHW,OAAO,uBAAuB,EAAE,SAAS,GACvC,cAAc,CAgC1B;AA/FD;;;;;;;;;;;;GAYG;AACH,uCAFU;IAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAC,CAE4C;;;;;eAoCpH,MAAM;;;;eACN,MAAM,EAAE;;;;sBACR,MAAM,EAAE;;;;YACR,MAAM,EAAE;;;;mBACR,MAAM,EAAE;;;;mBACR,MAAM;;;;qBACN,MAAM"}
1
+ {"version":3,"file":"tree_render_cost.d.ts","sourceRoot":"","sources":["../../../../../src/generation/foliage/analysis/tree_render_cost.js"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,yDAJW,MAAM,UAAU,MAAM,CAAC,CAAC,WACxB,MAAM,GACJ,MAAM,CA8ClB;AAiBD;;;;;;;;;;GAUG;AACH,+CAPW,OAAO,6BAA6B,EAAE,YAAY,UAClD,OAAO,8CAA8C,EAAE,QAAQ,GAAC,IAAI,YAEpE,YAAY,GAAC,IAAI,GAEf,MAAM,CAelB;AAaD;;;;;;;;;GASG;AAEH;;;;;;GAMG;AACH,wCAHW,OAAO,uBAAuB,EAAE,SAAS,GACvC,cAAc,CA6B1B;AAjGD;;;;;;;;;;;;GAYG;AACH,uCAFU;IAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAC,CAE4C;;;;;eAyCpH,MAAM;;;;eACN,MAAM,EAAE;;;;sBACR,MAAM,EAAE;;;;YACR,MAAM,EAAE;;;;mBACR,MAAM,EAAE;;;;mBACR,MAAM;;;;qBACN,MAAM"}