@woosh/meep-engine 3.55.0 → 3.57.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 (650) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/DUPLICATION_REVIEW_2026_10_24.md +1072 -0
  4. package/src/core/binary/BitSet.js +1 -1
  5. package/src/core/binary/FLOAT16_MAX.d.ts +2 -0
  6. package/src/core/binary/FLOAT16_MAX.d.ts.map +1 -0
  7. package/src/core/binary/FLOAT16_MAX.js +1 -0
  8. package/src/core/binary/base58/base58_encode.js +2 -2
  9. package/src/core/binary/type/TypeBuilder.js +1 -1
  10. package/src/core/bvh2/bvh3/BVH.js +1 -1
  11. package/src/core/bvh2/bvh3/ebvh_optimize_treelet.d.ts.map +1 -1
  12. package/src/core/bvh2/bvh3/ebvh_optimize_treelet.js +7 -3
  13. package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.d.ts.map +1 -1
  14. package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.js +5 -1
  15. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.d.ts.map +1 -1
  16. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.js +195 -246
  17. package/src/core/collection/CuckooFilter.js +1 -1
  18. package/src/core/collection/array/isArrayEqual.d.ts.map +1 -1
  19. package/src/core/collection/array/isArrayEqual.js +33 -58
  20. package/src/core/collection/array/typed/array_buffer_hash.d.ts.map +1 -1
  21. package/src/core/collection/array/typed/array_buffer_hash.js +41 -39
  22. package/src/core/collection/array/typed/float32_array_hash.js +38 -38
  23. package/src/core/collection/array/typed/uint16_array_hash.d.ts +2 -1
  24. package/src/core/collection/array/typed/uint16_array_hash.d.ts.map +1 -1
  25. package/src/core/collection/array/typed/uint16_array_hash.js +30 -29
  26. package/src/core/collection/array/typed/uint32_array_hash.d.ts +2 -1
  27. package/src/core/collection/array/typed/uint32_array_hash.d.ts.map +1 -1
  28. package/src/core/collection/array/typed/uint32_array_hash.js +21 -20
  29. package/src/core/collection/array/typed/uint8_array_hash.d.ts +2 -1
  30. package/src/core/collection/array/typed/uint8_array_hash.d.ts.map +1 -1
  31. package/src/core/collection/array/typed/uint8_array_hash.js +37 -36
  32. package/src/core/collection/array/typed/uint_array_for_count.js +2 -2
  33. package/src/core/collection/list/List.d.ts.map +1 -1
  34. package/src/core/collection/list/List.js +3 -19
  35. package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
  36. package/src/core/collection/table/RowFirstTable.js +4 -28
  37. package/src/core/debug/matchers/DescribeAs.d.ts.map +1 -1
  38. package/src/core/debug/matchers/DescribeAs.js +62 -64
  39. package/src/core/function/FunctionCompiler.js +4 -4
  40. package/src/core/function/objectsEqual.d.ts.map +1 -1
  41. package/src/core/function/objectsEqual.js +3 -2
  42. package/src/core/geom/2d/bvh/BVH2D.d.ts.map +1 -1
  43. package/src/core/geom/2d/bvh/BVH2D.js +4 -3
  44. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts +5 -2
  45. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts.map +1 -1
  46. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js +49 -11
  47. package/src/core/geom/2d/hash-grid/shg_query_elements_circle.d.ts.map +1 -1
  48. package/src/core/geom/2d/hash-grid/shg_query_elements_circle.js +122 -159
  49. package/src/core/geom/2d/hash-grid/shg_query_elements_line.d.ts.map +1 -1
  50. package/src/core/geom/2d/hash-grid/shg_query_elements_line.js +8 -5
  51. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts +18 -0
  52. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts.map +1 -0
  53. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.js +97 -0
  54. package/src/core/geom/2d/r-tree/StaticR2Tree.js +2 -2
  55. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts +21 -0
  56. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts.map +1 -0
  57. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.js +54 -0
  58. package/src/core/geom/3d/aabb/aabb3_build_frustum.d.ts.map +1 -1
  59. package/src/core/geom/3d/aabb/aabb3_build_frustum.js +20 -53
  60. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts +1 -1
  61. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts.map +1 -1
  62. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.js +11 -42
  63. package/src/core/geom/3d/atlas/pack/atlas_pack_charts.d.ts.map +1 -1
  64. package/src/core/geom/3d/atlas/pack/atlas_pack_charts.js +30 -32
  65. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.d.ts.map +1 -1
  66. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.js +1 -5
  67. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.d.ts.map +1 -1
  68. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.js +1 -15
  69. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts.map +1 -1
  70. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.js +105 -116
  71. package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.d.ts.map +1 -1
  72. package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.js +36 -54
  73. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts +5 -10
  74. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts.map +1 -1
  75. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.js +20 -82
  76. package/src/core/geom/3d/plane/plane3_slerp.d.ts.map +1 -1
  77. package/src/core/geom/3d/plane/plane3_slerp.js +87 -102
  78. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts +12 -0
  79. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts.map +1 -1
  80. package/src/core/geom/3d/polygon/polygon3_compute_normal.js +107 -60
  81. package/src/core/geom/3d/ray/ray3_compute_closest_point.d.ts.map +1 -1
  82. package/src/core/geom/3d/ray/ray3_compute_closest_point.js +37 -43
  83. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
  84. package/src/core/geom/3d/shape/ConvexHullShape3D.js +5 -16
  85. package/src/core/geom/3d/shape/MeshShape3D.js +2 -56
  86. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  87. package/src/core/geom/3d/shape/TransformedShape3D.js +10 -7
  88. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  89. package/src/core/geom/3d/shape/UnionShape3D.js +9 -3
  90. package/src/core/geom/3d/shape/json/shape_to_type.js +2 -2
  91. package/src/core/geom/3d/sphere/harmonics/SH3_COEFFICIENTS.js +17 -17
  92. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.d.ts.map +1 -1
  93. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.js +6 -2
  94. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts.map +1 -1
  95. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js +3 -2
  96. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts +20 -2
  97. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts.map +1 -1
  98. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +52 -37
  99. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts.map +1 -1
  100. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js +40 -56
  101. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
  102. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +251 -260
  103. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.d.ts.map +1 -1
  104. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.js +104 -113
  105. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.d.ts.map +1 -1
  106. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.js +227 -238
  107. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  108. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +15 -24
  109. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.d.ts.map +1 -1
  110. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.js +31 -115
  111. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.d.ts.map +1 -1
  112. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.js +142 -150
  113. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
  114. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +151 -194
  115. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.d.ts.map +1 -1
  116. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.js +60 -85
  117. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.d.ts.map +1 -1
  118. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.js +156 -171
  119. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.d.ts.map +1 -1
  120. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.js +8 -44
  121. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
  122. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +2 -7
  123. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts.map +1 -1
  124. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.js +3 -2
  125. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.d.ts.map +1 -1
  126. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.js +128 -133
  127. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts +8 -14
  128. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts.map +1 -1
  129. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.js +36 -82
  130. package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts.map +1 -1
  131. package/src/core/geom/3d/triangle/tri3_ray_intersection.js +7 -144
  132. package/src/core/geom/ConicRay.d.ts.map +1 -1
  133. package/src/core/geom/ConicRay.js +230 -237
  134. package/src/core/localization/LocaleDataset.d.ts +6 -0
  135. package/src/core/localization/LocaleDataset.d.ts.map +1 -1
  136. package/src/core/localization/LocaleDataset.js +48 -37
  137. package/src/core/localization/LocalizationEngine.d.ts.map +1 -1
  138. package/src/core/localization/LocalizationEngine.js +3 -2
  139. package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
  140. package/src/core/math/lookup/ParameterLookupTable.js +3 -1
  141. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts.map +1 -1
  142. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.js +330 -400
  143. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts +16 -0
  144. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts.map +1 -1
  145. package/src/core/math/spline/spline3_hermite_nearest_point.js +134 -167
  146. package/src/core/model/DebouncedObservedBoolean.d.ts +1 -2
  147. package/src/core/model/DebouncedObservedBoolean.d.ts.map +1 -1
  148. package/src/core/model/DebouncedObservedBoolean.js +1 -1
  149. package/src/core/model/node-graph/node/NodeInstance.d.ts.map +1 -1
  150. package/src/core/model/node-graph/node/NodeInstance.js +2 -7
  151. package/src/core/model/node-graph/node/parameter/NodeParameterDescription.js +1 -1
  152. package/src/core/model/object/optional_equality.d.ts +3 -3
  153. package/src/core/model/object/optional_equality.d.ts.map +1 -1
  154. package/src/core/model/object/optional_equality.js +10 -27
  155. package/src/core/model/object/write_property.js +1 -1
  156. package/src/core/model/reactive/evaluation/MultiPredicateEvaluator.js +2 -2
  157. package/src/core/primitives/strings/string_compute_byte_size.d.ts +3 -3
  158. package/src/core/primitives/strings/string_compute_byte_size.d.ts.map +1 -1
  159. package/src/core/primitives/strings/string_compute_byte_size.js +8 -21
  160. package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
  161. package/src/core/process/executor/ConcurrentExecutor.js +14 -2
  162. package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts +6 -3
  163. package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts.map +1 -1
  164. package/src/engine/achievements/gateway/StorageAchievementGateway.js +31 -75
  165. package/src/engine/asset/loaders/SVGAssetLoader.d.ts.map +1 -1
  166. package/src/engine/asset/loaders/SVGAssetLoader.js +33 -31
  167. package/src/engine/control/first-person/math/criticallyDampedSpring.d.ts.map +1 -1
  168. package/src/engine/control/first-person/math/criticallyDampedSpring.js +3 -14
  169. package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
  170. package/src/engine/ecs/EntityComponentDataset.js +4 -1
  171. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts +0 -2
  172. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts.map +1 -1
  173. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.js +3 -3
  174. package/src/engine/ecs/terrain/ecs/layers/TerrainLayer.js +2 -2
  175. package/src/engine/ecs/transform/Transform64.d.ts +21 -0
  176. package/src/engine/ecs/transform/Transform64.d.ts.map +1 -1
  177. package/src/engine/ecs/transform/Transform64.js +26 -0
  178. package/src/engine/graphics/sh3/path_tracer/geometry/sort_triangles_by_distance_to_point.js +1 -1
  179. package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.js +1 -1
  180. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  181. package/src/engine/graphics3/WaterSystem.js +2 -1
  182. package/src/engine/graphics3/prefab/prefab_skin_frame.d.ts.map +1 -1
  183. package/src/engine/graphics3/prefab/prefab_skin_frame.js +1 -12
  184. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts +1 -1
  185. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
  186. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +141 -137
  187. package/src/engine/input/ecs/systems/InputControllerSystem.d.ts.map +1 -1
  188. package/src/engine/input/ecs/systems/InputControllerSystem.js +13 -3
  189. package/src/engine/input/ecs/systems/InputSystem.d.ts.map +1 -1
  190. package/src/engine/input/ecs/systems/InputSystem.js +2 -1
  191. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts +1 -1
  192. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts.map +1 -1
  193. package/src/engine/intelligence/behavior/composite/ParallelBehavior.js +4 -1
  194. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.d.ts.map +1 -1
  195. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.js +3 -1
  196. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.d.ts.map +1 -1
  197. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.js +3 -1
  198. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.d.ts.map +1 -1
  199. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.js +39 -33
  200. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts +5 -0
  201. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts.map +1 -1
  202. package/src/engine/intelligence/behavior/util/ConditionalBehavior.js +93 -75
  203. package/src/engine/intelligence/behavior/util/RotationBehavior.d.ts.map +1 -1
  204. package/src/engine/intelligence/behavior/util/RotationBehavior.js +79 -76
  205. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts +1 -0
  206. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts.map +1 -1
  207. package/src/engine/intelligence/blackboard/BlackboardStack.js +159 -123
  208. package/src/engine/intelligence/mcts/StateNode.d.ts.map +1 -1
  209. package/src/engine/intelligence/mcts/StateNode.js +366 -364
  210. package/src/engine/intelligence/resource/ResourceAllocationSolver.js +1 -1
  211. package/src/engine/navigation/ecs/components/Path.d.ts.map +1 -1
  212. package/src/engine/navigation/ecs/components/Path.js +2 -1
  213. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
  214. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +5 -2
  215. package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
  216. package/src/engine/physics/body/SolverBodyState.js +2 -6
  217. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  218. package/src/engine/physics/ccd/linear_sweep.js +3 -16
  219. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  220. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +2 -16
  221. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +13 -1
  222. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  223. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +15 -4
  224. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  225. package/src/engine/physics/ecs/PhysicsSystem.js +2 -5
  226. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts +12 -0
  227. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts.map +1 -0
  228. package/src/engine/physics/inertia/locked_inverse_inertia.js +22 -0
  229. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
  230. package/src/engine/physics/integration/integrate_velocity.js +3 -18
  231. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts +1 -0
  232. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
  233. package/src/engine/physics/mls-mpm/MLS_MPM.js +5 -4
  234. package/src/engine/physics/narrowphase/convex_decomposition.d.ts.map +1 -1
  235. package/src/engine/physics/narrowphase/convex_decomposition.js +7 -16
  236. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  237. package/src/engine/physics/vehicle/RaycastVehicle.js +15 -5
  238. package/src/engine/save/StorageBackedList.d.ts +5 -0
  239. package/src/engine/save/StorageBackedList.d.ts.map +1 -1
  240. package/src/engine/save/StorageBackedList.js +161 -144
  241. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  242. package/src/engine/simulation/Ticker.js +394 -391
  243. package/src/engine/sound/simulation/probe/AcousticProbeField.d.ts.map +1 -1
  244. package/src/engine/sound/simulation/probe/AcousticProbeField.js +6 -19
  245. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts +15 -0
  246. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts.map +1 -1
  247. package/src/engine/sound/simulation/probe/probe_edge_visible.js +59 -41
  248. package/src/engine/sound/simulation/probe/probe_refine_connectivity.d.ts.map +1 -1
  249. package/src/engine/sound/simulation/probe/probe_refine_connectivity.js +164 -181
  250. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts.map +1 -1
  251. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +20 -5
  252. package/src/format/image/avif/av1/decode/Av1FrameContext.d.ts.map +1 -1
  253. package/src/format/image/avif/av1/decode/Av1FrameContext.js +3 -10
  254. package/src/format/image/avif/av1/decode/reconstruct.d.ts +20 -0
  255. package/src/format/image/avif/av1/decode/reconstruct.d.ts.map +1 -1
  256. package/src/format/image/avif/av1/decode/reconstruct.js +22 -9
  257. package/src/format/image/avif/av1/encode/choose_restoration.js +2 -18
  258. package/src/format/image/avif/av1/encode/quantise.d.ts.map +1 -1
  259. package/src/format/image/avif/av1/encode/quantise.js +1 -55
  260. package/src/format/image/avif/av1/filter/loop_restoration.d.ts +9 -0
  261. package/src/format/image/avif/av1/filter/loop_restoration.d.ts.map +1 -1
  262. package/src/format/image/avif/av1/filter/loop_restoration.js +1 -1
  263. package/src/format/texture/basis/transcode/etc1s_to_bc7.js +2 -33
  264. package/src/format/texture/basis/transcode/fit_endpoints.d.ts +11 -0
  265. package/src/format/texture/basis/transcode/fit_endpoints.d.ts.map +1 -1
  266. package/src/format/texture/basis/transcode/fit_endpoints.js +1 -1
  267. package/src/format/texture/basis/uastc/uastc_decode_block.d.ts.map +1 -1
  268. package/src/format/texture/basis/uastc/uastc_decode_block.js +2 -19
  269. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +220 -0
  270. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +172 -0
  271. package/src/generation/foliage/FOLIAGE_DESIGN.md +165 -15
  272. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +158 -0
  273. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +248 -0
  274. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +694 -0
  275. package/src/generation/foliage/analysis/CrownOpacity.d.ts +118 -0
  276. package/src/generation/foliage/analysis/CrownOpacity.d.ts.map +1 -0
  277. package/src/generation/foliage/analysis/CrownOpacity.js +182 -0
  278. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts +10 -0
  279. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts.map +1 -0
  280. package/src/generation/foliage/analysis/crown_opacity_frames.js +132 -0
  281. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts +51 -0
  282. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts.map +1 -0
  283. package/src/generation/foliage/analysis/crown_opacity_measure.js +649 -0
  284. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts +66 -0
  285. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts.map +1 -0
  286. package/src/generation/foliage/analysis/foliage_measure_leaf_area.js +192 -0
  287. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts +27 -0
  288. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts.map +1 -0
  289. package/src/generation/foliage/analysis/tree_crown_opacity.js +58 -0
  290. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts +3 -2
  291. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts.map +1 -1
  292. package/src/generation/foliage/animation/build_tree_wind_rig.js +12 -30
  293. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts +12 -0
  294. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts.map +1 -0
  295. package/src/generation/foliage/animation/tree_wind_bend_limit.js +13 -0
  296. package/src/generation/foliage/asset/TreeAsset.d.ts +5 -0
  297. package/src/generation/foliage/asset/TreeAsset.d.ts.map +1 -1
  298. package/src/generation/foliage/asset/TreeAsset.js +6 -0
  299. package/src/generation/foliage/asset/generate_tree.d.ts.map +1 -1
  300. package/src/generation/foliage/asset/generate_tree.js +23 -6
  301. package/src/generation/foliage/config/{BranchLevelConfig.d.ts → BranchGeneratorConfig.d.ts} +61 -75
  302. package/src/generation/foliage/config/BranchGeneratorConfig.d.ts.map +1 -0
  303. package/src/generation/foliage/config/{BranchLevelConfig.js → BranchGeneratorConfig.js} +83 -126
  304. package/src/generation/foliage/config/BranchSpawnRule.d.ts +118 -0
  305. package/src/generation/foliage/config/BranchSpawnRule.d.ts.map +1 -0
  306. package/src/generation/foliage/config/BranchSpawnRule.js +217 -0
  307. package/src/generation/foliage/config/FoliageCardType.d.ts +1 -1
  308. package/src/generation/foliage/config/FoliageCardType.js +2 -2
  309. package/src/generation/foliage/config/FoliageConfig.d.ts +23 -45
  310. package/src/generation/foliage/config/FoliageConfig.d.ts.map +1 -1
  311. package/src/generation/foliage/config/FoliageConfig.js +47 -93
  312. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts +12 -20
  313. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts.map +1 -1
  314. package/src/generation/foliage/config/FoliageMaterialConfig.js +261 -279
  315. package/src/generation/foliage/config/FoliageSpawnRule.d.ts +77 -0
  316. package/src/generation/foliage/config/FoliageSpawnRule.d.ts.map +1 -0
  317. package/src/generation/foliage/config/FoliageSpawnRule.js +135 -0
  318. package/src/generation/foliage/config/FoliageTileContent.d.ts +9 -0
  319. package/src/generation/foliage/config/FoliageTileContent.d.ts.map +1 -0
  320. package/src/generation/foliage/config/FoliageTileContent.js +12 -0
  321. package/src/generation/foliage/config/LeafApexShape.d.ts +12 -0
  322. package/src/generation/foliage/config/LeafApexShape.d.ts.map +1 -0
  323. package/src/generation/foliage/config/LeafApexShape.js +17 -0
  324. package/src/generation/foliage/config/LeafArchitecture.d.ts +155 -0
  325. package/src/generation/foliage/config/LeafArchitecture.d.ts.map +1 -0
  326. package/src/generation/foliage/config/LeafArchitecture.js +288 -0
  327. package/src/generation/foliage/config/LeafBaseShape.d.ts +14 -0
  328. package/src/generation/foliage/config/LeafBaseShape.d.ts.map +1 -0
  329. package/src/generation/foliage/config/LeafBaseShape.js +21 -0
  330. package/src/generation/foliage/config/LeafLobation.d.ts +10 -0
  331. package/src/generation/foliage/config/LeafLobation.d.ts.map +1 -0
  332. package/src/generation/foliage/config/LeafLobation.js +14 -0
  333. package/src/generation/foliage/config/PhyllotaxisMode.d.ts +11 -0
  334. package/src/generation/foliage/config/PhyllotaxisMode.d.ts.map +1 -1
  335. package/src/generation/foliage/config/PhyllotaxisMode.js +36 -0
  336. package/src/generation/foliage/config/ShootBudZone.d.ts +105 -0
  337. package/src/generation/foliage/config/ShootBudZone.d.ts.map +1 -0
  338. package/src/generation/foliage/config/ShootBudZone.js +219 -0
  339. package/src/generation/foliage/config/ShootGrowthConfig.d.ts +84 -0
  340. package/src/generation/foliage/config/ShootGrowthConfig.d.ts.map +1 -0
  341. package/src/generation/foliage/config/ShootGrowthConfig.js +146 -0
  342. package/src/generation/foliage/config/ShootSystemRule.d.ts +144 -0
  343. package/src/generation/foliage/config/ShootSystemRule.d.ts.map +1 -0
  344. package/src/generation/foliage/config/ShootSystemRule.js +316 -0
  345. package/src/generation/foliage/config/TreeLODConfig.d.ts +1 -1
  346. package/src/generation/foliage/config/TreeLODConfig.js +1 -1
  347. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts +40 -8
  348. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts.map +1 -1
  349. package/src/generation/foliage/config/TreeSpeciesConfig.js +124 -68
  350. package/src/generation/foliage/config/TreeWindConfig.d.ts +23 -10
  351. package/src/generation/foliage/config/TreeWindConfig.d.ts.map +1 -1
  352. package/src/generation/foliage/config/TreeWindConfig.js +34 -25
  353. package/src/generation/foliage/index.d.ts +19 -2
  354. package/src/generation/foliage/index.js +63 -44
  355. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts +59 -0
  356. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts.map +1 -0
  357. package/src/generation/foliage/material/FoliageAtlasCutout.js +93 -0
  358. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts +26 -0
  359. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts.map +1 -0
  360. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.js +63 -0
  361. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts +34 -0
  362. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts.map +1 -0
  363. package/src/generation/foliage/material/foliage_atlas_cutout.js +174 -0
  364. package/src/generation/foliage/material/foliage_tile.d.ts +110 -0
  365. package/src/generation/foliage/material/foliage_tile.d.ts.map +1 -0
  366. package/src/generation/foliage/material/foliage_tile.js +286 -0
  367. package/src/generation/foliage/material/leaf_geometry.d.ts +103 -0
  368. package/src/generation/foliage/material/leaf_geometry.d.ts.map +1 -0
  369. package/src/generation/foliage/material/leaf_geometry.js +528 -0
  370. package/src/generation/foliage/material/make_foliage_material.d.ts +13 -33
  371. package/src/generation/foliage/material/make_foliage_material.d.ts.map +1 -1
  372. package/src/generation/foliage/material/make_foliage_material.js +356 -605
  373. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts +39 -4
  374. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts.map +1 -1
  375. package/src/generation/foliage/mesh/foliage_collect_attachments.js +637 -569
  376. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts +48 -0
  377. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts.map +1 -0
  378. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.js +232 -0
  379. package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
  380. package/src/generation/foliage/mesh/tree_mesh_build_bark.js +1023 -1049
  381. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts +9 -2
  382. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts.map +1 -1
  383. package/src/generation/foliage/mesh/tree_mesh_build_foliage.js +467 -454
  384. package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
  385. package/src/generation/foliage/presets/make_tree_species_preset.js +1648 -870
  386. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts +35 -0
  387. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts.map +1 -0
  388. package/src/generation/foliage/skeleton/ShootFrameworkHash.js +129 -0
  389. package/src/generation/foliage/skeleton/ShootGirth.d.ts +51 -0
  390. package/src/generation/foliage/skeleton/ShootGirth.d.ts.map +1 -0
  391. package/src/generation/foliage/skeleton/ShootGirth.js +212 -0
  392. package/src/generation/foliage/skeleton/ShootLightField.d.ts +73 -0
  393. package/src/generation/foliage/skeleton/ShootLightField.d.ts.map +1 -0
  394. package/src/generation/foliage/skeleton/ShootLightField.js +197 -0
  395. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts +106 -3
  396. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts.map +1 -1
  397. package/src/generation/foliage/skeleton/TreeSkeleton.js +217 -39
  398. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts +13 -0
  399. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts.map +1 -0
  400. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.js +16 -0
  401. package/src/generation/foliage/skeleton/foliage_card_density.d.ts +71 -0
  402. package/src/generation/foliage/skeleton/foliage_card_density.d.ts.map +1 -0
  403. package/src/generation/foliage/skeleton/foliage_card_density.js +101 -0
  404. package/src/generation/foliage/skeleton/foliage_senescence.d.ts +101 -0
  405. package/src/generation/foliage/skeleton/foliage_senescence.d.ts.map +1 -0
  406. package/src/generation/foliage/skeleton/foliage_senescence.js +149 -0
  407. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts +76 -0
  408. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts.map +1 -0
  409. package/src/generation/foliage/skeleton/foliage_unit_cards.js +95 -0
  410. package/src/generation/foliage/skeleton/shoot_demography.d.ts +22 -0
  411. package/src/generation/foliage/skeleton/shoot_demography.d.ts.map +1 -0
  412. package/src/generation/foliage/skeleton/shoot_demography.js +96 -0
  413. package/src/generation/foliage/skeleton/shoot_geometry.d.ts +66 -0
  414. package/src/generation/foliage/skeleton/shoot_geometry.d.ts.map +1 -0
  415. package/src/generation/foliage/skeleton/shoot_geometry.js +109 -0
  416. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts +166 -0
  417. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts.map +1 -0
  418. package/src/generation/foliage/skeleton/shoot_systems_simulate.js +588 -0
  419. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts +28 -12
  420. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts.map +1 -1
  421. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.js +137 -102
  422. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts +112 -0
  423. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts.map +1 -0
  424. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js +408 -0
  425. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts.map +1 -1
  426. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js +208 -206
  427. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts +5 -2
  428. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
  429. package/src/generation/foliage/skeleton/tree_skeleton_grow.js +2048 -1871
  430. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts +17 -0
  431. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts.map +1 -0
  432. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.js +231 -0
  433. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts +14 -0
  434. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts.map +1 -0
  435. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.js +26 -0
  436. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts +10 -0
  437. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts.map +1 -0
  438. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.js +20 -0
  439. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts.map +1 -1
  440. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +4 -1
  441. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts +1 -0
  442. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts.map +1 -1
  443. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +98 -86
  444. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +263 -0
  445. package/src/shade/descriptor/WebGPUExtensionType.d.ts +17 -0
  446. package/src/shade/descriptor/WebGPUExtensionType.d.ts.map +1 -1
  447. package/src/shade/descriptor/WebGPUExtensionType.js +31 -1
  448. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts +37 -0
  449. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts.map +1 -0
  450. package/src/shade/playground/foliage_wind/FoliageRigOverlay.js +491 -0
  451. package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -1
  452. package/src/shade/playground/foliage_wind/foliage_world.js +600 -602
  453. package/src/shade/playground/foliage_wind/index.html +6 -0
  454. package/src/shade/playground/foliage_wind/main.js +14 -0
  455. package/src/shade/renderer/Renderer.d.ts +5 -0
  456. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  457. package/src/shade/renderer/Renderer.js +25 -2
  458. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  459. package/src/shade/renderer/animation/GPUAnimationManager.js +2 -1
  460. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts +2 -1
  461. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts.map +1 -1
  462. package/src/shade/renderer/animation/foliage/FoliageWindJoint.js +2 -1
  463. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.d.ts.map +1 -1
  464. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.js +4 -2
  465. package/src/shade/renderer/buffer/table/GPUTypedTable.js +1 -1
  466. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
  467. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +403 -401
  468. package/src/shade/renderer/camera/OrbitalCameraController.d.ts +1 -62
  469. package/src/shade/renderer/camera/OrbitalCameraController.d.ts.map +1 -1
  470. package/src/shade/renderer/camera/OrbitalCameraController.js +1 -374
  471. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.d.ts.map +1 -1
  472. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.js +3 -0
  473. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.d.ts.map +1 -1
  474. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.js +6 -1
  475. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +1 -1
  476. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +2 -2
  477. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts.map +1 -1
  478. package/src/shade/renderer/fluid/GPUFluidCascade.js +6 -3
  479. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +361 -0
  480. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.d.ts.map +1 -1
  481. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js +335 -241
  482. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.d.ts.map +1 -1
  483. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js +108 -101
  484. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.d.ts.map +1 -1
  485. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.js +69 -67
  486. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts +7 -6
  487. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts.map +1 -1
  488. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js +341 -287
  489. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts +6 -4
  490. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts.map +1 -1
  491. package/src/shade/renderer/fluid/mac/FluidMacPasses.js +427 -400
  492. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts +10 -5
  493. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts.map +1 -1
  494. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.js +532 -190
  495. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.d.ts.map +1 -1
  496. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.js +231 -237
  497. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts +2 -2
  498. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts.map +1 -1
  499. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js +282 -245
  500. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts +1 -3
  501. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts.map +1 -1
  502. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.js +139 -109
  503. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts +6 -6
  504. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts.map +1 -1
  505. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.js +257 -222
  506. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts +8 -7
  507. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts.map +1 -1
  508. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.js +119 -92
  509. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts +6 -9
  510. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts.map +1 -1
  511. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.js +229 -181
  512. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +17 -7
  513. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts.map +1 -1
  514. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.js +634 -621
  515. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts +8 -6
  516. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts.map +1 -1
  517. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js +166 -149
  518. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts +8 -6
  519. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts.map +1 -1
  520. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js +219 -183
  521. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.d.ts.map +1 -1
  522. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.js +142 -122
  523. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +674 -663
  524. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +1 -1
  525. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  526. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +63 -29
  527. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  528. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +77 -87
  529. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.d.ts.map +1 -1
  530. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.js +4 -3
  531. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts +11 -11
  532. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts.map +1 -1
  533. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.js +17 -19
  534. package/src/shade/renderer/global_illumination/lpv/graph_bake_irradiance_lookup_2d.js +4 -4
  535. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.d.ts.map +1 -1
  536. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.js +5 -1
  537. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  538. package/src/shade/renderer/loader/gltf/load_gltf.js +11 -35
  539. package/src/shade/renderer/loader/usd/load_usd.d.ts.map +1 -1
  540. package/src/shade/renderer/loader/usd/load_usd.js +6 -19
  541. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +2 -1
  542. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  543. package/src/shade/renderer/particles/GPUParticleSystem.js +1 -1
  544. package/src/shade/renderer/particles/graph_particles_avboit.d.ts +2 -2
  545. package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
  546. package/src/shade/renderer/particles/graph_particles_avboit.js +4 -9
  547. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
  548. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +199 -193
  549. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts.map +1 -1
  550. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.js +151 -143
  551. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.d.ts.map +1 -1
  552. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.js +11 -5
  553. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.d.ts.map +1 -1
  554. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.js +6 -18
  555. package/src/shade/renderer/postprocess/gtao/GTAO.js +1 -1
  556. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  557. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +3 -5
  558. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +1 -1
  559. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  560. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.d.ts.map +1 -1
  561. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.js +7 -3
  562. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
  563. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +4 -2
  564. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.d.ts.map +1 -1
  565. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +4 -1
  566. package/src/shade/renderer/postprocess/ssr/downsample_karis.d.ts.map +1 -1
  567. package/src/shade/renderer/postprocess/ssr/downsample_karis.js +6 -3
  568. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
  569. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +4 -3
  570. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.d.ts.map +1 -1
  571. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.js +4 -1
  572. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
  573. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +4 -2
  574. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts.map +1 -1
  575. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.js +35 -39
  576. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.d.ts.map +1 -1
  577. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.js +20 -17
  578. package/src/shade/renderer/postprocess/taa/shader_taa.d.ts.map +1 -1
  579. package/src/shade/renderer/postprocess/taa/shader_taa.js +6 -3
  580. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  581. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -1
  582. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +1 -1
  583. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js +2 -2
  584. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +1 -1
  585. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.d.ts.map +1 -1
  586. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.js +92 -83
  587. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +1 -1
  588. package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
  589. package/src/shade/renderer/shader/ShaderDescriptor.js +12 -4
  590. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.d.ts.map +1 -1
  591. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.js +294 -286
  592. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_interpolate_probe_irradiance8.js +5 -5
  593. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.d.ts.map +1 -1
  594. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.js +5 -3
  595. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.d.ts.map +1 -1
  596. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.js +9 -6
  597. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.d.ts.map +1 -1
  598. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.js +33 -38
  599. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  600. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +690 -675
  601. package/src/shade/renderer/shader/type/WebGPUArray.d.ts +3 -0
  602. package/src/shade/renderer/shader/type/WebGPUArray.d.ts.map +1 -1
  603. package/src/shade/renderer/shader/type/WebGPUArray.js +185 -167
  604. package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
  605. package/src/shade/renderer/shader/type/WebGPUStruct.js +461 -455
  606. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.d.ts.map +1 -1
  607. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.js +335 -211
  608. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.d.ts.map +1 -1
  609. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.js +329 -221
  610. package/src/shade/renderer/shader/type/type_has_f16.d.ts +12 -0
  611. package/src/shade/renderer/shader/type/type_has_f16.d.ts.map +1 -0
  612. package/src/shade/renderer/shader/type/type_has_f16.js +66 -0
  613. package/src/shade/renderer/view/GPUViewContext.d.ts +0 -14
  614. package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
  615. package/src/shade/renderer/view/GPUViewContext.js +0 -29
  616. package/src/shade/renderer/view/ViewManager.d.ts +1 -1
  617. package/src/shade/renderer/view/ViewManager.js +1 -1
  618. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +40 -3
  619. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  620. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +660 -583
  621. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  622. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +16 -2
  623. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts.map +1 -1
  624. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +5 -2
  625. package/src/shade/renderer/water/shader_water_avboit.js +1 -1
  626. package/src/shade/renderer/wind/GPUSceneWind.d.ts +1 -1
  627. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  628. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +260 -23
  629. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts +6 -7
  630. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  631. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +269 -69
  632. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  633. package/src/shade/wgsl/validate_wgsl_source.js +27 -1
  634. package/src/view/controller/controls/ListController.d.ts.map +1 -1
  635. package/src/view/controller/controls/ListController.js +118 -113
  636. package/src/view/controller/controls/Vector1Control.js +97 -97
  637. package/src/view/elements/image/SvgImageView.d.ts +1 -0
  638. package/src/view/elements/image/SvgImageView.d.ts.map +1 -1
  639. package/src/view/elements/image/SvgImageView.js +92 -90
  640. package/src/view/minimap/dom/MinimapTerrainView.d.ts +1 -0
  641. package/src/view/minimap/dom/MinimapTerrainView.d.ts.map +1 -1
  642. package/src/view/minimap/dom/MinimapTerrainView.js +151 -147
  643. package/src/view/tooltip/gml/TooltipParser.js +2 -2
  644. package/src/engine/network/PriorityFetch.d.ts +0 -59
  645. package/src/engine/network/PriorityFetch.d.ts.map +0 -1
  646. package/src/engine/network/PriorityFetch.js +0 -193
  647. package/src/generation/foliage/config/BranchLevelConfig.d.ts.map +0 -1
  648. package/src/shade/renderer/volumetrics/VOLUMETRICS_RESOLUTION_Z.d.ts +0 -2
  649. package/src/shade/renderer/volumetrics/VOLUMETRICS_RESOLUTION_Z.d.ts.map +0 -1
  650. package/src/shade/renderer/volumetrics/VOLUMETRICS_RESOLUTION_Z.js +0 -1
