@woosh/meep-engine 3.56.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 (625) 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/graphics/sh3/path_tracer/geometry/sort_triangles_by_distance_to_point.js +1 -1
  176. package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.js +1 -1
  177. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  178. package/src/engine/graphics3/WaterSystem.js +2 -1
  179. package/src/engine/graphics3/prefab/prefab_skin_frame.d.ts.map +1 -1
  180. package/src/engine/graphics3/prefab/prefab_skin_frame.js +1 -12
  181. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts +1 -1
  182. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
  183. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +141 -137
  184. package/src/engine/input/ecs/systems/InputControllerSystem.d.ts.map +1 -1
  185. package/src/engine/input/ecs/systems/InputControllerSystem.js +13 -3
  186. package/src/engine/input/ecs/systems/InputSystem.d.ts.map +1 -1
  187. package/src/engine/input/ecs/systems/InputSystem.js +2 -1
  188. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts +1 -1
  189. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts.map +1 -1
  190. package/src/engine/intelligence/behavior/composite/ParallelBehavior.js +4 -1
  191. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.d.ts.map +1 -1
  192. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.js +3 -1
  193. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.d.ts.map +1 -1
  194. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.js +3 -1
  195. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.d.ts.map +1 -1
  196. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.js +39 -33
  197. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts +5 -0
  198. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts.map +1 -1
  199. package/src/engine/intelligence/behavior/util/ConditionalBehavior.js +93 -75
  200. package/src/engine/intelligence/behavior/util/RotationBehavior.d.ts.map +1 -1
  201. package/src/engine/intelligence/behavior/util/RotationBehavior.js +79 -76
  202. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts +1 -0
  203. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts.map +1 -1
  204. package/src/engine/intelligence/blackboard/BlackboardStack.js +159 -123
  205. package/src/engine/intelligence/mcts/StateNode.d.ts.map +1 -1
  206. package/src/engine/intelligence/mcts/StateNode.js +366 -364
  207. package/src/engine/intelligence/resource/ResourceAllocationSolver.js +1 -1
  208. package/src/engine/navigation/ecs/components/Path.d.ts.map +1 -1
  209. package/src/engine/navigation/ecs/components/Path.js +2 -1
  210. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
  211. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +5 -2
  212. package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
  213. package/src/engine/physics/body/SolverBodyState.js +2 -6
  214. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  215. package/src/engine/physics/ccd/linear_sweep.js +3 -16
  216. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  217. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +2 -16
  218. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +13 -1
  219. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  220. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +15 -4
  221. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  222. package/src/engine/physics/ecs/PhysicsSystem.js +2 -5
  223. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts +12 -0
  224. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts.map +1 -0
  225. package/src/engine/physics/inertia/locked_inverse_inertia.js +22 -0
  226. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
  227. package/src/engine/physics/integration/integrate_velocity.js +3 -18
  228. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts +1 -0
  229. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
  230. package/src/engine/physics/mls-mpm/MLS_MPM.js +5 -4
  231. package/src/engine/physics/narrowphase/convex_decomposition.d.ts.map +1 -1
  232. package/src/engine/physics/narrowphase/convex_decomposition.js +7 -16
  233. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  234. package/src/engine/physics/vehicle/RaycastVehicle.js +15 -5
  235. package/src/engine/save/StorageBackedList.d.ts +5 -0
  236. package/src/engine/save/StorageBackedList.d.ts.map +1 -1
  237. package/src/engine/save/StorageBackedList.js +161 -144
  238. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  239. package/src/engine/simulation/Ticker.js +394 -391
  240. package/src/engine/sound/simulation/probe/AcousticProbeField.d.ts.map +1 -1
  241. package/src/engine/sound/simulation/probe/AcousticProbeField.js +6 -19
  242. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts +15 -0
  243. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts.map +1 -1
  244. package/src/engine/sound/simulation/probe/probe_edge_visible.js +59 -41
  245. package/src/engine/sound/simulation/probe/probe_refine_connectivity.d.ts.map +1 -1
  246. package/src/engine/sound/simulation/probe/probe_refine_connectivity.js +164 -181
  247. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts.map +1 -1
  248. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +20 -5
  249. package/src/format/image/avif/av1/decode/Av1FrameContext.d.ts.map +1 -1
  250. package/src/format/image/avif/av1/decode/Av1FrameContext.js +3 -10
  251. package/src/format/image/avif/av1/decode/reconstruct.d.ts +20 -0
  252. package/src/format/image/avif/av1/decode/reconstruct.d.ts.map +1 -1
  253. package/src/format/image/avif/av1/decode/reconstruct.js +22 -9
  254. package/src/format/image/avif/av1/encode/choose_restoration.js +2 -18
  255. package/src/format/image/avif/av1/encode/quantise.d.ts.map +1 -1
  256. package/src/format/image/avif/av1/encode/quantise.js +1 -55
  257. package/src/format/image/avif/av1/filter/loop_restoration.d.ts +9 -0
  258. package/src/format/image/avif/av1/filter/loop_restoration.d.ts.map +1 -1
  259. package/src/format/image/avif/av1/filter/loop_restoration.js +1 -1
  260. package/src/format/texture/basis/transcode/etc1s_to_bc7.js +2 -33
  261. package/src/format/texture/basis/transcode/fit_endpoints.d.ts +11 -0
  262. package/src/format/texture/basis/transcode/fit_endpoints.d.ts.map +1 -1
  263. package/src/format/texture/basis/transcode/fit_endpoints.js +1 -1
  264. package/src/format/texture/basis/uastc/uastc_decode_block.d.ts.map +1 -1
  265. package/src/format/texture/basis/uastc/uastc_decode_block.js +2 -19
  266. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +220 -0
  267. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +172 -0
  268. package/src/generation/foliage/FOLIAGE_DESIGN.md +165 -15
  269. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +158 -0
  270. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +248 -0
  271. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +694 -0
  272. package/src/generation/foliage/analysis/CrownOpacity.d.ts +118 -0
  273. package/src/generation/foliage/analysis/CrownOpacity.d.ts.map +1 -0
  274. package/src/generation/foliage/analysis/CrownOpacity.js +182 -0
  275. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts +10 -0
  276. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts.map +1 -0
  277. package/src/generation/foliage/analysis/crown_opacity_frames.js +132 -0
  278. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts +51 -0
  279. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts.map +1 -0
  280. package/src/generation/foliage/analysis/crown_opacity_measure.js +649 -0
  281. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts +66 -0
  282. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts.map +1 -0
  283. package/src/generation/foliage/analysis/foliage_measure_leaf_area.js +192 -0
  284. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts +27 -0
  285. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts.map +1 -0
  286. package/src/generation/foliage/analysis/tree_crown_opacity.js +58 -0
  287. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts +3 -2
  288. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts.map +1 -1
  289. package/src/generation/foliage/animation/build_tree_wind_rig.js +12 -30
  290. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts +12 -0
  291. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts.map +1 -0
  292. package/src/generation/foliage/animation/tree_wind_bend_limit.js +13 -0
  293. package/src/generation/foliage/asset/TreeAsset.d.ts +5 -0
  294. package/src/generation/foliage/asset/TreeAsset.d.ts.map +1 -1
  295. package/src/generation/foliage/asset/TreeAsset.js +6 -0
  296. package/src/generation/foliage/asset/generate_tree.d.ts.map +1 -1
  297. package/src/generation/foliage/asset/generate_tree.js +23 -6
  298. package/src/generation/foliage/config/{BranchLevelConfig.d.ts → BranchGeneratorConfig.d.ts} +61 -75
  299. package/src/generation/foliage/config/BranchGeneratorConfig.d.ts.map +1 -0
  300. package/src/generation/foliage/config/{BranchLevelConfig.js → BranchGeneratorConfig.js} +83 -126
  301. package/src/generation/foliage/config/BranchSpawnRule.d.ts +118 -0
  302. package/src/generation/foliage/config/BranchSpawnRule.d.ts.map +1 -0
  303. package/src/generation/foliage/config/BranchSpawnRule.js +217 -0
  304. package/src/generation/foliage/config/FoliageCardType.d.ts +1 -1
  305. package/src/generation/foliage/config/FoliageCardType.js +2 -2
  306. package/src/generation/foliage/config/FoliageConfig.d.ts +23 -45
  307. package/src/generation/foliage/config/FoliageConfig.d.ts.map +1 -1
  308. package/src/generation/foliage/config/FoliageConfig.js +47 -93
  309. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts +12 -20
  310. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts.map +1 -1
  311. package/src/generation/foliage/config/FoliageMaterialConfig.js +261 -279
  312. package/src/generation/foliage/config/FoliageSpawnRule.d.ts +77 -0
  313. package/src/generation/foliage/config/FoliageSpawnRule.d.ts.map +1 -0
  314. package/src/generation/foliage/config/FoliageSpawnRule.js +135 -0
  315. package/src/generation/foliage/config/FoliageTileContent.d.ts +9 -0
  316. package/src/generation/foliage/config/FoliageTileContent.d.ts.map +1 -0
  317. package/src/generation/foliage/config/FoliageTileContent.js +12 -0
  318. package/src/generation/foliage/config/LeafApexShape.d.ts +12 -0
  319. package/src/generation/foliage/config/LeafApexShape.d.ts.map +1 -0
  320. package/src/generation/foliage/config/LeafApexShape.js +17 -0
  321. package/src/generation/foliage/config/LeafArchitecture.d.ts +155 -0
  322. package/src/generation/foliage/config/LeafArchitecture.d.ts.map +1 -0
  323. package/src/generation/foliage/config/LeafArchitecture.js +288 -0
  324. package/src/generation/foliage/config/LeafBaseShape.d.ts +14 -0
  325. package/src/generation/foliage/config/LeafBaseShape.d.ts.map +1 -0
  326. package/src/generation/foliage/config/LeafBaseShape.js +21 -0
  327. package/src/generation/foliage/config/LeafLobation.d.ts +10 -0
  328. package/src/generation/foliage/config/LeafLobation.d.ts.map +1 -0
  329. package/src/generation/foliage/config/LeafLobation.js +14 -0
  330. package/src/generation/foliage/config/PhyllotaxisMode.d.ts +11 -0
  331. package/src/generation/foliage/config/PhyllotaxisMode.d.ts.map +1 -1
  332. package/src/generation/foliage/config/PhyllotaxisMode.js +36 -0
  333. package/src/generation/foliage/config/ShootBudZone.d.ts +105 -0
  334. package/src/generation/foliage/config/ShootBudZone.d.ts.map +1 -0
  335. package/src/generation/foliage/config/ShootBudZone.js +219 -0
  336. package/src/generation/foliage/config/ShootGrowthConfig.d.ts +84 -0
  337. package/src/generation/foliage/config/ShootGrowthConfig.d.ts.map +1 -0
  338. package/src/generation/foliage/config/ShootGrowthConfig.js +146 -0
  339. package/src/generation/foliage/config/ShootSystemRule.d.ts +144 -0
  340. package/src/generation/foliage/config/ShootSystemRule.d.ts.map +1 -0
  341. package/src/generation/foliage/config/ShootSystemRule.js +316 -0
  342. package/src/generation/foliage/config/TreeLODConfig.d.ts +1 -1
  343. package/src/generation/foliage/config/TreeLODConfig.js +1 -1
  344. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts +40 -8
  345. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts.map +1 -1
  346. package/src/generation/foliage/config/TreeSpeciesConfig.js +124 -68
  347. package/src/generation/foliage/config/TreeWindConfig.d.ts +23 -10
  348. package/src/generation/foliage/config/TreeWindConfig.d.ts.map +1 -1
  349. package/src/generation/foliage/config/TreeWindConfig.js +34 -25
  350. package/src/generation/foliage/index.d.ts +19 -2
  351. package/src/generation/foliage/index.js +63 -44
  352. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts +59 -0
  353. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts.map +1 -0
  354. package/src/generation/foliage/material/FoliageAtlasCutout.js +93 -0
  355. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts +26 -0
  356. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts.map +1 -0
  357. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.js +63 -0
  358. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts +34 -0
  359. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts.map +1 -0
  360. package/src/generation/foliage/material/foliage_atlas_cutout.js +174 -0
  361. package/src/generation/foliage/material/foliage_tile.d.ts +110 -0
  362. package/src/generation/foliage/material/foliage_tile.d.ts.map +1 -0
  363. package/src/generation/foliage/material/foliage_tile.js +286 -0
  364. package/src/generation/foliage/material/leaf_geometry.d.ts +103 -0
  365. package/src/generation/foliage/material/leaf_geometry.d.ts.map +1 -0
  366. package/src/generation/foliage/material/leaf_geometry.js +528 -0
  367. package/src/generation/foliage/material/make_foliage_material.d.ts +13 -33
  368. package/src/generation/foliage/material/make_foliage_material.d.ts.map +1 -1
  369. package/src/generation/foliage/material/make_foliage_material.js +356 -605
  370. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts +39 -4
  371. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts.map +1 -1
  372. package/src/generation/foliage/mesh/foliage_collect_attachments.js +637 -569
  373. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts +48 -0
  374. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts.map +1 -0
  375. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.js +232 -0
  376. package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
  377. package/src/generation/foliage/mesh/tree_mesh_build_bark.js +1023 -1049
  378. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts +9 -2
  379. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts.map +1 -1
  380. package/src/generation/foliage/mesh/tree_mesh_build_foliage.js +467 -454
  381. package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
  382. package/src/generation/foliage/presets/make_tree_species_preset.js +1648 -870
  383. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts +35 -0
  384. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts.map +1 -0
  385. package/src/generation/foliage/skeleton/ShootFrameworkHash.js +129 -0
  386. package/src/generation/foliage/skeleton/ShootGirth.d.ts +51 -0
  387. package/src/generation/foliage/skeleton/ShootGirth.d.ts.map +1 -0
  388. package/src/generation/foliage/skeleton/ShootGirth.js +212 -0
  389. package/src/generation/foliage/skeleton/ShootLightField.d.ts +73 -0
  390. package/src/generation/foliage/skeleton/ShootLightField.d.ts.map +1 -0
  391. package/src/generation/foliage/skeleton/ShootLightField.js +197 -0
  392. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts +106 -3
  393. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts.map +1 -1
  394. package/src/generation/foliage/skeleton/TreeSkeleton.js +217 -39
  395. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts +13 -0
  396. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts.map +1 -0
  397. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.js +16 -0
  398. package/src/generation/foliage/skeleton/foliage_card_density.d.ts +71 -0
  399. package/src/generation/foliage/skeleton/foliage_card_density.d.ts.map +1 -0
  400. package/src/generation/foliage/skeleton/foliage_card_density.js +101 -0
  401. package/src/generation/foliage/skeleton/foliage_senescence.d.ts +101 -0
  402. package/src/generation/foliage/skeleton/foliage_senescence.d.ts.map +1 -0
  403. package/src/generation/foliage/skeleton/foliage_senescence.js +149 -0
  404. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts +76 -0
  405. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts.map +1 -0
  406. package/src/generation/foliage/skeleton/foliage_unit_cards.js +95 -0
  407. package/src/generation/foliage/skeleton/shoot_demography.d.ts +22 -0
  408. package/src/generation/foliage/skeleton/shoot_demography.d.ts.map +1 -0
  409. package/src/generation/foliage/skeleton/shoot_demography.js +96 -0
  410. package/src/generation/foliage/skeleton/shoot_geometry.d.ts +66 -0
  411. package/src/generation/foliage/skeleton/shoot_geometry.d.ts.map +1 -0
  412. package/src/generation/foliage/skeleton/shoot_geometry.js +109 -0
  413. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts +166 -0
  414. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts.map +1 -0
  415. package/src/generation/foliage/skeleton/shoot_systems_simulate.js +588 -0
  416. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts +28 -12
  417. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts.map +1 -1
  418. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.js +137 -102
  419. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts +112 -0
  420. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts.map +1 -0
  421. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js +408 -0
  422. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts.map +1 -1
  423. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js +208 -206
  424. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts +5 -2
  425. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
  426. package/src/generation/foliage/skeleton/tree_skeleton_grow.js +2048 -1871
  427. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts +17 -0
  428. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts.map +1 -0
  429. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.js +231 -0
  430. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts +14 -0
  431. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts.map +1 -0
  432. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.js +26 -0
  433. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts +10 -0
  434. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts.map +1 -0
  435. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.js +20 -0
  436. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts.map +1 -1
  437. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +4 -1
  438. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts +1 -0
  439. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts.map +1 -1
  440. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +98 -86
  441. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +263 -0
  442. package/src/shade/descriptor/WebGPUExtensionType.d.ts +17 -0
  443. package/src/shade/descriptor/WebGPUExtensionType.d.ts.map +1 -1
  444. package/src/shade/descriptor/WebGPUExtensionType.js +31 -1
  445. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts +37 -0
  446. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts.map +1 -0
  447. package/src/shade/playground/foliage_wind/FoliageRigOverlay.js +491 -0
  448. package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -1
  449. package/src/shade/playground/foliage_wind/foliage_world.js +600 -602
  450. package/src/shade/playground/foliage_wind/index.html +6 -0
  451. package/src/shade/playground/foliage_wind/main.js +14 -0
  452. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  453. package/src/shade/renderer/animation/GPUAnimationManager.js +2 -1
  454. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts +2 -1
  455. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts.map +1 -1
  456. package/src/shade/renderer/animation/foliage/FoliageWindJoint.js +2 -1
  457. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.d.ts.map +1 -1
  458. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.js +4 -2
  459. package/src/shade/renderer/buffer/table/GPUTypedTable.js +1 -1
  460. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
  461. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +403 -401
  462. package/src/shade/renderer/camera/OrbitalCameraController.d.ts +1 -62
  463. package/src/shade/renderer/camera/OrbitalCameraController.d.ts.map +1 -1
  464. package/src/shade/renderer/camera/OrbitalCameraController.js +1 -374
  465. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.d.ts.map +1 -1
  466. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.js +3 -0
  467. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.d.ts.map +1 -1
  468. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.js +6 -1
  469. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +1 -1
  470. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +2 -2
  471. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts.map +1 -1
  472. package/src/shade/renderer/fluid/GPUFluidCascade.js +6 -3
  473. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +361 -0
  474. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.d.ts.map +1 -1
  475. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js +335 -241
  476. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.d.ts.map +1 -1
  477. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js +108 -101
  478. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.d.ts.map +1 -1
  479. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.js +69 -67
  480. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts +7 -6
  481. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts.map +1 -1
  482. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js +341 -287
  483. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts +6 -4
  484. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts.map +1 -1
  485. package/src/shade/renderer/fluid/mac/FluidMacPasses.js +427 -400
  486. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts +10 -5
  487. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts.map +1 -1
  488. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.js +532 -190
  489. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.d.ts.map +1 -1
  490. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.js +231 -237
  491. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts +2 -2
  492. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts.map +1 -1
  493. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js +282 -245
  494. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts +1 -3
  495. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts.map +1 -1
  496. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.js +139 -109
  497. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts +6 -6
  498. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts.map +1 -1
  499. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.js +257 -222
  500. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts +8 -7
  501. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts.map +1 -1
  502. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.js +119 -92
  503. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts +6 -9
  504. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts.map +1 -1
  505. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.js +229 -181
  506. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +17 -7
  507. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts.map +1 -1
  508. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.js +634 -621
  509. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts +8 -6
  510. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts.map +1 -1
  511. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js +166 -149
  512. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts +8 -6
  513. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts.map +1 -1
  514. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js +219 -183
  515. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.d.ts.map +1 -1
  516. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.js +142 -122
  517. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +674 -663
  518. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +1 -1
  519. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  520. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +63 -29
  521. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  522. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +77 -87
  523. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.d.ts.map +1 -1
  524. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.js +4 -3
  525. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts +11 -11
  526. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts.map +1 -1
  527. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.js +17 -19
  528. package/src/shade/renderer/global_illumination/lpv/graph_bake_irradiance_lookup_2d.js +4 -4
  529. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.d.ts.map +1 -1
  530. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.js +5 -1
  531. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  532. package/src/shade/renderer/loader/gltf/load_gltf.js +11 -35
  533. package/src/shade/renderer/loader/usd/load_usd.d.ts.map +1 -1
  534. package/src/shade/renderer/loader/usd/load_usd.js +6 -19
  535. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
  536. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +199 -193
  537. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts.map +1 -1
  538. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.js +151 -143
  539. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.d.ts.map +1 -1
  540. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.js +11 -5
  541. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.d.ts.map +1 -1
  542. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.js +6 -18
  543. package/src/shade/renderer/postprocess/gtao/GTAO.js +1 -1
  544. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  545. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +3 -5
  546. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +1 -1
  547. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.d.ts.map +1 -1
  548. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.js +7 -3
  549. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
  550. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +4 -2
  551. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.d.ts.map +1 -1
  552. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +4 -1
  553. package/src/shade/renderer/postprocess/ssr/downsample_karis.d.ts.map +1 -1
  554. package/src/shade/renderer/postprocess/ssr/downsample_karis.js +6 -3
  555. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
  556. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +4 -3
  557. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.d.ts.map +1 -1
  558. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.js +4 -1
  559. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
  560. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +4 -2
  561. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts.map +1 -1
  562. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.js +35 -39
  563. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.d.ts.map +1 -1
  564. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.js +20 -17
  565. package/src/shade/renderer/postprocess/taa/shader_taa.d.ts.map +1 -1
  566. package/src/shade/renderer/postprocess/taa/shader_taa.js +6 -3
  567. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  568. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -1
  569. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +1 -1
  570. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js +2 -2
  571. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +1 -1
  572. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.d.ts.map +1 -1
  573. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.js +92 -83
  574. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +1 -1
  575. package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
  576. package/src/shade/renderer/shader/ShaderDescriptor.js +12 -4
  577. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.d.ts.map +1 -1
  578. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.js +294 -286
  579. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_interpolate_probe_irradiance8.js +5 -5
  580. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.d.ts.map +1 -1
  581. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.js +5 -3
  582. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.d.ts.map +1 -1
  583. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.js +9 -6
  584. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.d.ts.map +1 -1
  585. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.js +33 -38
  586. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  587. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +690 -675
  588. package/src/shade/renderer/shader/type/WebGPUArray.d.ts +3 -0
  589. package/src/shade/renderer/shader/type/WebGPUArray.d.ts.map +1 -1
  590. package/src/shade/renderer/shader/type/WebGPUArray.js +185 -167
  591. package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
  592. package/src/shade/renderer/shader/type/WebGPUStruct.js +461 -455
  593. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.d.ts.map +1 -1
  594. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.js +335 -211
  595. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.d.ts.map +1 -1
  596. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.js +329 -221
  597. package/src/shade/renderer/shader/type/type_has_f16.d.ts +12 -0
  598. package/src/shade/renderer/shader/type/type_has_f16.d.ts.map +1 -0
  599. package/src/shade/renderer/shader/type/type_has_f16.js +66 -0
  600. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  601. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +16 -2
  602. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts.map +1 -1
  603. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +5 -2
  604. package/src/shade/renderer/water/shader_water_avboit.js +1 -1
  605. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  606. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +260 -23
  607. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts +6 -7
  608. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  609. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +269 -69
  610. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  611. package/src/shade/wgsl/validate_wgsl_source.js +27 -1
  612. package/src/view/controller/controls/ListController.d.ts.map +1 -1
  613. package/src/view/controller/controls/ListController.js +118 -113
  614. package/src/view/controller/controls/Vector1Control.js +97 -97
  615. package/src/view/elements/image/SvgImageView.d.ts +1 -0
  616. package/src/view/elements/image/SvgImageView.d.ts.map +1 -1
  617. package/src/view/elements/image/SvgImageView.js +92 -90
  618. package/src/view/minimap/dom/MinimapTerrainView.d.ts +1 -0
  619. package/src/view/minimap/dom/MinimapTerrainView.d.ts.map +1 -1
  620. package/src/view/minimap/dom/MinimapTerrainView.js +151 -147
  621. package/src/view/tooltip/gml/TooltipParser.js +2 -2
  622. package/src/engine/network/PriorityFetch.d.ts +0 -59
  623. package/src/engine/network/PriorityFetch.d.ts.map +0 -1
  624. package/src/engine/network/PriorityFetch.js +0 -193
  625. package/src/generation/foliage/config/BranchLevelConfig.d.ts.map +0 -1
