@woosh/meep-engine 3.55.0 → 3.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (650) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/DUPLICATION_REVIEW_2026_10_24.md +1072 -0
  4. package/src/core/binary/BitSet.js +1 -1
  5. package/src/core/binary/FLOAT16_MAX.d.ts +2 -0
  6. package/src/core/binary/FLOAT16_MAX.d.ts.map +1 -0
  7. package/src/core/binary/FLOAT16_MAX.js +1 -0
  8. package/src/core/binary/base58/base58_encode.js +2 -2
  9. package/src/core/binary/type/TypeBuilder.js +1 -1
  10. package/src/core/bvh2/bvh3/BVH.js +1 -1
  11. package/src/core/bvh2/bvh3/ebvh_optimize_treelet.d.ts.map +1 -1
  12. package/src/core/bvh2/bvh3/ebvh_optimize_treelet.js +7 -3
  13. package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.d.ts.map +1 -1
  14. package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.js +5 -1
  15. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.d.ts.map +1 -1
  16. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.js +195 -246
  17. package/src/core/collection/CuckooFilter.js +1 -1
  18. package/src/core/collection/array/isArrayEqual.d.ts.map +1 -1
  19. package/src/core/collection/array/isArrayEqual.js +33 -58
  20. package/src/core/collection/array/typed/array_buffer_hash.d.ts.map +1 -1
  21. package/src/core/collection/array/typed/array_buffer_hash.js +41 -39
  22. package/src/core/collection/array/typed/float32_array_hash.js +38 -38
  23. package/src/core/collection/array/typed/uint16_array_hash.d.ts +2 -1
  24. package/src/core/collection/array/typed/uint16_array_hash.d.ts.map +1 -1
  25. package/src/core/collection/array/typed/uint16_array_hash.js +30 -29
  26. package/src/core/collection/array/typed/uint32_array_hash.d.ts +2 -1
  27. package/src/core/collection/array/typed/uint32_array_hash.d.ts.map +1 -1
  28. package/src/core/collection/array/typed/uint32_array_hash.js +21 -20
  29. package/src/core/collection/array/typed/uint8_array_hash.d.ts +2 -1
  30. package/src/core/collection/array/typed/uint8_array_hash.d.ts.map +1 -1
  31. package/src/core/collection/array/typed/uint8_array_hash.js +37 -36
  32. package/src/core/collection/array/typed/uint_array_for_count.js +2 -2
  33. package/src/core/collection/list/List.d.ts.map +1 -1
  34. package/src/core/collection/list/List.js +3 -19
  35. package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
  36. package/src/core/collection/table/RowFirstTable.js +4 -28
  37. package/src/core/debug/matchers/DescribeAs.d.ts.map +1 -1
  38. package/src/core/debug/matchers/DescribeAs.js +62 -64
  39. package/src/core/function/FunctionCompiler.js +4 -4
  40. package/src/core/function/objectsEqual.d.ts.map +1 -1
  41. package/src/core/function/objectsEqual.js +3 -2
  42. package/src/core/geom/2d/bvh/BVH2D.d.ts.map +1 -1
  43. package/src/core/geom/2d/bvh/BVH2D.js +4 -3
  44. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts +5 -2
  45. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts.map +1 -1
  46. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js +49 -11
  47. package/src/core/geom/2d/hash-grid/shg_query_elements_circle.d.ts.map +1 -1
  48. package/src/core/geom/2d/hash-grid/shg_query_elements_circle.js +122 -159
  49. package/src/core/geom/2d/hash-grid/shg_query_elements_line.d.ts.map +1 -1
  50. package/src/core/geom/2d/hash-grid/shg_query_elements_line.js +8 -5
  51. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts +18 -0
  52. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts.map +1 -0
  53. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.js +97 -0
  54. package/src/core/geom/2d/r-tree/StaticR2Tree.js +2 -2
  55. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts +21 -0
  56. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts.map +1 -0
  57. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.js +54 -0
  58. package/src/core/geom/3d/aabb/aabb3_build_frustum.d.ts.map +1 -1
  59. package/src/core/geom/3d/aabb/aabb3_build_frustum.js +20 -53
  60. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts +1 -1
  61. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts.map +1 -1
  62. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.js +11 -42
  63. package/src/core/geom/3d/atlas/pack/atlas_pack_charts.d.ts.map +1 -1
  64. package/src/core/geom/3d/atlas/pack/atlas_pack_charts.js +30 -32
  65. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.d.ts.map +1 -1
  66. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.js +1 -5
  67. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.d.ts.map +1 -1
  68. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.js +1 -15
  69. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts.map +1 -1
  70. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.js +105 -116
  71. package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.d.ts.map +1 -1
  72. package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.js +36 -54
  73. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts +5 -10
  74. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts.map +1 -1
  75. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.js +20 -82
  76. package/src/core/geom/3d/plane/plane3_slerp.d.ts.map +1 -1
  77. package/src/core/geom/3d/plane/plane3_slerp.js +87 -102
  78. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts +12 -0
  79. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts.map +1 -1
  80. package/src/core/geom/3d/polygon/polygon3_compute_normal.js +107 -60
  81. package/src/core/geom/3d/ray/ray3_compute_closest_point.d.ts.map +1 -1
  82. package/src/core/geom/3d/ray/ray3_compute_closest_point.js +37 -43
  83. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
  84. package/src/core/geom/3d/shape/ConvexHullShape3D.js +5 -16
  85. package/src/core/geom/3d/shape/MeshShape3D.js +2 -56
  86. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  87. package/src/core/geom/3d/shape/TransformedShape3D.js +10 -7
  88. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  89. package/src/core/geom/3d/shape/UnionShape3D.js +9 -3
  90. package/src/core/geom/3d/shape/json/shape_to_type.js +2 -2
  91. package/src/core/geom/3d/sphere/harmonics/SH3_COEFFICIENTS.js +17 -17
  92. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.d.ts.map +1 -1
  93. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.js +6 -2
  94. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts.map +1 -1
  95. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js +3 -2
  96. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts +20 -2
  97. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts.map +1 -1
  98. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +52 -37
  99. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts.map +1 -1
  100. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js +40 -56
  101. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
  102. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +251 -260
  103. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.d.ts.map +1 -1
  104. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.js +104 -113
  105. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.d.ts.map +1 -1
  106. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.js +227 -238
  107. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  108. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +15 -24
  109. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.d.ts.map +1 -1
  110. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.js +31 -115
  111. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.d.ts.map +1 -1
  112. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.js +142 -150
  113. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
  114. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +151 -194
  115. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.d.ts.map +1 -1
  116. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.js +60 -85
  117. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.d.ts.map +1 -1
  118. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.js +156 -171
  119. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.d.ts.map +1 -1
  120. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.js +8 -44
  121. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
  122. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +2 -7
  123. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts.map +1 -1
  124. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.js +3 -2
  125. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.d.ts.map +1 -1
  126. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.js +128 -133
  127. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts +8 -14
  128. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts.map +1 -1
  129. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.js +36 -82
  130. package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts.map +1 -1
  131. package/src/core/geom/3d/triangle/tri3_ray_intersection.js +7 -144
  132. package/src/core/geom/ConicRay.d.ts.map +1 -1
  133. package/src/core/geom/ConicRay.js +230 -237
  134. package/src/core/localization/LocaleDataset.d.ts +6 -0
  135. package/src/core/localization/LocaleDataset.d.ts.map +1 -1
  136. package/src/core/localization/LocaleDataset.js +48 -37
  137. package/src/core/localization/LocalizationEngine.d.ts.map +1 -1
  138. package/src/core/localization/LocalizationEngine.js +3 -2
  139. package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
  140. package/src/core/math/lookup/ParameterLookupTable.js +3 -1
  141. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts.map +1 -1
  142. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.js +330 -400
  143. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts +16 -0
  144. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts.map +1 -1
  145. package/src/core/math/spline/spline3_hermite_nearest_point.js +134 -167
  146. package/src/core/model/DebouncedObservedBoolean.d.ts +1 -2
  147. package/src/core/model/DebouncedObservedBoolean.d.ts.map +1 -1
  148. package/src/core/model/DebouncedObservedBoolean.js +1 -1
  149. package/src/core/model/node-graph/node/NodeInstance.d.ts.map +1 -1
  150. package/src/core/model/node-graph/node/NodeInstance.js +2 -7
  151. package/src/core/model/node-graph/node/parameter/NodeParameterDescription.js +1 -1
  152. package/src/core/model/object/optional_equality.d.ts +3 -3
  153. package/src/core/model/object/optional_equality.d.ts.map +1 -1
  154. package/src/core/model/object/optional_equality.js +10 -27
  155. package/src/core/model/object/write_property.js +1 -1
  156. package/src/core/model/reactive/evaluation/MultiPredicateEvaluator.js +2 -2
  157. package/src/core/primitives/strings/string_compute_byte_size.d.ts +3 -3
  158. package/src/core/primitives/strings/string_compute_byte_size.d.ts.map +1 -1
  159. package/src/core/primitives/strings/string_compute_byte_size.js +8 -21
  160. package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
  161. package/src/core/process/executor/ConcurrentExecutor.js +14 -2
  162. package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts +6 -3
  163. package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts.map +1 -1
  164. package/src/engine/achievements/gateway/StorageAchievementGateway.js +31 -75
  165. package/src/engine/asset/loaders/SVGAssetLoader.d.ts.map +1 -1
  166. package/src/engine/asset/loaders/SVGAssetLoader.js +33 -31
  167. package/src/engine/control/first-person/math/criticallyDampedSpring.d.ts.map +1 -1
  168. package/src/engine/control/first-person/math/criticallyDampedSpring.js +3 -14
  169. package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
  170. package/src/engine/ecs/EntityComponentDataset.js +4 -1
  171. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts +0 -2
  172. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts.map +1 -1
  173. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.js +3 -3
  174. package/src/engine/ecs/terrain/ecs/layers/TerrainLayer.js +2 -2
  175. package/src/engine/ecs/transform/Transform64.d.ts +21 -0
  176. package/src/engine/ecs/transform/Transform64.d.ts.map +1 -1
  177. package/src/engine/ecs/transform/Transform64.js +26 -0
  178. package/src/engine/graphics/sh3/path_tracer/geometry/sort_triangles_by_distance_to_point.js +1 -1
  179. package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.js +1 -1
  180. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  181. package/src/engine/graphics3/WaterSystem.js +2 -1
  182. package/src/engine/graphics3/prefab/prefab_skin_frame.d.ts.map +1 -1
  183. package/src/engine/graphics3/prefab/prefab_skin_frame.js +1 -12
  184. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts +1 -1
  185. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
  186. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +141 -137
  187. package/src/engine/input/ecs/systems/InputControllerSystem.d.ts.map +1 -1
  188. package/src/engine/input/ecs/systems/InputControllerSystem.js +13 -3
  189. package/src/engine/input/ecs/systems/InputSystem.d.ts.map +1 -1
  190. package/src/engine/input/ecs/systems/InputSystem.js +2 -1
  191. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts +1 -1
  192. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts.map +1 -1
  193. package/src/engine/intelligence/behavior/composite/ParallelBehavior.js +4 -1
  194. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.d.ts.map +1 -1
  195. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.js +3 -1
  196. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.d.ts.map +1 -1
  197. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.js +3 -1
  198. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.d.ts.map +1 -1
  199. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.js +39 -33
  200. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts +5 -0
  201. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts.map +1 -1
  202. package/src/engine/intelligence/behavior/util/ConditionalBehavior.js +93 -75
  203. package/src/engine/intelligence/behavior/util/RotationBehavior.d.ts.map +1 -1
  204. package/src/engine/intelligence/behavior/util/RotationBehavior.js +79 -76
  205. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts +1 -0
  206. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts.map +1 -1
  207. package/src/engine/intelligence/blackboard/BlackboardStack.js +159 -123
  208. package/src/engine/intelligence/mcts/StateNode.d.ts.map +1 -1
  209. package/src/engine/intelligence/mcts/StateNode.js +366 -364
  210. package/src/engine/intelligence/resource/ResourceAllocationSolver.js +1 -1
  211. package/src/engine/navigation/ecs/components/Path.d.ts.map +1 -1
  212. package/src/engine/navigation/ecs/components/Path.js +2 -1
  213. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
  214. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +5 -2
  215. package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
  216. package/src/engine/physics/body/SolverBodyState.js +2 -6
  217. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  218. package/src/engine/physics/ccd/linear_sweep.js +3 -16
  219. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  220. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +2 -16
  221. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +13 -1
  222. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  223. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +15 -4
  224. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  225. package/src/engine/physics/ecs/PhysicsSystem.js +2 -5
  226. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts +12 -0
  227. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts.map +1 -0
  228. package/src/engine/physics/inertia/locked_inverse_inertia.js +22 -0
  229. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
  230. package/src/engine/physics/integration/integrate_velocity.js +3 -18
  231. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts +1 -0
  232. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
  233. package/src/engine/physics/mls-mpm/MLS_MPM.js +5 -4
  234. package/src/engine/physics/narrowphase/convex_decomposition.d.ts.map +1 -1
  235. package/src/engine/physics/narrowphase/convex_decomposition.js +7 -16
  236. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  237. package/src/engine/physics/vehicle/RaycastVehicle.js +15 -5
  238. package/src/engine/save/StorageBackedList.d.ts +5 -0
  239. package/src/engine/save/StorageBackedList.d.ts.map +1 -1
  240. package/src/engine/save/StorageBackedList.js +161 -144
  241. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  242. package/src/engine/simulation/Ticker.js +394 -391
  243. package/src/engine/sound/simulation/probe/AcousticProbeField.d.ts.map +1 -1
  244. package/src/engine/sound/simulation/probe/AcousticProbeField.js +6 -19
  245. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts +15 -0
  246. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts.map +1 -1
  247. package/src/engine/sound/simulation/probe/probe_edge_visible.js +59 -41
  248. package/src/engine/sound/simulation/probe/probe_refine_connectivity.d.ts.map +1 -1
  249. package/src/engine/sound/simulation/probe/probe_refine_connectivity.js +164 -181
  250. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts.map +1 -1
  251. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +20 -5
  252. package/src/format/image/avif/av1/decode/Av1FrameContext.d.ts.map +1 -1
  253. package/src/format/image/avif/av1/decode/Av1FrameContext.js +3 -10
  254. package/src/format/image/avif/av1/decode/reconstruct.d.ts +20 -0
  255. package/src/format/image/avif/av1/decode/reconstruct.d.ts.map +1 -1
  256. package/src/format/image/avif/av1/decode/reconstruct.js +22 -9
  257. package/src/format/image/avif/av1/encode/choose_restoration.js +2 -18
  258. package/src/format/image/avif/av1/encode/quantise.d.ts.map +1 -1
  259. package/src/format/image/avif/av1/encode/quantise.js +1 -55
  260. package/src/format/image/avif/av1/filter/loop_restoration.d.ts +9 -0
  261. package/src/format/image/avif/av1/filter/loop_restoration.d.ts.map +1 -1
  262. package/src/format/image/avif/av1/filter/loop_restoration.js +1 -1
  263. package/src/format/texture/basis/transcode/etc1s_to_bc7.js +2 -33
  264. package/src/format/texture/basis/transcode/fit_endpoints.d.ts +11 -0
  265. package/src/format/texture/basis/transcode/fit_endpoints.d.ts.map +1 -1
  266. package/src/format/texture/basis/transcode/fit_endpoints.js +1 -1
  267. package/src/format/texture/basis/uastc/uastc_decode_block.d.ts.map +1 -1
  268. package/src/format/texture/basis/uastc/uastc_decode_block.js +2 -19
  269. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +220 -0
  270. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +172 -0
  271. package/src/generation/foliage/FOLIAGE_DESIGN.md +165 -15
  272. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +158 -0
  273. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +248 -0
  274. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +694 -0
  275. package/src/generation/foliage/analysis/CrownOpacity.d.ts +118 -0
  276. package/src/generation/foliage/analysis/CrownOpacity.d.ts.map +1 -0
  277. package/src/generation/foliage/analysis/CrownOpacity.js +182 -0
  278. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts +10 -0
  279. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts.map +1 -0
  280. package/src/generation/foliage/analysis/crown_opacity_frames.js +132 -0
  281. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts +51 -0
  282. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts.map +1 -0
  283. package/src/generation/foliage/analysis/crown_opacity_measure.js +649 -0
  284. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts +66 -0
  285. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts.map +1 -0
  286. package/src/generation/foliage/analysis/foliage_measure_leaf_area.js +192 -0
  287. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts +27 -0
  288. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts.map +1 -0
  289. package/src/generation/foliage/analysis/tree_crown_opacity.js +58 -0
  290. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts +3 -2
  291. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts.map +1 -1
  292. package/src/generation/foliage/animation/build_tree_wind_rig.js +12 -30
  293. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts +12 -0
  294. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts.map +1 -0
  295. package/src/generation/foliage/animation/tree_wind_bend_limit.js +13 -0
  296. package/src/generation/foliage/asset/TreeAsset.d.ts +5 -0
  297. package/src/generation/foliage/asset/TreeAsset.d.ts.map +1 -1
  298. package/src/generation/foliage/asset/TreeAsset.js +6 -0
  299. package/src/generation/foliage/asset/generate_tree.d.ts.map +1 -1
  300. package/src/generation/foliage/asset/generate_tree.js +23 -6
  301. package/src/generation/foliage/config/{BranchLevelConfig.d.ts → BranchGeneratorConfig.d.ts} +61 -75
  302. package/src/generation/foliage/config/BranchGeneratorConfig.d.ts.map +1 -0
  303. package/src/generation/foliage/config/{BranchLevelConfig.js → BranchGeneratorConfig.js} +83 -126
  304. package/src/generation/foliage/config/BranchSpawnRule.d.ts +118 -0
  305. package/src/generation/foliage/config/BranchSpawnRule.d.ts.map +1 -0
  306. package/src/generation/foliage/config/BranchSpawnRule.js +217 -0
  307. package/src/generation/foliage/config/FoliageCardType.d.ts +1 -1
  308. package/src/generation/foliage/config/FoliageCardType.js +2 -2
  309. package/src/generation/foliage/config/FoliageConfig.d.ts +23 -45
  310. package/src/generation/foliage/config/FoliageConfig.d.ts.map +1 -1
  311. package/src/generation/foliage/config/FoliageConfig.js +47 -93
  312. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts +12 -20
  313. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts.map +1 -1
  314. package/src/generation/foliage/config/FoliageMaterialConfig.js +261 -279
  315. package/src/generation/foliage/config/FoliageSpawnRule.d.ts +77 -0
  316. package/src/generation/foliage/config/FoliageSpawnRule.d.ts.map +1 -0
  317. package/src/generation/foliage/config/FoliageSpawnRule.js +135 -0
  318. package/src/generation/foliage/config/FoliageTileContent.d.ts +9 -0
  319. package/src/generation/foliage/config/FoliageTileContent.d.ts.map +1 -0
  320. package/src/generation/foliage/config/FoliageTileContent.js +12 -0
  321. package/src/generation/foliage/config/LeafApexShape.d.ts +12 -0
  322. package/src/generation/foliage/config/LeafApexShape.d.ts.map +1 -0
  323. package/src/generation/foliage/config/LeafApexShape.js +17 -0
  324. package/src/generation/foliage/config/LeafArchitecture.d.ts +155 -0
  325. package/src/generation/foliage/config/LeafArchitecture.d.ts.map +1 -0
  326. package/src/generation/foliage/config/LeafArchitecture.js +288 -0
  327. package/src/generation/foliage/config/LeafBaseShape.d.ts +14 -0
  328. package/src/generation/foliage/config/LeafBaseShape.d.ts.map +1 -0
  329. package/src/generation/foliage/config/LeafBaseShape.js +21 -0
  330. package/src/generation/foliage/config/LeafLobation.d.ts +10 -0
  331. package/src/generation/foliage/config/LeafLobation.d.ts.map +1 -0
  332. package/src/generation/foliage/config/LeafLobation.js +14 -0
  333. package/src/generation/foliage/config/PhyllotaxisMode.d.ts +11 -0
  334. package/src/generation/foliage/config/PhyllotaxisMode.d.ts.map +1 -1
  335. package/src/generation/foliage/config/PhyllotaxisMode.js +36 -0
  336. package/src/generation/foliage/config/ShootBudZone.d.ts +105 -0
  337. package/src/generation/foliage/config/ShootBudZone.d.ts.map +1 -0
  338. package/src/generation/foliage/config/ShootBudZone.js +219 -0
  339. package/src/generation/foliage/config/ShootGrowthConfig.d.ts +84 -0
  340. package/src/generation/foliage/config/ShootGrowthConfig.d.ts.map +1 -0
  341. package/src/generation/foliage/config/ShootGrowthConfig.js +146 -0
  342. package/src/generation/foliage/config/ShootSystemRule.d.ts +144 -0
  343. package/src/generation/foliage/config/ShootSystemRule.d.ts.map +1 -0
  344. package/src/generation/foliage/config/ShootSystemRule.js +316 -0
  345. package/src/generation/foliage/config/TreeLODConfig.d.ts +1 -1
  346. package/src/generation/foliage/config/TreeLODConfig.js +1 -1
  347. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts +40 -8
  348. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts.map +1 -1
  349. package/src/generation/foliage/config/TreeSpeciesConfig.js +124 -68
  350. package/src/generation/foliage/config/TreeWindConfig.d.ts +23 -10
  351. package/src/generation/foliage/config/TreeWindConfig.d.ts.map +1 -1
  352. package/src/generation/foliage/config/TreeWindConfig.js +34 -25
  353. package/src/generation/foliage/index.d.ts +19 -2
  354. package/src/generation/foliage/index.js +63 -44
  355. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts +59 -0
  356. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts.map +1 -0
  357. package/src/generation/foliage/material/FoliageAtlasCutout.js +93 -0
  358. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts +26 -0
  359. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts.map +1 -0
  360. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.js +63 -0
  361. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts +34 -0
  362. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts.map +1 -0
  363. package/src/generation/foliage/material/foliage_atlas_cutout.js +174 -0
  364. package/src/generation/foliage/material/foliage_tile.d.ts +110 -0
  365. package/src/generation/foliage/material/foliage_tile.d.ts.map +1 -0
  366. package/src/generation/foliage/material/foliage_tile.js +286 -0
  367. package/src/generation/foliage/material/leaf_geometry.d.ts +103 -0
  368. package/src/generation/foliage/material/leaf_geometry.d.ts.map +1 -0
  369. package/src/generation/foliage/material/leaf_geometry.js +528 -0
  370. package/src/generation/foliage/material/make_foliage_material.d.ts +13 -33
  371. package/src/generation/foliage/material/make_foliage_material.d.ts.map +1 -1
  372. package/src/generation/foliage/material/make_foliage_material.js +356 -605
  373. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts +39 -4
  374. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts.map +1 -1
  375. package/src/generation/foliage/mesh/foliage_collect_attachments.js +637 -569
  376. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts +48 -0
  377. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts.map +1 -0
  378. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.js +232 -0
  379. package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
  380. package/src/generation/foliage/mesh/tree_mesh_build_bark.js +1023 -1049
  381. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts +9 -2
  382. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts.map +1 -1
  383. package/src/generation/foliage/mesh/tree_mesh_build_foliage.js +467 -454
  384. package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
  385. package/src/generation/foliage/presets/make_tree_species_preset.js +1648 -870
  386. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts +35 -0
  387. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts.map +1 -0
  388. package/src/generation/foliage/skeleton/ShootFrameworkHash.js +129 -0
  389. package/src/generation/foliage/skeleton/ShootGirth.d.ts +51 -0
  390. package/src/generation/foliage/skeleton/ShootGirth.d.ts.map +1 -0
  391. package/src/generation/foliage/skeleton/ShootGirth.js +212 -0
  392. package/src/generation/foliage/skeleton/ShootLightField.d.ts +73 -0
  393. package/src/generation/foliage/skeleton/ShootLightField.d.ts.map +1 -0
  394. package/src/generation/foliage/skeleton/ShootLightField.js +197 -0
  395. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts +106 -3
  396. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts.map +1 -1
  397. package/src/generation/foliage/skeleton/TreeSkeleton.js +217 -39
  398. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts +13 -0
  399. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts.map +1 -0
  400. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.js +16 -0
  401. package/src/generation/foliage/skeleton/foliage_card_density.d.ts +71 -0
  402. package/src/generation/foliage/skeleton/foliage_card_density.d.ts.map +1 -0
  403. package/src/generation/foliage/skeleton/foliage_card_density.js +101 -0
  404. package/src/generation/foliage/skeleton/foliage_senescence.d.ts +101 -0
  405. package/src/generation/foliage/skeleton/foliage_senescence.d.ts.map +1 -0
  406. package/src/generation/foliage/skeleton/foliage_senescence.js +149 -0
  407. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts +76 -0
  408. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts.map +1 -0
  409. package/src/generation/foliage/skeleton/foliage_unit_cards.js +95 -0
  410. package/src/generation/foliage/skeleton/shoot_demography.d.ts +22 -0
  411. package/src/generation/foliage/skeleton/shoot_demography.d.ts.map +1 -0
  412. package/src/generation/foliage/skeleton/shoot_demography.js +96 -0
  413. package/src/generation/foliage/skeleton/shoot_geometry.d.ts +66 -0
  414. package/src/generation/foliage/skeleton/shoot_geometry.d.ts.map +1 -0
  415. package/src/generation/foliage/skeleton/shoot_geometry.js +109 -0
  416. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts +166 -0
  417. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts.map +1 -0
  418. package/src/generation/foliage/skeleton/shoot_systems_simulate.js +588 -0
  419. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts +28 -12
  420. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts.map +1 -1
  421. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.js +137 -102
  422. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts +112 -0
  423. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts.map +1 -0
  424. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js +408 -0
  425. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts.map +1 -1
  426. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js +208 -206
  427. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts +5 -2
  428. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
  429. package/src/generation/foliage/skeleton/tree_skeleton_grow.js +2048 -1871
  430. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts +17 -0
  431. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts.map +1 -0
  432. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.js +231 -0
  433. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts +14 -0
  434. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts.map +1 -0
  435. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.js +26 -0
  436. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts +10 -0
  437. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts.map +1 -0
  438. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.js +20 -0
  439. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts.map +1 -1
  440. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +4 -1
  441. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts +1 -0
  442. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts.map +1 -1
  443. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +98 -86
  444. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +263 -0
  445. package/src/shade/descriptor/WebGPUExtensionType.d.ts +17 -0
  446. package/src/shade/descriptor/WebGPUExtensionType.d.ts.map +1 -1
  447. package/src/shade/descriptor/WebGPUExtensionType.js +31 -1
  448. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts +37 -0
  449. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts.map +1 -0
  450. package/src/shade/playground/foliage_wind/FoliageRigOverlay.js +491 -0
  451. package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -1
  452. package/src/shade/playground/foliage_wind/foliage_world.js +600 -602
  453. package/src/shade/playground/foliage_wind/index.html +6 -0
  454. package/src/shade/playground/foliage_wind/main.js +14 -0
  455. package/src/shade/renderer/Renderer.d.ts +5 -0
  456. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  457. package/src/shade/renderer/Renderer.js +25 -2
  458. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  459. package/src/shade/renderer/animation/GPUAnimationManager.js +2 -1
  460. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts +2 -1
  461. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts.map +1 -1
  462. package/src/shade/renderer/animation/foliage/FoliageWindJoint.js +2 -1
  463. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.d.ts.map +1 -1
  464. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.js +4 -2
  465. package/src/shade/renderer/buffer/table/GPUTypedTable.js +1 -1
  466. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
  467. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +403 -401
  468. package/src/shade/renderer/camera/OrbitalCameraController.d.ts +1 -62
  469. package/src/shade/renderer/camera/OrbitalCameraController.d.ts.map +1 -1
  470. package/src/shade/renderer/camera/OrbitalCameraController.js +1 -374
  471. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.d.ts.map +1 -1
  472. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.js +3 -0
  473. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.d.ts.map +1 -1
  474. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.js +6 -1
  475. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +1 -1
  476. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +2 -2
  477. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts.map +1 -1
  478. package/src/shade/renderer/fluid/GPUFluidCascade.js +6 -3
  479. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +361 -0
  480. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.d.ts.map +1 -1
  481. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js +335 -241
  482. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.d.ts.map +1 -1
  483. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js +108 -101
  484. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.d.ts.map +1 -1
  485. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.js +69 -67
  486. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts +7 -6
  487. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts.map +1 -1
  488. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js +341 -287
  489. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts +6 -4
  490. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts.map +1 -1
  491. package/src/shade/renderer/fluid/mac/FluidMacPasses.js +427 -400
  492. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts +10 -5
  493. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts.map +1 -1
  494. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.js +532 -190
  495. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.d.ts.map +1 -1
  496. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.js +231 -237
  497. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts +2 -2
  498. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts.map +1 -1
  499. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js +282 -245
  500. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts +1 -3
  501. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts.map +1 -1
  502. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.js +139 -109
  503. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts +6 -6
  504. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts.map +1 -1
  505. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.js +257 -222
  506. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts +8 -7
  507. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts.map +1 -1
  508. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.js +119 -92
  509. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts +6 -9
  510. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts.map +1 -1
  511. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.js +229 -181
  512. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +17 -7
  513. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts.map +1 -1
  514. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.js +634 -621
  515. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts +8 -6
  516. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts.map +1 -1
  517. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js +166 -149
  518. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts +8 -6
  519. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts.map +1 -1
  520. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js +219 -183
  521. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.d.ts.map +1 -1
  522. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.js +142 -122
  523. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +674 -663
  524. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +1 -1
  525. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  526. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +63 -29
  527. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  528. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +77 -87
  529. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.d.ts.map +1 -1
  530. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.js +4 -3
  531. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts +11 -11
  532. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts.map +1 -1
  533. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.js +17 -19
  534. package/src/shade/renderer/global_illumination/lpv/graph_bake_irradiance_lookup_2d.js +4 -4
  535. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.d.ts.map +1 -1
  536. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.js +5 -1
  537. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  538. package/src/shade/renderer/loader/gltf/load_gltf.js +11 -35
  539. package/src/shade/renderer/loader/usd/load_usd.d.ts.map +1 -1
  540. package/src/shade/renderer/loader/usd/load_usd.js +6 -19
  541. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +2 -1
  542. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  543. package/src/shade/renderer/particles/GPUParticleSystem.js +1 -1
  544. package/src/shade/renderer/particles/graph_particles_avboit.d.ts +2 -2
  545. package/src/shade/renderer/particles/graph_particles_avboit.d.ts.map +1 -1
  546. package/src/shade/renderer/particles/graph_particles_avboit.js +4 -9
  547. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
  548. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +199 -193
  549. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts.map +1 -1
  550. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.js +151 -143
  551. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.d.ts.map +1 -1
  552. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.js +11 -5
  553. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.d.ts.map +1 -1
  554. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.js +6 -18
  555. package/src/shade/renderer/postprocess/gtao/GTAO.js +1 -1
  556. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  557. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +3 -5
  558. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +1 -1
  559. package/src/shade/renderer/postprocess/nss/NSS.d.ts +1 -1
  560. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.d.ts.map +1 -1
  561. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.js +7 -3
  562. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
  563. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +4 -2
  564. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.d.ts.map +1 -1
  565. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +4 -1
  566. package/src/shade/renderer/postprocess/ssr/downsample_karis.d.ts.map +1 -1
  567. package/src/shade/renderer/postprocess/ssr/downsample_karis.js +6 -3
  568. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
  569. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +4 -3
  570. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.d.ts.map +1 -1
  571. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.js +4 -1
  572. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
  573. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +4 -2
  574. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts.map +1 -1
  575. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.js +35 -39
  576. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.d.ts.map +1 -1
  577. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.js +20 -17
  578. package/src/shade/renderer/postprocess/taa/shader_taa.d.ts.map +1 -1
  579. package/src/shade/renderer/postprocess/taa/shader_taa.js +6 -3
  580. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  581. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -1
  582. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +1 -1
  583. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js +2 -2
  584. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +1 -1
  585. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.d.ts.map +1 -1
  586. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.js +92 -83
  587. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +1 -1
  588. package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
  589. package/src/shade/renderer/shader/ShaderDescriptor.js +12 -4
  590. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.d.ts.map +1 -1
  591. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.js +294 -286
  592. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_interpolate_probe_irradiance8.js +5 -5
  593. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.d.ts.map +1 -1
  594. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.js +5 -3
  595. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.d.ts.map +1 -1
  596. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.js +9 -6
  597. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.d.ts.map +1 -1
  598. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.js +33 -38
  599. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  600. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +690 -675
  601. package/src/shade/renderer/shader/type/WebGPUArray.d.ts +3 -0
  602. package/src/shade/renderer/shader/type/WebGPUArray.d.ts.map +1 -1
  603. package/src/shade/renderer/shader/type/WebGPUArray.js +185 -167
  604. package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
  605. package/src/shade/renderer/shader/type/WebGPUStruct.js +461 -455
  606. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.d.ts.map +1 -1
  607. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.js +335 -211
  608. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.d.ts.map +1 -1
  609. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.js +329 -221
  610. package/src/shade/renderer/shader/type/type_has_f16.d.ts +12 -0
  611. package/src/shade/renderer/shader/type/type_has_f16.d.ts.map +1 -0
  612. package/src/shade/renderer/shader/type/type_has_f16.js +66 -0
  613. package/src/shade/renderer/view/GPUViewContext.d.ts +0 -14
  614. package/src/shade/renderer/view/GPUViewContext.d.ts.map +1 -1
  615. package/src/shade/renderer/view/GPUViewContext.js +0 -29
  616. package/src/shade/renderer/view/ViewManager.d.ts +1 -1
  617. package/src/shade/renderer/view/ViewManager.js +1 -1
  618. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts +40 -3
  619. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  620. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +660 -583
  621. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  622. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +16 -2
  623. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts.map +1 -1
  624. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +5 -2
  625. package/src/shade/renderer/water/shader_water_avboit.js +1 -1
  626. package/src/shade/renderer/wind/GPUSceneWind.d.ts +1 -1
  627. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  628. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +260 -23
  629. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts +6 -7
  630. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  631. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +269 -69
  632. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  633. package/src/shade/wgsl/validate_wgsl_source.js +27 -1
  634. package/src/view/controller/controls/ListController.d.ts.map +1 -1
  635. package/src/view/controller/controls/ListController.js +118 -113
  636. package/src/view/controller/controls/Vector1Control.js +97 -97
  637. package/src/view/elements/image/SvgImageView.d.ts +1 -0
  638. package/src/view/elements/image/SvgImageView.d.ts.map +1 -1
  639. package/src/view/elements/image/SvgImageView.js +92 -90
  640. package/src/view/minimap/dom/MinimapTerrainView.d.ts +1 -0
  641. package/src/view/minimap/dom/MinimapTerrainView.d.ts.map +1 -1
  642. package/src/view/minimap/dom/MinimapTerrainView.js +151 -147
  643. package/src/view/tooltip/gml/TooltipParser.js +2 -2
  644. package/src/engine/network/PriorityFetch.d.ts +0 -59
  645. package/src/engine/network/PriorityFetch.d.ts.map +0 -1
  646. package/src/engine/network/PriorityFetch.js +0 -193
  647. package/src/generation/foliage/config/BranchLevelConfig.d.ts.map +0 -1
  648. package/src/shade/renderer/volumetrics/VOLUMETRICS_RESOLUTION_Z.d.ts +0 -2
  649. package/src/shade/renderer/volumetrics/VOLUMETRICS_RESOLUTION_Z.d.ts.map +0 -1
  650. package/src/shade/renderer/volumetrics/VOLUMETRICS_RESOLUTION_Z.js +0 -1