@@ -0,0 +1,172 @@
1
+ # Crown Filling by Light
2
+
3
+ Follows `SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md`, which grew every woody species' twigs from sourced shoot
4
+ demography and left the crowns barren.
5
+
6
+ ## Problem
7
+
8
+ Each carrier grows its twig system alone for a fixed number of years, at a fixed vigour (net shoots a shoot leaves a
9
+ year), with shoots shed by a chosen rank of age, order and length. Nothing in that knows where the crown is empty or
10
+ crowded. Seed 1337, against master's metre-long cards:
11
+
12
+ | preset | leaf area, master -> now | side opacity, master -> now |
13
+ | :--- | ---: | ---: |
14
+ | birch | 45 -> 2 m^2 | 0.44 -> 0.10 |
15
+ | willow | 241 -> 7 m^2 | 0.67 -> 0.18 |
16
+ | pine | 174 -> 24 m^2 | 0.69 -> 0.33 |
17
+ | spruce | 161 -> 20 m^2 | 0.57 -> 0.34 |
18
+ | maple | 150 -> 63 m^2 | 0.66 -> 0.43 |
19
+ | oak | 164 -> 113 m^2 | 0.64 -> 0.51 |
20
+
21
+ **The target** is the US Forest Inventory's crown ratings of 15,011 leaf-on trees seen from the side (Randolph 2006,
22
+ USDA GTR SRS-94, Tables 1-4). Healthy crowns block a mean 45% of their outline (oaks, maples, birches 46-51%), and their
23
+ foliated parts let about 15% of skylight through (interquartile 10-20%). From below, open-grown crowns intercept 0.75-0.92
24
+ of light (Nowak 1996, Forest Science 42: 504-507, Table 2).
25
+
26
+ ## Principle
27
+
28
+ A real crown is full because it grows until it shades itself. Shoots in light make more shoots; shoots in shade make
29
+ fewer, and an axis in deep shade dies. The papers already in hand measure exactly this:
30
+
31
+ - **Spruce.** Rb, the net shoots a shoot leaves a year, rises with the light a branch receives: about 0.65 at
32
+ 4-5 mol m^-2 d^-1 to about 2.2 at 10-12, against 37.1 under open sky, so 0.12 to 0.30 of full light. Below 1 in deep
33
+ shade, a branch's foliage shrinks with age (Niinemets & Lukjanova 2003, New Phytol. 158: 75-89, Fig. 5b, Table 1).
34
+ - **Pine.** Branching stops at a relative light of 0.20-0.25 (Ilonen et al. 1979, Silva Fennica 13: 319-321). A shoot
35
+ with no needles left is dead (Kellomäki & Kurttio 1991, p. 104).
36
+ - **Birch.** The bud population grows 1.52 a year in the top of the crown, 0.999 at its bottom (Maillette 1982, J.
37
+ Appl. Ecol. 19: 219-238, Table 1).
38
+ - **Red maple.** Shaded branches die, so foliage stays at the crown's periphery (Wilson 1966, Harvard Forest Paper 14,
39
+ p. 19).
40
+
41
+ So vigour becomes a function of light, and the crown's leaf area becomes an outcome: growth stops where the crown has
42
+ shaded its own interior to the light at which shoots no longer replace themselves.
43
+
44
+ ## Design
45
+
46
+ The framework (trunk, boughs and branches from the generator graph) stays as it is. Everything younger grows by light.
47
+ `tree_skeleton_grow_shoots` is rebuilt around one tree-wide simulation:
48
+
49
+ 1. **One season loop for the whole tree.** Every carrier's twig system grows in the same loop, so the systems compete
50
+ for the same light. `years` and the light response move from the per-carrier `ShootSystemRule` to a species-level
51
+ `ShootGrowthConfig`. The rules keep what differs by carrier: bud zones, lengths, orders, angles.
52
+ 2. **Shoots have geometry as they grow.** Each new unit's start, heading and end are fixed in its season (tropisms,
53
+ zigzag, insertion and phyllotaxis, as the writer does today), so light can be measured where the leaves are. The
54
+ writer then only turns the surviving axes into skeleton branches.
55
+ 3. **The light field.** Each season, the leaf area of every leaf-bearing unit is deposited in a voxel grid over the
56
+ crown.
57
+ - **Light at each voxel:** relative irradiance from the sky by Beer-Lambert, `exp(-G Omega LAD path)`.
58
+ - **Extinction:** `G = 0.5`, the projection of a spherical leaf angle distribution.
59
+ - **Clumping:** `Omega` is the species' shoot clumping; Scots pine about 0.58 from its silhouette-to-area ratio of
60
+ 0.146 (Smolander, Stenberg & Linder 1994, Tree Physiol. 14: 971-980), broadleaves 1 for want of data.
61
+ - **Sky:** a standard overcast sky, radiance `(1 + 2 sin elevation) / 3` (Moon & Spencer 1942), weighted for a
62
+ horizontal receiver as hemispherical photographs measure it.
63
+ - **Directions:** lattice directions, so each is one sweep of the grid. The cost is grid cells times directions,
64
+ whatever the leaf count.
65
+ 4. **Vigour follows light.** An axis in relative light `Q` leaves `Rb(Q)` net shoots a year. `Rb` rises linearly from 1
66
+ at the species' compensation light to its full vigour at its saturation light, flat above, and falls below 1 under
67
+ compensation. A season's new shoots on an axis survive at `Rb(Q) / yield`, its gross yield of new shoots. The shoots
68
+ kept are the best lit, with a dithered count so the total is exact on average. This replaces the chosen
69
+ age/order/length rank.
70
+ 5. **Death by shade is not a separate rule.** A terminal that is shed takes its axis with it [BB1998], and in shade the
71
+ terminal is shed. A shaded branch thins and dies as `Rb < 1` makes it.
72
+ 6. **Long enough to fill.** `years` covers the time the periphery takes to reach the light limit, so crown fullness is
73
+ set by light, not by when the simulation stops. The equilibrium is measured, not assumed.
74
+ 7. **Wood.** The [BB2000] Table 7 diameter holds only for current and year-old units, the shoots it was measured on.
75
+ Older wood is the pipe model plus what its laterals need where they join, for twig and carrier alike.
76
+ 8. **Framework avoidance** is tested when a unit grows, as now.
77
+
78
+ **Per-species light response:**
79
+
80
+ | preset | compensation `Q` | saturation `Q` | full vigour | source |
81
+ | :--- | ---: | ---: | ---: | :--- |
82
+ | spruce | 0.16 | 0.30 | 2.19 | [NL2003] Fig. 5b line through (0.12, 0.65), (0.30, 2.2); Table 1 max |
83
+ | pine | 0.22 | 0.30 | 1.867 | Ilonen 1979 (0.20-0.25); saturation spruce's; [NL2003] Fig. 2 |
84
+ | birch | 0.22 | 0.30 | 1.52 | top of crown [M1982]; light points pine's |
85
+ | oak, maple, willow, shrub | chosen | chosen | chosen | none found |
86
+
87
+ **Gaps.** Only spruce has a measured light curve. Pine has its compensation point. The others borrow the curve's
88
+ shape, and that is marked in the code.
89
+
90
+ ## Measuring
91
+
92
+ - **Fullness:** crown density and foliage transparency against Randolph 2006, and interception from below against Nowak
93
+ 1996, measured with the crown opacity benchmark being built in a sibling session. Until that lands, the scratchpad
94
+ probe stands in.
95
+ - **Specs, from the principle:**
96
+ - In a uniform light field, the twig population changes by `Rb(Q)` a year.
97
+ - Shoots in shade die.
98
+ - Leaf area stops growing with `years` once the crown is full.
99
+ - Doubling `years` past equilibrium changes leaf area little.
100
+ - A crown with more framework does not end up with proportionally more leaf.
101
+
102
+ ## Plan
103
+
104
+ 1. `ShootGrowthConfig`; the rule loses `years` and `vigour`.
105
+ 2. `shoot_light_field`: voxel leaf area, sky sweeps, irradiance query. Specs against Beer-Lambert in closed form.
106
+ 3. The tree-wide simulation with geometry, light-driven survival, framework avoidance at growth.
107
+ 4. The writer and radii on the simulated axes.
108
+ 5. Presets: light response per species.
109
+ 6. Specs green (including the willow seam and the season order), mutation-tested.
110
+ 7. Measure every preset against the targets; look at each in the playground.
111
+
112
+ ## Landed (2026-10-26, uncommitted)
113
+
114
+ As designed, plus what building it turned up:
115
+
116
+ - **The simulation:** `shoot_systems_simulate` runs every carrier's twig system in one season loop against a
117
+ `ShootLightField` (leaf-area voxels of `light_cell`, 17 lattice sweeps of the overcast sky, matches Beer-Lambert in
118
+ closed form within 0.01). Each season: extension with tropisms, short-shoot survival `short_shoot_survival x
119
+ min(1, Rb(Q))`, bursts, syllepsis, shedding to `Rb(Q) / yield` (rank: log keep share, age, order, length, jitter),
120
+ the cascade of a shed mother, then the wood.
121
+ - **Dynamic girth** (Alex's pick over a forecast radius): `ShootGirth` thickens the wood each season with what it
122
+ carries, never thinning: the pipe model at the species' `pipe_model_exponent` over the shoots' Table 7 radius, Table
123
+ 7 for a unit of its age, and `1 / SHOOT_LATERAL_RADIUS_RATIO` of a lateral where it joins, on twigs, carriers and the
124
+ framework above them. A shoot grows only where it clears today's wood; a shoot the wood has grown into by the end
125
+ of a season dies with all it carries. The framework hash (`ShootFrameworkHash`, allocation-free) is rebuilt each
126
+ season.
127
+ - **Framework ages** come from the leader growth: a branch is born when its parent's tip passed its seat, so a carrier
128
+ carries `round(age)` units over its whole length.
129
+ - **Cards follow leaves:** a unit carries its leaves (`leaves_per_unit + leaves_per_metre L`, times `leaf_survival` at
130
+ its age) over the leaves one card draws (`foliage_card_leaf_count`), dithered; short shoots get their own rosette
131
+ tiles (`foliage_atlas_tiles.js`).
132
+ - **Skinning seats** (found by the willow seam spec once twigs grew on twigs): where more than four joints meet, the
133
+ four kept are those that leave the seat least far from where all of them would carry it, and a dropped joint folds
134
+ into the kept one that carries the point most alike. "How far apart" is each joint on the path between them turning
135
+ by its reference-wind rotation about its pivot (`TreeSkeleton.joint_rotation`, written by
136
+ `tree_skeleton_assign_skin_joints`). Willow seats over the 1 cm tolerance: 178 by weight-then-hops, 6 by
137
+ weight-times-hops, 0 now.
138
+
139
+ **Specs restated from their principle** (each mutation-tested red):
140
+ - interpenetration: a child may meet its mother's wood only in the crotch, the run of its first segments that still
141
+ lie in her wood, and a child whose tip is in her wood is buried; twigs no longer get a year-old-girth allowance. The
142
+ spec finds candidate pairs by a grid (it was n^2 and timed out at 90k segments).
143
+ - conifer tiers: they come from the whorls (spiral boughs: empty bands 5.4x fewer on spruce, 3.9x on pine);
144
+ plagiotropism no longer moves them (0.95x).
145
+ - spire: the leader's top unit, clothed in at least half the needles a unit of `leader_growth` carries.
146
+ - autumn order: the leaves that fell were more exposed and younger than those kept, by a quarter of the summer spread.
147
+ - shoot demography: from `tree_skeleton_grow`'s records (zones, the four-bud whorl, ancestry, light response).
148
+
149
+ **Measured at seed 1337** with master's `foliage_measure_leaf_area` and `tree_crown_opacity` (copied in for the run):
150
+
151
+ | preset | leaf m^2 | crown LAI | side density | side transparency | below density | below transparency | generate |
152
+ | :--- | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
153
+ | oak | 90.9 | 3.11 | 0.51 | 0.44 | 0.53 | 0.38 | 0.9 s |
154
+ | pine | 35.0 | 1.60 | 0.38 | 0.60 | 0.41 | 0.53 | 1.0 s |
155
+ | birch | 64.5 | 6.59 | 0.56 | 0.38 | 0.80 | 0.15 | 2.5 s |
156
+ | willow | 136.3 | 3.68 | 0.69 | 0.30 | 0.71 | 0.25 | 2.0 s |
157
+ | maple | 36.3 | 1.42 | 0.33 | 0.55 | 0.32 | 0.43 | 1.1 s |
158
+ | spruce | 117.8 | 4.44 | 0.36 | 0.28 | 0.45 | 0.25 | 3.1 s |
159
+ | shrub | 57.8 | 4.65 | 0.62 | 0.34 | 0.77 | 0.18 | 0.3 s |
160
+
161
+ (generate: skeleton and cards, `probe_crowns.mjs`.) FIA's targets are density 45-51% and transparency about 15%
162
+ [Randolph 2006].
163
+
164
+ **Open, measured:**
165
+ - Every preset is far more see-through than FIA's 15%; only oak's density is in range.
166
+ - **The shrub was barren** at a chosen Rb of 1.3 (2.1 m^2, crown LAI 0.18): light did not limit it, the stool's young
167
+ stems seeded few lineages, and 1.3 of a gross yield of 7.17 kept under one burst shoot in five even in full sun. No
168
+ net shoot yield was found for hazel (Grisafi et al. 2024 report one season's bud fates; orchard LAI 0.80-2.86,
169
+ Oeztuerk et al. 2018, is per ground area). Alex's pick: full-sun vigour is the gross yield the rule's Grisafi
170
+ numbers give (`shoot_expected_yield`, 7.17), so only shade sheds hazel shoots. Light saturates the crown from about
171
+ 2.8 up. The shrub row above is measured at that vigour; master's leaf-area and opacity specs pass on this tree.
172
+ - Engulfment took birch from 115 to 83 m^2 (probe), willow from 167 to 157, spruce from 140 to 121.
@@ -7,7 +7,7 @@ This document specifies a production-grade, State-of-the-Art (SotA) procedural t
7
7
  ### Core Design Tenets
8
8
  1. **Turn-Key Top Layer, Layered Override API Underneath**:
9
9
  - **Top Layer (1-line turn-key)**: `generate_tree({ preset: TreePreset.Oak, seed: 42 })` or `place_tree(scene_context, dataset, { preset: "pine", position: [10, 0, -5] })` produces a complete, multi-LOD, wind-rigged, PBR-materialized tree asset (`TreeAsset` / `SceneBundle` / `Prefab`) with zero external asset files required.
10
- - **Mid Layer (Species & Generator Descriptors)**: Declarative `TreeSpeciesConfig`, `BranchLevelConfig`, `CrownConfig`, `FoliageConfig`, `BarkMaterialConfig`, `FoliageMaterialConfig`, and `TreeWindConfig` with `AnimationCurve` profiles and full JSON serialization.
10
+ - **Mid Layer (Species & Generator Descriptors)**: Declarative `TreeSpeciesConfig`, a branch generator graph (`BranchGeneratorConfig` nodes joined by `BranchSpawnRule` edges, foliage placed by `FoliageSpawnRule`s), `CrownConfig`, `FoliageConfig`, `BarkMaterialConfig`, `FoliageMaterialConfig`, and `TreeWindConfig` with `AnimationCurve` profiles and full JSON serialization.
11
11
  - **Low Layer (Pure Pipeline Passes)**: Composable, allocation-conscious pure functions operating on `Graph` skeletons, `Transform64` node frames, Hermite spine buffers, `PointHashGrid3` crown fields, and `Geometry` / `Attribute` buffers.
12
12
  2. **Zero Duplicate Adjacent Infrastructure**:
13
13
  - **Coordinate System**: Strictly Meep's right-handed **Y-up** convention (`Vector3.up = (0, 1, 0)`, ground plane `X-Z`).
@@ -106,23 +106,58 @@ Evaluating any point or derivative at local parameter $u \in [0, 1]$ along edge
106
106
  - `spline3_hermite_derivative(u, p0x, p1x, m0x, m1x)` (for $x, y, z$)
107
107
 
108
108
  ### 4.2 Hybrid Parametric + Space-Colonization Growth Algorithm
109
- For each recursion level $l \in \{0, \dots, L_{\max}\}$:
109
+ Branches are grown breadth-first from the trunk (`species.branches[0]`). Every `species.branch_rules` edge
110
+ `source -> target` (always `source < target`, so the graph is acyclic) spawns branches of generator `target` along
111
+ each branch of generator `source`; one generator may spawn several kinds of children (boughs, roots, stubs, sprouts,
112
+ inter-whorl branches) and several generators may spawn the same kind (fan-in). Branching depth $l$ counts lateral
113
+ hops from the trunk; split forks keep their parent's depth and generator.
110
114
  1. **Crown Envelope & Space Colonization Field**:
111
115
  - The crown volume is defined by a configurable `CrownEnvelopeType` (`Conical`, `Spherical`, `Hemispherical`, `Cylindrical`, `TaperedCylindrical`, `Flame`, `InverseConical`, `TendFlame`, `Weeping`, or custom `AnimationCurve` profile) centered at $(0, H_{\text{crown}}, 0)$.
112
116
  - When `space_colonization_weight > 0`, $N_{\text{attract}}$ attraction points are sampled deterministically inside the crown envelope using `seededRandom` and indexed in a `PointHashGrid3` with cell size equal to the attraction radius $d_i$.
113
117
  2. **Branch Spawn & Phyllotactic Budding**:
114
- - Along each parent branch of level $l - 1$, child branches are spawned above `bare_length_ratio` $t_{\text{bare}} \in [0, 1)$ according to the level's `PhyllotaxisMode` (`SpiralGolden` $137.507764^\circ$, `AlternateDistichous` $180^\circ$, `OppositeDecussate` $180^\circ + 90^\circ$ flip, `Opposite` $180^\circ$, `Whorled` $360^\circ / M$).
115
- - Child branch length $L_l(t_p)$ is modulated by the parent's `length_profile: AnimationCurve` and the crown envelope $S_{\text{env}}(h_{\text{norm}})$.
118
+ - Along each parent branch, each outgoing rule spawns its children inside `[attach_min, attach_max]` according to the rule's `PhyllotaxisMode` (`SpiralGolden` $137.507764^\circ$, `AlternateDistichous` $180^\circ$, `OppositeDecussate` $180^\circ + 90^\circ$ flip, `Opposite` $180^\circ$, `Whorled` $360^\circ / M$, `FlareLobes` on the crests of the parent's basal buttress lobes).
119
+ - Child branch length $L_l(t_p)$ is modulated by the rule's `length_profile: AnimationCurve` and, for rules with `crown_envelope`, the crown envelope $S_{\text{env}}(h_{\text{norm}})$. Children of a rule without `crown_envelope` (roots, trunk sprouts) are neither shrunk by the envelope nor kept inside it.
120
+ - Self-pruning: below a crown rule's `attach_min` the rule once grew children too, at the same nodes continued down the stem; they died in the crown's shade. Each keeps `(1 - self_pruning) - age` of its length as a dead stub (age 0 just below the living children, 1 at the stem base; size at death `(1 - age)` of today's), and once that no longer clears the bark it is grown over and becomes a bark scar (knot).
121
+ - Generators with `root` grow structural surface roots: they descend onto the ground plane $y = 0$ and creep along it, add no pipe-model area to their stem, and never receive a wind joint.
116
122
  - Initial child heading $\mathbf{T}_c(0)$ diverges from parent tangent $\mathbf{T}_p(t_p)$ by insertion angle $\alpha_{\text{insert}}(t_p)$ around the azimuth $\phi_k$ in the parent's RMF plane $(\mathbf{R}_p, \mathbf{S}_p)$.
117
123
  - The child's initial RMF normal $\mathbf{R}_c(0)$ is aligned with the adaxial (upper crotch) projection of $\mathbf{T}_p$:
118
124
  $$\mathbf{R}_c(0) = \text{normalize}\big(\mathbf{T}_p - (\mathbf{T}_p \cdot \mathbf{T}_c(0))\mathbf{T}_c(0)\big)$$
119
125
  guaranteeing that $\theta = 0$ on the child's cross-section always lies at the top of the branch collar.
126
+ - **Dorsiventral parents** (`BranchGeneratorConfig.plagiotropism` $p > 0$, lateral generators only):
127
+ - **The plane.** A plagiotropic parent bears its buds in the plane of its tangent $\mathbf{T}_p$ and the horizontal
128
+ $\mathbf{H} = \mathbf{T}_p \times \mathbf{e}_y$ across it. The plane's normal is
129
+ $\mathbf{N} = \mathbf{H} \times \mathbf{T}_p$, which points up.
130
+ - **Ventral knockout.** No bud is emitted into the downward cone of half-angle $p\,\pi/2$.
131
+ - A bud whose own heading points into the cone does not break. That test is about where the bud sits on the
132
+ bough.
133
+ - Nor may fanning, or a turn for clearance, carry a bud's emitted heading into the cone. Each such candidate is
134
+ rejected, and a bud with none left does not break.
135
+ - Contact projection of a child's first segment can still deflect it in afterwards.
136
+ - **Fanning.** The surviving buds' radial direction loses $p\,|\mathbf{H}|$ of its component along $\mathbf{N}$,
137
+ fanning them into the plane. A vertical parent has no such plane, and its children are not fanned.
138
+ - **Which species.** Plagiotropism follows the species' architectural model (Hallé, Oldeman & Tomlinson's architectural models, as listed by Pfisterer (2000, *Mitt. Biol. Bundesanst.* 370) and Millet, Bouchard & Édelin (1999, *Écoscience* 6: 187–203)):
139
+ - **Massart's model** (*Picea*, *Abies*): tiers of plagiotropic branches. The spruce preset sets it.
140
+ - **Rauh's model** (*Pinus*, *Acer*, *Quercus*, *Betula*): branches orthotropic and built like the trunk. Those
141
+ presets set none.
142
+ - **Troll's model** (*Fagus*, *Tilia*, *Ulmus*): every axis plagiotropic. Not among the presets.
143
+ - The knockout is the least sourced part: laterals of a plagiotropic branch lie in its horizontal plane, but no
144
+ *Picea*-specific source was found for the fate of its ventral buds. On spruce it barely acts, since the buds are
145
+ already distichous.
146
+ - **Replaces.** This replaces an undocumented emission rule keyed on the *child's* gravitropism, which biased every
147
+ lateral's buds upward and off its underside.
148
+ - **Pads:** its effect was small (oak 0.750 with it, 0.789 without).
149
+ - **Headings:** its effect was not. Without it, oak has 3.8% of twigs more than 30° below the horizontal against
150
+ 1.4% (mean heading y 0.327 against 0.398), and birch 1.2% against 0.6%.
151
+ - **No basis:** Rauh-model branches are orthotropic and branch radially, and the positional bias reported for
152
+ some of them is slight hypotony (lower-side laterals favoured; Millet et al. 1999), not an upward one.
120
153
  3. **Stepped Spine Integration with Tropisms, Gnarl, & Splits**:
121
154
  - As segment $k \to k+1$ advances by $\Delta s = L_l / N_{\text{seg}}$:
122
155
  - **Intrinsic curvature**: Pitch rotation around $\mathbf{S}_k$ by $\Delta \theta_{\text{curve}}(t_k)$ and helical twist around $\mathbf{T}_k$.
123
156
  - **Gravitropism (Y-up)**: Bending toward $-\mathbf{e}_y = (0, -1, 0)$ (or $+\mathbf{e}_y$ for negative gravitropism), weighted by mechanical tip compliance $\text{lerp}(0.2, 1.0, t^\gamma)$.
124
157
  - **Phototropism**: Steering toward $\text{normalize}(\alpha_{\text{sky}}\mathbf{e}_y + (1-\alpha_{\text{sky}})\mathbf{d}_{\text{radial}})$ to seek sky light and escape interior crown self-shading.
125
158
  - **Curl / Simplex Gnarl**: 3D divergence-free `curl_noise_3d` (or `sdnoise3_array`) projected perpendicular to $\mathbf{T}_k$.
159
+ - **Plagiotropism**: a lateral shoot with `plagiotropism` $p$ is steered by $-p\,T_{k,y}\,\mathbf{e}_y$ towards the horizontal. The apical `tip_upcurl` still turns its tip up, so conifer boughs keep their upturned ends.
160
+ - **Straightness**: `straightness` $\lambda$ adds $\lambda(\mathbf{T}_0 - \mathbf{T}_k)$, a pull back towards the heading the branch was given, so strong gnarl does not carry a branch out of its sector. $\mathbf{T}_0$ is the bud's heading. For the fork that continues a split it becomes the heading the split deflected it to, as the other forks aim along their own. It resists every deviation from that heading, droop included.
126
161
  - **Space Colonization Pull**: Queries `PointHashGrid3.forEachNear` around $\mathbf{p}_k$, pulling $\mathbf{T}_{k+1}$ toward unclaimed attraction points within radius $d_i$ and marking attraction points within kill radius $d_k$ as consumed.