@@ -1,569 +1,637 @@
1
- import { GOLDEN_RATIO } from "../../../core/math/GOLDEN_RATIO.js";
2
- import { PI2 } from "../../../core/math/PI2.js";
3
- import { clamp } from "../../../core/math/clamp.js";
4
- import { lerp } from "../../../core/math/lerp.js";
5
- import { seededRandom } from "../../../core/math/random/seededRandom.js";
6
- import { t64_look_rotation } from "../../../engine/ecs/transform/t64_look_rotation.js";
7
- import { Transform64 } from "../../../engine/ecs/transform/Transform64.js";
8
- import { Attribute } from "../../../shade/renderer/geometry/Attribute.js";
9
- import { CrownEnvelopeType } from "../config/CrownEnvelopeType.js";
10
- import { PhyllotaxisMode } from "../config/PhyllotaxisMode.js";
11
- import { TreeSpeciesConfig } from "../config/TreeSpeciesConfig.js";
12
- import { spine_frame_double_reflection } from "../skeleton/spine_frame_double_reflection.js";
13
- import { tree_mesh_compute_branch_rings } from "./tree_mesh_build_bark.js";
14
-
15
- const GOLDEN_CONJUGATE = 1.0 / GOLDEN_RATIO; // ~0.6180339887498949
16
- const GOLDEN_ANGLE = PI2 / (GOLDEN_RATIO * GOLDEN_RATIO);
17
-
18
- const SCRATCH_POS = new Float32Array(3);
19
- const SCRATCH_TAN = new Float32Array(3);
20
- const SCRATCH_P0 = new Float32Array(3);
21
- const SCRATCH_T0 = new Float32Array(3);
22
- const SCRATCH_R0 = new Float32Array(3);
23
- const SCRATCH_RMF = new Float64Array(6);
24
-
25
- /**
26
- * Flat typed-array structure holding all phyllotactic foliage attachment points and oriented card frames.
27
- *
28
- * @typedef {Object} FoliageAttachmentSet
29
- * @property {number} count number of foliage attachments
30
- * @property {Float32Array} positions `count * 3` attachment world/local positions
31
- * @property {Float32Array} forward `count * 3` unit card length axis F
32
- * @property {Float32Array} up `count * 3` unit card outward normal U
33
- * @property {Float32Array} right `count * 3` unit card width axis W = F x U (so W x F = +U)
34
- * @property {Float32Array} scales `count` per-card size multiplier
35
- * @property {Float32Array} ranks `count` golden-ratio low-discrepancy decimation rank in [0, 1)
36
- * @property {Float32Array} phases `count` per-card wind phase in [0, 1)
37
- * @property {Float32Array} branch_sway `count` parent branch sway weight in [0, 1]
38
- * @property {Float32Array} color_jitter `count` per-card luminance/tint jitter in [-1, 1]
39
- * @property {Float32Array} maturities `count` per-card ontogenetic leaf maturity in [0, 1] (0 = juvenile tip, 1 = mature base)
40
- * @property {Float32Array} sun_exposure `count` per-card canopy solar irradiance exposure in [0, 1]
41
- * @property {Uint8Array} variant_indices `count` assigned foliage atlas variant index in `[0, variant_count - 1]`
42
- * @property {Uint16Array} joints `count * 2` `[j_primary, j_parent]`
43
- * @property {Float32Array} weights `count * 2` `[w_primary, w_parent]`
44
- */
45
-
46
- /**
47
- * Generates phyllotactic foliage card attachment transforms along all eligible branches of a `TreeSkeleton`.
48
- *
49
- * @param {import("../skeleton/TreeSkeleton.js").TreeSkeleton} skeleton
50
- * @param {TreeSpeciesConfig} [config]
51
- * @returns {FoliageAttachmentSet}
52
- */
53
- export function foliage_collect_attachments(skeleton, config = new TreeSpeciesConfig()) {
54
- const species = config && config.isTreeSpeciesConfig ? config : TreeSpeciesConfig.from(config);
55
- const fol = species.foliage;
56
- if (!fol.enabled || skeleton.branch_count === 0) {
57
- return {
58
- count: 0,
59
- transforms: [],
60
- positions: new Float32Array(0),
61
- forward: new Float32Array(0),
62
- up: new Float32Array(0),
63
- right: new Float32Array(0),
64
- scales: new Float32Array(0),
65
- ranks: new Float32Array(0),
66
- phases: new Float32Array(0),
67
- branch_sway: new Float32Array(0),
68
- color_jitter: new Float32Array(0),
69
- maturities: new Float32Array(0),
70
- sun_exposure: new Float32Array(0),
71
- variant_indices: new Uint8Array(0),
72
- joints: new Uint16Array(0),
73
- weights: new Float32Array(0),
74
- joints4: new Uint16Array(0),
75
- weights4: new Float32Array(0),
76
- attr_ranks: Attribute.from(new Float32Array(0), 1, "foliage_ranks"),
77
- attr_phases: Attribute.from(new Float32Array(0), 1, "foliage_phases"),
78
- attr_branch_sway: Attribute.from(new Float32Array(0), 1, "foliage_branch_sway"),
79
- attr_color_jitter: Attribute.from(new Float32Array(0), 1, "foliage_color_jitter"),
80
- attr_maturities: Attribute.from(new Float32Array(0), 1, "foliage_maturities"),
81
- attr_variant_indices: Attribute.from(new Uint8Array(0), 1, "foliage_variant_indices"),
82
- attr_joints: Attribute.from(new Uint16Array(0), 2, "foliage_joints"),
83
- attr_weights: Attribute.from(new Float32Array(0), 2, "foliage_weights")
84
- };
85
- }
86
-
87
- const rng = seededRandom((species.seed ^ 0x5A3C9E17) | 0);
88
- const max_existing_level = Math.max(0, species.levels.length - 1);
89
- const min_level = Math.min(fol.attach_min_level, max_existing_level);
90
- const branch_rings = tree_mesh_compute_branch_rings(skeleton, species, species.lods?.[0]);
91
- const variant_count = clamp((species.foliage_material?.variant_count ?? 4) | 0, 1, 16);
92
-
93
- const crown = species.crown;
94
- const is_conical_crown = crown.envelope_type === CrownEnvelopeType.Conical;
95
- const cx = skeleton.crown_center[0];
96
- const cy = skeleton.crown_center[1];
97
- const cz = skeleton.crown_center[2];
98
- const rx_crown = Math.max(0.5, skeleton.crown_radii[0]);
99
- const ry = Math.max(0.5, skeleton.crown_radii[1]);
100
- const rz_crown = Math.max(0.5, skeleton.crown_radii[2]);
101
- const ref_card_len = Math.max(0.25, fol.card_length);
102
-
103
- // First collect eligible branch edge chains via `skeleton.graph`
104
- const eligible_branches = [];
105
- for (let b = 0; b < skeleton.branch_count; b++) {
106
- const level = skeleton.branch_level[b];
107
- if (level < min_level) continue;
108
-
109
- const nodes = [];
110
- const edges = [];
111
- skeleton.collect_branch_chain(b, nodes, edges);
112
- if (edges.length === 0) continue;
113
-
114
- const t_norms = new Array(nodes.length);
115
- for (let i = 0; i < nodes.length; i++) {
116
- t_norms[i] = skeleton.node_t_norm(nodes[i]);
117
- }
118
-
119
- eligible_branches.push({ branch_id: b, level, nodes, edges, t_norms });
120
- }
121
-
122
- const lateral_count = Math.max(0, fol.cards_per_branch | 0);
123
- const rosette_count = Math.max(0, fol.terminal_rosette_count | 0);
124
- const per_branch = lateral_count + rosette_count;
125
- const total_count = eligible_branches.length * per_branch;
126
-
127
- /** @type {Transform64[]} */
128
- const transforms = new Array(total_count);
129
- const positions = new Float32Array(total_count * 3);
130
- const forward = new Float32Array(total_count * 3);
131
- const up = new Float32Array(total_count * 3);
132
- const right = new Float32Array(total_count * 3);
133
- const scales = new Float32Array(total_count);
134
- const ranks = new Float32Array(total_count);
135
- const phases = new Float32Array(total_count);
136
- const branch_sway = new Float32Array(total_count);
137
- const color_jitter = new Float32Array(total_count);
138
- const maturities = new Float32Array(total_count);
139
- const sun_exposure = new Float32Array(total_count);
140
- const variant_indices = new Uint8Array(total_count);
141
- const joints = new Uint16Array(total_count * 2);
142
- const weights = new Float32Array(total_count * 2);
143
- const joints4 = new Uint16Array(total_count * 4);
144
- const weights4 = new Float32Array(total_count * 4);
145
-
146
- let cursor = 0;
147
- const bare = clamp(fol.bare_ratio, 0.0, 0.92);
148
-
149
- for (let eb = 0; eb < eligible_branches.length; eb++) {
150
- const item = eligible_branches[eb];
151
- const level = item.level;
152
- const nodes = item.nodes;
153
- const edges = item.edges;
154
- const t_norms = item.t_norms;
155
- const b_rings = branch_rings.get(item.branch_id);
156
- const b_len = Math.max(0.12, skeleton.branch_length[item.branch_id]);
157
- const shoot_scale = clamp(b_len / (ref_card_len * 0.95), 0.22, 1.0);
158
- const t_min = Math.max(bare, t_norms[0]);
159
- const t_max = t_norms[t_norms.length - 1];
160
- const base_phi = rng() * PI2;
161
- const b_phase = skeleton.branch_phase_hash[item.branch_id];
162
-
163
- for (let k = 0; k < per_branch; k++) {
164
- const is_rosette = k >= lateral_count;
165
- let t_attach = 1.0;
166
-
167
- if (!is_rosette && lateral_count > 0) {
168
- let u_k = (k + 0.5) / lateral_count;
169
- if (fol.phyllotaxis_mode === PhyllotaxisMode.Opposite
170
- || fol.phyllotaxis_mode === PhyllotaxisMode.OppositeDecussate) {
171
- const pair_idx = k >> 1;
172
- const pair_total = Math.max(1, Math.ceil(lateral_count / 2));
173
- u_k = (pair_idx + 0.5) / pair_total;
174
- } else if (fol.phyllotaxis_mode === PhyllotaxisMode.Whorled) {
175
- const w_size = Math.max(1, fol.whorl_count | 0);
176
- const w_idx = Math.floor(k / w_size);
177
- const w_total = Math.max(1, Math.ceil(lateral_count / w_size));
178
- u_k = (w_idx + 0.5) / w_total;
179
- }
180
- t_attach = clamp(lerp(t_min, t_max * 0.92, u_k), t_min, t_max * 0.95);
181
- } else {
182
- const ros_idx = k - lateral_count;
183
- const u_ros = (ros_idx + 0.5) / Math.max(1, rosette_count);
184
- t_attach = clamp(lerp(Math.max(t_min, t_max * 0.88), t_max * 0.96, u_ros), t_min, t_max * 0.96);
185
- }
186
-
187
- // Locate segment containing t_attach
188
- let seg_idx = edges.length - 1;
189
- for (let s = 0; s < edges.length; s++) {
190
- if (t_attach >= t_norms[s] && t_attach <= t_norms[s + 1]) {
191
- seg_idx = s;
192
- break;
193
- }
194
- }
195
-
196
- const edge_id = edges[seg_idx];
197
- const v0 = nodes[seg_idx];
198
- const v1 = nodes[seg_idx + 1];
199
- const t0 = t_norms[seg_idx];
200
- const t1 = t_norms[seg_idx + 1];
201
- const local_u = clamp((t_attach - t0) / Math.max(1e-5, t1 - t0), 0.05, 0.95);
202
-
203
- skeleton.evaluate_segment_position(SCRATCH_POS, 0, edge_id, local_u);
204
- skeleton.evaluate_segment_tangent(SCRATCH_TAN, 0, edge_id, local_u);
205
- skeleton.node_read_position(SCRATCH_P0, 0, v0);
206
- skeleton.node_read_tangent(SCRATCH_T0, 0, v0);
207
- skeleton.node_read_frame_r(SCRATCH_R0, 0, v0);
208
-
209
- spine_frame_double_reflection(
210
- SCRATCH_RMF, 0,
211
- SCRATCH_P0[0], SCRATCH_P0[1], SCRATCH_P0[2],
212
- SCRATCH_T0[0], SCRATCH_T0[1], SCRATCH_T0[2],
213
- SCRATCH_R0[0], SCRATCH_R0[1], SCRATCH_R0[2],
214
- SCRATCH_POS[0], SCRATCH_POS[1], SCRATCH_POS[2],
215
- SCRATCH_TAN[0], SCRATCH_TAN[1], SCRATCH_TAN[2]
216
- );
217
- const rx = SCRATCH_RMF[0], ry_f = SCRATCH_RMF[1], rz = SCRATCH_RMF[2];
218
- const sx = SCRATCH_RMF[3], sy_f = SCRATCH_RMF[4], sz = SCRATCH_RMF[5];
219
-
220
- // Phyllotactic angle phi
221
- let phi = base_phi;
222
- if (is_rosette) {
223
- const r_idx = k - lateral_count;
224
- phi += (r_idx * PI2) / Math.max(1, rosette_count);
225
- } else {
226
- switch (fol.phyllotaxis_mode) {
227
- case PhyllotaxisMode.AlternateDistichous:
228
- phi += k * Math.PI;
229
- break;
230
- case PhyllotaxisMode.Tristichous:
231
- phi += k * (PI2 / 3.0);
232
- break;
233
- case PhyllotaxisMode.Opposite:
234
- phi += (k & 1) * Math.PI;
235
- break;
236
- case PhyllotaxisMode.OppositeDecussate:
237
- phi += (k & 1) * Math.PI + (k >> 1) * (Math.PI * 0.5);
238
- break;
239
- case PhyllotaxisMode.Whorled: {
240
- const w_size = Math.max(1, fol.whorl_count | 0);
241
- const w_idx = Math.floor(k / w_size);
242
- const sub_idx = k % w_size;
243
- phi += (sub_idx * PI2) / w_size + (w_idx * Math.PI) / w_size;
244
- break;
245
- }
246
- case PhyllotaxisMode.SpiralGolden:
247
- default:
248
- phi += k * GOLDEN_ANGLE;
249
- break;
250
- }
251
- }
252
- phi += (rng() * 2.0 - 1.0) * fol.angular_jitter;
253
-
254
- const cos_p = Math.cos(phi);
255
- const sin_p = Math.sin(phi);
256
- const drx = cos_p * rx + sin_p * sx;
257
- const dry = cos_p * ry_f + sin_p * sy_f;
258
- const drz = cos_p * rz + sin_p * sz;
259
-
260
- // Anchor card stem origin on the actual meshed bark frustum chord [ra, rb]
261
- // and interpolate the carrier frustum's exact 4-slot skinning weights
262
- let px = SCRATCH_POS[0];
263
- let py = SCRATCH_POS[1];
264
- let pz = SCRATCH_POS[2];
265
- let seg_tx = SCRATCH_TAN[0];
266
- let seg_ty = SCRATCH_TAN[1];
267
- let seg_tz = SCRATCH_TAN[2];
268
-
269
- const c4 = cursor * 4;
270
- const c2 = cursor * 2;
271
-
272
- if (b_rings && b_rings.length >= 2) {
273
- const ring_idx = Math.min(seg_idx, b_rings.length - 2);
274
- const ra = b_rings[ring_idx];
275
- const rb = b_rings[ring_idx + 1];
276
- const xi = clamp((t_attach - ra.t_norm) / Math.max(1e-5, rb.t_norm - ra.t_norm), 0.05, 0.95);
277
-
278
- px = lerp(ra.cx, rb.cx, xi);
279
- py = lerp(ra.cy, rb.cy, xi);
280
- pz = lerp(ra.cz, rb.cz, xi);
281
-
282
- const dx_seg = rb.cx - ra.cx;
283
- const dy_seg = rb.cy - ra.cy;
284
- const dz_seg = rb.cz - ra.cz;
285
- const seg_len = Math.hypot(dx_seg, dy_seg, dz_seg);
286
- if (seg_len > 1e-6) {
287
- seg_tx = dx_seg / seg_len;
288
- seg_ty = dy_seg / seg_len;
289
- seg_tz = dz_seg / seg_len;
290
- }
291
-
292
- // Merge 4-slot skinning weights from ra (weight 1 - xi) and rb (weight xi)
293
- const merged_j = [-1, -1, -1, -1, -1, -1, -1, -1];
294
- const merged_w = [0, 0, 0, 0, 0, 0, 0, 0];
295
- let m_count = 0;
296
-
297
- const accumulate_joint = (j_id, w_val) => {
298
- if (w_val <= 1e-7) return;
299
- for (let m = 0; m < m_count; m++) {
300
- if (merged_j[m] === j_id) {
301
- merged_w[m] += w_val;
302
- return;
303
- }
304
- }
305
- merged_j[m_count] = j_id;
306
- merged_w[m_count] = w_val;
307
- m_count++;
308
- };
309
-
310
- const w_a = 1.0 - xi;
311
- const w_b = xi;
312
- accumulate_joint(ra.j0, ra.w0 * w_a);
313
- accumulate_joint(ra.j1, ra.w1 * w_a);
314
- accumulate_joint(ra.j2, ra.w2 * w_a);
315
- accumulate_joint(ra.j3, ra.w3 * w_a);
316
- accumulate_joint(rb.j0, rb.w0 * w_b);
317
- accumulate_joint(rb.j1, rb.w1 * w_b);
318
- accumulate_joint(rb.j2, rb.w2 * w_b);
319
- accumulate_joint(rb.j3, rb.w3 * w_b);
320
-
321
- // Sort descending by weight and normalize top 4
322
- for (let a = 0; a < m_count - 1; a++) {
323
- for (let b_sort = a + 1; b_sort < m_count; b_sort++) {
324
- if (merged_w[b_sort] > merged_w[a]) {
325
- const tw = merged_w[a];
326
- merged_w[a] = merged_w[b_sort];
327
- merged_w[b_sort] = tw;
328
- const tj = merged_j[a];
329
- merged_j[a] = merged_j[b_sort];
330
- merged_j[b_sort] = tj;
331
- }
332
- }
333
- }
334
-
335
- const top_k = Math.min(4, m_count);
336
- let w4_sum = 0.0;
337
- for (let s = 0; s < top_k; s++) w4_sum += merged_w[s];
338
- const inv_w4 = w4_sum > 1e-7 ? 1.0 / w4_sum : 1.0;
339
-
340
- for (let s = 0; s < 4; s++) {
341
- if (s < top_k) {
342
- joints4[c4 + s] = merged_j[s];
343
- weights4[c4 + s] = merged_w[s] * inv_w4;
344
- } else {
345
- joints4[c4 + s] = 0;
346
- weights4[c4 + s] = 0.0;
347
- }
348
- }
349
-
350
- // Populate 2-slot legacy joints/weights normalized to sum to 1.0
351
- const j_prim = top_k > 0 ? merged_j[0] : 0;
352
- const j_par = top_k > 1 ? merged_j[1] : j_prim;
353
- const w0_raw = top_k > 0 ? merged_w[0] : 1.0;
354
- const w1_raw = top_k > 1 ? merged_w[1] : 0.0;
355
- const w2_sum = w0_raw + w1_raw;
356
- joints[c2] = j_prim;
357
- joints[c2 + 1] = j_par;
358
- weights[c2] = w2_sum > 1e-7 ? w0_raw / w2_sum : 1.0;
359
- weights[c2 + 1] = w2_sum > 1e-7 ? w1_raw / w2_sum : 0.0;
360
- } else {
361
- const j_prim = skeleton.node_read_joint(v1, 0);
362
- const j_par = skeleton.node_read_joint(v1, 1);
363
- const w_prim = j_prim === j_par ? 1.0 : clamp(0.35 + 0.65 * t_attach, 0.0, 1.0);
364
- joints[c2] = j_prim;
365
- joints[c2 + 1] = j_par;
366
- weights[c2] = w_prim;
367
- weights[c2 + 1] = 1.0 - w_prim;
368
- joints4[c4] = j_prim;
369
- joints4[c4 + 1] = j_par;
370
- weights4[c4] = w_prim;
371
- weights4[c4 + 1] = 1.0 - w_prim;
372
- }
373
-
374
- // Outward canopy normal n_canopy from crown center
375
- let ncx = px - cx;
376
- let ncy = (py - cy) + 0.35 * ry;
377
- let ncz = pz - cz;
378
- const nc_len = Math.sqrt(ncx * ncx + ncy * ncy + ncz * ncz);
379
- if (nc_len > 1e-6) {
380
- ncx /= nc_len;
381
- ncy /= nc_len;
382
- ncz /= nc_len;
383
- } else {
384
- ncx = 0.0;
385
- ncy = 1.0;
386
- ncz = 0.0;
387
- }
388
-
389
- const h_norm_card = clamp((py - crown.base_height) / Math.max(0.1, crown.height), 0.0, 1.0);
390
- const w_apex_spire = is_conical_crown && h_norm_card > 0.72
391
- ? Math.pow(clamp((h_norm_card - 0.72) / 0.25, 0.0, 1.0), 1.35)
392
- : 0.0;
393
-
394
- // Initial card forward axis F along insertion angle from branch frustum tangent toward D_rad
395
- const base_ins = is_rosette ? fol.insertion_angle * 0.55 : fol.insertion_angle;
396
- const ins_angle = base_ins * (1.0 - 0.65 * w_apex_spire);
397
- const cos_a = Math.cos(ins_angle);
398
- const sin_a = Math.sin(ins_angle);
399
- let fx = cos_a * seg_tx + sin_a * drx;
400
- let fy = cos_a * seg_ty + sin_a * dry;
401
- let fz = cos_a * seg_tz + sin_a * drz;
402
-
403
- // Blend phototropism (outward/sky), gravitropism (downward droop along -Y), and orthotropic apical candle spire
404
- const grav_atten = 1.0 - 0.90 * w_apex_spire;
405
- const out_atten = 1.0 - 0.75 * w_apex_spire;
406
- fx += fol.phototropism * 0.45 * out_atten * ncx + (rng() * 2.0 - 1.0) * fol.angular_jitter * 0.35 * out_atten;
407
- fy += fol.phototropism * 0.25 * Math.max(0.0, ncy) - fol.gravitropism * 0.85 * grav_atten;
408
- fz += fol.phototropism * 0.45 * out_atten * ncz + (rng() * 2.0 - 1.0) * fol.angular_jitter * 0.35 * out_atten;
409
-
410
- if (w_apex_spire > 1e-4) {
411
- const w_spire = clamp(w_apex_spire * (is_rosette ? 0.92 : 0.78), 0.0, 0.94);
412
- fx = lerp(fx, -0.15 * ncx, w_spire);
413
- fy = lerp(fy, 1.0, w_spire);
414
- fz = lerp(fz, -0.15 * ncz, w_spire);
415
- }
416
-
417
- const f_len = Math.sqrt(fx * fx + fy * fy + fz * fz);
418
- if (f_len > 1e-8) {
419
- fx /= f_len;
420
- fy /= f_len;
421
- fz /= f_len;
422
- } else {
423
- fx = drx;
424
- fy = dry;
425
- fz = drz;
426
- }
427
-
428
- // Desired card upward normal U: blend of world +Y and outward canopy normal n_canopy
429
- let ux = ncx * 0.45;
430
- let uy = 0.65 + ncy * 0.35;
431
- let uz = ncz * 0.45;
432
- // Gram-Schmidt orthogonalize U against F
433
- const dot_uf = ux * fx + uy * fy + uz * fz;
434
- ux -= dot_uf * fx;
435
- uy -= dot_uf * fy;
436
- uz -= dot_uf * fz;
437
- const u_len = Math.sqrt(ux * ux + uy * uy + uz * uz);
438
- if (u_len > 1e-6) {
439
- ux /= u_len;
440
- uy /= u_len;
441
- uz /= u_len;
442
- } else {
443
- // Fallback perpendicular to F
444
- if (Math.abs(fy) < 0.9) {
445
- ux = -fz;
446
- uy = 0.0;
447
- uz = fx;
448
- } else {
449
- ux = 1.0;
450
- uy = 0.0;
451
- uz = 0.0;
452
- }
453
- const d2 = ux * fx + uy * fy + uz * fz;
454
- ux -= d2 * fx;
455
- uy -= d2 * fy;
456
- uz -= d2 * fz;
457
- const l2 = Math.sqrt(ux * ux + uy * uy + uz * uz);
458
- ux /= l2;
459
- uy /= l2;
460
- uz /= l2;
461
- }
462
-
463
- // Enforce outward/sky hemisphere alignment: dot(U, n_canopy + (0, 0.5, 0)) >= 0
464
- if (ux * ncx + uy * (ncy + 0.5) + uz * ncz < 0.0) {
465
- ux = -ux;
466
- uy = -uy;
467
- uz = -uz;
468
- }
469
-
470
- // W = F x U so that (W, F) card triangles have face normal W x F = +U!
471
- const wx = fy * uz - fz * uy;
472
- const wy = fz * ux - fx * uz;
473
- const wz = fx * uy - fy * ux;
474
-
475
- const c3 = cursor * 3;
476
-
477
- positions[c3] = px;
478
- positions[c3 + 1] = py;
479
- positions[c3 + 2] = pz;
480
-
481
- forward[c3] = fx;
482
- forward[c3 + 1] = fy;
483
- forward[c3 + 2] = fz;
484
-
485
- up[c3] = ux;
486
- up[c3 + 1] = uy;
487
- up[c3 + 2] = uz;
488
-
489
- right[c3] = wx;
490
- right[c3 + 1] = wy;
491
- right[c3 + 2] = wz;
492
-
493
- const apex_env_scale = is_conical_crown && h_norm_card > 0.70
494
- ? lerp(1.0, 0.24, Math.pow(clamp((h_norm_card - 0.70) / 0.28, 0.0, 1.0), 1.15))
495
- : 1.0;
496
- const scale_var = 1.0 + (rng() * 2.0 - 1.0) * fol.size_variance;
497
- const card_scale = Math.max(
498
- 0.18,
499
- scale_var * (is_rosette ? 0.92 : 1.0) * Math.min(shoot_scale, apex_env_scale)
500
- );
501
- scales[cursor] = card_scale;
502
-
503
- const t64 = new Transform64();
504
- t64.setTranslation(px, py, pz);
505
- t64_look_rotation(t64, fx, fy, fz, ux, uy, uz);
506
- t64.setScaleScalar(card_scale);
507
- t64.updateMatrix();
508
- transforms[cursor] = t64;
509
-
510
- // Golden-ratio low-discrepancy rank in [0, 1)
511
- ranks[cursor] = ((cursor * GOLDEN_CONJUGATE) + b_phase * 0.13) % 1.0;
512
- phases[cursor] = (b_phase + k * 0.17) % 1.0;
513
- branch_sway[cursor] = clamp((level + t_attach) * 0.28, 0.1, 1.0);
514
- const c_jit = rng() * 2.0 - 1.0;
515
- color_jitter[cursor] = c_jit;
516
-
517
- // Ontogenetic leaf maturity mu_i in [0, 1]:
518
- // Acropetal shoot progression (terminal rosette / distal tip -> 0 juvenile, basal nodes -> 1 mature)
519
- // combined with crown shell periphery (outer shell -> younger shoots, inner core -> older shade leaves)
520
- const u_shoot = is_rosette
521
- ? clamp(0.88 + 0.12 * ((k - lateral_count + 0.5) / Math.max(1, rosette_count)), 0.88, 1.0)
522
- : clamp((t_attach - t_min) / Math.max(1e-4, t_max * 0.92 - t_min), 0.0, 1.0);
523
- const ndx_c = (px - cx) / rx_crown;
524
- const ndy_c = (py - cy) / ry;
525
- const ndz_c = (pz - cz) / rz_crown;
526
- const rho_shell = clamp(Math.sqrt(ndx_c * ndx_c + ndy_c * ndy_c + ndz_c * ndz_c), 0.0, 1.0);
527
- const maturity = clamp(
528
- 0.66 * (1.0 - u_shoot) + 0.24 * (1.0 - rho_shell) + 0.05 + 0.07 * c_jit,
529
- 0.0,
530
- 1.0
531
- );
532
- const sun_exp = clamp(0.62 * rho_shell + 0.38 * h_norm_card, 0.0, 1.0);
533
- maturities[cursor] = maturity;
534
- sun_exposure[cursor] = sun_exp;
535
- variant_indices[cursor] = clamp(Math.floor(maturity * variant_count), 0, variant_count - 1);
536
-
537
- cursor++;
538
- }
539
- }
540
-
541
- return {
542
- count: cursor,
543
- transforms,
544
- positions,
545
- forward,
546
- up,
547
- right,
548
- scales,
549
- ranks,
550
- phases,
551
- branch_sway,
552
- color_jitter,
553
- maturities,
554
- sun_exposure,
555
- variant_indices,
556
- joints,
557
- weights,
558
- joints4,
559
- weights4,
560
- attr_ranks: Attribute.from(ranks, 1, "foliage_ranks"),
561
- attr_phases: Attribute.from(phases, 1, "foliage_phases"),
562
- attr_branch_sway: Attribute.from(branch_sway, 1, "foliage_branch_sway"),
563
- attr_color_jitter: Attribute.from(color_jitter, 1, "foliage_color_jitter"),
564
- attr_maturities: Attribute.from(maturities, 1, "foliage_maturities"),
565
- attr_variant_indices: Attribute.from(variant_indices, 1, "foliage_variant_indices"),
566
- attr_joints: Attribute.from(joints, 2, "foliage_joints"),
567
- attr_weights: Attribute.from(weights, 2, "foliage_weights")
568
- };
569
- }
1
+ import { GOLDEN_RATIO } from "../../../core/math/GOLDEN_RATIO.js";
2
+ import { PI2 } from "../../../core/math/PI2.js";
3
+ import { clamp } from "../../../core/math/clamp.js";
4
+ import { lerp } from "../../../core/math/lerp.js";
5
+ import { seededRandom } from "../../../core/math/random/seededRandom.js";
6
+ import { t64_look_rotation } from "../../../engine/ecs/transform/t64_look_rotation.js";
7
+ import { Transform64 } from "../../../engine/ecs/transform/Transform64.js";
8
+ import { Attribute } from "../../../shade/renderer/geometry/Attribute.js";
9
+ import { CrownEnvelopeType } from "../config/CrownEnvelopeType.js";
10
+ import { FoliageTileContent } from "../config/FoliageTileContent.js";
11
+ import { PhyllotaxisMode, phyllotaxis_sample_angle } from "../config/PhyllotaxisMode.js";
12
+ import { TreeSpeciesConfig } from "../config/TreeSpeciesConfig.js";
13
+ import { foliage_atlas_cutout } from "../material/foliage_atlas_cutout.js";
14
+ import { spine_frame_double_reflection } from "../skeleton/spine_frame_double_reflection.js";
15
+ import {
16
+ foliage_cards_per_metre,
17
+ foliage_leafy_span_start,
18
+ foliage_shoot_card_scale
19
+ } from "../skeleton/foliage_card_density.js";
20
+ import { foliage_unit_card_spans } from "../skeleton/foliage_unit_cards.js";
21
+ import { foliage_tile_layout } from "../material/foliage_tile.js";
22
+ import {
23
+ foliage_abscission_threshold,
24
+ foliage_crown_height_norm,
25
+ foliage_crown_rho,
26
+ foliage_leaf_dryness,
27
+ foliage_leaf_maturity,
28
+ foliage_leaf_variant,
29
+ foliage_sun_exposure,
30
+ foliage_variant_abscission_onset,
31
+ foliage_variant_maturity
32
+ } from "../skeleton/foliage_senescence.js";
33
+ import { interpolate_ring_skin_weights4 } from "./interpolate_ring_skin_weights4.js";
34
+ import { tree_skeleton_read_joint_motion } from "../skeleton/tree_skeleton_read_joint_motion.js";
35
+ import { tree_mesh_compute_branch_rings } from "./tree_mesh_build_bark.js";
36
+
37
+ const GOLDEN_CONJUGATE = 1.0 / GOLDEN_RATIO; // ~0.6180339887498949
38
+ const GOLDEN_ANGLE = PI2 / (GOLDEN_RATIO * GOLDEN_RATIO);
39
+
40
+ const SCRATCH_POS = new Float32Array(3);
41
+ const SCRATCH_TAN = new Float32Array(3);
42
+ const SCRATCH_P0 = new Float32Array(3);
43
+ const SCRATCH_T0 = new Float32Array(3);
44
+ const SCRATCH_R0 = new Float32Array(3);
45
+ const SCRATCH_RMF = new Float64Array(6);
46
+ /** @type {import("../skeleton/foliage_unit_cards.js").FoliageUnitCardSpan[]} */
47
+ const SCRATCH_SPANS = [];
48
+
49
+ /**
50
+ * Flat typed-array structure holding all phyllotactic foliage attachment points and oriented card frames.
51
+ *
52
+ * @typedef {Object} FoliageAttachmentSet
53
+ * @property {number} count number of foliage attachments
54
+ * @property {Uint32Array} carriers `count` skeleton branch carrying each card
55
+ * @property {Float32Array} positions `count * 3` attachment world/local positions
56
+ * @property {Float32Array} forward `count * 3` unit card length axis F
57
+ * @property {Float32Array} up `count * 3` unit card outward normal U
58
+ * @property {Float32Array} right `count * 3` unit card width axis W = F x U (so W x F = +U)
59
+ * @property {Float32Array} scales `count` per-card size multiplier
60
+ * @property {Float32Array} ranks `count` golden-ratio low-discrepancy decimation rank in [0, 1)
61
+ * @property {Float32Array} phases `count` per-card wind phase in [0, 1)
62
+ * @property {Float32Array} branch_sway `count` parent branch sway weight in [0, 1]
63
+ * @property {Float32Array} color_jitter `count` per-card luminance/tint jitter in [-1, 1]
64
+ * @property {Float32Array} maturities `count` per-card ontogenetic leaf maturity in [0, 1] (0 = juvenile tip, 1 = mature base)
65
+ * @property {Float32Array} sun_exposure `count` per-card canopy solar irradiance exposure in [0, 1]
66
+ * @property {Uint8Array} variant_indices `count` assigned foliage atlas tile: its maturity variant in `[0, variant_count - 1]`
67
+ * @property {Float32Array} dryness `count` how far each still-attached leaf has dried with senescence, `[0, 1)`
68
+ * @property {Float32Array} tints `count * 3` linear RGB multiplier of each card's albedo; may exceed 1
69
+ * @property {number} tint_scale the largest tint channel, at least 1: vertex colours carry `tint / tint_scale` so
70
+ * they fit `unorm8`, and the foliage material's `diffuse_color` carries `tint_scale` back
71
+ * @property {Uint16Array} joints `count * 2` `[j_primary, j_parent]`
72
+ * @property {Float32Array} weights `count * 2` `[w_primary, w_parent]`
73
+ */
74
+
75
+ /**
76
+ * Generates phyllotactic foliage card attachment transforms along every branch whose generator is the
77
+ * `source` of a `species.foliage_rules` entry, one set of cards per (branch, rule) pair.
78
+ *
79
+ * On a branch grown by annual units every leaf is a card, at its own node along its unit, leaving the shoot at the
80
+ * rule's insertion angle and turned by its phyllotaxis (`foliage_unit_card_spans`); a needle-shoot card lies along
81
+ * the stretch of shoot it draws. Elsewhere how many cards a carrier gets follows from its leafy length and the card
82
+ * it carries (`foliage_cards_per_metre`): enough leaf that a line of sight through the shoot's foliage sleeve meets
83
+ * one leaf on average, rounded with a per-branch dither, so short shoots carry their share on average rather than a
84
+ * card each.
85
+ *
86
+ * With `foliage_material.senescence`, leaves are shed outer and apical first (`foliage_abscission_threshold`); the
87
+ * cards still attached carry how far they have dried.
88
+ *
89
+ * @param {import("../skeleton/TreeSkeleton.js").TreeSkeleton} skeleton
90
+ * @param {TreeSpeciesConfig} [config]
91
+ * @param {import("../material/FoliageAtlasCutout.js").FoliageAtlasCutout} [cutout] shape of the foliage atlas the
92
+ * cards will show; fitted from `config.foliage_material` when omitted
93
+ * @returns {FoliageAttachmentSet}
94
+ */
95
+ export function foliage_collect_attachments(skeleton, config = new TreeSpeciesConfig(), cutout) {
96
+ const species = config && config.isTreeSpeciesConfig ? config : TreeSpeciesConfig.from(config);
97
+ const fol = species.foliage;
98
+ if (species.foliage_rules.length === 0 || skeleton.branch_count === 0) {
99
+ return {
100
+ count: 0,
101
+ carriers: new Uint32Array(0),
102
+ transforms: [],
103
+ positions: new Float32Array(0),
104
+ forward: new Float32Array(0),
105
+ up: new Float32Array(0),
106
+ right: new Float32Array(0),
107
+ scales: new Float32Array(0),
108
+ ranks: new Float32Array(0),
109
+ phases: new Float32Array(0),
110
+ branch_sway: new Float32Array(0),
111
+ color_jitter: new Float32Array(0),
112
+ maturities: new Float32Array(0),
113
+ sun_exposure: new Float32Array(0),
114
+ variant_indices: new Uint8Array(0),
115
+ dryness: new Float32Array(0),
116
+ tints: new Float32Array(0),
117
+ tint_scale: 1.0,
118
+ joints: new Uint16Array(0),
119
+ weights: new Float32Array(0),
120
+ joints4: new Uint16Array(0),
121
+ weights4: new Float32Array(0),
122
+ attr_ranks: Attribute.from(new Float32Array(0), 1, "foliage_ranks"),
123
+ attr_phases: Attribute.from(new Float32Array(0), 1, "foliage_phases"),
124
+ attr_branch_sway: Attribute.from(new Float32Array(0), 1, "foliage_branch_sway"),
125
+ attr_color_jitter: Attribute.from(new Float32Array(0), 1, "foliage_color_jitter"),
126
+ attr_maturities: Attribute.from(new Float32Array(0), 1, "foliage_maturities"),
127
+ attr_variant_indices: Attribute.from(new Uint8Array(0), 1, "foliage_variant_indices"),
128
+ attr_joints: Attribute.from(new Uint16Array(0), 2, "foliage_joints"),
129
+ attr_weights: Attribute.from(new Float32Array(0), 2, "foliage_weights")
130
+ };
131
+ }
132
+
133
+ const rng = seededRandom((species.seed ^ 0x5A3C9E17) | 0);
134
+ const branch_rings = tree_mesh_compute_branch_rings(skeleton, species, species.lods?.[0]);
135
+ const layout = foliage_tile_layout(species);
136
+ const variant_count = layout.variant_count;
137
+ const needle_shoot = species.foliage_material.tile_content === FoliageTileContent.NeedleShoot;
138
+
139
+ const crown = species.crown;
140
+ const is_conical_crown = crown.envelope_type === CrownEnvelopeType.Conical;
141
+ const cx = skeleton.crown_center[0];
142
+ const cy = skeleton.crown_center[1];
143
+ const cz = skeleton.crown_center[2];
144
+ const ry = Math.max(0.5, skeleton.crown_radii[1]);
145
+ const atlas = cutout ?? foliage_atlas_cutout(species);
146
+ const coverage = atlas.mean_coverage();
147
+
148
+ const fol_mat = species.foliage_material;
149
+ const senescence = clamp(Math.max(fol_mat?.senescence ?? 0.0, fol_mat?.autumn_tint ?? 0.0), 0.0, 1.0);
150
+ const color_var_amp = clamp(fol.color_variation ?? 0.08, 0.0, 0.35);
151
+ const juv_shift = clamp(fol_mat?.juvenile_color_shift ?? 0.38, 0.0, 1.0);
152
+ const antho_pot = clamp(fol_mat?.anthocyanin_potential ?? 0.35, 0.0, 1.0);
153
+
154
+ // First collect (carrier branch, foliage rule) pairs with the branch edge chains via `skeleton.graph`
155
+ const foliage_rules = species.foliage_rules;
156
+ const eligible_branches = [];
157
+ let total_count = 0;
158
+ for (let b = 0; b < skeleton.branch_count; b++) {
159
+ // dead branches carry no leaves
160
+ if (skeleton.branch_dead[b]) continue;
161
+ const generator = skeleton.branch_generator[b];
162
+ let chain = null;
163
+
164
+ for (let r = 0; r < foliage_rules.length; r++) {
165
+ const rule = foliage_rules[r];
166
+ if (rule.source !== generator) continue;
167
+
168
+ if (chain === null) {
169
+ const nodes = [];
170
+ const edges = [];
171
+ skeleton.collect_branch_chain(b, nodes, edges);
172
+ const t_norms = new Array(nodes.length);
173
+ for (let i = 0; i < nodes.length; i++) {
174
+ t_norms[i] = skeleton.node_t_norm(nodes[i]);
175
+ }
176
+ chain = { nodes, edges, t_norms };
177
+ }
178
+ if (chain.edges.length === 0) break;
179
+
180
+ const t_norms = chain.t_norms;
181
+ const t_first = t_norms[0];
182
+ const t_max = t_norms[t_norms.length - 1];
183
+
184
+ if (skeleton.branch_unit_count[b] > 0) {
185
+ // a branch grown by annual units bears leaves on its units young enough to keep them: a leaf at each of
186
+ // its nodes, spaced along the unit; a needle-shoot card covers a stretch of it from its start and lies
187
+ // along it
188
+ foliage_unit_card_spans(skeleton, species, b, rule, layout.leaves_per_card, SCRATCH_SPANS);
189
+ for (let i = 0; i < SCRATCH_SPANS.length; i++) {
190
+ const span = SCRATCH_SPANS[i];
191
+ eligible_branches.push({
192
+ branch_id: b,
193
+ level: skeleton.branch_level[b],
194
+ nodes: chain.nodes,
195
+ edges: chain.edges,
196
+ t_norms,
197
+ t_min: span.t_min,
198
+ t_max: span.t_max,
199
+ slot_offset: needle_shoot ? 0.0 : 0.5,
200
+ shoot_scale: span.scale,
201
+ insertion_angle: needle_shoot ? 0.0 : rule.insertion_angle,
202
+ u_from: span.u_min,
203
+ u_to: span.u_max,
204
+ count: span.count,
205
+ rule
206
+ });
207
+ total_count += span.count;
208
+ }
209
+ break;
210
+ }
211
+
212
+ const t_min = Math.max(foliage_leafy_span_start(rule.attach_min), t_first);
213
+ const b_len = Math.max(0.12, skeleton.branch_length[b]);
214
+ const leafy_len = b_len * Math.max(0.0, t_max - t_min) / Math.max(1e-6, t_max - t_first);
215
+ const shoot_scale = foliage_shoot_card_scale(layout.card_size, b_len);
216
+ const expected = leafy_len * foliage_cards_per_metre(layout, fol.card_type, coverage, rule.insertion_angle, shoot_scale);
217
+ // golden-ratio dither per (branch, rule): exact on average, deterministic per branch
218
+ const dither = (skeleton.branch_phase_hash[b] + r * GOLDEN_CONJUGATE) % 1.0;
219
+ const count = Math.floor(expected + dither);
220
+ if (count === 0) continue;
221
+
222
+ eligible_branches.push({
223
+ branch_id: b,
224
+ level: skeleton.branch_level[b],
225
+ nodes: chain.nodes,
226
+ edges: chain.edges,
227
+ t_norms,
228
+ t_min,
229
+ t_max,
230
+ slot_offset: 0.5,
231
+ shoot_scale,
232
+ insertion_angle: rule.insertion_angle,
233
+ u_from: -1.0,
234
+ u_to: -1.0,
235
+ count,
236
+ rule
237
+ });
238
+ total_count += count;
239
+ }
240
+ }
241
+
242
+ /** @type {Transform64[]} */
243
+ const transforms = new Array(total_count);
244
+ const carriers = new Uint32Array(total_count);
245
+ const positions = new Float32Array(total_count * 3);
246
+ const forward = new Float32Array(total_count * 3);
247
+ const up = new Float32Array(total_count * 3);
248
+ const right = new Float32Array(total_count * 3);
249
+ const scales = new Float32Array(total_count);
250
+ const ranks = new Float32Array(total_count);
251
+ const phases = new Float32Array(total_count);
252
+ const branch_sway = new Float32Array(total_count);
253
+ const color_jitter = new Float32Array(total_count);
254
+ const maturities = new Float32Array(total_count);
255
+ const sun_exposure = new Float32Array(total_count);
256
+ const variant_indices = new Uint8Array(total_count);
257
+ const dryness = new Float32Array(total_count);
258
+ const tints = new Float32Array(total_count * 3);
259
+ let tint_scale = 1.0;
260
+ const joints = new Uint16Array(total_count * 2);
261
+ const weights = new Float32Array(total_count * 2);
262
+ const joints4 = new Uint16Array(total_count * 4);
263
+ const joint_motion = tree_skeleton_read_joint_motion(skeleton);
264
+ const weights4 = new Float32Array(total_count * 4);
265
+
266
+ let cursor = 0;
267
+
268
+ for (let eb = 0; eb < eligible_branches.length; eb++) {
269
+ const item = eligible_branches[eb];
270
+ const rule = item.rule;
271
+ const level = item.level;
272
+ const card_count = item.count;
273
+ const nodes = item.nodes;
274
+ const edges = item.edges;
275
+ const t_norms = item.t_norms;
276
+ const b_rings = branch_rings.get(item.branch_id);
277
+ const shoot_scale = item.shoot_scale;
278
+ const t_min = item.t_min;
279
+ const t_max = item.t_max;
280
+ const base_phi = rng() * PI2;
281
+ const b_phase = skeleton.branch_phase_hash[item.branch_id];
282
+
283
+ for (let k = 0; k < card_count; k++) {
284
+ // nodes evenly spaced over the leafy span, as many leaves at each as the phyllotaxis puts there; a card that
285
+ // covers a stretch of shoot hangs from that stretch's start
286
+ const slot_offset = item.slot_offset;
287
+ let u_k = (k + slot_offset) / card_count;
288
+ if (rule.phyllotaxis_mode === PhyllotaxisMode.Opposite
289
+ || rule.phyllotaxis_mode === PhyllotaxisMode.OppositeDecussate) {
290
+ const pair_idx = k >> 1;
291
+ const pair_total = Math.max(1, Math.ceil(card_count / 2));
292
+ u_k = (pair_idx + slot_offset) / pair_total;
293
+ } else if (rule.phyllotaxis_mode === PhyllotaxisMode.Whorled) {
294
+ const w_size = Math.max(1, rule.whorl_count | 0);
295
+ const w_idx = Math.floor(k / w_size);
296
+ const w_total = Math.max(1, Math.ceil(card_count / w_size));
297
+ u_k = (w_idx + slot_offset) / w_total;
298
+ }
299
+ const t_attach = lerp(t_min, t_max, u_k);
300
+
301
+ // Locate segment containing t_attach
302
+ let seg_idx = edges.length - 1;
303
+ for (let s = 0; s < edges.length; s++) {
304
+ if (t_attach >= t_norms[s] && t_attach <= t_norms[s + 1]) {
305
+ seg_idx = s;
306
+ break;
307
+ }
308
+ }
309
+
310
+ const edge_id = edges[seg_idx];
311
+ const v0 = nodes[seg_idx];
312
+ const v1 = nodes[seg_idx + 1];
313
+ const t0 = t_norms[seg_idx];
314
+ const t1 = t_norms[seg_idx + 1];
315
+ const local_u = clamp((t_attach - t0) / Math.max(1e-5, t1 - t0), 0.05, 0.95);
316
+
317
+ skeleton.evaluate_segment_position(SCRATCH_POS, 0, edge_id, local_u);
318
+ skeleton.evaluate_segment_tangent(SCRATCH_TAN, 0, edge_id, local_u);
319
+ skeleton.node_read_position(SCRATCH_P0, 0, v0);
320
+ skeleton.node_read_tangent(SCRATCH_T0, 0, v0);
321
+ skeleton.node_read_frame_r(SCRATCH_R0, 0, v0);
322
+
323
+ spine_frame_double_reflection(
324
+ SCRATCH_RMF, 0,
325
+ SCRATCH_P0[0], SCRATCH_P0[1], SCRATCH_P0[2],
326
+ SCRATCH_T0[0], SCRATCH_T0[1], SCRATCH_T0[2],
327
+ SCRATCH_R0[0], SCRATCH_R0[1], SCRATCH_R0[2],
328
+ SCRATCH_POS[0], SCRATCH_POS[1], SCRATCH_POS[2],
329
+ SCRATCH_TAN[0], SCRATCH_TAN[1], SCRATCH_TAN[2]
330
+ );
331
+ const rx = SCRATCH_RMF[0], ry_f = SCRATCH_RMF[1], rz = SCRATCH_RMF[2];
332
+ const sx = SCRATCH_RMF[3], sy_f = SCRATCH_RMF[4], sz = SCRATCH_RMF[5];
333
+
334
+ // Phyllotactic angle phi
335
+ let phi = phyllotaxis_sample_angle(rule.phyllotaxis_mode, k, rule.whorl_count, base_phi);
336
+ phi += (rng() * 2.0 - 1.0) * fol.angular_jitter;
337
+
338
+ const cos_p = Math.cos(phi);
339
+ const sin_p = Math.sin(phi);
340
+ const drx = cos_p * rx + sin_p * sx;
341
+ const dry = cos_p * ry_f + sin_p * sy_f;
342
+ const drz = cos_p * rz + sin_p * sz;
343
+
344
+ // Anchor card stem origin on the actual meshed bark frustum chord [ra, rb]
345
+ // and interpolate the carrier frustum's exact 4-slot skinning weights
346
+ let px = SCRATCH_POS[0];
347
+ let py = SCRATCH_POS[1];
348
+ let pz = SCRATCH_POS[2];
349
+ let seg_tx = SCRATCH_TAN[0];
350
+ let seg_ty = SCRATCH_TAN[1];
351
+ let seg_tz = SCRATCH_TAN[2];
352
+
353
+ const c4 = cursor * 4;
354
+ const c2 = cursor * 2;
355
+
356
+ if (b_rings && b_rings.length >= 2) {
357
+ const ring_idx = Math.min(seg_idx, b_rings.length - 2);
358
+ const ra = b_rings[ring_idx];
359
+ const rb = b_rings[ring_idx + 1];
360
+ const xi = clamp((t_attach - ra.t_norm) / Math.max(1e-5, rb.t_norm - ra.t_norm), 0.05, 0.95);
361
+
362
+ px = lerp(ra.cx, rb.cx, xi);
363
+ py = lerp(ra.cy, rb.cy, xi);
364
+ pz = lerp(ra.cz, rb.cz, xi);
365
+
366
+ const dx_seg = rb.cx - ra.cx;
367
+ const dy_seg = rb.cy - ra.cy;
368
+ const dz_seg = rb.cz - ra.cz;
369
+ const seg_len = Math.hypot(dx_seg, dy_seg, dz_seg);
370
+ if (seg_len > 1e-6) {
371
+ seg_tx = dx_seg / seg_len;
372
+ seg_ty = dy_seg / seg_len;
373
+ seg_tz = dz_seg / seg_len;
374
+ }
375
+
376
+ // Merge 4-slot skinning weights from ra (weight 1 - xi) and rb (weight xi)
377
+ const top_k = interpolate_ring_skin_weights4(joints4, c4, weights4, c4, ra, rb, xi, joint_motion, px, py, pz);
378
+
379
+ // Populate 2-slot legacy joints/weights normalized to sum to 1.0
380
+ const j_prim = joints4[c4];
381
+ const j_par = top_k > 1 ? joints4[c4 + 1] : j_prim;
382
+ const w0_raw = weights4[c4];
383
+ const w1_raw = top_k > 1 ? weights4[c4 + 1] : 0.0;
384
+ const w2_sum = w0_raw + w1_raw;
385
+ joints[c2] = j_prim;
386
+ joints[c2 + 1] = j_par;
387
+ weights[c2] = w2_sum > 1e-7 ? w0_raw / w2_sum : 1.0;
388
+ weights[c2 + 1] = w2_sum > 1e-7 ? w1_raw / w2_sum : 0.0;
389
+ } else {
390
+ const j_prim = skeleton.node_read_joint(v1, 0);
391
+ const j_par = skeleton.node_read_joint(v1, 1);
392
+ const w_prim = j_prim === j_par ? 1.0 : clamp(0.35 + 0.65 * t_attach, 0.0, 1.0);
393
+ joints[c2] = j_prim;
394
+ joints[c2 + 1] = j_par;
395
+ weights[c2] = w_prim;
396
+ weights[c2 + 1] = 1.0 - w_prim;
397
+ joints4[c4] = j_prim;
398
+ joints4[c4 + 1] = j_par;
399
+ weights4[c4] = w_prim;
400
+ weights4[c4 + 1] = 1.0 - w_prim;
401
+ }
402
+
403
+ // Outward canopy normal n_canopy from crown center
404
+ let ncx = px - cx;
405
+ let ncy = (py - cy) + 0.35 * ry;
406
+ let ncz = pz - cz;
407
+ const nc_len = Math.sqrt(ncx * ncx + ncy * ncy + ncz * ncz);
408
+ if (nc_len > 1e-6) {
409
+ ncx /= nc_len;
410
+ ncy /= nc_len;
411
+ ncz /= nc_len;
412
+ } else {
413
+ ncx = 0.0;
414
+ ncy = 1.0;
415
+ ncz = 0.0;
416
+ }
417
+
418
+ const h_norm_card = foliage_crown_height_norm(crown, py);
419
+ const w_apex_spire = is_conical_crown && h_norm_card > 0.72
420
+ ? Math.pow(clamp((h_norm_card - 0.72) / 0.25, 0.0, 1.0), 1.35)
421
+ : 0.0;
422
+
423
+ // Initial card forward axis F along insertion angle from branch frustum tangent toward D_rad
424
+ const ins_angle = item.insertion_angle * (1.0 - 0.65 * w_apex_spire);
425
+ const cos_a = Math.cos(ins_angle);
426
+ const sin_a = Math.sin(ins_angle);
427
+ let fx = cos_a * seg_tx + sin_a * drx;
428
+ let fy = cos_a * seg_ty + sin_a * dry;
429
+ let fz = cos_a * seg_tz + sin_a * drz;
430
+
431
+ // Blend phototropism (outward/sky), gravitropism (downward droop along -Y), and orthotropic apical candle spire
432
+ const grav_atten = 1.0 - 0.90 * w_apex_spire;
433
+ const out_atten = 1.0 - 0.75 * w_apex_spire;
434
+ fx += fol.phototropism * 0.45 * out_atten * ncx + (rng() * 2.0 - 1.0) * fol.angular_jitter * 0.35 * out_atten;
435
+ fy += fol.phototropism * 0.25 * Math.max(0.0, ncy) - fol.gravitropism * 0.85 * grav_atten;
436
+ fz += fol.phototropism * 0.45 * out_atten * ncz + (rng() * 2.0 - 1.0) * fol.angular_jitter * 0.35 * out_atten;
437
+
438
+ if (w_apex_spire > 1e-4) {
439
+ const w_spire = clamp(w_apex_spire * 0.78, 0.0, 0.94);
440
+ fx = lerp(fx, -0.15 * ncx, w_spire);
441
+ fy = lerp(fy, 1.0, w_spire);
442
+ fz = lerp(fz, -0.15 * ncz, w_spire);
443
+ }
444
+
445
+ const f_len = Math.sqrt(fx * fx + fy * fy + fz * fz);
446
+ if (f_len > 1e-8) {
447
+ fx /= f_len;
448
+ fy /= f_len;
449
+ fz /= f_len;
450
+ } else {
451
+ fx = drx;
452
+ fy = dry;
453
+ fz = drz;
454
+ }
455
+
456
+ // Desired card upward normal U: blend of world +Y and outward canopy normal n_canopy
457
+ let ux = ncx * 0.45;
458
+ let uy = 0.65 + ncy * 0.35;
459
+ let uz = ncz * 0.45;
460
+ // Gram-Schmidt orthogonalize U against F
461
+ const dot_uf = ux * fx + uy * fy + uz * fz;
462
+ ux -= dot_uf * fx;
463
+ uy -= dot_uf * fy;
464
+ uz -= dot_uf * fz;
465
+ const u_len = Math.sqrt(ux * ux + uy * uy + uz * uz);
466
+ if (u_len > 1e-6) {
467
+ ux /= u_len;
468
+ uy /= u_len;
469
+ uz /= u_len;
470
+ } else {
471
+ // Fallback perpendicular to F
472
+ if (Math.abs(fy) < 0.9) {
473
+ ux = -fz;
474
+ uy = 0.0;
475
+ uz = fx;
476
+ } else {
477
+ ux = 1.0;
478
+ uy = 0.0;
479
+ uz = 0.0;
480
+ }
481
+ const d2 = ux * fx + uy * fy + uz * fz;
482
+ ux -= d2 * fx;
483
+ uy -= d2 * fy;
484
+ uz -= d2 * fz;
485
+ const l2 = Math.sqrt(ux * ux + uy * uy + uz * uz);
486
+ ux /= l2;
487
+ uy /= l2;
488
+ uz /= l2;
489
+ }
490
+
491
+ // Enforce outward/sky hemisphere alignment: dot(U, n_canopy + (0, 0.5, 0)) >= 0
492
+ if (ux * ncx + uy * (ncy + 0.5) + uz * ncz < 0.0) {
493
+ ux = -ux;
494
+ uy = -uy;
495
+ uz = -uz;
496
+ }
497
+
498
+ // W = F x U so that (W, F) card triangles have face normal W x F = +U!
499
+ const wx = fy * uz - fz * uy;
500
+ const wy = fz * ux - fx * uz;
501
+ const wz = fx * uy - fy * ux;
502
+
503
+ const c3 = cursor * 3;
504
+
505
+ carriers[cursor] = item.branch_id;
506
+
507
+ positions[c3] = px;
508
+ positions[c3 + 1] = py;
509
+ positions[c3 + 2] = pz;
510
+
511
+ forward[c3] = fx;
512
+ forward[c3 + 1] = fy;
513
+ forward[c3 + 2] = fz;
514
+
515
+ up[c3] = ux;
516
+ up[c3 + 1] = uy;
517
+ up[c3 + 2] = uz;
518
+
519
+ right[c3] = wx;
520
+ right[c3 + 1] = wy;
521
+ right[c3 + 2] = wz;
522
+
523
+ const apex_env_scale = is_conical_crown && h_norm_card > 0.70
524
+ ? lerp(1.0, 0.24, Math.pow(clamp((h_norm_card - 0.70) / 0.28, 0.0, 1.0), 1.15))
525
+ : 1.0;
526
+ const scale_var = 1.0 + (rng() * 2.0 - 1.0) * fol.size_variance;
527
+ const card_scale = Math.max(
528
+ 0.18,
529
+ scale_var * Math.min(shoot_scale, apex_env_scale)
530
+ );
531
+ scales[cursor] = card_scale;
532
+
533
+ const t64 = new Transform64();
534
+ t64.setTranslation(px, py, pz);
535
+ t64_look_rotation(t64, fx, fy, fz, ux, uy, uz);
536
+ t64.setScaleScalar(card_scale);
537
+ t64.updateMatrix();
538
+ transforms[cursor] = t64;
539
+
540
+ // Golden-ratio low-discrepancy rank in [0, 1)
541
+ ranks[cursor] = ((cursor * GOLDEN_CONJUGATE) + b_phase * 0.13) % 1.0;
542
+ phases[cursor] = (b_phase + k * 0.17) % 1.0;
543
+ branch_sway[cursor] = clamp((level + t_attach) * 0.28, 0.1, 1.0);
544
+ const c_jit = rng() * 2.0 - 1.0;
545
+ color_jitter[cursor] = c_jit;
546
+
547
+ // Ontogenetic leaf maturity mu_i in [0, 1]:
548
+ // Acropetal shoot progression (distal tip -> 0 juvenile, basal nodes -> 1 mature)
549
+ // combined with crown shell periphery (outer shell -> younger shoots, inner core -> older shade leaves)
550
+ const u_shoot = item.u_from >= 0.0
551
+ ? lerp(item.u_from, item.u_to, (k + 0.5) / card_count)
552
+ : clamp((t_attach - t_min) / Math.max(1e-4, t_max - t_min), 0.0, 1.0);
553
+ const rho_shell = foliage_crown_rho(skeleton, px, py, pz);
554
+ const maturity = foliage_leaf_maturity(u_shoot, rho_shell, c_jit);
555
+ const variant = foliage_leaf_variant(maturity, variant_count);
556
+ const sun_exp = foliage_sun_exposure(rho_shell, h_norm_card);
557
+
558
+ // abscission: on its tile's schedule, past its threshold the leaf has fallen
559
+ const onset = foliage_variant_abscission_onset(foliage_variant_maturity(variant, variant_count));
560
+ const threshold = foliage_abscission_threshold(onset, sun_exp, u_shoot);
561
+ if (senescence >= threshold) {
562
+ continue;
563
+ }
564
+ dryness[cursor] = foliage_leaf_dryness(senescence, onset, threshold);
565
+
566
+ // Continuous ontogenetic & crown-shell photoprotective tint, free to brighten as well as darken
567
+ const c_tint = c_jit * color_var_amp;
568
+ const juv_lift = (0.5 - maturity) * juv_shift * 0.14;
569
+ let r_col = Math.max(0.68, 1.0 + c_tint * 1.1 + juv_lift * 0.9);
570
+ let g_col = Math.max(0.68, 1.0 + c_tint * 0.8 + juv_lift * 1.1);
571
+ let b_col = Math.max(0.68, 1.0 - c_tint * 0.6 - juv_lift * 0.5);
572
+ if (senescence > 1e-4) {
573
+ // Sun-exposed outer crown shell expresses stronger anthocyanin/carotenoid warmth than shaded interior
574
+ const shade_cool = (1.0 - sun_exp) * senescence * 0.22;
575
+ const sun_antho = sun_exp * senescence * antho_pot * 0.25;
576
+ r_col = Math.max(0.65, r_col * (1.0 - shade_cool * 0.45 + sun_antho * 0.18));
577
+ g_col = Math.max(0.55, g_col * (1.0 + shade_cool * 0.15 - sun_antho * 0.35));
578
+ b_col = Math.max(0.55, b_col * (1.0 - sun_antho * 0.30));
579
+ }
580
+ tints[c3] = r_col;
581
+ tints[c3 + 1] = g_col;
582
+ tints[c3 + 2] = b_col;
583
+ tint_scale = Math.max(tint_scale, r_col, g_col, b_col);
584
+
585
+ maturities[cursor] = maturity;
586
+ sun_exposure[cursor] = sun_exp;
587
+ variant_indices[cursor] = variant;
588
+
589
+ cursor++;
590
+ }
591
+ }
592
+
593
+ // shed leaves leave the arrays longer than the cards that remain: views of what remains
594
+ const n = cursor;
595
+ transforms.length = n;
596
+ const out_ranks = ranks.subarray(0, n);
597
+ const out_phases = phases.subarray(0, n);
598
+ const out_branch_sway = branch_sway.subarray(0, n);
599
+ const out_color_jitter = color_jitter.subarray(0, n);
600
+ const out_maturities = maturities.subarray(0, n);
601
+ const out_variant_indices = variant_indices.subarray(0, n);
602
+ const out_joints = joints.subarray(0, n * 2);
603
+ const out_weights = weights.subarray(0, n * 2);
604
+
605
+ return {
606
+ count: n,
607
+ carriers: carriers.subarray(0, n),
608
+ transforms,
609
+ positions: positions.subarray(0, n * 3),
610
+ forward: forward.subarray(0, n * 3),
611
+ up: up.subarray(0, n * 3),
612
+ right: right.subarray(0, n * 3),
613
+ scales: scales.subarray(0, n),
614
+ ranks: out_ranks,
615
+ phases: out_phases,
616
+ branch_sway: out_branch_sway,
617
+ color_jitter: out_color_jitter,
618
+ maturities: out_maturities,
619
+ sun_exposure: sun_exposure.subarray(0, n),
620
+ variant_indices: out_variant_indices,
621
+ dryness: dryness.subarray(0, n),
622
+ tints: tints.subarray(0, n * 3),
623
+ tint_scale,
624
+ joints: out_joints,
625
+ weights: out_weights,
626
+ joints4: joints4.subarray(0, n * 4),
627
+ weights4: weights4.subarray(0, n * 4),
628
+ attr_ranks: Attribute.from(out_ranks, 1, "foliage_ranks"),
629
+ attr_phases: Attribute.from(out_phases, 1, "foliage_phases"),
630
+ attr_branch_sway: Attribute.from(out_branch_sway, 1, "foliage_branch_sway"),
631
+ attr_color_jitter: Attribute.from(out_color_jitter, 1, "foliage_color_jitter"),
632
+ attr_maturities: Attribute.from(out_maturities, 1, "foliage_maturities"),
633
+ attr_variant_indices: Attribute.from(out_variant_indices, 1, "foliage_variant_indices"),
634
+ attr_joints: Attribute.from(out_joints, 2, "foliage_joints"),
635
+ attr_weights: Attribute.from(out_weights, 2, "foliage_weights")
636
+ };
637
+ }