@@ -1,870 +1,1648 @@
1
- import { AnimationCurve } from "../../../engine/animation/curve/AnimationCurve.js";
2
- import { CrownEnvelopeType } from "../config/CrownEnvelopeType.js";
3
- import { FoliageBarkType } from "../config/FoliageBarkType.js";
4
- import { FoliageCardType } from "../config/FoliageCardType.js";
5
- import { PhyllotaxisMode } from "../config/PhyllotaxisMode.js";
6
- import { TreePreset } from "../config/TreePreset.js";
7
- import { TreeSpeciesConfig } from "../config/TreeSpeciesConfig.js";
8
-
9
- /**
10
- * Returns a rich, botanically tuned `TreeSpeciesConfig` for one of the 9 built-in
11
- * `TreePreset` archetypes (`Oak`, `Pine`, `Birch`, `Willow`, `Maple`, `Spruce`, `Palm`, `Shrub`, `Fern`),
12
- * with optional deep parameter overrides.
13
- *
14
- * @param {TreePreset|string} [preset=TreePreset.Oak]
15
- * @param {Object} [overrides]
16
- * @returns {TreeSpeciesConfig}
17
- */
18
- export function make_tree_species_preset(preset = TreePreset.Oak, overrides = {}) {
19
- const config = new TreeSpeciesConfig();
20
- const key = typeof preset === "string" ? preset.toLowerCase() : TreePreset.Oak;
21
-
22
- switch (key) {
23
- case TreePreset.Pine: {
24
- config.name = "pine";
25
- config.preset = TreePreset.Pine;
26
- config.crown.applyOverrides({
27
- envelope_type: CrownEnvelopeType.Conical,
28
- height: 8.6,
29
- radius: 4.2,
30
- base_height: 2.2,
31
- prune_ratio: 0.25,
32
- space_colonization_weight: 0.08,
33
- pipe_model_exponent: 2.4,
34
- pipe_model_weight: 0.55,
35
- sky_phototropism_mix: 0.35
36
- });
37
- config.levels = [
38
- {
39
- level: 0,
40
- segments: 12,
41
- radial_segments_max: 14,
42
- radial_segments_min: 8,
43
- length: 11.2,
44
- length_variance: 0.05,
45
- radius_ratio: 0.038,
46
- taper: 0.88,
47
- bare_length_ratio: 0.24,
48
- child_count: 32,
49
- phyllotaxis_mode: PhyllotaxisMode.Whorled,
50
- whorl_count: 4,
51
- azimuth_jitter: 0.16,
52
- insertion_angle: 1.34,
53
- insertion_angle_variation: 0.08,
54
- insertion_angle_profile: AnimationCurve.linear(0, 1.05, 1, 0.52),
55
- curvature: 0.16,
56
- curve_back: -0.10,
57
- spiral_twist: 0.22,
58
- gravitropism: -0.06,
59
- phototropism: 0.10,
60
- gnarl_strength: 0.09,
61
- gnarl_frequency: 0.32,
62
- basal_lean: 0.015,
63
- nodal_kink_strength: 0.18,
64
- internode_zigzag: 0.04,
65
- kink_sharpness: 0.48,
66
- bark_displacement: 0.08,
67
- parent_collar_bulge: 0.26,
68
- knot_count: 6,
69
- knot_strength: 0.16,
70
- split_probability: 0.0,
71
- flare_amplitude: 0.28,
72
- flare_height_ratio: 0.15,
73
- flare_lobes: 4,
74
- flare_sharpness: 3.0,
75
- flute_amplitude: 0.015,
76
- flute_frequency: 3,
77
- collar_weld_rings: 0
78
- },
79
- {
80
- level: 1,
81
- segments: 7,
82
- radial_segments_max: 7,
83
- radial_segments_min: 4,
84
- length: 3.8,
85
- length_variance: 0.10,
86
- length_profile: AnimationCurve.linear(0, 1.0, 1, 0.72),
87
- radius_ratio: 0.035,
88
- taper: 0.85,
89
- bare_length_ratio: 0.12,
90
- child_count: 7,
91
- phyllotaxis_mode: PhyllotaxisMode.AlternateDistichous,
92
- azimuth_jitter: 0.14,
93
- insertion_angle: 0.88,
94
- insertion_angle_variation: 0.10,
95
- curvature: 0.16,
96
- curve_back: -0.12,
97
- gravitropism: 0.22,
98
- phototropism: 0.16,
99
- gnarl_strength: 0.12,
100
- nodal_kink_strength: 0.42,
101
- internode_zigzag: 0.09,
102
- kink_sharpness: 0.55,
103
- tip_upcurl: 0.34,
104
- oval_eccentricity: 0.16,
105
- bark_displacement: 0.06,
106
- knot_count: 2,
107
- knot_strength: 0.12,
108
- collar_weld_rings: 2
109
- },
110
- {
111
- level: 2,
112
- segments: 5,
113
- radial_segments_max: 5,
114
- radial_segments_min: 3,
115
- length: 1.4,
116
- length_variance: 0.14,
117
- length_profile: AnimationCurve.linear(0, 0.95, 1, 0.48),
118
- radius_ratio: 0.032,
119
- taper: 0.85,
120
- bare_length_ratio: 0.08,
121
- child_count: 0,
122
- insertion_angle: 0.78,
123
- curvature: 0.14,
124
- gravitropism: 0.08,
125
- phototropism: 0.24,
126
- gnarl_strength: 0.12,
127
- internode_zigzag: 0.12,
128
- tip_upcurl: 0.32,
129
- collar_weld_rings: 1
130
- }
131
- ];
132
- config.applyOverrides({ levels: config.levels, replace_levels: true });
133
- config.foliage.applyOverrides({
134
- enabled: true,
135
- card_type: FoliageCardType.TriStarCluster,
136
- attach_min_level: 1,
137
- cards_per_branch: 8,
138
- terminal_rosette_count: 3,
139
- bare_ratio: 0.18,
140
- phyllotaxis_mode: PhyllotaxisMode.SpiralGolden,
141
- card_width: 0.82,
142
- card_length: 0.88,
143
- phototropism: 0.45,
144
- gravitropism: 0.12
145
- });
146
- config.bark_material.applyOverrides({
147
- bark_type: FoliageBarkType.Plated,
148
- primary_color: [0.39, 0.28, 0.21],
149
- secondary_color: [0.14, 0.11, 0.09],
150
- inner_bark_color: [0.46, 0.31, 0.21],
151
- fissure_frequency: 6,
152
- fissure_depth: 0.76,
153
- plate_terrace: 0.52,
154
- knot_amount: 0.45,
155
- roughness: 0.90
156
- });
157
- config.foliage_material.applyOverrides({
158
- primary_color: [0.13, 0.32, 0.14],
159
- secondary_color: [0.08, 0.22, 0.09],
160
- leaf_shape: "needle",
161
- leaflets_per_cluster: 9,
162
- roughness: 0.55,
163
- juvenile_color_shift: 0.46,
164
- juvenile_anthocyanin: 0.0,
165
- carotenoid_density: 0.35,
166
- anthocyanin_potential: 0.0,
167
- tannin_oxidation: 0.30
168
- });
169
- break;
170
- }
171
-
172
- case TreePreset.Birch: {
173
- config.name = "birch";
174
- config.preset = TreePreset.Birch;
175
- config.crown.applyOverrides({
176
- envelope_type: CrownEnvelopeType.Flame,
177
- height: 12.5,
178
- radius: 3.4,
179
- base_height: 2.5,
180
- prune_ratio: 0.3,
181
- space_colonization_weight: 0.25,
182
- pipe_model_exponent: 2.15,
183
- pipe_model_weight: 0.6
184
- });
185
- config.levels = [
186
- {
187
- level: 0,
188
- segments: 12,
189
- radial_segments_max: 14,
190
- radial_segments_min: 8,
191
- length: 11.5,
192
- length_variance: 0.08,
193
- radius_ratio: 0.032,
194
- taper: 0.86,
195
- bare_length_ratio: 0.24,
196
- child_count: 12,
197
- phyllotaxis_mode: PhyllotaxisMode.SpiralGolden,
198
- insertion_angle: 0.58,
199
- insertion_angle_variation: 0.14,
200
- curvature: 0.32,
201
- curve_back: -0.22,
202
- spiral_twist: 0.28,
203
- gravitropism: -0.06,
204
- phototropism: 0.20,
205
- gnarl_strength: 0.15,
206
- gnarl_frequency: 0.36,
207
- basal_lean: 0.04,
208
- nodal_kink_strength: 0.48,
209
- internode_zigzag: 0.07,
210
- kink_sharpness: 0.62,
211
- bark_displacement: 0.075,
212
- parent_collar_bulge: 0.30,
213
- knot_count: 6,
214
- knot_strength: 0.16,
215
- split_probability: 0.28,
216
- split_count: 2,
217
- split_angle: 0.38,
218
- flare_amplitude: 0.24,
219
- flare_height_ratio: 0.15,
220
- flare_lobes: 4,
221
- flute_amplitude: 0.010,
222
- flute_frequency: 3,
223
- collar_weld_rings: 0
224
- },
225
- {
226
- level: 1,
227
- segments: 8,
228
- radial_segments_max: 7,
229
- radial_segments_min: 4,
230
- length: 3.6,
231
- length_variance: 0.15,
232
- length_profile: AnimationCurve.linear(0, 0.85, 1, 0.45),
233
- radius_ratio: 0.034,
234
- taper: 0.86,
235
- bare_length_ratio: 0.15,
236
- child_count: 6,
237
- phyllotaxis_mode: PhyllotaxisMode.AlternateDistichous,
238
- insertion_angle: 0.58,
239
- curvature: 0.28,
240
- curve_back: -0.18,
241
- gravitropism: 0.22,
242
- phototropism: 0.24,
243
- gnarl_strength: 0.20,
244
- nodal_kink_strength: 0.72,
245
- internode_zigzag: 0.15,
246
- kink_sharpness: 0.65,
247
- tip_upcurl: 0.20,
248
- oval_eccentricity: 0.15,
249
- bark_displacement: 0.06,
250
- knot_count: 3,
251
- knot_strength: 0.14,
252
- collar_weld_rings: 2
253
- },
254
- {
255
- level: 2,
256
- segments: 6,
257
- radial_segments_max: 5,
258
- radial_segments_min: 3,
259
- length: 1.7,
260
- length_variance: 0.18,
261
- radius_ratio: 0.028,
262
- taper: 0.9,
263
- bare_length_ratio: 0.1,
264
- child_count: 0,
265
- phyllotaxis_mode: PhyllotaxisMode.AlternateDistichous,
266
- insertion_angle: 0.52,
267
- curvature: 0.32,
268
- gravitropism: 0.42,
269
- phototropism: 0.12,
270
- gnarl_strength: 0.18,
271
- internode_zigzag: 0.18,
272
- kink_sharpness: 0.58,
273
- tip_upcurl: 0.06,
274
- collar_weld_rings: 1
275
- }
276
- ];
277
- config.applyOverrides({ levels: config.levels, replace_levels: true });
278
- config.foliage.applyOverrides({
279
- enabled: true,
280
- card_type: FoliageCardType.FoldedVCard,
281
- attach_min_level: 1,
282
- cards_per_branch: 8,
283
- terminal_rosette_count: 3,
284
- card_width: 0.75,
285
- card_length: 0.85,
286
- fold_angle: 0.24,
287
- gravitropism: 0.35,
288
- phototropism: 0.55
289
- });
290
- config.bark_material.applyOverrides({
291
- bark_type: FoliageBarkType.Birch,
292
- primary_color: [0.85, 0.83, 0.80],
293
- secondary_color: [0.17, 0.16, 0.15],
294
- inner_bark_color: [0.52, 0.35, 0.23],
295
- moss_color: [0.24, 0.30, 0.19],
296
- moss_amount: 0.04,
297
- fissure_frequency: 4,
298
- fissure_depth: 0.62,
299
- lenticel_amount: 0.78,
300
- peel_amount: 0.35,
301
- knot_amount: 0.58,
302
- roughness: 0.88
303
- });
304
- config.foliage_material.applyOverrides({
305
- primary_color: [0.32, 0.52, 0.18],
306
- secondary_color: [0.22, 0.40, 0.12],
307
- leaf_shape: "serrated",
308
- leaflets_per_cluster: 5,
309
- roughness: 0.52,
310
- juvenile_color_shift: 0.42,
311
- juvenile_anthocyanin: 0.0,
312
- carotenoid_density: 0.94,
313
- anthocyanin_potential: 0.06,
314
- tannin_oxidation: 0.16
315
- });
316
- break;
317
- }
318
-
319
- case TreePreset.Willow: {
320
- config.name = "willow";
321
- config.preset = TreePreset.Willow;
322
- config.crown.applyOverrides({
323
- envelope_type: CrownEnvelopeType.Weeping,
324
- height: 11.0,
325
- radius: 5.5,
326
- base_height: 1.6,
327
- prune_ratio: 0.2,
328
- space_colonization_weight: 0.2,
329
- pipe_model_exponent: 2.25,
330
- pipe_model_weight: 0.65
331
- });
332
- config.levels = [
333
- {
334
- level: 0,
335
- segments: 11,
336
- radial_segments_max: 13,
337
- radial_segments_min: 7,
338
- length: 7.5,
339
- radius_ratio: 0.065,
340
- taper: 0.75,
341
- bare_length_ratio: 0.25,
342
- child_count: 9,
343
- insertion_angle: 0.68,
344
- curvature: 0.32,
345
- curve_back: -0.18,
346
- spiral_twist: 0.38,
347
- gravitropism: -0.05,
348
- phototropism: 0.15,
349
- gnarl_strength: 0.18,
350
- basal_lean: 0.05,
351
- nodal_kink_strength: 0.55,
352
- internode_zigzag: 0.08,
353
- kink_sharpness: 0.65,
354
- bark_displacement: 0.11,
355
- parent_collar_bulge: 0.35,
356
- knot_count: 6,
357
- knot_strength: 0.20,
358
- split_probability: 0.35,
359
- split_count: 2,
360
- split_angle: 0.52,
361
- flare_amplitude: 0.38,
362
- flare_lobes: 5,
363
- flute_amplitude: 0.055,
364
- flute_frequency: 5,
365
- collar_weld_rings: 0
366
- },
367
- {
368
- level: 1,
369
- segments: 8,
370
- radial_segments_max: 8,
371
- radial_segments_min: 4,
372
- length: 4.8,
373
- radius_ratio: 0.042,
374
- taper: 0.84,
375
- bare_length_ratio: 0.15,
376
- child_count: 9,
377
- insertion_angle: 0.65,
378
- curvature: 0.38,
379
- curve_back: -0.15,
380
- gravitropism: 0.32,
381
- phototropism: 0.22,
382
- gnarl_strength: 0.22,
383
- nodal_kink_strength: 0.72,
384
- internode_zigzag: 0.14,
385
- kink_sharpness: 0.60,
386
- tip_upcurl: 0.10,
387
- oval_eccentricity: 0.18,
388
- bark_displacement: 0.08,
389
- knot_count: 3,
390
- knot_strength: 0.15,
391
- collar_weld_rings: 2
392
- },
393
- {
394
- level: 2,
395
- segments: 8,
396
- radial_segments_max: 4,
397
- radial_segments_min: 3,
398
- length: 3.4,
399
- radius_ratio: 0.02,
400
- taper: 0.92,
401
- bare_length_ratio: 0.08,
402
- child_count: 0,
403
- insertion_angle: 0.55,
404
- curvature: 0.45,
405
- gravitropism: 0.88,
406
- phototropism: 0.04,
407
- gnarl_strength: 0.12,
408
- internode_zigzag: 0.09,
409
- kink_sharpness: 0.25,
410
- tip_upcurl: 0.0,
411
- collar_weld_rings: 1
412
- }
413
- ];
414
- config.applyOverrides({ levels: config.levels, replace_levels: true });
415
- config.foliage.applyOverrides({
416
- enabled: true,
417
- card_type: FoliageCardType.RibbedFrond,
418
- attach_min_level: 2,
419
- cards_per_branch: 9,
420
- terminal_rosette_count: 2,
421
- card_width: 0.55,
422
- card_length: 1.35,
423
- arch_height: 0.12,
424
- camber_droop: 0.28,
425
- frond_segments: 5,
426
- gravitropism: 0.72,
427
- phototropism: 0.25
428
- });
429
- config.bark_material.applyOverrides({
430
- bark_type: FoliageBarkType.Fissured,
431
- primary_color: [0.35, 0.32, 0.27],
432
- secondary_color: [0.15, 0.13, 0.11],
433
- inner_bark_color: [0.39, 0.32, 0.25],
434
- fissure_frequency: 8,
435
- fissure_depth: 0.76,
436
- roughness: 0.91
437
- });
438
- config.foliage_material.applyOverrides({
439
- primary_color: [0.34, 0.50, 0.20],
440
- secondary_color: [0.24, 0.38, 0.14],
441
- leaf_shape: "frond",
442
- leaflets_per_cluster: 9,
443
- juvenile_color_shift: 0.44,
444
- juvenile_anthocyanin: 0.0,
445
- carotenoid_density: 0.84,
446
- anthocyanin_potential: 0.04,
447
- tannin_oxidation: 0.22
448
- });
449
- break;
450
- }
451
-
452
- case TreePreset.Maple: {
453
- config.name = "maple";
454
- config.preset = TreePreset.Maple;
455
- config.crown.applyOverrides({
456
- envelope_type: CrownEnvelopeType.Spherical,
457
- height: 11.5,
458
- radius: 4.8,
459
- base_height: 2.2,
460
- prune_ratio: 0.35,
461
- space_colonization_weight: 0.3,
462
- pipe_model_exponent: 2.25,
463
- pipe_model_weight: 0.65
464
- });
465
- config.levels[0].applyOverrides({
466
- phyllotaxis_mode: PhyllotaxisMode.OppositeDecussate,
467
- child_count: 10,
468
- flare_amplitude: 0.3,
469
- flare_lobes: 5
470
- });
471
- config.levels[1].applyOverrides({
472
- phyllotaxis_mode: PhyllotaxisMode.OppositeDecussate,
473
- child_count: 8,
474
- insertion_angle: 0.68
475
- });
476
- config.levels[2].applyOverrides({
477
- phyllotaxis_mode: PhyllotaxisMode.OppositeDecussate
478
- });
479
- config.foliage.applyOverrides({
480
- enabled: true,
481
- card_type: FoliageCardType.OctagonalCutoutHull,
482
- attach_min_level: 1,
483
- cards_per_branch: 8,
484
- terminal_rosette_count: 3,
485
- phyllotaxis_mode: PhyllotaxisMode.OppositeDecussate,
486
- card_width: 0.9,
487
- card_length: 0.95,
488
- fold_angle: 0.25
489
- });
490
- config.bark_material.applyOverrides({
491
- bark_type: FoliageBarkType.Fissured,
492
- primary_color: [0.36, 0.34, 0.31],
493
- secondary_color: [0.16, 0.15, 0.14],
494
- inner_bark_color: [0.38, 0.32, 0.27],
495
- fissure_frequency: 7,
496
- fissure_depth: 0.66,
497
- roughness: 0.90
498
- });
499
- config.foliage_material.applyOverrides({
500
- primary_color: [0.24, 0.45, 0.15],
501
- secondary_color: [0.42, 0.28, 0.12],
502
- autumn_tint: 0.22,
503
- leaf_shape: "palmate",
504
- leaflets_per_cluster: 5,
505
- juvenile_color_shift: 0.40,
506
- juvenile_anthocyanin: 0.18,
507
- carotenoid_density: 0.88,
508
- anthocyanin_potential: 0.90,
509
- tannin_oxidation: 0.18
510
- });
511
- break;
512
- }
513
-
514
- case TreePreset.Spruce: {
515
- config.name = "spruce";
516
- config.preset = TreePreset.Spruce;
517
- config.crown.applyOverrides({
518
- envelope_type: CrownEnvelopeType.Conical,
519
- height: 9.5,
520
- radius: 3.6,
521
- base_height: 1.4,
522
- prune_ratio: 0.3,
523
- space_colonization_weight: 0.08,
524
- pipe_model_exponent: 2.45,
525
- pipe_model_weight: 0.55,
526
- sky_phototropism_mix: 0.3
527
- });
528
- config.levels = [
529
- {
530
- level: 0,
531
- segments: 10,
532
- radial_segments_max: 10,
533
- radial_segments_min: 4,
534
- length: 11.8,
535
- radius_ratio: 0.036,
536
- taper: 0.92,
537
- bare_length_ratio: 0.12,
538
- child_count: 35,
539
- phyllotaxis_mode: PhyllotaxisMode.Whorled,
540
- whorl_count: 5,
541
- insertion_angle: 1.38,
542
- insertion_angle_profile: AnimationCurve.linear(0, 1.05, 1, 0.56),
543
- curvature: 0.02,
544
- gravitropism: -0.08,
545
- phototropism: 0.06,
546
- gnarl_strength: 0.02,
547
- flare_amplitude: 0.2,
548
- flare_lobes: 4,
549
- collar_weld_rings: 0
550
- },
551
- {
552
- level: 1,
553
- segments: 5,
554
- radial_segments_max: 6,
555
- radial_segments_min: 3,
556
- length: 3.6,
557
- length_profile: AnimationCurve.linear(0, 1.0, 1, 0.68),
558
- radius_ratio: 0.032,
559
- taper: 0.86,
560
- bare_length_ratio: 0.1,
561
- child_count: 6,
562
- phyllotaxis_mode: PhyllotaxisMode.AlternateDistichous,
563
- insertion_angle: 0.9,
564
- curvature: 0.18,
565
- curve_back: -0.10,
566
- gravitropism: 0.16,
567
- phototropism: 0.12,
568
- collar_weld_rings: 2
569
- },
570
- {
571
- level: 2,
572
- segments: 3,
573
- radial_segments_max: 4,
574
- radial_segments_min: 3,
575
- length: 1.1,
576
- radius_ratio: 0.03,
577
- taper: 0.85,
578
- bare_length_ratio: 0.08,
579
- child_count: 0,
580
- insertion_angle: 0.8,
581
- curvature: 0.15,
582
- gravitropism: 0.18,
583
- phototropism: 0.2,
584
- collar_weld_rings: 1
585
- }
586
- ];
587
- config.applyOverrides({ levels: config.levels, replace_levels: true });
588
- config.foliage.applyOverrides({
589
- enabled: true,
590
- card_type: FoliageCardType.CrossCard,
591
- attach_min_level: 1,
592
- cards_per_branch: 7,
593
- terminal_rosette_count: 2,
594
- card_width: 0.68,
595
- card_length: 0.75
596
- });
597
- config.bark_material.applyOverrides({
598
- bark_type: FoliageBarkType.Plated,
599
- primary_color: [0.36, 0.29, 0.24],
600
- secondary_color: [0.15, 0.12, 0.10],
601
- inner_bark_color: [0.42, 0.30, 0.22],
602
- fissure_frequency: 8,
603
- fissure_depth: 0.72,
604
- roughness: 0.91
605
- });
606
- config.foliage_material.applyOverrides({
607
- primary_color: [0.11, 0.27, 0.15],
608
- secondary_color: [0.07, 0.18, 0.10],
609
- leaf_shape: "needle",
610
- leaflets_per_cluster: 9,
611
- juvenile_color_shift: 0.46,
612
- juvenile_anthocyanin: 0.0,
613
- carotenoid_density: 0.35,
614
- anthocyanin_potential: 0.0,
615
- tannin_oxidation: 0.30
616
- });
617
- break;
618
- }
619
-
620
- case TreePreset.Palm: {
621
- config.name = "palm";
622
- config.preset = TreePreset.Palm;
623
- config.crown.applyOverrides({
624
- envelope_type: CrownEnvelopeType.Hemispherical,
625
- height: 11.0,
626
- radius: 4.2,
627
- base_height: 7.5,
628
- prune_ratio: 0.1,
629
- space_colonization_weight: 0.0,
630
- pipe_model_weight: 0.15
631
- });
632
- config.levels = [
633
- {
634
- level: 0,
635
- segments: 10,
636
- radial_segments_max: 10,
637
- radial_segments_min: 7,
638
- length: 9.5,
639
- radius_ratio: 0.038,
640
- taper: 0.35,
641
- bare_length_ratio: 0.92,
642
- child_count: 12,
643
- phyllotaxis_mode: PhyllotaxisMode.SpiralGolden,
644
- insertion_angle: 0.95,
645
- insertion_angle_variation: 0.25,
646
- curvature: 0.28,
647
- curve_back: -0.12,
648
- gravitropism: -0.08,
649
- phototropism: 0.22,
650
- gnarl_strength: 0.04,
651
- flare_amplitude: 0.25,
652
- flare_height_ratio: 0.12,
653
- flare_lobes: 6,
654
- collar_weld_rings: 0
655
- },
656
- {
657
- level: 1,
658
- segments: 5,
659
- radial_segments_max: 5,
660
- radial_segments_min: 3,
661
- length: 2.8,
662
- radius_ratio: 0.025,
663
- taper: 0.9,
664
- bare_length_ratio: 0.05,
665
- child_count: 0,
666
- insertion_angle: 0.85,
667
- curvature: 0.55,
668
- gravitropism: 0.48,
669
- phototropism: 0.15,
670
- collar_weld_rings: 1
671
- }
672
- ];
673
- config.applyOverrides({ levels: config.levels, replace_levels: true });
674
- config.foliage.applyOverrides({
675
- enabled: true,
676
- card_type: FoliageCardType.RibbedFrond,
677
- attach_min_level: 1,
678
- cards_per_branch: 4,
679
- terminal_rosette_count: 3,
680
- bare_ratio: 0.05,
681
- card_width: 0.95,
682
- card_length: 1.85,
683
- fold_angle: 0.32,
684
- arch_height: 0.22,
685
- camber_droop: 0.32,
686
- frond_segments: 6,
687
- gravitropism: 0.45,
688
- phototropism: 0.4
689
- });
690
- config.bark_material.applyOverrides({
691
- bark_type: FoliageBarkType.Ringed,
692
- primary_color: [0.54, 0.46, 0.36],
693
- secondary_color: [0.26, 0.21, 0.15],
694
- fissure_frequency: 5,
695
- fissure_depth: 0.62,
696
- lenticel_amount: 0.45
697
- });
698
- config.foliage_material.applyOverrides({
699
- primary_color: [0.22, 0.46, 0.14],
700
- secondary_color: [0.15, 0.34, 0.09],
701
- leaf_shape: "frond",
702
- leaflets_per_cluster: 11
703
- });
704
- break;
705
- }
706
-
707
- case TreePreset.Shrub: {
708
- config.name = "shrub";
709
- config.preset = TreePreset.Shrub;
710
- config.crown.applyOverrides({
711
- envelope_type: CrownEnvelopeType.Hemispherical,
712
- height: 2.8,
713
- radius: 2.2,
714
- base_height: 0.15,
715
- prune_ratio: 0.25,
716
- space_colonization_weight: 0.3,
717
- pipe_model_exponent: 2.1,
718
- pipe_model_weight: 0.55
719
- });
720
- config.levels = [
721
- {
722
- level: 0,
723
- segments: 5,
724
- radial_segments_max: 7,
725
- radial_segments_min: 4,
726
- length: 1.8,
727
- radius_ratio: 0.055,
728
- taper: 0.8,
729
- bare_length_ratio: 0.08,
730
- child_count: 8,
731
- phyllotaxis_mode: PhyllotaxisMode.SpiralGolden,
732
- insertion_angle: 0.82,
733
- curvature: 0.25,
734
- gravitropism: -0.05,
735
- phototropism: 0.28,
736
- gnarl_strength: 0.12,
737
- split_probability: 0.45,
738
- split_count: 3,
739
- split_angle: 0.52,
740
- collar_weld_rings: 0
741
- },
742
- {
743
- level: 1,
744
- segments: 4,
745
- radial_segments_max: 5,
746
- radial_segments_min: 3,
747
- length: 1.2,
748
- radius_ratio: 0.04,
749
- taper: 0.85,
750
- bare_length_ratio: 0.1,
751
- child_count: 0,
752
- insertion_angle: 0.72,
753
- curvature: 0.2,
754
- gravitropism: 0.06,
755
- phototropism: 0.35,
756
- collar_weld_rings: 1
757
- }
758
- ];
759
- config.applyOverrides({ levels: config.levels, replace_levels: true });
760
- config.foliage.applyOverrides({
761
- enabled: true,
762
- card_type: FoliageCardType.FoldedVCard,
763
- attach_min_level: 1,
764
- cards_per_branch: 9,
765
- terminal_rosette_count: 4,
766
- card_width: 0.55,
767
- card_length: 0.62,
768
- phototropism: 0.7
769
- });
770
- config.foliage_material.applyOverrides({
771
- primary_color: [0.22, 0.44, 0.16],
772
- secondary_color: [0.14, 0.30, 0.10],
773
- leaf_shape: "ovate",
774
- leaflets_per_cluster: 7
775
- });
776
- break;
777
- }
778
-
779
- case TreePreset.Fern: {
780
- config.name = "fern";
781
- config.preset = TreePreset.Fern;
782
- config.crown.applyOverrides({
783
- envelope_type: CrownEnvelopeType.InverseConical,
784
- height: 1.6,
785
- radius: 1.5,
786
- base_height: 0.05,
787
- prune_ratio: 0.05,
788
- space_colonization_weight: 0.0,
789
- pipe_model_weight: 0.2
790
- });
791
- config.levels = [
792
- {
793
- level: 0,
794
- segments: 3,
795
- radial_segments_max: 6,
796
- radial_segments_min: 4,
797
- length: 0.35,
798
- radius_ratio: 0.18,
799
- taper: 0.6,
800
- bare_length_ratio: 0.1,
801
- child_count: 9,
802
- phyllotaxis_mode: PhyllotaxisMode.SpiralGolden,
803
- insertion_angle: 0.95,
804
- curvature: 0.1,
805
- collar_weld_rings: 0
806
- },
807
- {
808
- level: 1,
809
- segments: 5,
810
- radial_segments_max: 4,
811
- radial_segments_min: 3,
812
- length: 1.15,
813
- radius_ratio: 0.025,
814
- taper: 0.92,
815
- bare_length_ratio: 0.05,
816
- child_count: 0,
817
- insertion_angle: 0.85,
818
- curvature: 0.48,
819
- gravitropism: 0.38,
820
- phototropism: 0.2,
821
- collar_weld_rings: 1
822
- }
823
- ];
824
- config.applyOverrides({ levels: config.levels, replace_levels: true });
825
- config.foliage.applyOverrides({
826
- enabled: true,
827
- card_type: FoliageCardType.RibbedFrond,
828
- attach_min_level: 1,
829
- cards_per_branch: 3,
830
- terminal_rosette_count: 2,
831
- bare_ratio: 0.05,
832
- card_width: 0.48,
833
- card_length: 0.95,
834
- fold_angle: 0.28,
835
- arch_height: 0.16,
836
- camber_droop: 0.24,
837
- frond_segments: 6,
838
- gravitropism: 0.35,
839
- phototropism: 0.55
840
- });
841
- config.foliage_material.applyOverrides({
842
- primary_color: [0.24, 0.50, 0.16],
843
- secondary_color: [0.16, 0.36, 0.10],
844
- leaf_shape: "frond",
845
- leaflets_per_cluster: 11
846
- });
847
- break;
848
- }
849
-
850
- case TreePreset.Oak:
851
- default: {
852
- config.name = "oak";
853
- config.preset = TreePreset.Oak;
854
- config.foliage_material.applyOverrides({
855
- juvenile_color_shift: 0.38,
856
- juvenile_anthocyanin: 0.14,
857
- carotenoid_density: 0.72,
858
- anthocyanin_potential: 0.52,
859
- tannin_oxidation: 0.68
860
- });
861
- break;
862
- }
863
- }
864
-
865
- if (overrides !== undefined && overrides !== null) {
866
- config.applyOverrides(overrides);
867
- }
868
-
869
- return config;
870
- }
1
+ import { AnimationCurve } from "../../../engine/animation/curve/AnimationCurve.js";
2
+ import { CrownEnvelopeType } from "../config/CrownEnvelopeType.js";
3
+ import { FoliageBarkType } from "../config/FoliageBarkType.js";
4
+ import { FoliageCardType } from "../config/FoliageCardType.js";
5
+ import { PhyllotaxisMode } from "../config/PhyllotaxisMode.js";
6
+ import { TreePreset } from "../config/TreePreset.js";
7
+ import { TreeSpeciesConfig } from "../config/TreeSpeciesConfig.js";
8
+ import { BranchGeneratorConfig } from "../config/BranchGeneratorConfig.js";
9
+ import { BranchSpawnRule } from "../config/BranchSpawnRule.js";
10
+ import { FoliageSpawnRule } from "../config/FoliageSpawnRule.js";
11
+ import { FoliageTileContent } from "../config/FoliageTileContent.js";
12
+ import { LeafApexShape } from "../config/LeafApexShape.js";
13
+ import { LeafBaseShape } from "../config/LeafBaseShape.js";
14
+ import { LeafLobation } from "../config/LeafLobation.js";
15
+ import { ShootBudZone } from "../config/ShootBudZone.js";
16
+ import { ShootSystemRule } from "../config/ShootSystemRule.js";
17
+ import { shoot_expected_yield } from "../skeleton/shoot_demography.js";
18
+
19
+ /**
20
+ * Structural surface roots: thick, fast-tapering, they leave the trunk on its basal flare crests and creep along
21
+ * the ground, sinking into it about halfway out.
22
+ * @param {number} length nominal root length (meters)
23
+ * @returns {BranchGeneratorConfig}
24
+ */
25
+ function make_surface_roots(length) {
26
+ return BranchGeneratorConfig.from({
27
+ root: true,
28
+ segments: 3,
29
+ radial_segments_max: 9,
30
+ radial_segments_min: 4,
31
+ length: length,
32
+ length_variance: 0.3,
33
+ radius_ratio: 0.11,
34
+ taper: 0.95,
35
+ curvature: 0.0,
36
+ gravitropism: 0.0,
37
+ phototropism: 0.35,
38
+ gnarl_strength: 0.3,
39
+ gnarl_frequency: 0.8,
40
+ nodal_kink_strength: 0.0,
41
+ internode_zigzag: 0.05,
42
+ tip_upcurl: 0.0,
43
+ oval_eccentricity: 0.0,
44
+ bark_displacement: 0.1,
45
+ parent_collar_bulge: 0.0,
46
+ collar_weld_rings: 2,
47
+ collar_length_ratio: 0.14,
48
+ collar_spread_upper: 0.3,
49
+ collar_spread_lower: 0.5
50
+ });
51
+ }
52
+
53
+ /**
54
+ * Trunk -> surface roots: one on each crest of the trunk's basal flare lobes, at the very base, outside the crown.
55
+ * @param {number} target surface roots generator
56
+ * @param {number} flare_lobes the trunk generator's `flare_lobes`
57
+ * @returns {BranchSpawnRule}
58
+ */
59
+ function make_surface_roots_rule(target, flare_lobes) {
60
+ return BranchSpawnRule.from({
61
+ source: 0,
62
+ target: target,
63
+ count: flare_lobes,
64
+ attach_min: 0.0,
65
+ attach_max: 0.03,
66
+ phyllotaxis_mode: PhyllotaxisMode.FlareLobes,
67
+ azimuth_jitter: 0.04,
68
+ insertion_angle: 1.7,
69
+ insertion_angle_variation: 0.08,
70
+ insertion_angle_profile: AnimationCurve.constant(0, 1, 1),
71
+ parent_kink: 0.0,
72
+ crown_envelope: false
73
+ });
74
+ }
75
+
76
+ /**
77
+ * Long shoots of a species' peripheral twig system, grown year by year (`TreeSpeciesConfig.shoot_rules`): one segment
78
+ * a year, thin and lightly bent; how they turn is the species'.
79
+ * @param {Partial<BranchGeneratorConfig>} overrides
80
+ * @returns {BranchGeneratorConfig}
81
+ */
82
+ function make_twig_generator(overrides) {
83
+ return BranchGeneratorConfig.from({
84
+ segments: 1,
85
+ radial_segments_max: 4,
86
+ radial_segments_min: 3,
87
+ length: 0.1,
88
+ radius_ratio: 0.03,
89
+ taper: 0.6,
90
+ gravitropism: 0.1,
91
+ phototropism: 0.3,
92
+ internode_zigzag: 0.15,
93
+ collar_weld_rings: 0,
94
+ ...overrides
95
+ });
96
+ }
97
+
98
+ /**
99
+ * Short shoots of a species' twig system: a few millimetres of growth a year, straight, no laterals.
100
+ * @returns {BranchGeneratorConfig}
101
+ */
102
+ function make_short_shoot_generator() {
103
+ return BranchGeneratorConfig.from({
104
+ segments: 1,
105
+ radial_segments_max: 3,
106
+ radial_segments_min: 3,
107
+ length: 0.01,
108
+ radius_ratio: 0.03,
109
+ taper: 0.8,
110
+ gravitropism: 0.0,
111
+ phototropism: 0.0,
112
+ internode_zigzag: 0.0,
113
+ collar_weld_rings: 0
114
+ });
115
+ }
116
+
117
+ /**
118
+ * Scots pine's twig system after Kellomäki & Kurttio (1991), A model for the structural development of a Scots pine
119
+ * crown based on modular growth, For. Ecol. Manage. 43: 103-123 [KK1991], with the whorl branch as order 1. Norway
120
+ * spruce has no such fit, so it borrows these counts and ratios with its own shoot length.
121
+ * @param {number} source
122
+ * @param {number} target
123
+ * @param {Partial<ShootSystemRule>} overrides
124
+ * @returns {ShootSystemRule}
125
+ */
126
+ function make_conifer_shoot_rule(source, target, overrides) {
127
+ return ShootSystemRule.from({
128
+ source,
129
+ target,
130
+ max_order: 6,
131
+ // a terminal follows the unit before it: 0.995, 0.913, 0.938, 0.999 of it by order [KK1991 Table 4]
132
+ terminal_length: [0],
133
+ terminal_length_slope: [0.995, 0.913, 0.938, 0.999],
134
+ length_negative_binomial_p: [],
135
+ zones: [
136
+ // pine is uninodal: its laterals grow from the whorl of buds under the terminal bud. Daughters, the terminal
137
+ // among them, are k + c L of a parent L cm long: 0.992 + 0.161 L, 0.544 + 0.149 L, 0.861 + 0.041 L by parent
138
+ // order 1-3 [KK1991 Table 3]; a lateral is 0.458, 0.355, 0.475 of its parent [KK1991 Table 4]
139
+ ShootBudZone.from({
140
+ u_min: 0.92,
141
+ u_max: 0.99,
142
+ buds: [0.992 - 1, 0.544 - 1, 0.861 - 1],
143
+ buds_per_metre: [16.1, 14.9, 4.1],
144
+ long: [1],
145
+ length: [0],
146
+ length_slope: [0.458, 0.355, 0.475]
147
+ })
148
+ ],
149
+ ...overrides
150
+ });
151
+ }
152
+
153
+ /**
154
+ * A conifer leader's own annual units, so the top of the stem keeps its needles as the branches do: no laterals (the
155
+ * whorl branches are the framework's); its units are the leader's yearly growth (`ShootGrowthConfig.leader_growth`).
156
+ * @param {number} target
157
+ * @returns {ShootSystemRule}
158
+ */
159
+ function make_conifer_leader_rule(target) {
160
+ return ShootSystemRule.from({
161
+ source: 0,
162
+ target,
163
+ mean_unit_length: 0.475,
164
+ max_unit_length: [0.475],
165
+ length_negative_binomial_p: [],
166
+ zones: []
167
+ });
168
+ }
169
+
170
+ /**
171
+ * Returns a rich, botanically tuned `TreeSpeciesConfig` for one of the 9 built-in
172
+ * `TreePreset` archetypes (`Oak`, `Pine`, `Birch`, `Willow`, `Maple`, `Spruce`, `Palm`, `Shrub`, `Fern`),
173
+ * with optional deep parameter overrides.
174
+ *
175
+ * @param {TreePreset|string} [preset=TreePreset.Oak]
176
+ * @param {Object} [overrides]
177
+ * @returns {TreeSpeciesConfig}
178
+ */
179
+ export function make_tree_species_preset(preset = TreePreset.Oak, overrides = {}) {
180
+ const config = new TreeSpeciesConfig();
181
+ const key = typeof preset === "string" ? preset.toLowerCase() : TreePreset.Oak;
182
+
183
+ switch (key) {
184
+ case TreePreset.Pine: {
185
+ // Pinus follows Rauh's model (Pfisterer 2000): its branches are orthotropic, built like the trunk, so they carry no
186
+ // plagiotropism.
187
+ // The tiers come from one whorl of branches a year.
188
+ config.name = "pine";
189
+ config.preset = TreePreset.Pine;
190
+ config.crown.applyOverrides({
191
+ envelope_type: CrownEnvelopeType.Conical,
192
+ height: 8.6,
193
+ radius: 4.2,
194
+ base_height: 2.2,
195
+ prune_ratio: 0.25,
196
+ space_colonization_weight: 0.08,
197
+ pipe_model_exponent: 2.4,
198
+ pipe_model_weight: 0.55,
199
+ sky_phototropism_mix: 0.35
200
+ });
201
+ config.branches = [
202
+ BranchGeneratorConfig.from({
203
+ excurrent: true,
204
+ segments: 12,
205
+ radial_segments_max: 14,
206
+ radial_segments_min: 8,
207
+ length: 11.2,
208
+ length_variance: 0.05,
209
+ radius_ratio: 0.038,
210
+ taper: 0.88,
211
+ curvature: 0.16,
212
+ curve_back: -0.10,
213
+ spiral_twist: 0.22,
214
+ gravitropism: -0.06,
215
+ phototropism: 0.10,
216
+ gnarl_strength: 0.09,
217
+ gnarl_frequency: 0.32,
218
+ basal_lean: 0.015,
219
+ nodal_kink_strength: 0.18,
220
+ internode_zigzag: 0.04,
221
+ kink_sharpness: 0.48,
222
+ bark_displacement: 0.08,
223
+ parent_collar_bulge: 0.26,
224
+ split_probability: 0.0,
225
+ flare_amplitude: 0.28,
226
+ flare_height_ratio: 0.15,
227
+ flare_lobes: 4,
228
+ flare_sharpness: 3.0,
229
+ flute_amplitude: 0.015,
230
+ flute_frequency: 3,
231
+ collar_weld_rings: 0
232
+ }),
233
+ BranchGeneratorConfig.from({
234
+ self_pruning: 0.55, // open-grown Scots pine holds dead lower branches for a while
235
+ segments: 7,
236
+ radial_segments_max: 7,
237
+ radial_segments_min: 4,
238
+ length: 3.8,
239
+ length_variance: 0.10,
240
+ radius_ratio: 0.035,
241
+ taper: 0.85,
242
+ curvature: 0.16,
243
+ curve_back: -0.12,
244
+ gravitropism: 0.22,
245
+ phototropism: 0.16,
246
+ gnarl_strength: 0.12,
247
+ nodal_kink_strength: 0.42,
248
+ internode_zigzag: 0.09,
249
+ kink_sharpness: 0.55,
250
+ tip_upcurl: 0.34,
251
+ oval_eccentricity: 0.16,
252
+ bark_displacement: 0.06,
253
+ collar_weld_rings: 2
254
+ }),
255
+ // Inter-whorl branches: short laterals spiralling along the internodes between whorls
256
+ BranchGeneratorConfig.from({
257
+ self_pruning: 0.55, // open-grown Scots pine holds dead lower branches for a while
258
+ segments: 5,
259
+ radial_segments_max: 5,
260
+ radial_segments_min: 3,
261
+ length: 1.9,
262
+ length_variance: 0.18,
263
+ radius_ratio: 0.034,
264
+ taper: 0.86,
265
+ curvature: 0.14,
266
+ curve_back: -0.10,
267
+ gravitropism: 0.26,
268
+ phototropism: 0.14,
269
+ gnarl_strength: 0.12,
270
+ nodal_kink_strength: 0.30,
271
+ internode_zigzag: 0.10,
272
+ kink_sharpness: 0.55,
273
+ tip_upcurl: 0.30,
274
+ oval_eccentricity: 0.12,
275
+ bark_displacement: 0.05,
276
+ collar_weld_rings: 1
277
+ }),
278
+ BranchGeneratorConfig.from({
279
+ segments: 5,
280
+ radial_segments_max: 5,
281
+ radial_segments_min: 3,
282
+ length: 1.4,
283
+ length_variance: 0.14,
284
+ radius_ratio: 0.032,
285
+ taper: 0.85,
286
+ curvature: 0.14,
287
+ gravitropism: 0.08,
288
+ phototropism: 0.24,
289
+ gnarl_strength: 0.12,
290
+ internode_zigzag: 0.12,
291
+ tip_upcurl: 0.32,
292
+ collar_weld_rings: 1
293
+ })
294
+ ];
295
+ config.branch_rules = [
296
+ BranchSpawnRule.from({
297
+ source: 0,
298
+ target: 1,
299
+ count: 32,
300
+ attach_min: 0.24,
301
+ phyllotaxis_mode: PhyllotaxisMode.Whorled,
302
+ whorl_count: 4,
303
+ azimuth_jitter: 0.16,
304
+ insertion_angle: 1.34,
305
+ insertion_angle_variation: 0.08,
306
+ insertion_angle_profile: AnimationCurve.linear(0, 1.05, 1, 0.52),
307
+ length_profile: AnimationCurve.linear(0, 1.0, 1, 0.72),
308
+ parent_kink: 0.0
309
+ }),
310
+ BranchSpawnRule.from({
311
+ source: 0,
312
+ target: 2,
313
+ count: 14,
314
+ attach_min: 0.30,
315
+ phyllotaxis_mode: PhyllotaxisMode.SpiralGolden,
316
+ azimuth_jitter: 0.30,
317
+ insertion_angle: 1.22,
318
+ insertion_angle_variation: 0.12,
319
+ insertion_angle_profile: AnimationCurve.linear(0, 1.05, 1, 0.55),
320
+ length_profile: AnimationCurve.linear(0, 1.0, 1, 0.6),
321
+ parent_kink: 0.0
322
+ }),
323
+ // Whorl boughs and inter-whorl branches both carry the same twigs
324
+ BranchSpawnRule.from({
325
+ source: 1,
326
+ target: 3,
327
+ count: 7,
328
+ attach_min: 0.12,
329
+ phyllotaxis_mode: PhyllotaxisMode.AlternateDistichous,
330
+ azimuth_jitter: 0.14,
331
+ insertion_angle: 0.88,
332
+ insertion_angle_variation: 0.10,
333
+ length_profile: AnimationCurve.linear(0, 0.95, 1, 0.48)
334
+ }),
335
+ BranchSpawnRule.from({
336
+ source: 2,
337
+ target: 3,
338
+ count: 4,
339
+ attach_min: 0.15,
340
+ phyllotaxis_mode: PhyllotaxisMode.AlternateDistichous,
341
+ azimuth_jitter: 0.14,
342
+ insertion_angle: 0.88,
343
+ insertion_angle_variation: 0.10,
344
+ length_profile: AnimationCurve.linear(0, 0.8, 1, 0.45)
345
+ })
346
+ ];
347
+ // 4: surface roots on the flare crests
348
+ config.branches.push(make_surface_roots(1.8));
349
+ config.branch_rules.push(make_surface_roots_rule(4, config.branches[0].flare_lobes));
350
+ // 5: the twig system, grown year by year on the boughs, inter-whorl branches and twigs
351
+ config.branches.push(make_twig_generator({ gravitropism: 0.08, phototropism: 0.24, tip_upcurl: 0.3 }));
352
+ // Shoots average 11.02 cm on the whorl branches, at most 47.5 cm [KK1991 Table 4, Eq. 6]; branching angles 61,
353
+ // 59, 65 degrees by the lateral's order 2-4 [KK1991 Fig. 2]
354
+ config.shoot_rules = [1, 2, 3].map(source => make_conifer_shoot_rule(source, 5, {
355
+ carrier_order: source === 3 ? 2 : 1,
356
+ mean_unit_length: 0.1102,
357
+ max_unit_length: [0.475],
358
+ insertion_angle: [1.065, 1.030, 1.134]
359
+ }));
360
+ config.shoot_rules.push(make_conifer_leader_rule(5));
361
+ // Scots pine stops branching below a relative light of 0.20-0.25 [Ilonen et al. 1979, Silva Fennica 13: 319-321];
362
+ // Rb in full light is the example branch's 1.867 [Niinemets & Lukjanova 2003, New Phytol. 158: 75-89, Fig. 2];
363
+ // where it saturates is spruce's (below). A shoot's needles are bunched: its silhouette is 0.146 of its needle
364
+ // area against a random 0.25 [Smolander, Stenberg & Linder 1994, Tree Physiol. 14: 971-980]
365
+ // a Scots pine leader grows 47.5 cm a year once the tree is past 3.5-4.5 m [KK1991 Eq. 6, p. 111]
366
+ config.shoot_growth.applyOverrides({
367
+ leader_growth: 0.475,
368
+ vigour: 1.867,
369
+ compensation_light: 0.22,
370
+ saturation_light: 0.30,
371
+ leaf_clumping: 0.146 / 0.25
372
+ });
373
+ // Needles 52 mm long [Niinemets & Lukjanova 2003, Ann. For. Sci. 60: 195-208, Table I], in fascicles of two,
374
+ // 7.8 fascicles a cm [Salminen & Jalkanen 2006, Silva Fennica 40: 183-194, Table 3]; of a year's needles 1,
375
+ // 0.90, 0.69, 0.22 are alive at ages 1-4, none after [KK1991 p. 113]. A card is a stretch of shoot as long as a
376
+ // needle with the needles the shoot bears there, on three planes round it (foliage_tile_layout)
377
+ config.foliage.applyOverrides({
378
+ card_type: FoliageCardType.TriStarCluster,
379
+ leaves_per_unit: 0,
380
+ leaves_per_metre: 1560,
381
+ leaf_survival: [1, 0.90, 0.69, 0.22],
382
+ phototropism: 0.45,
383
+ gravitropism: 0.12
384
+ });
385
+ config.foliage_rules = [0, 1, 2, 3, 5].map(source => FoliageSpawnRule.from({
386
+ source,
387
+ phyllotaxis_mode: PhyllotaxisMode.SpiralGolden
388
+ }));
389
+ config.bark_material.applyOverrides({
390
+ bark_type: FoliageBarkType.Plated,
391
+ primary_color: [0.39, 0.28, 0.21],
392
+ secondary_color: [0.14, 0.11, 0.09],
393
+ inner_bark_color: [0.46, 0.31, 0.21],
394
+ fissure_frequency: 6,
395
+ fissure_depth: 0.76,
396
+ plate_terrace: 0.52,
397
+ knot_amount: 0.45,
398
+ roughness: 0.90
399
+ });
400
+ config.foliage_material.applyOverrides({
401
+ primary_color: [0.13, 0.32, 0.14],
402
+ secondary_color: [0.08, 0.22, 0.09],
403
+ tile_content: FoliageTileContent.NeedleShoot,
404
+ // the needle, 52 mm [Niinemets & Lukjanova 2003]; no width was found: 1.6 mm is chosen
405
+ leaf: {
406
+ blade_length: 0.052,
407
+ length_width_ratio: 0.052 / 0.0016,
408
+ widest_at: 0.3,
409
+ apex_angle: 0.4,
410
+ apex_shape: LeafApexShape.Straight,
411
+ base_angle: 0.6,
412
+ base_shape: LeafBaseShape.Straight,
413
+ secondary_veins: 0,
414
+ petiole_length: 0
415
+ },
416
+ roughness: 0.55,
417
+ juvenile_color_shift: 0.46,
418
+ juvenile_anthocyanin: 0.0,
419
+ carotenoid_density: 0.35,
420
+ anthocyanin_potential: 0.0,
421
+ tannin_oxidation: 0.30
422
+ });
423
+ break;
424
+ }
425
+
426
+ case TreePreset.Birch: {
427
+ config.name = "birch";
428
+ // Betula follows Rauh's model (Millet et al. 1999): orthotropic, radially branched axes, so no plagiotropism
429
+ config.preset = TreePreset.Birch;
430
+ config.crown.applyOverrides({
431
+ envelope_type: CrownEnvelopeType.Flame,
432
+ height: 12.5,
433
+ radius: 3.4,
434
+ base_height: 2.5,
435
+ prune_ratio: 0.3,
436
+ space_colonization_weight: 0.25,
437
+ pipe_model_exponent: 2.15,
438
+ pipe_model_weight: 0.6
439
+ });
440
+ config.branches = [
441
+ BranchGeneratorConfig.from({
442
+ segments: 12,
443
+ radial_segments_max: 14,
444
+ radial_segments_min: 8,
445
+ length: 11.5,
446
+ length_variance: 0.08,
447
+ radius_ratio: 0.032,
448
+ taper: 0.86,
449
+ curvature: 0.32,
450
+ curve_back: -0.22,
451
+ spiral_twist: 0.28,
452
+ gravitropism: -0.06,
453
+ phototropism: 0.20,
454
+ gnarl_strength: 0.15,
455
+ gnarl_frequency: 0.36,
456
+ basal_lean: 0.04,
457
+ nodal_kink_strength: 0.48,
458
+ internode_zigzag: 0.07,
459
+ kink_sharpness: 0.62,
460
+ bark_displacement: 0.075,
461
+ parent_collar_bulge: 0.30,
462
+ split_probability: 0.28,
463
+ split_count: 2,
464
+ split_angle: 0.38,
465
+ flare_amplitude: 0.24,
466
+ flare_height_ratio: 0.15,
467
+ flare_lobes: 4,
468
+ flute_amplitude: 0.010,
469
+ flute_frequency: 3,
470
+ collar_weld_rings: 0
471
+ }),
472
+ BranchGeneratorConfig.from({
473
+ self_pruning: 0.85, // birch sheds its shaded branches cleanly
474
+ segments: 8,
475
+ radial_segments_max: 7,
476
+ radial_segments_min: 4,
477
+ length: 3.6,
478
+ length_variance: 0.15,
479
+ radius_ratio: 0.034,
480
+ taper: 0.86,
481
+ curvature: 0.28,
482
+ curve_back: -0.18,
483
+ gravitropism: 0.22,
484
+ phototropism: 0.24,
485
+ gnarl_strength: 0.20,
486
+ nodal_kink_strength: 0.72,
487
+ internode_zigzag: 0.15,
488
+ kink_sharpness: 0.65,
489
+ tip_upcurl: 0.20,
490
+ oval_eccentricity: 0.15,
491
+ bark_displacement: 0.06,
492
+ collar_weld_rings: 2
493
+ }),
494
+ BranchGeneratorConfig.from({
495
+ segments: 6,
496
+ radial_segments_max: 5,
497
+ radial_segments_min: 3,
498
+ length: 1.7,
499
+ length_variance: 0.18,
500
+ radius_ratio: 0.028,
501
+ taper: 0.9,
502
+ curvature: 0.32,
503
+ gravitropism: 0.42,
504
+ phototropism: 0.12,
505
+ gnarl_strength: 0.18,
506
+ internode_zigzag: 0.18,
507
+ kink_sharpness: 0.58,
508
+ tip_upcurl: 0.06,
509
+ collar_weld_rings: 1
510
+ })
511
+ ];
512
+ config.branch_rules = [
513
+ BranchSpawnRule.from({
514
+ source: 0,
515
+ target: 1,
516
+ count: 12,
517
+ attach_min: 0.24,
518
+ phyllotaxis_mode: PhyllotaxisMode.SpiralGolden,
519
+ insertion_angle: 0.58,
520
+ insertion_angle_variation: 0.14,
521
+ length_profile: AnimationCurve.linear(0, 0.85, 1, 0.45)
522
+ }),
523
+ BranchSpawnRule.from({
524
+ source: 1,
525
+ target: 2,
526
+ count: 6,
527
+ attach_min: 0.15,
528
+ phyllotaxis_mode: PhyllotaxisMode.AlternateDistichous,
529
+ insertion_angle: 0.58
530
+ })
531
+ ];
532
+ // 3: surface roots on the flare crests
533
+ config.branches.push(make_surface_roots(1.7));
534
+ config.branch_rules.push(make_surface_roots_rule(3, config.branches[0].flare_lobes));
535
+ // 4: long shoots and 5: short shoots of the twig system, grown year by year on the boughs and branches
536
+ config.branches.push(make_twig_generator({ gravitropism: 0.42, phototropism: 0.12, internode_zigzag: 0.18 }), make_short_shoot_generator());
537
+ // Silver birch's long and short shoots, from Maillette (1982), Structural dynamics of silver birch I-II, J. Appl.
538
+ // Ecol. 19: 203-238 [M1982]; Jones & Harper (1987), Proc. R. Soc. Lond. B 232: 19-33 [JH1987]; and Lintunen et al.
539
+ // (2011), Can. J. For. Res. 41: 1779-1794 [L2011]:
540
+ // - a long shoot's apex always aborts, and the 4 buds (mode) on its late leaves carry the axis on [M1982 I p. 206,
541
+ // 213]: the terminal and 3 laterals;
542
+ // - about 50% of a long shoot's buds grow long shoots on young branches, falling to 16-26% on older ones, nearly
543
+ // all the rest surviving the year [JH1987 pp. 21-22] as short shoots. The fall tracks local shoot density and
544
+ // light [JH1987 p. 32], which the light field gives, so every order takes the young branches' shares;
545
+ // - a long shoot in the branches is 14.6 cm [L2011 Table A2]; the modal class is 51-100 mm [M1982 Fig. 6a], taken
546
+ // for higher orders;
547
+ // - a short shoot grows under 3 mm a year and carries 2 leaves [M1982 I p. 205-209, L2011]; buds survive a year at
548
+ // about 60% [JH1987 p. 26];
549
+ // - the bud population grows 1.52 a year in the top of the crown, 0.999 at its bottom [M1982 II Table 1]: the
550
+ // vigour in full light, and a shoot that just replaces itself in the shade. Where in the light those are was
551
+ // not measured: the compensation light is Scots pine's, another pioneer's, the saturation spruce's.
552
+ // a long shoot of the stem is 26.3 cm [L2011 Table A2, B20]: the leader's growth
553
+ config.shoot_growth.applyOverrides({
554
+ leader_growth: 0.263,
555
+ vigour: 1.52,
556
+ compensation_light: 0.22,
557
+ saturation_light: 0.30
558
+ });
559
+ config.shoot_rules = [1, 2].map(source => ShootSystemRule.from({
560
+ source,
561
+ target: 4,
562
+ short_target: 5,
563
+ max_order: 6,
564
+ mean_unit_length: 0.146,
565
+ terminal_length: [0.146, 0.075],
566
+ max_unit_length: [1.2],
567
+ length_negative_binomial_p: [],
568
+ zones: [
569
+ ShootBudZone.from({
570
+ u_min: 0.5,
571
+ u_max: 0.99,
572
+ buds: [3],
573
+ long: [0.5],
574
+ short: [0.49],
575
+ length: [0.075]
576
+ })
577
+ ],
578
+ short_shoot_growth: 0.002,
579
+ short_shoot_survival: 0.6,
580
+ phyllotaxis_mode: PhyllotaxisMode.AlternateDistichous
581
+ }));
582
+ // a leaf every 20 mm of long shoot [JH1987 p. 20], 2 a short shoot [M1982 I p. 205-209]; a card a leaf
583
+ config.foliage.applyOverrides({
584
+ card_type: FoliageCardType.CutoutHull,
585
+ leaves_per_unit: 0,
586
+ leaves_per_metre: 50,
587
+ leaves_per_short_shoot: 2,
588
+ fold_angle: 0.24,
589
+ gravitropism: 0.35,
590
+ phototropism: 0.55
591
+ });
592
+ config.foliage_rules = [
593
+ FoliageSpawnRule.from({
594
+ source: 1,
595
+ }),
596
+ FoliageSpawnRule.from({
597
+ source: 2,
598
+ }),
599
+ FoliageSpawnRule.from({
600
+ source: 4,
601
+ }),
602
+ FoliageSpawnRule.from({
603
+ source: 5,
604
+ short_shoot: true
605
+ })
606
+ ];
607
+ config.bark_material.applyOverrides({
608
+ bark_type: FoliageBarkType.Birch,
609
+ primary_color: [0.85, 0.83, 0.80],
610
+ secondary_color: [0.17, 0.16, 0.15],
611
+ inner_bark_color: [0.52, 0.35, 0.23],
612
+ moss_color: [0.24, 0.30, 0.19],
613
+ moss_amount: 0.04,
614
+ fissure_frequency: 4,
615
+ fissure_depth: 0.62,
616
+ lenticel_amount: 0.78,
617
+ peel_amount: 0.35,
618
+ knot_amount: 0.58,
619
+ roughness: 0.88
620
+ });
621
+ config.foliage_material.applyOverrides({
622
+ primary_color: [0.32, 0.52, 0.18],
623
+ secondary_color: [0.22, 0.40, 0.12],
624
+ // Betula pendula's leaf [Flora of North America vol. 3; Flora of China vol. 4]: 3-7 x 2.5-5 cm, taken at the
625
+ // middle, broadly ovate to rhombic, apex acuminate, base cuneate, coarsely and sharply doubly serrate, 6-8 lateral
626
+ // veins a side (FoC), petiole 2-3 cm (FoC). A primary tooth ends each lateral vein. No angles, tooth sizes or
627
+ // position of the widest point were found: those are estimates from the shape terms
628
+ leaf: {
629
+ blade_length: 0.05,
630
+ length_width_ratio: 5 / 3.75,
631
+ widest_at: 0.35,
632
+ apex_angle: 1.05,
633
+ apex_shape: LeafApexShape.Acuminate,
634
+ base_angle: 1.75,
635
+ base_shape: LeafBaseShape.Straight,
636
+ teeth_per_cm: 1.3,
637
+ tooth_depth: 0.0015,
638
+ tooth_orders: 2,
639
+ secondary_veins: 7,
640
+ secondary_angle: 0.8,
641
+ petiole_length: 0.025
642
+ },
643
+ roughness: 0.52,
644
+ juvenile_color_shift: 0.42,
645
+ juvenile_anthocyanin: 0.0,
646
+ carotenoid_density: 0.94,
647
+ anthocyanin_potential: 0.06,
648
+ tannin_oxidation: 0.16
649
+ });
650
+ break;
651
+ }
652
+
653
+ case TreePreset.Willow: {
654
+ config.name = "willow";
655
+ config.preset = TreePreset.Willow;
656
+ config.crown.applyOverrides({
657
+ envelope_type: CrownEnvelopeType.Weeping,
658
+ height: 11.0,
659
+ radius: 5.5,
660
+ base_height: 1.6,
661
+ prune_ratio: 0.2,
662
+ space_colonization_weight: 0.2,
663
+ pipe_model_exponent: 2.25,
664
+ pipe_model_weight: 0.65
665
+ });
666
+ config.branches = [
667
+ BranchGeneratorConfig.from({
668
+ segments: 11,
669
+ radial_segments_max: 13,
670
+ radial_segments_min: 7,
671
+ length: 7.5,
672
+ radius_ratio: 0.065,
673
+ taper: 0.75,
674
+ curvature: 0.32,
675
+ curve_back: -0.18,
676
+ spiral_twist: 0.38,
677
+ gravitropism: -0.05,
678
+ phototropism: 0.15,
679
+ gnarl_strength: 0.18,
680
+ basal_lean: 0.05,
681
+ nodal_kink_strength: 0.55,
682
+ internode_zigzag: 0.08,
683
+ kink_sharpness: 0.65,
684
+ bark_displacement: 0.11,
685
+ parent_collar_bulge: 0.35,
686
+ split_probability: 0.35,
687
+ split_count: 2,
688
+ split_angle: 0.52,
689
+ flare_amplitude: 0.38,
690
+ flare_lobes: 5,
691
+ flute_amplitude: 0.055,
692
+ flute_frequency: 5,
693
+ collar_weld_rings: 0
694
+ }),
695
+ BranchGeneratorConfig.from({
696
+ self_pruning: 0.75, // willow wood is brittle: dead branches snap off early
697
+ segments: 8,
698
+ radial_segments_max: 8,
699
+ radial_segments_min: 4,
700
+ length: 4.8,
701
+ radius_ratio: 0.042,
702
+ taper: 0.84,
703
+ curvature: 0.38,
704
+ curve_back: -0.15,
705
+ gravitropism: 0.32,
706
+ phototropism: 0.22,
707
+ gnarl_strength: 0.22,
708
+ nodal_kink_strength: 0.72,
709
+ internode_zigzag: 0.14,
710
+ kink_sharpness: 0.60,
711
+ tip_upcurl: 0.10,
712
+ oval_eccentricity: 0.18,
713
+ bark_displacement: 0.08,
714
+ collar_weld_rings: 2
715
+ }),
716
+ BranchGeneratorConfig.from({
717
+ segments: 8,
718
+ radial_segments_max: 4,
719
+ radial_segments_min: 3,
720
+ length: 3.4,
721
+ radius_ratio: 0.02,
722
+ taper: 0.92,
723
+ curvature: 0.45,
724
+ gravitropism: 0.88,
725
+ phototropism: 0.04,
726
+ gnarl_strength: 0.12,
727
+ internode_zigzag: 0.09,
728
+ kink_sharpness: 0.25,
729
+ tip_upcurl: 0.0,
730
+ collar_weld_rings: 1
731
+ })
732
+ ];
733
+ config.branch_rules = [
734
+ BranchSpawnRule.from({
735
+ source: 0,
736
+ target: 1,
737
+ count: 9,
738
+ attach_min: 0.25,
739
+ insertion_angle: 0.68
740
+ }),
741
+ BranchSpawnRule.from({
742
+ source: 1,
743
+ target: 2,
744
+ count: 9,
745
+ attach_min: 0.15,
746
+ insertion_angle: 0.65
747
+ })
748
+ ];
749
+ // 3: surface roots on the flare crests
750
+ config.branches.push(make_surface_roots(2.5));
751
+ config.branch_rules.push(make_surface_roots_rule(3, config.branches[0].flare_lobes));
752
+ // 4: the twig system on the hanging branchlets; this year's shoots hang at -80 to -88 degrees in summer
753
+ // [Remphrey & Pearn 2006, Can. J. Bot. 84: 1531-1541, Fig. 7]
754
+ config.branches.push(make_twig_generator({ gravitropism: 0.9, phototropism: 0.04, internode_zigzag: 0.09 }));
755
+ // A pendulous willow's buds, by quarter of their unit from its base: 51, 69, 40, 0% grow sylleptic shoots and 37,
756
+ // 24, 36, 21% proleptic ones; the terminal aborts [Remphrey & Pearn 2006 Table 1, p. 1532], 42 nodes on 1.104 m
757
+ // [p. 1533]. Those shares are of first-order shoots: of their own laterals' buds 2% are sylleptic [p. 1534], so
758
+ // the higher orders keep their proleptic shares with 2% syllepsis. Annual shoots of mature Salix alba are 5-25
759
+ // cm, at 30-60 degrees [Héja 2007, Tilia 13: 77-94, p. 82]. Of a year's laterals 46% are still there in their
760
+ // fourth year [Remphrey & Pearn 2006 p. 1535]: with 69% of buds growing out, on the 5.7 nodes of a 15 cm unit, a
761
+ // shoot leaves 1 + 0.69 x 0.46 x 5.7 = 2.8 shoots, the vigour (young trees). No light response was found: the
762
+ // compensation light is Scots pine's (willows are as light-demanding), the saturation spruce's.
763
+ const willow_quarter = (u_min, u_max, sylleptic, long) => ShootBudZone.from({
764
+ u_min,
765
+ u_max,
766
+ buds: [0],
767
+ buds_per_metre: [42 / 1.104 / 4],
768
+ sylleptic: [sylleptic, 0.02],
769
+ long: [long],
770
+ length: [0.15]
771
+ });
772
+ // young pendulous willows grow 1.0-1.3 m main-stem shoots a year [Remphrey & Pearn 2006 Table 3]; a mature
773
+ // tree's leader slower, 0.5 m chosen
774
+ config.shoot_growth.applyOverrides({
775
+ leader_growth: 0.5,
776
+ vigour: 1 + 0.69 * 0.46 * (0.15 * 42 / 1.104),
777
+ compensation_light: 0.22,
778
+ saturation_light: 0.30
779
+ });
780
+ // the boughs and the hanging branchlets both carry twigs
781
+ config.shoot_rules = [1, 2].map(source => ShootSystemRule.from({
782
+ source,
783
+ target: 4,
784
+ max_order: 6,
785
+ mean_unit_length: 0.15,
786
+ terminal_length: [0.15],
787
+ max_unit_length: [0.25],
788
+ length_negative_binomial_p: [],
789
+ zones: [
790
+ willow_quarter(0.0, 0.25, 0.512, 0.366),
791
+ willow_quarter(0.25, 0.5, 0.690, 0.238),
792
+ willow_quarter(0.5, 0.75, 0.405, 0.357),
793
+ willow_quarter(0.75, 0.99, 0.0, 0.214)
794
+ ],
795
+ insertion_angle: [0.785]
796
+ }));
797
+ // a leaf a node, 42 nodes on 1.104 m [Remphrey & Pearn 2006 p. 1533]; a card a leaf
798
+ config.foliage.applyOverrides({
799
+ card_type: FoliageCardType.CutoutHull,
800
+ leaves_per_unit: 0,
801
+ leaves_per_metre: 42 / 1.104,
802
+ arch_height: 0.12,
803
+ camber_droop: 0.28,
804
+ gravitropism: 0.72,
805
+ phototropism: 0.25
806
+ });
807
+ config.foliage_rules = [1, 2, 4].map(source => FoliageSpawnRule.from({ source }));
808
+ config.bark_material.applyOverrides({
809
+ bark_type: FoliageBarkType.Fissured,
810
+ primary_color: [0.35, 0.32, 0.27],
811
+ secondary_color: [0.15, 0.13, 0.11],
812
+ inner_bark_color: [0.39, 0.32, 0.25],
813
+ fissure_frequency: 8,
814
+ fissure_depth: 0.76,
815
+ roughness: 0.91
816
+ });
817
+ config.foliage_material.applyOverrides({
818
+ primary_color: [0.34, 0.50, 0.20],
819
+ secondary_color: [0.24, 0.38, 0.14],
820
+ // a weeping willow's leaf [Flora of North America vol. 7, S. babylonica]: 90-160 x 5-20 mm, taken at 12.5 cm,
821
+ // 5.5-10.5 times as long as wide (8), lanceolate to narrowly elliptic, apex acuminate, base cuneate, serrulate
822
+ // but entire near the base, petiole 7-9 mm. No angles, tooth sizes or vein counts were found: those are
823
+ // estimates from the shape terms
824
+ leaf: {
825
+ blade_length: 0.125,
826
+ length_width_ratio: 8,
827
+ widest_at: 0.4,
828
+ apex_angle: 0.44,
829
+ apex_shape: LeafApexShape.Acuminate,
830
+ base_angle: 0.52,
831
+ base_shape: LeafBaseShape.Straight,
832
+ teeth_per_cm: 5,
833
+ tooth_depth: 0.0003,
834
+ secondary_veins: 12,
835
+ secondary_angle: 0.9,
836
+ petiole_length: 0.008
837
+ },
838
+ juvenile_color_shift: 0.44,
839
+ juvenile_anthocyanin: 0.0,
840
+ carotenoid_density: 0.84,
841
+ anthocyanin_potential: 0.04,
842
+ tannin_oxidation: 0.22
843
+ });
844
+ break;
845
+ }
846
+
847
+ case TreePreset.Maple: {
848
+ config.name = "maple";
849
+ config.preset = TreePreset.Maple;
850
+ config.crown.applyOverrides({
851
+ envelope_type: CrownEnvelopeType.Spherical,
852
+ height: 11.5,
853
+ radius: 4.8,
854
+ base_height: 2.2,
855
+ prune_ratio: 0.35,
856
+ space_colonization_weight: 0.3,
857
+ pipe_model_exponent: 2.25,
858
+ pipe_model_weight: 0.65
859
+ });
860
+ config.branches[0].applyOverrides({
861
+ flare_amplitude: 0.3,
862
+ flare_lobes: 5
863
+ });
864
+ config.branch_rules[0].applyOverrides({
865
+ phyllotaxis_mode: PhyllotaxisMode.OppositeDecussate,
866
+ count: 10
867
+ });
868
+ config.branch_rules[1].applyOverrides({
869
+ phyllotaxis_mode: PhyllotaxisMode.OppositeDecussate,
870
+ count: 8,
871
+ insertion_angle: 0.68
872
+ });
873
+ // maples are shade-tolerant, and with that poor self-pruners in open growth: dead lower limbs persist
874
+ config.branches[1].self_pruning = 0.5;
875
+ // Acer follows Rauh's model (Pfisterer 2000): orthotropic branches built like the trunk, so no plagiotropism
876
+ // 3: surface roots on the flare crests
877
+ config.branches.push(make_surface_roots(2.2));
878
+ config.branch_rules.push(make_surface_roots_rule(3, config.branches[0].flare_lobes));
879
+ // 4: long shoots and 5: short shoots of the twig system, grown year by year on the boughs and branches
880
+ config.branches.push(make_twig_generator({ gravitropism: 0.06, phototropism: 0.3 }), make_short_shoot_generator());
881
+ // Red maple's long and short shoots, from Wilson (1966), Development of the shoot system of Acer rubrum L.,
882
+ // Harvard Forest Paper 14 [W1966], and Critchfield (1971), J. Arnold Arboretum 52: 240-266 [C1971], in Wilson's
883
+ // orders (the stem is 1): a bough is his 2nd order, a branch his 3rd:
884
+ // - a long shoot's top pairs grow long shoots, its middle pairs short ones [W1966 p. 3, Fig. 1]: net, 1.8, 1.5,
885
+ // 0.1, 0.03 long and 4 short laterals a year from orders 1-4 [W1966 p. 10, Table 2]. These are net counts, so
886
+ // nothing is shed past them in light: the vigour, 2.8, is above every order's yield. Red maple bears shade, so
887
+ // its compensation light is spruce's, as is its saturation; neither was measured for maple;
888
+ // - long shoots grow 8.8, 4.5, 3.6, 3.4, 2.7 cm a year at orders 2-6 [W1966 p. 6], the leader about 30 cm
889
+ // [W1966 p. 6], at most 54 cm [C1971 p. 242];
890
+ // - a short shoot grows under 2 cm a year and bears 2 leaf pairs [W1966 p. 2; C1971 Table 1]. Its yearly survival
891
+ // is fitted so short shoots are 85-95% of all shoots [W1966 p. 10]. Its growth is chosen within that bound.
892
+ const MAPLE_TERMINAL_LENGTH = [0.30, 0.088, 0.045, 0.036, 0.034, 0.027];
893
+ // the leader grows about 30 cm a year for 40 years [W1966 p. 6]
894
+ config.shoot_growth.applyOverrides({
895
+ leader_growth: 0.30,
896
+ vigour: 2.8,
897
+ compensation_light: 0.16,
898
+ saturation_light: 0.30
899
+ });
900
+ config.shoot_rules = [1, 2].map(source => ShootSystemRule.from({
901
+ source,
902
+ target: 4,
903
+ short_target: 5,
904
+ max_order: 7,
905
+ carrier_order: source + 1,
906
+ terminal_length: MAPLE_TERMINAL_LENGTH,
907
+ mean_unit_length: MAPLE_TERMINAL_LENGTH[source],
908
+ max_unit_length: [0.54],
909
+ length_negative_binomial_p: [],
910
+ zones: [
911
+ ShootBudZone.from({
912
+ u_min: 0.8,
913
+ u_max: 0.99,
914
+ buds: [2],
915
+ long: [0.9, 0.75, 0.05, 0.015],
916
+ length: [0.088, 0.045, 0.036, 0.034, 0.027]
917
+ }),
918
+ ShootBudZone.from({
919
+ u_min: 0.3,
920
+ u_max: 0.8,
921
+ buds: [4],
922
+ short: [1]
923
+ })
924
+ ],
925
+ short_shoot_growth: 0.005,
926
+ short_shoot_survival: 0.85,
927
+ phyllotaxis_mode: PhyllotaxisMode.OppositeDecussate
928
+ }));
929
+ // A long shoot bears 2 preformed leaf pairs [C1971 p. 244] and 7.8 pairs at 8.8 cm [C1971 Table 1; W1966 p. 6];
930
+ // a short shoot 2 pairs [W1966 p. 2; C1971 Table 1]; a card a leaf
931
+ config.foliage.applyOverrides({
932
+ card_type: FoliageCardType.CutoutHull,
933
+ leaves_per_unit: 4,
934
+ leaves_per_metre: (15.6 - 4) / 0.088,
935
+ leaves_per_short_shoot: 4,
936
+ fold_angle: 0.25
937
+ });
938
+ config.foliage_rules = [1, 2, 4].map(source => FoliageSpawnRule.from({
939
+ source,
940
+ phyllotaxis_mode: PhyllotaxisMode.OppositeDecussate
941
+ }));
942
+ config.foliage_rules.push(FoliageSpawnRule.from({ source: 5, short_shoot: true }));
943
+ config.bark_material.applyOverrides({
944
+ bark_type: FoliageBarkType.Fissured,
945
+ primary_color: [0.36, 0.34, 0.31],
946
+ secondary_color: [0.16, 0.15, 0.14],
947
+ inner_bark_color: [0.38, 0.32, 0.27],
948
+ fissure_frequency: 7,
949
+ fissure_depth: 0.66,
950
+ roughness: 0.90
951
+ });
952
+ config.foliage_material.applyOverrides({
953
+ primary_color: [0.24, 0.45, 0.15],
954
+ secondary_color: [0.42, 0.28, 0.12],
955
+ autumn_tint: 0.22,
956
+ // Red maple's leaf: 6.8 cm long, a long-shoot leaf of 39 cm^2 [W1966 p. 6, Table 4]; palmately 3-lobed, the
957
+ // early leaves' lobes nearly equal, the lateral lobes' axes 73-86 degrees apart, the midlobe 46-56% of the blade
958
+ // (its sinuses about half way to the petiole), the petiole 60-114% of the blade [C1971]; lobes acute and coarsely
959
+ // doubly serrate (Gleason & Cronquist); base truncate to cordate (Trees and Shrubs Online). The lobes' own
960
+ // shape, the lateral lobes' length and the teeth are estimates
961
+ leaf: {
962
+ blade_length: 0.068,
963
+ length_width_ratio: 1.2,
964
+ widest_at: 0.3,
965
+ apex_angle: 1.2,
966
+ apex_shape: LeafApexShape.Straight,
967
+ base_angle: 2.0,
968
+ base_shape: LeafBaseShape.Rounded,
969
+ lobation: LeafLobation.Palmate,
970
+ lobes: 3,
971
+ lobe_spread: 80 * Math.PI / 180,
972
+ lateral_lobe_length: 0.85,
973
+ sinus_depth: 0.5,
974
+ teeth_per_cm: 3,
975
+ tooth_depth: 0.0015,
976
+ tooth_orders: 2,
977
+ secondary_veins: 3,
978
+ secondary_angle: 0.8,
979
+ petiole_length: 0.87 * 0.068
980
+ },
981
+ juvenile_color_shift: 0.40,
982
+ juvenile_anthocyanin: 0.18,
983
+ carotenoid_density: 0.88,
984
+ anthocyanin_potential: 0.90,
985
+ tannin_oxidation: 0.18
986
+ });
987
+ break;
988
+ }
989
+
990
+ case TreePreset.Spruce: {
991
+ config.name = "spruce";
992
+ config.preset = TreePreset.Spruce;
993
+ config.crown.applyOverrides({
994
+ envelope_type: CrownEnvelopeType.Conical,
995
+ height: 9.5,
996
+ radius: 3.6,
997
+ base_height: 1.4,
998
+ prune_ratio: 0.3,
999
+ space_colonization_weight: 0.08,
1000
+ pipe_model_exponent: 2.45,
1001
+ pipe_model_weight: 0.55,
1002
+ sky_phototropism_mix: 0.3
1003
+ });
1004
+ config.branches = [
1005
+ BranchGeneratorConfig.from({
1006
+ excurrent: true,
1007
+ segments: 10,
1008
+ radial_segments_max: 10,
1009
+ radial_segments_min: 4,
1010
+ length: 11.8,
1011
+ radius_ratio: 0.036,
1012
+ taper: 0.92,
1013
+ curvature: 0.02,
1014
+ gravitropism: -0.08,
1015
+ phototropism: 0.06,
1016
+ gnarl_strength: 0.02,
1017
+ flare_amplitude: 0.2,
1018
+ flare_lobes: 4,
1019
+ collar_weld_rings: 0
1020
+ }),
1021
+ BranchGeneratorConfig.from({
1022
+ self_pruning: 0.2, // Norway spruce keeps a skirt of dead branches for decades
1023
+ segments: 5,
1024
+ radial_segments_max: 6,
1025
+ radial_segments_min: 3,
1026
+ length: 3.6,
1027
+ radius_ratio: 0.032,
1028
+ taper: 0.86,
1029
+ curvature: 0.18,
1030
+ curve_back: -0.10,
1031
+ gravitropism: 0.16,
1032
+ plagiotropism: 0.7, // Massart's model (Pfisterer 2000): tiers of plagiotropic branches
1033
+ phototropism: 0.12,
1034
+ collar_weld_rings: 2
1035
+ }),
1036
+ // Inter-whorl branches: short laterals spiralling along the internodes between whorls
1037
+ BranchGeneratorConfig.from({
1038
+ self_pruning: 0.2, // Norway spruce keeps a skirt of dead branches for decades
1039
+ segments: 4,
1040
+ radial_segments_max: 5,
1041
+ radial_segments_min: 3,
1042
+ length: 1.7,
1043
+ length_variance: 0.18,
1044
+ radius_ratio: 0.031,
1045
+ taper: 0.86,
1046
+ curvature: 0.16,
1047
+ curve_back: -0.08,
1048
+ gravitropism: 0.20,
1049
+ plagiotropism: 0.7, // Massart's model (Pfisterer 2000): tiers of plagiotropic branches
1050
+ phototropism: 0.12,
1051
+ collar_weld_rings: 1
1052
+ }),
1053
+ BranchGeneratorConfig.from({
1054
+ segments: 3,
1055
+ radial_segments_max: 4,
1056
+ radial_segments_min: 3,
1057
+ length: 1.1,
1058
+ radius_ratio: 0.03,
1059
+ taper: 0.85,
1060
+ curvature: 0.15,
1061
+ gravitropism: 0.18,
1062
+ plagiotropism: 0.7, // Massart's model (Pfisterer 2000): tiers of plagiotropic branches
1063
+ phototropism: 0.2,
1064
+ collar_weld_rings: 1
1065
+ })
1066
+ ];
1067
+ config.branch_rules = [
1068
+ BranchSpawnRule.from({
1069
+ source: 0,
1070
+ target: 1,
1071
+ count: 35,
1072
+ attach_min: 0.12,
1073
+ phyllotaxis_mode: PhyllotaxisMode.Whorled,
1074
+ whorl_count: 5,
1075
+ insertion_angle: 1.38,
1076
+ insertion_angle_profile: AnimationCurve.linear(0, 1.05, 1, 0.56),
1077
+ length_profile: AnimationCurve.linear(0, 1.0, 1, 0.68),
1078
+ parent_kink: 0.0
1079
+ }),
1080
+ BranchSpawnRule.from({
1081
+ source: 0,
1082
+ target: 2,
1083
+ count: 16,
1084
+ attach_min: 0.16,
1085
+ phyllotaxis_mode: PhyllotaxisMode.SpiralGolden,
1086
+ azimuth_jitter: 0.30,
1087
+ insertion_angle: 1.25,
1088
+ insertion_angle_profile: AnimationCurve.linear(0, 1.05, 1, 0.58),
1089
+ length_profile: AnimationCurve.linear(0, 1.0, 1, 0.55),
1090
+ parent_kink: 0.0
1091
+ }),
1092
+ // Whorl boughs and inter-whorl branches both carry the same twigs
1093
+ BranchSpawnRule.from({
1094
+ source: 1,
1095
+ target: 3,
1096
+ count: 6,
1097
+ attach_min: 0.1,
1098
+ phyllotaxis_mode: PhyllotaxisMode.AlternateDistichous,
1099
+ insertion_angle: 0.9
1100
+ }),
1101
+ BranchSpawnRule.from({
1102
+ source: 2,
1103
+ target: 3,
1104
+ count: 3,
1105
+ attach_min: 0.15,
1106
+ phyllotaxis_mode: PhyllotaxisMode.AlternateDistichous,
1107
+ insertion_angle: 0.9
1108
+ })
1109
+ ];
1110
+ // 4: surface roots on the flare crests
1111
+ config.branches.push(make_surface_roots(1.7));
1112
+ config.branch_rules.push(make_surface_roots_rule(4, config.branches[0].flare_lobes));
1113
+ // 5: the twig system, grown year by year on the boughs, inter-whorl branches and twigs, in their plane
1114
+ config.branches.push(make_twig_generator({ gravitropism: 0.18, phototropism: 0.2, plagiotropism: 0.7 }));
1115
+ // No fit of spruce's bud counts was found: each shoot grows one lateral from its whorl, the top 20% of a unit
1116
+ // [Colin & Houllier 1992, Ann. Sci. For. 49: 511-538], and shedding by light keeps Rb. Its new
1117
+ // shoots are 4.8 cm (2.2-11.3) [Bellan et al. 2019, Austrian J. For. Sci. 136: 1-26], at 40-70 degrees [Fabrika
1118
+ // et al. 2019, BioResources 14: 908-921, Table 7]; how lengths fall with order is Scots pine's [KK1991]
1119
+ // Rb, the net shoots a shoot leaves a year, rises with light from about 0.65 at 0.12 of full light to 2.2 at 0.30,
1120
+ // up to 2.19 measured [Niinemets & Lukjanova 2003, New Phytol. 158: 75-89, Fig. 5b, Table 1]: 1 at 0.16. A
1121
+ // shoot's needles are bunched: its silhouette is 0.164 of its needle area against a random 0.25 (Stenberg et al.
1122
+ // 1995, Tree Physiol. 15: 705-712, as recalculated in later work; second-hand)
1123
+ // no spruce leader growth was found: Scots pine's [KK1991 Eq. 6]
1124
+ config.shoot_growth.applyOverrides({
1125
+ leader_growth: 0.475,
1126
+ vigour: 2.19,
1127
+ compensation_light: 0.16,
1128
+ saturation_light: 0.30,
1129
+ leaf_clumping: 0.164 / 0.25
1130
+ });
1131
+ config.shoot_rules = [1, 2, 3].map(source => make_conifer_shoot_rule(source, 5, {
1132
+ carrier_order: source === 3 ? 2 : 1,
1133
+ mean_unit_length: 0.048,
1134
+ max_unit_length: [0.113],
1135
+ insertion_angle: [0.96],
1136
+ zones: [
1137
+ ShootBudZone.from({
1138
+ u_min: 0.8,
1139
+ u_max: 0.99,
1140
+ buds: [1],
1141
+ long: [1],
1142
+ length: [0],
1143
+ length_slope: [0.458, 0.355, 0.475]
1144
+ })
1145
+ ]
1146
+ }));
1147
+ // the leader as Scots pine's: no spruce leader growth was found
1148
+ config.shoot_rules.push(make_conifer_leader_rule(5));
1149
+ // Needles 18-31 a cm [Bellan et al. 2019]; of a year's needles about 1, 0.93, 0.93, 0.80, 0.76, 0.70, 0.57, 0.55,
1150
+ // 0.19 are alive at ages 1-9 [Niinemets & Lukjanova 2003 Fig. 4]. No needle length was found: 18 mm is chosen
1151
+ config.foliage.applyOverrides({
1152
+ card_type: FoliageCardType.CrossCard,
1153
+ leaves_per_unit: 0,
1154
+ leaves_per_metre: 2450,
1155
+ leaf_survival: [1, 0.93, 0.93, 0.80, 0.76, 0.70, 0.57, 0.55, 0.19]
1156
+ });
1157
+ config.foliage_rules = [0, 1, 2, 3, 5].map(source => FoliageSpawnRule.from({ source }));
1158
+ config.bark_material.applyOverrides({
1159
+ bark_type: FoliageBarkType.Plated,
1160
+ primary_color: [0.36, 0.29, 0.24],
1161
+ secondary_color: [0.15, 0.12, 0.10],
1162
+ inner_bark_color: [0.42, 0.30, 0.22],
1163
+ fissure_frequency: 8,
1164
+ fissure_depth: 0.72,
1165
+ roughness: 0.91
1166
+ });
1167
+ config.foliage_material.applyOverrides({
1168
+ primary_color: [0.11, 0.27, 0.15],
1169
+ secondary_color: [0.07, 0.18, 0.10],
1170
+ // a card is a stretch of shoot as long as a needle with the needles the shoot bears there, on two planes
1171
+ tile_content: FoliageTileContent.NeedleShoot,
1172
+ // the needle, 18 mm (chosen, above); no width was found: 1 mm is chosen
1173
+ leaf: {
1174
+ blade_length: 0.018,
1175
+ length_width_ratio: 18,
1176
+ widest_at: 0.4,
1177
+ apex_angle: 0.5,
1178
+ apex_shape: LeafApexShape.Straight,
1179
+ base_angle: 0.6,
1180
+ base_shape: LeafBaseShape.Straight,
1181
+ secondary_veins: 0,
1182
+ petiole_length: 0
1183
+ },
1184
+ juvenile_color_shift: 0.46,
1185
+ juvenile_anthocyanin: 0.0,
1186
+ carotenoid_density: 0.35,
1187
+ anthocyanin_potential: 0.0,
1188
+ tannin_oxidation: 0.30
1189
+ });
1190
+ break;
1191
+ }
1192
+
1193
+ case TreePreset.Palm: {
1194
+ config.name = "palm";
1195
+ config.preset = TreePreset.Palm;
1196
+ config.crown.applyOverrides({
1197
+ envelope_type: CrownEnvelopeType.Hemispherical,
1198
+ height: 11.0,
1199
+ radius: 4.2,
1200
+ base_height: 7.5,
1201
+ prune_ratio: 0.1,
1202
+ space_colonization_weight: 0.0,
1203
+ pipe_model_weight: 0.15
1204
+ });
1205
+ config.branches = [
1206
+ BranchGeneratorConfig.from({
1207
+ segments: 10,
1208
+ radial_segments_max: 10,
1209
+ radial_segments_min: 7,
1210
+ length: 9.5,
1211
+ radius_ratio: 0.038,
1212
+ taper: 0.35,
1213
+ curvature: 0.28,
1214
+ curve_back: -0.12,
1215
+ gravitropism: -0.08,
1216
+ phototropism: 0.22,
1217
+ gnarl_strength: 0.04,
1218
+ flare_amplitude: 0.25,
1219
+ flare_height_ratio: 0.12,
1220
+ flare_lobes: 6,
1221
+ collar_weld_rings: 0
1222
+ }),
1223
+ BranchGeneratorConfig.from({
1224
+ segments: 5,
1225
+ radial_segments_max: 5,
1226
+ radial_segments_min: 3,
1227
+ length: 2.8,
1228
+ radius_ratio: 0.025,
1229
+ taper: 0.9,
1230
+ curvature: 0.55,
1231
+ gravitropism: 0.48,
1232
+ phototropism: 0.15,
1233
+ collar_weld_rings: 1
1234
+ })
1235
+ ];
1236
+ config.branch_rules = [
1237
+ BranchSpawnRule.from({
1238
+ source: 0,
1239
+ target: 1,
1240
+ count: 12,
1241
+ attach_min: 0.92,
1242
+ phyllotaxis_mode: PhyllotaxisMode.SpiralGolden,
1243
+ insertion_angle: 0.95,
1244
+ insertion_angle_variation: 0.25,
1245
+ // a palm is a monocot: its fronds leave ringed scars but never deflect the stem
1246
+ parent_kink: 0.0
1247
+ })
1248
+ ];
1249
+ config.foliage.applyOverrides({
1250
+ card_type: FoliageCardType.RibbedFrond,
1251
+ fold_angle: 0.32,
1252
+ arch_height: 0.22,
1253
+ camber_droop: 0.32,
1254
+ frond_segments: 6,
1255
+ gravitropism: 0.45,
1256
+ phototropism: 0.4
1257
+ });
1258
+ config.foliage_rules = [
1259
+ FoliageSpawnRule.from({
1260
+ source: 1,
1261
+ attach_min: 0.05
1262
+ })
1263
+ ];
1264
+ config.bark_material.applyOverrides({
1265
+ bark_type: FoliageBarkType.Ringed,
1266
+ primary_color: [0.54, 0.46, 0.36],
1267
+ secondary_color: [0.26, 0.21, 0.15],
1268
+ fissure_frequency: 5,
1269
+ fissure_depth: 0.62,
1270
+ lenticel_amount: 0.45
1271
+ });
1272
+ config.foliage_material.applyOverrides({
1273
+ primary_color: [0.22, 0.46, 0.14],
1274
+ secondary_color: [0.15, 0.34, 0.09],
1275
+ // a pinnate frond, its leaflets in pairs along the rachis. The palm is no particular species: its sizes are
1276
+ // chosen
1277
+ leaf: {
1278
+ blade_length: 0.74,
1279
+ length_width_ratio: 2.8,
1280
+ widest_at: 0.45,
1281
+ apex_angle: 0.7,
1282
+ apex_shape: LeafApexShape.Straight,
1283
+ base_angle: 0.7,
1284
+ base_shape: LeafBaseShape.Straight,
1285
+ secondary_veins: 0,
1286
+ petiole_length: 0.07,
1287
+ leaflets: 11,
1288
+ rachis_length: 1.0
1289
+ }
1290
+ });
1291
+ break;
1292
+ }
1293
+
1294
+ case TreePreset.Shrub: {
1295
+ config.name = "shrub";
1296
+ config.preset = TreePreset.Shrub;
1297
+ config.crown.applyOverrides({
1298
+ envelope_type: CrownEnvelopeType.Hemispherical,
1299
+ height: 2.8,
1300
+ radius: 2.2,
1301
+ base_height: 0.15,
1302
+ prune_ratio: 0.25,
1303
+ space_colonization_weight: 0.3,
1304
+ pipe_model_exponent: 2.1,
1305
+ pipe_model_weight: 0.55
1306
+ });
1307
+ config.branches = [
1308
+ BranchGeneratorConfig.from({
1309
+ segments: 5,
1310
+ radial_segments_max: 7,
1311
+ radial_segments_min: 4,
1312
+ length: 1.8,
1313
+ radius_ratio: 0.055,
1314
+ taper: 0.8,
1315
+ curvature: 0.25,
1316
+ gravitropism: -0.05,
1317
+ phototropism: 0.28,
1318
+ gnarl_strength: 0.12,
1319
+ split_probability: 0.45,
1320
+ split_count: 3,
1321
+ split_angle: 0.52,
1322
+ collar_weld_rings: 0
1323
+ }),
1324
+ BranchGeneratorConfig.from({
1325
+ segments: 4,
1326
+ radial_segments_max: 5,
1327
+ radial_segments_min: 3,
1328
+ length: 1.2,
1329
+ radius_ratio: 0.04,
1330
+ taper: 0.85,
1331
+ curvature: 0.2,
1332
+ gravitropism: 0.06,
1333
+ phototropism: 0.35,
1334
+ collar_weld_rings: 1
1335
+ })
1336
+ ];
1337
+ config.branch_rules = [
1338
+ BranchSpawnRule.from({
1339
+ source: 0,
1340
+ target: 1,
1341
+ count: 8,
1342
+ attach_min: 0.08,
1343
+ phyllotaxis_mode: PhyllotaxisMode.SpiralGolden,
1344
+ insertion_angle: 0.82
1345
+ })
1346
+ ];
1347
+ // 2: the twig system, grown year by year on the branches
1348
+ config.branches.push(make_twig_generator({ gravitropism: 0.05, phototropism: 0.35 }));
1349
+ // The shrub is a hazel (Corylus avellana). Its numbers are Grisafi et al. (2024), in silico Plants 6(1) diae004,
1350
+ // on an orchard cultivar, as read through a summary of the paper: not yet checked against its tables. A node
1351
+ // holds 1.13 buds; a vegetative bud bursts at 0.97 distally to 0.62 proximally, 86% of nodes bearing one (40%
1352
+ // vegetative, 46% mixed); its shoot is 6.84 cm distally to 0.58 cm proximally; 8 nodes on a 10-25 cm shoot. The
1353
+ // apical bud dies: growth is sympodial. Shoot length is chosen; hazel grows in woodland shade, so its
1354
+ // compensation light is spruce's, as is its saturation. No net shoot yield was found for hazel: in full light a
1355
+ // shoot keeps every shoot its buds grow, the gross yield Grisafi et al. measured on orchard trees in full sun,
1356
+ // so only shade sheds them (Alex's pick, 2026-10-26).
1357
+ const hazel_third = (u_min, u_max, burst, length) => ShootBudZone.from({
1358
+ u_min,
1359
+ u_max,
1360
+ buds: [0],
1361
+ buds_per_metre: [8 / 0.175 * 1.13 / 3],
1362
+ long: [burst * 0.86],
1363
+ length: [length]
1364
+ });
1365
+ // the stems and their branches both carry twigs
1366
+ config.shoot_rules = [0, 1].map(source => ShootSystemRule.from({
1367
+ source,
1368
+ target: 2,
1369
+ max_order: 5,
1370
+ mean_unit_length: 0.175,
1371
+ terminal_length: [0.175],
1372
+ max_unit_length: [0.7],
1373
+ length_negative_binomial_p: [],
1374
+ zones: [
1375
+ hazel_third(0.66, 0.99, 0.97, 0.0684),
1376
+ hazel_third(0.33, 0.66, 0.80, 0.0414),
1377
+ hazel_third(0.0, 0.33, 0.62, 0.0058)
1378
+ ],
1379
+ phyllotaxis_mode: PhyllotaxisMode.AlternateDistichous
1380
+ }));
1381
+ // a hazel stem soon stops gaining height; 0.1 m a year is chosen, so the stool's stems are about 18 years old
1382
+ config.shoot_growth.applyOverrides({
1383
+ leader_growth: 0.1,
1384
+ vigour: shoot_expected_yield(config.shoot_rules[0]),
1385
+ compensation_light: 0.16,
1386
+ saturation_light: 0.30
1387
+ });
1388
+ // 8 leaves a 17.5 cm shoot [Grisafi et al. 2024]; a card a leaf
1389
+ config.foliage.applyOverrides({
1390
+ card_type: FoliageCardType.CutoutHull,
1391
+ leaves_per_unit: 0,
1392
+ leaves_per_metre: 8 / 0.175,
1393
+ phototropism: 0.7
1394
+ });
1395
+ config.foliage_rules = [0, 1, 2].map(source => FoliageSpawnRule.from({ source }));
1396
+ config.foliage_material.applyOverrides({
1397
+ primary_color: [0.22, 0.44, 0.16],
1398
+ secondary_color: [0.14, 0.30, 0.10],
1399
+ // Corylus avellana's leaf [Flora of North America vol. 3; Trees and Shrubs Online]: 5-12 x 4-12 cm, broadly
1400
+ // ovate to elliptic, apex abruptly acuminate, base narrowly cordate, coarsely doubly serrate, 8 or fewer pairs
1401
+ // of lateral veins, petiole 6-12 mm. 8 cm long gives about the 41 cm^2 of a sun leaf [Catoni et al. 2015,
1402
+ // Photosynthetica 53: 35-46, Table 2]. The angles, the lobes' depth below the petiole and the teeth are
1403
+ // estimates from the shape terms
1404
+ leaf: {
1405
+ blade_length: 0.08,
1406
+ length_width_ratio: 8.5 / 8,
1407
+ widest_at: 0.55,
1408
+ apex_angle: 1.6,
1409
+ apex_shape: LeafApexShape.Acuminate,
1410
+ base_angle: 2.6,
1411
+ base_shape: LeafBaseShape.Cordate,
1412
+ base_lobe_depth: 0.06,
1413
+ teeth_per_cm: 0.7,
1414
+ tooth_depth: 0.0025,
1415
+ tooth_orders: 2,
1416
+ secondary_veins: 7,
1417
+ secondary_angle: 0.8,
1418
+ petiole_length: 0.009
1419
+ }
1420
+ });
1421
+ break;
1422
+ }
1423
+
1424
+ case TreePreset.Fern: {
1425
+ config.name = "fern";
1426
+ config.preset = TreePreset.Fern;
1427
+ config.crown.applyOverrides({
1428
+ envelope_type: CrownEnvelopeType.InverseConical,
1429
+ height: 1.6,
1430
+ radius: 1.5,
1431
+ base_height: 0.05,
1432
+ prune_ratio: 0.05,
1433
+ space_colonization_weight: 0.0,
1434
+ pipe_model_weight: 0.2
1435
+ });
1436
+ config.branches = [
1437
+ BranchGeneratorConfig.from({
1438
+ segments: 3,
1439
+ radial_segments_max: 6,
1440
+ radial_segments_min: 4,
1441
+ length: 0.35,
1442
+ radius_ratio: 0.18,
1443
+ taper: 0.6,
1444
+ curvature: 0.1,
1445
+ collar_weld_rings: 0
1446
+ }),
1447
+ BranchGeneratorConfig.from({
1448
+ segments: 5,
1449
+ radial_segments_max: 4,
1450
+ radial_segments_min: 3,
1451
+ length: 1.15,
1452
+ radius_ratio: 0.025,
1453
+ taper: 0.92,
1454
+ curvature: 0.48,
1455
+ gravitropism: 0.38,
1456
+ phototropism: 0.2,
1457
+ collar_weld_rings: 1
1458
+ })
1459
+ ];
1460
+ config.branch_rules = [
1461
+ BranchSpawnRule.from({
1462
+ source: 0,
1463
+ target: 1,
1464
+ count: 9,
1465
+ attach_min: 0.1,
1466
+ phyllotaxis_mode: PhyllotaxisMode.SpiralGolden,
1467
+ insertion_angle: 0.95,
1468
+ // fern fronds rise from the rhizome crown without deflecting it
1469
+ parent_kink: 0.0
1470
+ })
1471
+ ];
1472
+ config.foliage.applyOverrides({
1473
+ card_type: FoliageCardType.RibbedFrond,
1474
+ fold_angle: 0.28,
1475
+ arch_height: 0.16,
1476
+ camber_droop: 0.24,
1477
+ frond_segments: 6,
1478
+ gravitropism: 0.35,
1479
+ phototropism: 0.55
1480
+ });
1481
+ config.foliage_rules = [
1482
+ FoliageSpawnRule.from({
1483
+ source: 1,
1484
+ attach_min: 0.05
1485
+ })
1486
+ ];
1487
+ config.foliage_material.applyOverrides({
1488
+ primary_color: [0.24, 0.50, 0.16],
1489
+ secondary_color: [0.16, 0.36, 0.10],
1490
+ // a pinnate frond, its pinnae in pairs along the rachis. The fern is no particular species: its sizes are
1491
+ // chosen
1492
+ leaf: {
1493
+ blade_length: 0.38,
1494
+ length_width_ratio: 2.8,
1495
+ widest_at: 0.45,
1496
+ apex_angle: 0.7,
1497
+ apex_shape: LeafApexShape.Straight,
1498
+ base_angle: 0.7,
1499
+ base_shape: LeafBaseShape.Straight,
1500
+ secondary_veins: 0,
1501
+ petiole_length: 0.04,
1502
+ leaflets: 11,
1503
+ rachis_length: 0.53
1504
+ }
1505
+ });
1506
+ break;
1507
+ }
1508
+
1509
+ case TreePreset.Oak:
1510
+ default: {
1511
+ config.name = "oak";
1512
+ // Quercus follows Rauh's model (Pfisterer 2000): orthotropic branches built like the trunk, so no plagiotropism
1513
+ config.preset = TreePreset.Oak;
1514
+ // Default trunk (0) -> primary boughs (1) -> secondary branches (2), plus a mature oak's base and bole.
1515
+ // Oak is a moderate self-pruner.
1516
+ config.branches[1].self_pruning = 0.7;
1517
+ config.branches.push(
1518
+ // 3: structural surface roots continuing the trunk's buttress lobes
1519
+ make_surface_roots(2.4),
1520
+ // 4: epicormic water sprouts on the bole and boughs
1521
+ BranchGeneratorConfig.from({
1522
+ segments: 4,
1523
+ radial_segments_max: 4,
1524
+ radial_segments_min: 3,
1525
+ length: 1.6,
1526
+ length_variance: 0.3,
1527
+ radius_ratio: 0.03,
1528
+ taper: 0.9,
1529
+ curvature: 0.25,
1530
+ gravitropism: -0.12,
1531
+ phototropism: 0.5,
1532
+ gnarl_strength: 0.15,
1533
+ internode_zigzag: 0.12,
1534
+ tip_upcurl: 0.2,
1535
+ collar_weld_rings: 1
1536
+ }),
1537
+ // 5: the peripheral twig system, grown year by year on the boughs, branches and sprouts (shoot_rules)
1538
+ BranchGeneratorConfig.from({
1539
+ segments: 1,
1540
+ radial_segments_max: 4,
1541
+ radial_segments_min: 3,
1542
+ length: 0.1,
1543
+ radius_ratio: 0.03,
1544
+ taper: 0.6,
1545
+ gravitropism: 0.1,
1546
+ phototropism: 0.3,
1547
+ internode_zigzag: 0.15,
1548
+ collar_weld_rings: 0
1549
+ })
1550
+ );
1551
+ // Oak's twigs and leaves from the shoot demography of mature oak crowns (Buck-Sorlin & Bell 2000, Forestry
1552
+ // 73(1): 1-19; 1998, Bot. J. Linn. Soc. 127: 371-391): ShootSystemRule's defaults, on every peripheral axis.
1553
+ // No light response was found for oak: the vigour is chosen, the compensation light is Scots pine's (oak is as
1554
+ // light-demanding), the saturation spruce's.
1555
+ // no oak leader growth was found: 0.3 m a year is chosen
1556
+ config.shoot_growth.applyOverrides({
1557
+ leader_growth: 0.3,
1558
+ vigour: 1.3,
1559
+ compensation_light: 0.22,
1560
+ saturation_light: 0.30
1561
+ });
1562
+ config.shoot_rules = [
1563
+ ShootSystemRule.from({ source: 1, target: 5 }),
1564
+ ShootSystemRule.from({ source: 2, target: 5 }),
1565
+ ShootSystemRule.from({ source: 4, target: 5 })
1566
+ ];
1567
+ config.branch_rules.push(
1568
+ make_surface_roots_rule(3, config.branches[0].flare_lobes),
1569
+ BranchSpawnRule.from({
1570
+ source: 0,
1571
+ target: 4,
1572
+ count: 5,
1573
+ attach_min: 0.15,
1574
+ attach_max: 0.6,
1575
+ azimuth_jitter: 0.5,
1576
+ insertion_angle: 0.75,
1577
+ insertion_angle_variation: 0.25,
1578
+ insertion_angle_profile: AnimationCurve.constant(0, 1, 1),
1579
+ parent_kink: 0.0,
1580
+ crown_envelope: false
1581
+ }),
1582
+ BranchSpawnRule.from({
1583
+ source: 1,
1584
+ target: 4,
1585
+ count: 2,
1586
+ attach_min: 0.1,
1587
+ attach_max: 0.5,
1588
+ azimuth_jitter: 0.5,
1589
+ insertion_angle: 0.6,
1590
+ insertion_angle_variation: 0.25,
1591
+ parent_kink: 0.0
1592
+ })
1593
+ );
1594
+ config.foliage_rules = [
1595
+ FoliageSpawnRule.from({
1596
+ source: 2
1597
+ }),
1598
+ FoliageSpawnRule.from({
1599
+ source: 4,
1600
+ }),
1601
+ FoliageSpawnRule.from({
1602
+ source: 5
1603
+ })
1604
+ ];
1605
+ // a leaf in the axil of each bud, FoliageConfig's default leaves per unit (Buck-Sorlin & Bell 2000); a card a leaf
1606
+ config.foliage.applyOverrides({
1607
+ card_type: FoliageCardType.CutoutHull
1608
+ });
1609
+ config.foliage_material.applyOverrides({
1610
+ // Quercus robur's leaf. Mean blade 10.6 and 12.0 cm long, 1.8 and 1.64 times as long as wide, 0.81-0.85 of its
1611
+ // greatest width at mid-length and 0.47-0.50 at 90% of it, the petiole 7.4-8.0% of the blade [Boratynski et al.
1612
+ // 2008, Silva Fennica 42: 115-124, Table 4]: the widest point, the apex and the base angles are fitted to those
1613
+ // widths. Obovate, apex broadly rounded, sinuses 1/3-7/8 of the way to the midrib (the middle taken), entire
1614
+ // [Flora of North America vol. 3]; 5-7 rounded lobes a side [Flora of China], up to 5 pairs [BSBI Plant Crib],
1615
+ // one secondary vein to each; auricles at the base usually strong [BSBI]. The auricles' size and the veins'
1616
+ // angle are estimates
1617
+ leaf: {
1618
+ blade_length: 0.113,
1619
+ length_width_ratio: 1.72,
1620
+ widest_at: 0.675,
1621
+ apex_angle: 1.2,
1622
+ apex_shape: LeafApexShape.Rounded,
1623
+ base_angle: 0.8,
1624
+ base_shape: LeafBaseShape.Lobate,
1625
+ base_lobe_depth: 0.05,
1626
+ lobation: LeafLobation.Pinnate,
1627
+ lobes: 5,
1628
+ sinus_depth: 0.6,
1629
+ secondary_veins: 5,
1630
+ secondary_angle: 0.95,
1631
+ petiole_length: 0.077 * 0.113
1632
+ },
1633
+ juvenile_color_shift: 0.38,
1634
+ juvenile_anthocyanin: 0.14,
1635
+ carotenoid_density: 0.72,
1636
+ anthocyanin_potential: 0.52,
1637
+ tannin_oxidation: 0.68
1638
+ });
1639
+ break;
1640
+ }
1641
+ }
1642
+
1643
+ if (overrides !== undefined && overrides !== null) {
1644
+ config.applyOverrides(overrides);
1645
+ }
1646
+
1647
+ return config;
1648
+ }