127
162
  - **Sympodial / Dichotomous Forking (`split_probability`, `split_angle`, `split_Spread`)**: At segment $k$, a stem can bifurcate or trifurcate into $M \in \{2, 3\}$ daughter branches that diverge symmetrically in azimuth and pitch.
128
163
  - **RMF Transport**: Advances $(\mathbf{R}_k, \mathbf{S}_k) \to (\mathbf{R}_{k+1}, \mathbf{S}_{k+1})$ via Wang et al. (2008) **Double Reflection** with fallback to `tube_frame_transport`.
@@ -130,6 +165,26 @@ For each recursion level $l \in \{0, \dots, L_{\max}\}$:
130
165
  - After all branch levels are generated in `skeleton.graph`, a bottom-up post-order pass accumulates cross-sectional area using the Da Vinci / Murray Pipe Model law:
131
166
  $$R_{\text{pipe}}(v) = \left( R_{\text{tip}}^\alpha + \sum_{e=(v \to u)} R_{\text{pipe}}(u)^\alpha \right)^{1/\alpha}, \quad \alpha \in [2.0, 2.8]$$
132
167
  - The final radius at node $v$ blends the artist-controlled parametric taper curve (`radius_profile: AnimationCurve`) with the physical pipe model via `pipe_model_weight` $\in [0, 1]$.
168
+ 5. **Annual Shoot Layer** (`skeleton/tree_skeleton_grow_shoots.js`, `skeleton/shoot_systems_simulate.js`; see
169
+ `CROWN_FILLING_BRIEF_2026_10_26.md`):
170
+ - **Input.** Each `species.shoot_rules` entry (`ShootSystemRule`, its bud zones `ShootBudZone`) grows the
171
+ peripheral twig system on every living branch of its `source` generator, after the pipe-model pass. The twigs are
172
+ branches of generator `target` (short shoots `short_target`), one level below their carrier.
173
+ - **The carrier's growth.** A framework branch is born when its parent's tip passed its seat, at the species'
174
+ `shoot_growth.leader_growth`; it carries `round(age)` annual units over its whole length.
175
+ - **Each season, tree-wide**, under a voxel light field (`ShootLightField`: leaf area, Beer-Lambert from a standard
176
+ overcast sky):
177
+ - Every living axis grows a terminal unit; short shoots survive as their light allows.
178
+ - Last season's units burst their zones' buds (and this season's, sylleptically). Unit lengths are drawn per
179
+ order.
180
+ - New shoots are kept to their light's net yield, `shoot_growth.net_yield(Q)` over the rule's gross yield. A shed
181
+ axis takes everything on it.
182
+ - The wood thickens with what it carries (`ShootGirth`): Table 7 (`d = 0.27 + 0.13 age + 0.02 l` cm) for a unit
183
+ of its age, the pipe model at the species' exponent, and 1 / 0.82 of a lateral where it joins, on twigs,
184
+ carriers and the framework above them.
185
+ - **Avoidance.** A unit grows only where it clears today's wood; a shoot the wood has grown into dies.
186
+ - **The record.** Every carrier and twig records where each of its annual units starts
187
+ (`TreeSkeleton.branch_unit_start_t`), for the foliage pass (§6.1).
133
188
 
134
189
  ---
135
190
 
@@ -167,17 +222,94 @@ For any lateral branch ($l \ge 1$) attached to a parent branch of radius $R_p$ a
167
222
 
168
223
  ### 6.1 Phyllotactic Attachment Generator
169
224
  Generates `FoliageAttachment` transforms along carrier branches of levels $l \in [l_{\text{min}}, L_{\max}]$:
170
- - Supports `SpiralGolden` ($137.507764^\circ$), `AlternateDistichous` ($180^\circ$), `Tristichous` ($120^\circ$), `Opposite` ($2\times 180^\circ$), `OppositeDecussate` ($2\times 180^\circ$ with $90^\circ$ alternation), and `Whorled` ($M$ organs per node), plus terminal rosette clustering at branch tips ($t \to 1$).
225
+ - Supports `SpiralGolden` ($137.507764^\circ$), `AlternateDistichous` ($180^\circ$), `Tristichous` ($120^\circ$), `Opposite` ($2\times 180^\circ$), `OppositeDecussate` ($2\times 180^\circ$ with $90^\circ$ alternation), and `Whorled` ($M$ organs per node), with nodes spaced evenly over the carrier's leafy span.
226
+ - **Card density is derived, not authored** (`skeleton/foliage_card_density.js`):
227
+ - **The sleeve.** A card leaves the shoot at insertion angle $\alpha$ and reaches $L$, so the shoot wears a foliage
228
+ sleeve of radius $R = L \sin\alpha$.
229
+ - **One leaf per line of sight.** The carrier holds just enough leaf that a line of sight through that sleeve meets
230
+ one leaf on average. By Cauchy's formula the sleeve's mean projected area is a quarter of its surface ($2\pi R$ per
231
+ metre), and a flat leaf's is half its area. So the leaf area is $\pi R$ per metre, and
232
+ $$n = \frac{\pi \sin\alpha \,(1 - v_a)}{S \, s \, \phi \, P}\ \text{cards per metre}.$$
233
+ The terms:
234
+ - $S$ is the side of the species' square card, the size its tile draws its leaf at (`foliage_tile_layout`, §6.3),
235
+ and $s$ the card scale on that shoot.
236
+ - $\phi$ is the atlas's measured leaf coverage (`FoliageAtlasCutout.coverage`).
237
+ - $P$ is the number of planes a card stands up (2 for `CrossCard`, 3 for `TriStarCluster`).
238
+ - $v_a$ is where the tile's leaf attaches (`FoliageTileLayout.anchor_v`): the card's length spans the tile from
239
+ there.
240
+ - **Leafy span.** It starts at the rule's `attach_min`, honoured up to 0.92 (`foliage_leafy_span_start`), for the
241
+ cards and the sail alike.
242
+ - **Rounding.** The expected count is rounded with a golden-ratio dither per (branch, rule), so it is exact on
243
+ average.
244
+ - **Annual units replace the rule.** A branch that records its annual units (`TreeSkeleton.branch_unit_start_t`,
245
+ written by the annual shoot layer, §4.2) carries, on each unit, its leaves (`leaves_per_unit + leaves_per_metre L`,
246
+ times `leaf_survival` at the unit's age; a short shoot `leaves_per_short_shoot` at its tip), in place of the
247
+ density rule (`foliage_unit_card_spans`).
248
+ - **A card a leaf.** Each leaf is a card at its own node along the unit, leaving the shoot at the rule's insertion
249
+ angle and turned by its phyllotaxis. A needle-shoot card draws a stretch of shoot with its needles instead, as
250
+ many as the shoot bears there, and lies along it.
251
+ - **Maturity.** Each card draws its own maturity from its branch.
252
+ - **Wind.** The joint mechanics load the same card on that unit.
253
+ - **Wind.** The joint mechanics take the same $\pi R$ per metre as the foliage's sail. The wind rig and the cards
254
+ agree within 0–3.5% on every preset (size variance and length floors).
255
+ - **Abscission and wilt** (`skeleton/foliage_senescence.js`):
256
+ - **Each tile's onset.** The pigment model ages each atlas tile at its own pace: a tile of maturity $\mu$ is at stage
257
+ $\sigma_k = \sigma(0.80 + 0.36|\mu - 0.35|) + 0.12\sigma^2$ (`foliage_variant_senescence`), and retains
258
+ $1 - \sigma_k(1.36 - \text{shielding})$ of its chlorophyll. Its exposed lamina is bare once $\sigma_k = 1/1.36$.
259
+ `foliage_variant_abscission_onset` solves that for the tree's senescence, $\sigma_0(\mu)$: 0.66 for mature tiles,
260
+ 0.73 for juvenile ones and 0.82 at $\mu = 0.35$. No leaf falls or dries before its own tile's onset.
261
+ - **Each card's threshold.** After that, exposure orders the fall. A card's threshold
262
+ $\theta \in [\sigma_0(\mu), 1]$ comes from the mean of its sun exposure ($0.62\,\rho_{\text{shell}} + 0.38\,h_{\text{norm}}$)
263
+ and its position along its shoot. Outer and apical leaves fall first, and the crown is bare at $\sigma = 1$.
264
+ - **Dryness.** Between its onset and its fall the card dries: $d = (\sigma - \sigma_0)/(\theta - \sigma_0)$.
265
+ - The mesh builder takes a folding card (`FoldedVCard`, `RibbedFrond`, `CutoutHull`) towards a leaf with no turgor:
266
+ the fold closes towards $\pi/2$, the arch goes to 0, and the droop goes to 1. `CrossCard` and `TriStarCluster`
267
+ have no fold and do not wilt.
268
+ - A card just before its fall is nearly shut, a valid sliver.
269
+ - **Wind.** The joint mechanics shed the same leaves from their sail. They judge the expected leaf (no jitter) at each
270
+ segment's middle.
171
271
  - **Heliotropic & Gravitropic Orientation**:
172
272
  - Reorients each leaf/frond basis $(\mathbf{F}, \mathbf{U}, \mathbf{W})$ so its adaxial normal $\mathbf{U}$ tilts toward the sky + canopy-outward light vector (`phototropism` $\in [0, 1]$) while its forward tip $\mathbf{F}$ droops under `gravitropism` $\in [-1, 1]$, with seeded angular jitter to prevent specular aliasing.
173
273
 
174
274
  ### 6.2 Foliage Topologies
175
275
  Supports 5 production real-time foliage card/mesh archetypes:
176
- 1. **`FoldedVCard` (Default Broadleaf Cluster)**: $2 \times 2$ or $2 \times 3$ grid with transverse V-fold angle $\beta_{\text{fold}}$, longitudinal midrib arch $h_{\text{arch}} \sin(\pi v)$, and tip camber $-h_{\text{camber}} v^2$. Never appears razor-flat at grazing view angles.
177
- 2. **`CrossCard` (Conifer Needle Tuft / Dense Shrub Cluster)**: Two orthogonal intersecting V-cards rotated by $90^\circ$ around the petiole axis $\mathbf{F}$.
178
- 3. **`TriStarCluster` (Volumetric Bush / Pine Shoot)**: Three cards arranged at $60^\circ$ star angles with radial offset.
276
+ 1. **`FoldedVCard`**: $2 \times 2$ or $2 \times 3$ grid with transverse V-fold angle $\beta_{\text{fold}}$, longitudinal midrib arch $h_{\text{arch}} \sin(\pi v)$, and tip camber $-h_{\text{camber}} v^2$. Never appears razor-flat at grazing view angles.
277
+ 2. **`CrossCard` (needle shoot)**: Two orthogonal intersecting V-cards rotated by $90^\circ$ around the shoot axis $\mathbf{F}$; each plane draws the needles in its sector round the shoot (§6.3).
278
+ 3. **`TriStarCluster` (needle shoot)**: Three cards arranged at $60^\circ$ star angles, each drawing its sector's needles.
179
279
  4. **`RibbedFrond` (Palms, Ferns, Cycads, Weeping Boughs)**: Multi-segment curved Cubic Hermite frond spine with RMF transport, longitudinal V-fold variation, and width profile $W(t) = W_{\max} \sin(\pi t^{p_w})$.
180
- 5. **`OctagonalCutoutHull` (Tight Alpha-Bound Card)**: 6-vertex diamond/hexagonal hull trimming empty corner texels to cut alpha-test quad overdraw by ~35%.
280
+ 5. **`CutoutHull` (Fitted Alpha-Bound Card, the broadleaves' leaf)**: the convex hull of everything its atlas tile
281
+ draws, reduced to 6 vertices and fanned around a midrib vertex.
282
+ - **Shape.** Each half turns about the midrib by `fold_angle`, and the card arches and droops along its length like
283
+ a frond spine.
284
+ - **Fitting.** `make_foliage_material` fits the hulls while it synthesizes the atlas (`FoliageAtlasCutout`):
285
+ - Each covered texel row contributes the outer corners of its first and last texel that has any alpha.
286
+ - `convex_hull_monotone_2d` hulls those points.
287
+ - `convex_hull_fixed_count_2d_relaxation` reduces the hull to 6 vertices inside the tile, inset by half a texel
288
+ (its `bounds`), so no corner reaches the atlas neighbour.
289
+ - When no edge can be removed without leaving the tile, the unbounded fit is clipped to the tile
290
+ (`polygon2_clip_axis_halfplane`) and relaxed again.
291
+ - If that stalls too, the hull is the silhouette's bounding box as a hexagon. It is looser, but it holds every drawn
292
+ texel. Clamping the unbounded fit's corners instead would cut the leaf.
293
+ - **Result.** A willow's lanceolate leaf is cut far tighter than a hazel's broad one (`foliage_atlas_cutout.spec`).
294
+ - **Custom material.** With a caller's own material, the cards cover whole tiles.
295
+
296
+ ### 6.3 Leaf Architecture and the Atlas Tile
297
+ Every tile draws the species' own leaf at its true size (`material/leaf_geometry.js`, `material/foliage_tile.js`;
298
+ `LEAF_ARCHITECTURE_BRIEF_2026_10_26.md`):
299
+ - **The leaf, as floras describe it** (`LeafArchitecture`, in the terms of Ellis et al. 2009, *Manual of Leaf
300
+ Architecture*): blade length and length/width ratio, where it is widest, apex and base angles and shapes, pinnate or
301
+ palmate lobes with their sinus depth, teeth a centimetre and their depth and order, secondary veins and their
302
+ angle, petiole length; a compound leaf's leaflets and rachis. Each preset cites its flora.
303
+ - **The outline** is a monotone cubic Hermite envelope through the base, the base angle's point a quarter of the way up,
304
+ the widest point, the apex angle's point and the apex; rounded ends are arcs, acuminate ones concave. A pinnately
305
+ lobed blade is a body out to the sinus floors plus a rounded lobe along each secondary vein; a palmate one is a lobe
306
+ per primary vein over a body; teeth are offset along the outline's normal. All contours wind the same way, so
307
+ `polygon2_rasterize_coverage` fills their union by the nonzero rule with exact coverage across each row.
308
+ - **The tile** draws the mature leaf filling it within a 2% margin, attached at the bottom middle; younger leaves are
309
+ smaller. The card is that tile at that scale: its size is the leaf's. The resolution draws the leaf's finest feature
310
+ (a tooth, a sinus) four texels across and its stems two, so they survive the alpha test.
311
+ - **Needle shoots** draw a stretch of shoot as long as a needle, its needles shared among the card's planes, each
312
+ plane showing those in its sector round the shoot, foreshortened by their azimuth.
181
313
 
182
314
  ---
183
315
 
@@ -187,6 +319,11 @@ Supports 5 production real-time foliage card/mesh archetypes:
187
319
  - **Per-Vertex Canopy AO (`StandardAttributes.Color`)**:
188
320
  - Combines macro crown ellipsoid depth $AO_{\text{crown}}(\mathbf{v}) \in [AO_{\text{core}}, 1.0]$ with local hierarchy depth $AO_{\text{local}}(v) \in [0.7, 1.0]$ (darkening inner branch crotches and petiole bases while brightening outer sun-exposed tips).
189
321
  - Multiplied with optional per-cluster hue/value jitter in `StandardAttributes.Color` (`vec3<f32>`), which `StandardShadeMaterial` automatically multiplies with `texture_albedo` in the G-buffer pass.
322
+ - **Tint headroom.** Vertex colours are encoded as `unorm8`, so on their own they can only darken. Each card's tint
323
+ (`FoliageAttachmentSet.tints`) is free to exceed 1. The builder writes `tint / tint_scale`, where `tint_scale` is
324
+ the largest tint channel, and the foliage material's `diffuse_color` (the shader's `albedo_color`) carries
325
+ `tint_scale` back. The product is exactly `albedo · tint · AO`. Across the presets `tint_scale` is about 1.1, and
326
+ about half of all tint channels exceed 1.
190
327
  - **Spherized / Puffed Foliage Normals (`StandardAttributes.Normal`)**:
191
328
  - Blends the geometric card normal $\mathbf{n}_{\text{card}}$ with the canopy-outward normal $\text{normalize}(\mathbf{v} - \mathbf{C}_{\text{crown}})$ by `normal_puffiness` $\in [0, 0.85]$ before running `geometry.ensureTangents()`, giving leaf clusters soft volumetric canopy lighting.
192
329
 
@@ -212,8 +349,8 @@ Meep's visibility-buffer renderer (`Shade`) deforms `MeshletGeometry` on the GPU
212
349
  When the caller does not pass custom `bark_material` or `foliage_material`, the system synthesizes studio-quality procedural PBR textures using `Sampler2D` $\to$ `ShadeImage.fromSampler2D` $\to$ `ShadeTexture.from`:
213
350
  1. **`make_bark_material(config)`**:
214
351
  - Generates tileable (`TextureWrapType.Repeat`) bark **Albedo** (fissured ridges, lenticels/stripes for birch, warm heartwood/moss undertones), **Tangent-Space Normal Map** (derived analytically from height gradients), and **ORM Map** (`R`: fissure occlusion, `G`: micro-roughness, `B`: 0 metalness) on a `StandardShadeMaterial` (`TransparencyMode.Opaque`, `ShadeDrawSide.Front`).
215
- 2. **`make_foliage_material(config)`**:
216
- - Generates a botanical twig/leaf or conifer-needle cluster **Albedo + Alpha Cutout** texture (serrated/lobed/ovate/palmate/needle silhouettes, midrib & lateral venation, premultiplied RGBA compatible with Shade's `albedo_unpremultiply` and hashed alpha test), **Tangent-Space Normal Map** (vein relief), and **ORM Map** on a `StandardShadeMaterial` (`TransparencyMode.AlphaTested`, `ShadeDrawSide.Double`, `transmission_factor: 0.25`).
352
+ 2. **`make_foliage_material(species)`**:
353
+ - Generates the species' leaf (or needle shoot) **Albedo + Alpha Cutout** texture from its `LeafArchitecture` (§6.3: outline coverage, midvein and secondary veins, petiole, premultiplied RGBA compatible with Shade's `albedo_unpremultiply` and hashed alpha test), **Tangent-Space Normal Map** (camber, vein relief, bullation), and **ORM Map** on a `StandardShadeMaterial` (`TransparencyMode.AlphaTested`, `ShadeDrawSide.Double`, `transmission_factor: 0`).
217
354
 
218
355
  ### 7.4 Multi-LOD Chain with Area-Compensated Foliage Decimation
219
356
  Generates a configurable $N$-level LOD chain (default 4 levels: `LOD0`, `LOD1`, `LOD2`, `LOD3`):
@@ -239,10 +376,13 @@ src/generation/foliage/
239
376
  config/
240
377
  CrownEnvelopeType.js
241
378
  PhyllotaxisMode.js
242
- FoliageCardType.js
379
+ FoliageCardType.js
243
380
  FoliageBarkType.js
244
381
  TreePreset.js
245
- BranchLevelConfig.js
382
+ BranchGeneratorConfig.js
383
+ BranchSpawnRule.js
384
+ FoliageSpawnRule.js
385
+ ShootSystemRule.js
246
386
  CrownConfig.js
247
387
  FoliageConfig.js
248
388
  BarkMaterialConfig.js
@@ -258,17 +398,27 @@ src/generation/foliage/
258
398
  spine_frame_double_reflection.js (+ .spec.js)
259
399
  tree_skeleton_grow.js (+ .spec.js)
260
400
  tree_skeleton_compute_pipe_radii.js (+ .spec.js)
401
+ shoot_demography.js (+ .spec.js)
402
+ tree_skeleton_grow_shoots.js (+ .spec.js)
261
403
  tree_skeleton_assign_skin_joints.js (+ .spec.js)
404
+ tree_skeleton_grow_growth_modifiers.spec.js
405
+ foliage_card_density.js
406
+ foliage_senescence.js
262
407
  mesh/
263
408
  branch_collar_project.js (+ .spec.js)
264
409
  branch_ring_triangulate.js (+ .spec.js)
265
410
  tree_mesh_build_bark.js (+ .spec.js)
266
- foliage_collect_attachments.js (+ .spec.js)
267
- tree_mesh_build_foliage.js (+ .spec.js)
411
+ foliage_collect_attachments.js (+ .spec.js, _density.spec.js)
412
+ foliage_seasons.spec.js
413
+ tree_mesh_build_foliage.js (+ .spec.js, _cutout.spec.js)
268
414
  tree_mesh_apply_canopy_ao.js (+ .spec.js)
269
415
  material/
270
416
  make_bark_material.js (+ .spec.js)
271
417
  make_foliage_material.js (+ .spec.js)
418
+ compute_foliage_variant_atlas_layout.js
419
+ foliage_leaf_silhouette.js
420
+ FoliageAtlasCutout.js
421
+ foliage_atlas_cutout.js (+ .spec.js)
272
422
  animation/
273
423
  build_tree_wind_rig.js (+ .spec.js)
274
424
  asset/
@@ -0,0 +1,158 @@
1
+ # Leaf Architecture
2
+
3
+ ## Problem
4
+
5
+ The oak's cards did not look like oak leaves (Alex, 2026-10-26: "What the fuck is that?"). Two causes, both hacks:
6
+
7
+ - **The leaf outline was code, not botany.** `foliage_leaf_silhouette.js` switched on a string, `"lobed"` (a ±28% sine
8
+ ripple, "oak-like"), `"serrated"` (a sawtooth), `"palmate"` (a cosine), each with hand-picked constants. The oak's
9
+ `"lobed"` blade was widest near its base, with shallow wavy edges: a Christmas tree.
10
+ - **A whole shoot was painted flat into one texture.** The `"rosette"` arrangement drew 11 leaves from one point,
11
+ fanned over ±83°, each three-quarters as wide as long. They merged into one blob with 11 tips. A `TriStarCluster`
12
+ stood three of those on crossing planes, which is the star in the screenshot. Meanwhile the simulation grows the
13
+ real shoots, so the tile duplicated the shoot geometry and contradicted it.
14
+
15
+ Fixing the oak's outline alone would have kept both hacks.
16
+
17
+ ## Principle
18
+
19
+ - **A leaf is data, described as floras describe it.** Ellis et al. (2009), *Manual of Leaf Architecture*, gives the
20
+ vocabulary; each preset cites its flora.
21
+ - **A card is one leaf, on its shoot.** Each leaf is a card at its own node, leaving the shoot at the rule's insertion
22
+ angle and turned by its phyllotaxis.
23
+ - **Needles stay shoot cards.** Pine bears 1,560 needles per metre and spruce 2,450 (sourced in the presets). A card
24
+ per needle is out of reach, and the needle shoot is the unit those papers measure.
25
+
26
+ ## Design
27
+
28
+ - **`LeafArchitecture`** (`FoliageMaterialConfig.leaf`):
29
+ - blade length, length/width ratio, where it is widest;
30
+ - apex and base angle and shape (`LeafApexShape`, `LeafBaseShape`; the angles measured as Ellis et al. define them,
31
+ a quarter of the blade's length from the tip or the base);
32
+ - lobation (`LeafLobation`), lobes, sinus depth, palmate spread and lateral lobe length;
33
+ - teeth per cm, tooth depth and order;
34
+ - secondary veins and their angle;
35
+ - petiole length;
36
+ - a compound leaf's leaflets and rachis.
37
+ - **`leaf_geometry`** turns that into outline contours, veins and stems in metres:
38
+ - **Envelope:** a monotone cubic Hermite (Fritsch-Carlson) through the base, the base angle's point, the widest point,
39
+ the apex angle's point and the apex. The shapes set the end slopes. A rounded end is an elliptic arc; an acuminate
40
+ one is shallow, so the margin is concave near the tip.
41
+ - **Pinnate lobes:** the blade reaches only to the sinus floor, `1 - sinus_depth` of the outline's width. Each lateral
42
+ lobe is a rounded blade of its own along its secondary vein (so it leans by the vein's angle), out to the outline.
43
+ The veins leave the midvein evenly spaced.
44
+ - **Palmate lobes:** a blade per primary lobe, radiating across `lobe_spread`, over a body to the sinus floors.
45
+ - **Base lobes:** cordate and lobate bases are a cubic Bezier from the petiole sinus round the basal lobe, solved to
46
+ reach exactly `base_lobe_depth` below the petiole.
47
+ - **Teeth:** offset along the outline's normal, spaced along the untoothed margin, with a second order a third the
48
+ size.
49
+ - **Union:** every contour winds the same way, so the union of lobes, leaflets and petiole is filled by the nonzero
50
+ rule (`polygon2_rasterize_coverage`, exact across each row, 4 samples down it).
51
+ - **`foliage_tile_layout`** (one place for every consumer):
52
+ - The mature leaf fills the tile within a 2% margin, attached at the bottom middle. Every tile draws at that scale,
53
+ so the card's size in metres is the leaf's (`card_size`).
54
+ - **Resolution:** the finest feature (a tooth, a sinus) is drawn 4 texels across. The narrowest stem is drawn 2
55
+ texels across, so wherever it falls it covers a whole texel and survives the alpha test.
56
+ - **Needle shoots:** a stretch of shoot as long as a needle, with the needles the shoot bears there
57
+ (`leaves_per_metre`), shared among the card's planes. Each plane draws the needles in its sector round the shoot,
58
+ foreshortened by their azimuth.
59
+ - **`foliage_tile_raster`:**
60
+ - Coverage, veins stamped near each segment, distance to the margin and to the midvein by chamfer, camber,
61
+ bullation, and the petiole.
62
+ - The pigment, senescence and normal code of `make_foliage_material` is unchanged. It now skips the texels the leaf
63
+ leaves empty, which keep the dilated fill.
64
+ - **Cards:**
65
+ - **Broadleaves:** a card per leaf. A short shoot's `leaves_per_short_shoot` sit at its tip. The presets draw
66
+ `CutoutHull` cards.
67
+ - **Needle cards** lie along the shoot.
68
+ - **Density path:** branches not grown by annual units keep it, on the layout's card size and anchor.
69
+
70
+ ## Sources per species
71
+
72
+ | preset | leaf | sources | estimated, not found |
73
+ | :--- | :--- | :--- | :--- |
74
+ | oak (*Quercus robur*) | mean blade 10.6 and 12.0 cm; L/W 1.8, 1.64; width 0.81-0.85 of max at 0.5 L, 0.47-0.50 at 0.9 L; petiole 7.4-8.0% of blade | Boratyński et al. 2008, *Silva Fennica* 42: 115-124, Table 4. Fitted: widest at 0.675, apex angle 1.2, base 0.8 rad (both widths within 0.01) | auricle size, secondary angle |
75
+ | | obovate; apex broadly rounded; sinuses 1/3-7/8 to midrib; entire; 5-7 secondaries | FNA vol. 3 | |
76
+ | | 5-7 lobes a side | Flora of China | |
77
+ | | up to 5 pairs; auricles usually strong | BSBI Plant Crib | |
78
+ | birch (*Betula pendula*) | 3-7 × 2.5-5 cm, ovate-rhombic, acuminate, cuneate, doubly serrate | FNA | apex and base angles, teeth (1.3 a cm, 1.5 mm), widest point |
79
+ | | 6-8 lateral veins; petiole 2-3 cm | FoC | |
80
+ | | 2 leaves a short shoot | Maillette 1982 | |
81
+ | willow (*Salix babylonica*) | 90-160 × 5-20 mm, L/W 5.5-10.5, acuminate, cuneate, serrulate; petiole 7-9 mm | FNA vol. 7 | angles, teeth (5 a cm, 0.3 mm), veins |
82
+ | maple (*Acer rubrum*) | 6.8 cm, 39 cm² | Wilson 1966 | lobe outline, lateral lobe length 0.85, teeth (3 a cm, 1.5 mm) |
83
+ | | 3 lobes; lateral axes 73-86° apart; midlobe 46-56% of blade; petiole 60-114% of blade; 2 leaf pairs a short shoot | Critchfield 1971 | |
84
+ | | doubly serrate | Gleason & Cronquist | |
85
+ | | base truncate to cordate | Trees and Shrubs Online | |
86
+ | shrub (*Corylus avellana*) | 5-12 × 4-12 cm, abruptly acuminate, narrowly cordate, doubly serrate, ≤ 8 vein pairs | FNA | angles, base lobe depth, teeth (0.7 a cm, 2.5 mm) |
87
+ | | petiole 6-12 mm | Trees and Shrubs Online | |
88
+ | | 8 cm gives the 41 cm² of a sun leaf | Catoni et al. 2015 | |
89
+ | pine, spruce needles | 52 mm [Niinemets & Lukjanova 2003]; spruce's 18 mm was already chosen | | widths 1.6 and 1 mm; needle angle 0.6 rad |
90
+ | palm, fern | no species named: the old frond's sizes are kept | | everything |
91
+
92
+ The botanical data was gathered by a research subagent from efloras.org (FNA, FoC), BSBI, VicFlora, Go Botany, Trees
93
+ and Shrubs Online, SEINet and the papers above. Its quotes and URLs are in the session's scratchpad (`leaf/`).
94
+ floranorthamerica.org refused access, and HAL (Kremer et al. 2002) is behind a bot check.
95
+
96
+ ## Measured
97
+
98
+ *Seed 1337 unless noted; the "before" figures are from 49845ff00.*
99
+
100
+ **Atlas, from the drawn tiles:**
101
+
102
+ | preset | resolution | card | coverage | one leaf |
103
+ | :--- | ---: | ---: | ---: | ---: |
104
+ | oak | 128 | 12.7 cm | 0.208 | 33 cm² |
105
+ | birch | 256 | 7.8 cm | 0.174 | 10.6 cm² |
106
+ | willow | 512 | 13.9 cm | 0.073 | 14 cm² |
107
+ | maple | 512 | 13.2 cm | 0.213 | 37 cm² |
108
+ | shrub | 128 | 9.3 cm | 0.522 | 45 cm² |
109
+ | pine | 256 | 9.8 cm (81 needles) | | |
110
+ | spruce | 256 | 3.4 cm (44 needles) | | |
111
+ | palm | 128 | | | |
112
+ | fern | 128 | | | |
113
+
114
+ Leaf areas against the sources:
115
+ - maple: 37 cm² against Wilson's 39;
116
+ - hazel: 45 cm² against Catoni's 41;
117
+ - birch: 10.6 cm² against about 11 from FNA's sizes.
118
+
119
+ **Cost:** cards, LOD0 triangles, and `generate_tree` time with the LOD0 meshes.
120
+
121
+ | preset | cards | foliage tris | bark tris | generate + LOD0 |
122
+ | :--- | ---: | ---: | ---: | ---: |
123
+ | oak | 25,622 | 153,732 | 81,587 | 0.77 + 0.06 s |
124
+ | pine | 3,554 | 21,324 | 39,817 | 0.71 + 0.03 s |
125
+ | birch | 63,909 | 383,454 | 454,735 | 1.73 + 0.56 s |
126
+ | willow | 113,001 | 678,006 | 410,091 | 1.81 + 0.46 s |
127
+ | maple | 13,008 | 78,048 | 37,774 | 1.16 + 0.05 s |
128
+ | spruce | 176,311 | 705,244 | 1,085,114 | 3.12 + 1.23 s |
129
+ | shrub | 16,976 | 101,856 | 62,817 | 0.52 + 0.05 s |
130
+
131
+ **Crowns,** measured with `foliage_measure_leaf_area` and `tree_crown_opacity`; "before" is 49845ff00:
132
+
133
+ | preset | leaf m² (before) | crown LAI | side density | side transparency | below density | below transparency |
134
+ | :--- | ---: | ---: | ---: | ---: | ---: | ---: |
135
+ | oak | 89.4 (90.9) | 3.11 | 0.50 | 0.42 | 0.58 | 0.27 |
136
+ | pine | 15.7 (35.0) | 0.74 | 0.34 | 0.64 | 0.35 | 0.62 |
137
+ | birch | 70.4 (64.5) | 6.77 | 0.56 | 0.33 | 0.75 | 0.12 |
138
+ | willow | 232.6 (136.3) | 6.43 | 0.75 | 0.18 | 0.74 | 0.19 |
139
+ | maple | 50.7 (36.3) | 1.97 | 0.41 | 0.42 | 0.42 | 0.32 |
140
+ | spruce | 78.4 (117.8) | 3.03 | 0.33 | 0.31 | 0.42 | 0.29 |
141
+ | shrub | 62.5 (57.8) | 4.52 | 0.63 | 0.22 | 0.64 | 0.16 |
142
+
143
+ - **Pine and spruce lost leaf area** because their old tiles overdrew. Every plane of a card drew all of its needles,
144
+ three times over on pine, and wider than the needles are. Now each needle is drawn once at its width.
145
+ - **Willow gained,** its lanceolate leaves replacing a frond drawing. Its transparency, 0.18, is near FIA's 15%.
146
+
147
+ ## Open (measured, not argued)
148
+
149
+ - **Card counts rose where a card used to hold several leaves:** birch 5×, willow 9×, oak 11×. Pine and spruce rose
150
+ 2.4×, because a needle card now covers one needle length of shoot, not 2.4. That stretch is chosen, not sourced.
151
+ - **Estimates:** the angles, tooth sizes and widest points the floras do not give are marked in each preset.
152
+ - **Palm and fern** name no species, so their leaves are not sourced.
153
+ - **Wind sail:**
154
+ - `TreeWindConfig.elastic_modulus` is fitted to the oak, whose leaf area moved by 2% (90.9 to 89.4 m²); it was not
155
+ refit.
156
+ - Pine's and spruce's sails fell with their leaf area (to 0.45 and 0.67), so they will sway less. That sway is not
157
+ measured.
158
+ - **Transparency:** every crown but willow's is still far above FIA's 15% transparency.