@woosh/meep-engine 3.56.0 → 3.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (625) hide show
  1. package/build/bundle-worker-terrain.js +1 -1
  2. package/package.json +1 -1
  3. package/src/DUPLICATION_REVIEW_2026_10_24.md +1072 -0
  4. package/src/core/binary/BitSet.js +1 -1
  5. package/src/core/binary/FLOAT16_MAX.d.ts +2 -0
  6. package/src/core/binary/FLOAT16_MAX.d.ts.map +1 -0
  7. package/src/core/binary/FLOAT16_MAX.js +1 -0
  8. package/src/core/binary/base58/base58_encode.js +2 -2
  9. package/src/core/binary/type/TypeBuilder.js +1 -1
  10. package/src/core/bvh2/bvh3/BVH.js +1 -1
  11. package/src/core/bvh2/bvh3/ebvh_optimize_treelet.d.ts.map +1 -1
  12. package/src/core/bvh2/bvh3/ebvh_optimize_treelet.js +7 -3
  13. package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.d.ts.map +1 -1
  14. package/src/core/bvh2/bvh3/ebvh_update_hierarchy_bounds.js +5 -1
  15. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.d.ts.map +1 -1
  16. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.js +195 -246
  17. package/src/core/collection/CuckooFilter.js +1 -1
  18. package/src/core/collection/array/isArrayEqual.d.ts.map +1 -1
  19. package/src/core/collection/array/isArrayEqual.js +33 -58
  20. package/src/core/collection/array/typed/array_buffer_hash.d.ts.map +1 -1
  21. package/src/core/collection/array/typed/array_buffer_hash.js +41 -39
  22. package/src/core/collection/array/typed/float32_array_hash.js +38 -38
  23. package/src/core/collection/array/typed/uint16_array_hash.d.ts +2 -1
  24. package/src/core/collection/array/typed/uint16_array_hash.d.ts.map +1 -1
  25. package/src/core/collection/array/typed/uint16_array_hash.js +30 -29
  26. package/src/core/collection/array/typed/uint32_array_hash.d.ts +2 -1
  27. package/src/core/collection/array/typed/uint32_array_hash.d.ts.map +1 -1
  28. package/src/core/collection/array/typed/uint32_array_hash.js +21 -20
  29. package/src/core/collection/array/typed/uint8_array_hash.d.ts +2 -1
  30. package/src/core/collection/array/typed/uint8_array_hash.d.ts.map +1 -1
  31. package/src/core/collection/array/typed/uint8_array_hash.js +37 -36
  32. package/src/core/collection/array/typed/uint_array_for_count.js +2 -2
  33. package/src/core/collection/list/List.d.ts.map +1 -1
  34. package/src/core/collection/list/List.js +3 -19
  35. package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
  36. package/src/core/collection/table/RowFirstTable.js +4 -28
  37. package/src/core/debug/matchers/DescribeAs.d.ts.map +1 -1
  38. package/src/core/debug/matchers/DescribeAs.js +62 -64
  39. package/src/core/function/FunctionCompiler.js +4 -4
  40. package/src/core/function/objectsEqual.d.ts.map +1 -1
  41. package/src/core/function/objectsEqual.js +3 -2
  42. package/src/core/geom/2d/bvh/BVH2D.d.ts.map +1 -1
  43. package/src/core/geom/2d/bvh/BVH2D.js +4 -3
  44. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts +5 -2
  45. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts.map +1 -1
  46. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js +49 -11
  47. package/src/core/geom/2d/hash-grid/shg_query_elements_circle.d.ts.map +1 -1
  48. package/src/core/geom/2d/hash-grid/shg_query_elements_circle.js +122 -159
  49. package/src/core/geom/2d/hash-grid/shg_query_elements_line.d.ts.map +1 -1
  50. package/src/core/geom/2d/hash-grid/shg_query_elements_line.js +8 -5
  51. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts +18 -0
  52. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.d.ts.map +1 -0
  53. package/src/core/geom/2d/polygon/polygon2_rasterize_coverage.js +97 -0
  54. package/src/core/geom/2d/r-tree/StaticR2Tree.js +2 -2
  55. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts +21 -0
  56. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.d.ts.map +1 -0
  57. package/src/core/geom/2d/triangle/tri2_rasterize_coverage.js +54 -0
  58. package/src/core/geom/3d/aabb/aabb3_build_frustum.d.ts.map +1 -1
  59. package/src/core/geom/3d/aabb/aabb3_build_frustum.js +20 -53
  60. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts +1 -1
  61. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.d.ts.map +1 -1
  62. package/src/core/geom/3d/aabb/aabb3_score_boxes_SAH.js +11 -42
  63. package/src/core/geom/3d/atlas/pack/atlas_pack_charts.d.ts.map +1 -1
  64. package/src/core/geom/3d/atlas/pack/atlas_pack_charts.js +30 -32
  65. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.d.ts.map +1 -1
  66. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.js +1 -5
  67. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.d.ts.map +1 -1
  68. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.js +1 -15
  69. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.d.ts.map +1 -1
  70. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.js +105 -116
  71. package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.d.ts.map +1 -1
  72. package/src/core/geom/3d/line/line3_compute_segment_point_distance_sqr.js +36 -54
  73. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts +5 -10
  74. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.d.ts.map +1 -1
  75. package/src/core/geom/3d/plane/plane3_compute_intersection_objects.js +20 -82
  76. package/src/core/geom/3d/plane/plane3_slerp.d.ts.map +1 -1
  77. package/src/core/geom/3d/plane/plane3_slerp.js +87 -102
  78. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts +12 -0
  79. package/src/core/geom/3d/polygon/polygon3_compute_normal.d.ts.map +1 -1
  80. package/src/core/geom/3d/polygon/polygon3_compute_normal.js +107 -60
  81. package/src/core/geom/3d/ray/ray3_compute_closest_point.d.ts.map +1 -1
  82. package/src/core/geom/3d/ray/ray3_compute_closest_point.js +37 -43
  83. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
  84. package/src/core/geom/3d/shape/ConvexHullShape3D.js +5 -16
  85. package/src/core/geom/3d/shape/MeshShape3D.js +2 -56
  86. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  87. package/src/core/geom/3d/shape/TransformedShape3D.js +10 -7
  88. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  89. package/src/core/geom/3d/shape/UnionShape3D.js +9 -3
  90. package/src/core/geom/3d/shape/json/shape_to_type.js +2 -2
  91. package/src/core/geom/3d/sphere/harmonics/SH3_COEFFICIENTS.js +17 -17
  92. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.d.ts.map +1 -1
  93. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.js +6 -2
  94. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.d.ts.map +1 -1
  95. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js +3 -2
  96. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts +20 -2
  97. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts.map +1 -1
  98. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +52 -37
  99. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.d.ts.map +1 -1
  100. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js +40 -56
  101. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
  102. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +251 -260
  103. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.d.ts.map +1 -1
  104. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_wedge_attribute_quadrics.js +104 -113
  105. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.d.ts.map +1 -1
  106. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_resolve_t_junctions.js +227 -238
  107. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  108. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +15 -24
  109. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.d.ts.map +1 -1
  110. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.js +31 -115
  111. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.d.ts.map +1 -1
  112. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.js +142 -150
  113. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
  114. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +151 -194
  115. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.d.ts.map +1 -1
  116. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_incenter.js +60 -85
  117. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.d.ts.map +1 -1
  118. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.js +156 -171
  119. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.d.ts.map +1 -1
  120. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.js +8 -44
  121. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
  122. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +2 -7
  123. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.d.ts.map +1 -1
  124. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.js +3 -2
  125. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.d.ts.map +1 -1
  126. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.js +128 -133
  127. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts +8 -14
  128. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.d.ts.map +1 -1
  129. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.js +36 -82
  130. package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts.map +1 -1
  131. package/src/core/geom/3d/triangle/tri3_ray_intersection.js +7 -144
  132. package/src/core/geom/ConicRay.d.ts.map +1 -1
  133. package/src/core/geom/ConicRay.js +230 -237
  134. package/src/core/localization/LocaleDataset.d.ts +6 -0
  135. package/src/core/localization/LocaleDataset.d.ts.map +1 -1
  136. package/src/core/localization/LocaleDataset.js +48 -37
  137. package/src/core/localization/LocalizationEngine.d.ts.map +1 -1
  138. package/src/core/localization/LocalizationEngine.js +3 -2
  139. package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
  140. package/src/core/math/lookup/ParameterLookupTable.js +3 -1
  141. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.d.ts.map +1 -1
  142. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_nd.js +330 -400
  143. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts +16 -0
  144. package/src/core/math/spline/spline3_hermite_nearest_point.d.ts.map +1 -1
  145. package/src/core/math/spline/spline3_hermite_nearest_point.js +134 -167
  146. package/src/core/model/DebouncedObservedBoolean.d.ts +1 -2
  147. package/src/core/model/DebouncedObservedBoolean.d.ts.map +1 -1
  148. package/src/core/model/DebouncedObservedBoolean.js +1 -1
  149. package/src/core/model/node-graph/node/NodeInstance.d.ts.map +1 -1
  150. package/src/core/model/node-graph/node/NodeInstance.js +2 -7
  151. package/src/core/model/node-graph/node/parameter/NodeParameterDescription.js +1 -1
  152. package/src/core/model/object/optional_equality.d.ts +3 -3
  153. package/src/core/model/object/optional_equality.d.ts.map +1 -1
  154. package/src/core/model/object/optional_equality.js +10 -27
  155. package/src/core/model/object/write_property.js +1 -1
  156. package/src/core/model/reactive/evaluation/MultiPredicateEvaluator.js +2 -2
  157. package/src/core/primitives/strings/string_compute_byte_size.d.ts +3 -3
  158. package/src/core/primitives/strings/string_compute_byte_size.d.ts.map +1 -1
  159. package/src/core/primitives/strings/string_compute_byte_size.js +8 -21
  160. package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
  161. package/src/core/process/executor/ConcurrentExecutor.js +14 -2
  162. package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts +6 -3
  163. package/src/engine/achievements/gateway/StorageAchievementGateway.d.ts.map +1 -1
  164. package/src/engine/achievements/gateway/StorageAchievementGateway.js +31 -75
  165. package/src/engine/asset/loaders/SVGAssetLoader.d.ts.map +1 -1
  166. package/src/engine/asset/loaders/SVGAssetLoader.js +33 -31
  167. package/src/engine/control/first-person/math/criticallyDampedSpring.d.ts.map +1 -1
  168. package/src/engine/control/first-person/math/criticallyDampedSpring.js +3 -14
  169. package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
  170. package/src/engine/ecs/EntityComponentDataset.js +4 -1
  171. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts +0 -2
  172. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.d.ts.map +1 -1
  173. package/src/engine/ecs/storage/binary/object/BinaryObjectSerializationAdapter.js +3 -3
  174. package/src/engine/ecs/terrain/ecs/layers/TerrainLayer.js +2 -2
  175. package/src/engine/graphics/sh3/path_tracer/geometry/sort_triangles_by_distance_to_point.js +1 -1
  176. package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.js +1 -1
  177. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  178. package/src/engine/graphics3/WaterSystem.js +2 -1
  179. package/src/engine/graphics3/prefab/prefab_skin_frame.d.ts.map +1 -1
  180. package/src/engine/graphics3/prefab/prefab_skin_frame.js +1 -12
  181. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts +1 -1
  182. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
  183. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +141 -137
  184. package/src/engine/input/ecs/systems/InputControllerSystem.d.ts.map +1 -1
  185. package/src/engine/input/ecs/systems/InputControllerSystem.js +13 -3
  186. package/src/engine/input/ecs/systems/InputSystem.d.ts.map +1 -1
  187. package/src/engine/input/ecs/systems/InputSystem.js +2 -1
  188. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts +1 -1
  189. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts.map +1 -1
  190. package/src/engine/intelligence/behavior/composite/ParallelBehavior.js +4 -1
  191. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.d.ts.map +1 -1
  192. package/src/engine/intelligence/behavior/decorator/InvertStatusBehavior.js +3 -1
  193. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.d.ts.map +1 -1
  194. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.js +3 -1
  195. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.d.ts.map +1 -1
  196. package/src/engine/intelligence/behavior/decorator/RepeatBehaviorSerializationAdapter.js +39 -33
  197. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts +5 -0
  198. package/src/engine/intelligence/behavior/util/ConditionalBehavior.d.ts.map +1 -1
  199. package/src/engine/intelligence/behavior/util/ConditionalBehavior.js +93 -75
  200. package/src/engine/intelligence/behavior/util/RotationBehavior.d.ts.map +1 -1
  201. package/src/engine/intelligence/behavior/util/RotationBehavior.js +79 -76
  202. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts +1 -0
  203. package/src/engine/intelligence/blackboard/BlackboardStack.d.ts.map +1 -1
  204. package/src/engine/intelligence/blackboard/BlackboardStack.js +159 -123
  205. package/src/engine/intelligence/mcts/StateNode.d.ts.map +1 -1
  206. package/src/engine/intelligence/mcts/StateNode.js +366 -364
  207. package/src/engine/intelligence/resource/ResourceAllocationSolver.js +1 -1
  208. package/src/engine/navigation/ecs/components/Path.d.ts.map +1 -1
  209. package/src/engine/navigation/ecs/components/Path.js +2 -1
  210. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.d.ts.map +1 -1
  211. package/src/engine/navigation/ecs/path_following/PathFollowingSystem.js +5 -2
  212. package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
  213. package/src/engine/physics/body/SolverBodyState.js +2 -6
  214. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  215. package/src/engine/physics/ccd/linear_sweep.js +3 -16
  216. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.d.ts.map +1 -1
  217. package/src/engine/physics/cloth/build/cloth_proxy_from_joints.js +2 -16
  218. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts +13 -1
  219. package/src/engine/physics/cloth/ecs/cloth_build_rows.d.ts.map +1 -1
  220. package/src/engine/physics/cloth/ecs/cloth_build_rows.js +15 -4
  221. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  222. package/src/engine/physics/ecs/PhysicsSystem.js +2 -5
  223. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts +12 -0
  224. package/src/engine/physics/inertia/locked_inverse_inertia.d.ts.map +1 -0
  225. package/src/engine/physics/inertia/locked_inverse_inertia.js +22 -0
  226. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
  227. package/src/engine/physics/integration/integrate_velocity.js +3 -18
  228. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts +1 -0
  229. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
  230. package/src/engine/physics/mls-mpm/MLS_MPM.js +5 -4
  231. package/src/engine/physics/narrowphase/convex_decomposition.d.ts.map +1 -1
  232. package/src/engine/physics/narrowphase/convex_decomposition.js +7 -16
  233. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  234. package/src/engine/physics/vehicle/RaycastVehicle.js +15 -5
  235. package/src/engine/save/StorageBackedList.d.ts +5 -0
  236. package/src/engine/save/StorageBackedList.d.ts.map +1 -1
  237. package/src/engine/save/StorageBackedList.js +161 -144
  238. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  239. package/src/engine/simulation/Ticker.js +394 -391
  240. package/src/engine/sound/simulation/probe/AcousticProbeField.d.ts.map +1 -1
  241. package/src/engine/sound/simulation/probe/AcousticProbeField.js +6 -19
  242. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts +15 -0
  243. package/src/engine/sound/simulation/probe/probe_edge_visible.d.ts.map +1 -1
  244. package/src/engine/sound/simulation/probe/probe_edge_visible.js +59 -41
  245. package/src/engine/sound/simulation/probe/probe_refine_connectivity.d.ts.map +1 -1
  246. package/src/engine/sound/simulation/probe/probe_refine_connectivity.js +164 -181
  247. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts.map +1 -1
  248. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +20 -5
  249. package/src/format/image/avif/av1/decode/Av1FrameContext.d.ts.map +1 -1
  250. package/src/format/image/avif/av1/decode/Av1FrameContext.js +3 -10
  251. package/src/format/image/avif/av1/decode/reconstruct.d.ts +20 -0
  252. package/src/format/image/avif/av1/decode/reconstruct.d.ts.map +1 -1
  253. package/src/format/image/avif/av1/decode/reconstruct.js +22 -9
  254. package/src/format/image/avif/av1/encode/choose_restoration.js +2 -18
  255. package/src/format/image/avif/av1/encode/quantise.d.ts.map +1 -1
  256. package/src/format/image/avif/av1/encode/quantise.js +1 -55
  257. package/src/format/image/avif/av1/filter/loop_restoration.d.ts +9 -0
  258. package/src/format/image/avif/av1/filter/loop_restoration.d.ts.map +1 -1
  259. package/src/format/image/avif/av1/filter/loop_restoration.js +1 -1
  260. package/src/format/texture/basis/transcode/etc1s_to_bc7.js +2 -33
  261. package/src/format/texture/basis/transcode/fit_endpoints.d.ts +11 -0
  262. package/src/format/texture/basis/transcode/fit_endpoints.d.ts.map +1 -1
  263. package/src/format/texture/basis/transcode/fit_endpoints.js +1 -1
  264. package/src/format/texture/basis/uastc/uastc_decode_block.d.ts.map +1 -1
  265. package/src/format/texture/basis/uastc/uastc_decode_block.js +2 -19
  266. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +220 -0
  267. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +172 -0
  268. package/src/generation/foliage/FOLIAGE_DESIGN.md +165 -15
  269. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +158 -0
  270. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +248 -0
  271. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +694 -0
  272. package/src/generation/foliage/analysis/CrownOpacity.d.ts +118 -0
  273. package/src/generation/foliage/analysis/CrownOpacity.d.ts.map +1 -0
  274. package/src/generation/foliage/analysis/CrownOpacity.js +182 -0
  275. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts +10 -0
  276. package/src/generation/foliage/analysis/crown_opacity_frames.d.ts.map +1 -0
  277. package/src/generation/foliage/analysis/crown_opacity_frames.js +132 -0
  278. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts +51 -0
  279. package/src/generation/foliage/analysis/crown_opacity_measure.d.ts.map +1 -0
  280. package/src/generation/foliage/analysis/crown_opacity_measure.js +649 -0
  281. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts +66 -0
  282. package/src/generation/foliage/analysis/foliage_measure_leaf_area.d.ts.map +1 -0
  283. package/src/generation/foliage/analysis/foliage_measure_leaf_area.js +192 -0
  284. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts +27 -0
  285. package/src/generation/foliage/analysis/tree_crown_opacity.d.ts.map +1 -0
  286. package/src/generation/foliage/analysis/tree_crown_opacity.js +58 -0
  287. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts +3 -2
  288. package/src/generation/foliage/animation/build_tree_wind_rig.d.ts.map +1 -1
  289. package/src/generation/foliage/animation/build_tree_wind_rig.js +12 -30
  290. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts +12 -0
  291. package/src/generation/foliage/animation/tree_wind_bend_limit.d.ts.map +1 -0
  292. package/src/generation/foliage/animation/tree_wind_bend_limit.js +13 -0
  293. package/src/generation/foliage/asset/TreeAsset.d.ts +5 -0
  294. package/src/generation/foliage/asset/TreeAsset.d.ts.map +1 -1
  295. package/src/generation/foliage/asset/TreeAsset.js +6 -0
  296. package/src/generation/foliage/asset/generate_tree.d.ts.map +1 -1
  297. package/src/generation/foliage/asset/generate_tree.js +23 -6
  298. package/src/generation/foliage/config/{BranchLevelConfig.d.ts → BranchGeneratorConfig.d.ts} +61 -75
  299. package/src/generation/foliage/config/BranchGeneratorConfig.d.ts.map +1 -0
  300. package/src/generation/foliage/config/{BranchLevelConfig.js → BranchGeneratorConfig.js} +83 -126
  301. package/src/generation/foliage/config/BranchSpawnRule.d.ts +118 -0
  302. package/src/generation/foliage/config/BranchSpawnRule.d.ts.map +1 -0
  303. package/src/generation/foliage/config/BranchSpawnRule.js +217 -0
  304. package/src/generation/foliage/config/FoliageCardType.d.ts +1 -1
  305. package/src/generation/foliage/config/FoliageCardType.js +2 -2
  306. package/src/generation/foliage/config/FoliageConfig.d.ts +23 -45
  307. package/src/generation/foliage/config/FoliageConfig.d.ts.map +1 -1
  308. package/src/generation/foliage/config/FoliageConfig.js +47 -93
  309. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts +12 -20
  310. package/src/generation/foliage/config/FoliageMaterialConfig.d.ts.map +1 -1
  311. package/src/generation/foliage/config/FoliageMaterialConfig.js +261 -279
  312. package/src/generation/foliage/config/FoliageSpawnRule.d.ts +77 -0
  313. package/src/generation/foliage/config/FoliageSpawnRule.d.ts.map +1 -0
  314. package/src/generation/foliage/config/FoliageSpawnRule.js +135 -0
  315. package/src/generation/foliage/config/FoliageTileContent.d.ts +9 -0
  316. package/src/generation/foliage/config/FoliageTileContent.d.ts.map +1 -0
  317. package/src/generation/foliage/config/FoliageTileContent.js +12 -0
  318. package/src/generation/foliage/config/LeafApexShape.d.ts +12 -0
  319. package/src/generation/foliage/config/LeafApexShape.d.ts.map +1 -0
  320. package/src/generation/foliage/config/LeafApexShape.js +17 -0
  321. package/src/generation/foliage/config/LeafArchitecture.d.ts +155 -0
  322. package/src/generation/foliage/config/LeafArchitecture.d.ts.map +1 -0
  323. package/src/generation/foliage/config/LeafArchitecture.js +288 -0
  324. package/src/generation/foliage/config/LeafBaseShape.d.ts +14 -0
  325. package/src/generation/foliage/config/LeafBaseShape.d.ts.map +1 -0
  326. package/src/generation/foliage/config/LeafBaseShape.js +21 -0
  327. package/src/generation/foliage/config/LeafLobation.d.ts +10 -0
  328. package/src/generation/foliage/config/LeafLobation.d.ts.map +1 -0
  329. package/src/generation/foliage/config/LeafLobation.js +14 -0
  330. package/src/generation/foliage/config/PhyllotaxisMode.d.ts +11 -0
  331. package/src/generation/foliage/config/PhyllotaxisMode.d.ts.map +1 -1
  332. package/src/generation/foliage/config/PhyllotaxisMode.js +36 -0
  333. package/src/generation/foliage/config/ShootBudZone.d.ts +105 -0
  334. package/src/generation/foliage/config/ShootBudZone.d.ts.map +1 -0
  335. package/src/generation/foliage/config/ShootBudZone.js +219 -0
  336. package/src/generation/foliage/config/ShootGrowthConfig.d.ts +84 -0
  337. package/src/generation/foliage/config/ShootGrowthConfig.d.ts.map +1 -0
  338. package/src/generation/foliage/config/ShootGrowthConfig.js +146 -0
  339. package/src/generation/foliage/config/ShootSystemRule.d.ts +144 -0
  340. package/src/generation/foliage/config/ShootSystemRule.d.ts.map +1 -0
  341. package/src/generation/foliage/config/ShootSystemRule.js +316 -0
  342. package/src/generation/foliage/config/TreeLODConfig.d.ts +1 -1
  343. package/src/generation/foliage/config/TreeLODConfig.js +1 -1
  344. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts +40 -8
  345. package/src/generation/foliage/config/TreeSpeciesConfig.d.ts.map +1 -1
  346. package/src/generation/foliage/config/TreeSpeciesConfig.js +124 -68
  347. package/src/generation/foliage/config/TreeWindConfig.d.ts +23 -10
  348. package/src/generation/foliage/config/TreeWindConfig.d.ts.map +1 -1
  349. package/src/generation/foliage/config/TreeWindConfig.js +34 -25
  350. package/src/generation/foliage/index.d.ts +19 -2
  351. package/src/generation/foliage/index.js +63 -44
  352. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts +59 -0
  353. package/src/generation/foliage/material/FoliageAtlasCutout.d.ts.map +1 -0
  354. package/src/generation/foliage/material/FoliageAtlasCutout.js +93 -0
  355. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts +26 -0
  356. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.d.ts.map +1 -0
  357. package/src/generation/foliage/material/compute_foliage_variant_atlas_layout.js +63 -0
  358. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts +34 -0
  359. package/src/generation/foliage/material/foliage_atlas_cutout.d.ts.map +1 -0
  360. package/src/generation/foliage/material/foliage_atlas_cutout.js +174 -0
  361. package/src/generation/foliage/material/foliage_tile.d.ts +110 -0
  362. package/src/generation/foliage/material/foliage_tile.d.ts.map +1 -0
  363. package/src/generation/foliage/material/foliage_tile.js +286 -0
  364. package/src/generation/foliage/material/leaf_geometry.d.ts +103 -0
  365. package/src/generation/foliage/material/leaf_geometry.d.ts.map +1 -0
  366. package/src/generation/foliage/material/leaf_geometry.js +528 -0
  367. package/src/generation/foliage/material/make_foliage_material.d.ts +13 -33
  368. package/src/generation/foliage/material/make_foliage_material.d.ts.map +1 -1
  369. package/src/generation/foliage/material/make_foliage_material.js +356 -605
  370. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts +39 -4
  371. package/src/generation/foliage/mesh/foliage_collect_attachments.d.ts.map +1 -1
  372. package/src/generation/foliage/mesh/foliage_collect_attachments.js +637 -569
  373. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts +48 -0
  374. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.d.ts.map +1 -0
  375. package/src/generation/foliage/mesh/interpolate_ring_skin_weights4.js +232 -0
  376. package/src/generation/foliage/mesh/tree_mesh_build_bark.d.ts.map +1 -1
  377. package/src/generation/foliage/mesh/tree_mesh_build_bark.js +1023 -1049
  378. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts +9 -2
  379. package/src/generation/foliage/mesh/tree_mesh_build_foliage.d.ts.map +1 -1
  380. package/src/generation/foliage/mesh/tree_mesh_build_foliage.js +467 -454
  381. package/src/generation/foliage/presets/make_tree_species_preset.d.ts.map +1 -1
  382. package/src/generation/foliage/presets/make_tree_species_preset.js +1648 -870
  383. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts +35 -0
  384. package/src/generation/foliage/skeleton/ShootFrameworkHash.d.ts.map +1 -0
  385. package/src/generation/foliage/skeleton/ShootFrameworkHash.js +129 -0
  386. package/src/generation/foliage/skeleton/ShootGirth.d.ts +51 -0
  387. package/src/generation/foliage/skeleton/ShootGirth.d.ts.map +1 -0
  388. package/src/generation/foliage/skeleton/ShootGirth.js +212 -0
  389. package/src/generation/foliage/skeleton/ShootLightField.d.ts +73 -0
  390. package/src/generation/foliage/skeleton/ShootLightField.d.ts.map +1 -0
  391. package/src/generation/foliage/skeleton/ShootLightField.js +197 -0
  392. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts +106 -3
  393. package/src/generation/foliage/skeleton/TreeSkeleton.d.ts.map +1 -1
  394. package/src/generation/foliage/skeleton/TreeSkeleton.js +217 -39
  395. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts +13 -0
  396. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.d.ts.map +1 -0
  397. package/src/generation/foliage/skeleton/flare_lobe_phase_offset.js +16 -0
  398. package/src/generation/foliage/skeleton/foliage_card_density.d.ts +71 -0
  399. package/src/generation/foliage/skeleton/foliage_card_density.d.ts.map +1 -0
  400. package/src/generation/foliage/skeleton/foliage_card_density.js +101 -0
  401. package/src/generation/foliage/skeleton/foliage_senescence.d.ts +101 -0
  402. package/src/generation/foliage/skeleton/foliage_senescence.d.ts.map +1 -0
  403. package/src/generation/foliage/skeleton/foliage_senescence.js +149 -0
  404. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts +76 -0
  405. package/src/generation/foliage/skeleton/foliage_unit_cards.d.ts.map +1 -0
  406. package/src/generation/foliage/skeleton/foliage_unit_cards.js +95 -0
  407. package/src/generation/foliage/skeleton/shoot_demography.d.ts +22 -0
  408. package/src/generation/foliage/skeleton/shoot_demography.d.ts.map +1 -0
  409. package/src/generation/foliage/skeleton/shoot_demography.js +96 -0
  410. package/src/generation/foliage/skeleton/shoot_geometry.d.ts +66 -0
  411. package/src/generation/foliage/skeleton/shoot_geometry.d.ts.map +1 -0
  412. package/src/generation/foliage/skeleton/shoot_geometry.js +109 -0
  413. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts +166 -0
  414. package/src/generation/foliage/skeleton/shoot_systems_simulate.d.ts.map +1 -0
  415. package/src/generation/foliage/skeleton/shoot_systems_simulate.js +588 -0
  416. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts +28 -12
  417. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.d.ts.map +1 -1
  418. package/src/generation/foliage/skeleton/tree_skeleton_assign_skin_joints.js +137 -102
  419. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts +112 -0
  420. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.d.ts.map +1 -0
  421. package/src/generation/foliage/skeleton/tree_skeleton_compute_joint_mechanics.js +408 -0
  422. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.d.ts.map +1 -1
  423. package/src/generation/foliage/skeleton/tree_skeleton_compute_pipe_radii.js +208 -206
  424. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts +5 -2
  425. package/src/generation/foliage/skeleton/tree_skeleton_grow.d.ts.map +1 -1
  426. package/src/generation/foliage/skeleton/tree_skeleton_grow.js +2048 -1871
  427. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts +17 -0
  428. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.d.ts.map +1 -0
  429. package/src/generation/foliage/skeleton/tree_skeleton_grow_shoots.js +231 -0
  430. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts +14 -0
  431. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.d.ts.map +1 -0
  432. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_motion.js +26 -0
  433. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts +10 -0
  434. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.d.ts.map +1 -0
  435. package/src/generation/foliage/skeleton/tree_skeleton_read_joint_parents.js +20 -0
  436. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts.map +1 -1
  437. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +4 -1
  438. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts +1 -0
  439. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts.map +1 -1
  440. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +98 -86
  441. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +263 -0
  442. package/src/shade/descriptor/WebGPUExtensionType.d.ts +17 -0
  443. package/src/shade/descriptor/WebGPUExtensionType.d.ts.map +1 -1
  444. package/src/shade/descriptor/WebGPUExtensionType.js +31 -1
  445. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts +37 -0
  446. package/src/shade/playground/foliage_wind/FoliageRigOverlay.d.ts.map +1 -0
  447. package/src/shade/playground/foliage_wind/FoliageRigOverlay.js +491 -0
  448. package/src/shade/playground/foliage_wind/foliage_world.d.ts.map +1 -1
  449. package/src/shade/playground/foliage_wind/foliage_world.js +600 -602
  450. package/src/shade/playground/foliage_wind/index.html +6 -0
  451. package/src/shade/playground/foliage_wind/main.js +14 -0
  452. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  453. package/src/shade/renderer/animation/GPUAnimationManager.js +2 -1
  454. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts +2 -1
  455. package/src/shade/renderer/animation/foliage/FoliageWindJoint.d.ts.map +1 -1
  456. package/src/shade/renderer/animation/foliage/FoliageWindJoint.js +2 -1
  457. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.d.ts.map +1 -1
  458. package/src/shade/renderer/animation/foliage/chunk_foliage_wind_step.js +4 -2
  459. package/src/shade/renderer/buffer/table/GPUTypedTable.js +1 -1
  460. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.d.ts.map +1 -1
  461. package/src/shade/renderer/buffer/table/single/GPUSingleTypeTable.js +403 -401
  462. package/src/shade/renderer/camera/OrbitalCameraController.d.ts +1 -62
  463. package/src/shade/renderer/camera/OrbitalCameraController.d.ts.map +1 -1
  464. package/src/shade/renderer/camera/OrbitalCameraController.js +1 -374
  465. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.d.ts.map +1 -1
  466. package/src/shade/renderer/deferred/indirect/chunk_lpv_2d_cache_sample_irradiance.js +3 -0
  467. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.d.ts.map +1 -1
  468. package/src/shade/renderer/deferred/indirect/chunk_lpv_sample_light.js +6 -1
  469. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +1 -1
  470. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +2 -2
  471. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts.map +1 -1
  472. package/src/shade/renderer/fluid/GPUFluidCascade.js +6 -3
  473. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +361 -0
  474. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.d.ts.map +1 -1
  475. package/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js +335 -241
  476. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.d.ts.map +1 -1
  477. package/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js +108 -101
  478. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.d.ts.map +1 -1
  479. package/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_query_select.js +69 -67
  480. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts +7 -6
  481. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.d.ts.map +1 -1
  482. package/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js +341 -287
  483. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts +6 -4
  484. package/src/shade/renderer/fluid/mac/FluidMacPasses.d.ts.map +1 -1
  485. package/src/shade/renderer/fluid/mac/FluidMacPasses.js +427 -400
  486. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts +10 -5
  487. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.d.ts.map +1 -1
  488. package/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.js +532 -190
  489. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.d.ts.map +1 -1
  490. package/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.js +231 -237
  491. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts +2 -2
  492. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.d.ts.map +1 -1
  493. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js +282 -245
  494. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts +1 -3
  495. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.d.ts.map +1 -1
  496. package/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.js +139 -109
  497. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts +6 -6
  498. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.d.ts.map +1 -1
  499. package/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.js +257 -222
  500. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts +8 -7
  501. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.d.ts.map +1 -1
  502. package/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.js +119 -92
  503. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts +6 -9
  504. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.d.ts.map +1 -1
  505. package/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.js +229 -181
  506. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +17 -7
  507. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts.map +1 -1
  508. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.js +634 -621
  509. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts +8 -6
  510. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.d.ts.map +1 -1
  511. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js +166 -149
  512. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts +8 -6
  513. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.d.ts.map +1 -1
  514. package/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js +219 -183
  515. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.d.ts.map +1 -1
  516. package/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.js +142 -122
  517. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +674 -663
  518. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +1 -1
  519. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  520. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +63 -29
  521. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  522. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +77 -87
  523. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.d.ts.map +1 -1
  524. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/meshopt_clusterizer.js +4 -3
  525. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts +11 -11
  526. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.d.ts.map +1 -1
  527. package/src/shade/renderer/geometry/meshlet/shader_meshlet_metadata_address_patch.js +17 -19
  528. package/src/shade/renderer/global_illumination/lpv/graph_bake_irradiance_lookup_2d.js +4 -4
  529. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.d.ts.map +1 -1
  530. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_mesh_interpolate_radiance_via_atlas.js +5 -1
  531. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  532. package/src/shade/renderer/loader/gltf/load_gltf.js +11 -35
  533. package/src/shade/renderer/loader/usd/load_usd.d.ts.map +1 -1
  534. package/src/shade/renderer/loader/usd/load_usd.js +6 -19
  535. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.d.ts.map +1 -1
  536. package/src/shade/renderer/particles/shaders/shader_particle_avboit_draw.js +199 -193
  537. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts.map +1 -1
  538. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.js +151 -143
  539. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.d.ts.map +1 -1
  540. package/src/shade/renderer/postprocess/bloom/chunk_karis_blur4x4_sample.js +11 -5
  541. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.d.ts.map +1 -1
  542. package/src/shade/renderer/postprocess/denoise/graph_atorus_denoise_luma.js +6 -18
  543. package/src/shade/renderer/postprocess/gtao/GTAO.js +1 -1
  544. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  545. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +3 -5
  546. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +1 -1
  547. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.d.ts.map +1 -1
  548. package/src/shade/renderer/postprocess/nss/chunk_nss_luma_derivative.js +7 -3
  549. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
  550. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +4 -2
  551. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.d.ts.map +1 -1
  552. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +4 -1
  553. package/src/shade/renderer/postprocess/ssr/downsample_karis.d.ts.map +1 -1
  554. package/src/shade/renderer/postprocess/ssr/downsample_karis.js +6 -3
  555. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.d.ts.map +1 -1
  556. package/src/shade/renderer/postprocess/ssr/reproject/chunk_ssr_temporal_accumulate.js +4 -3
  557. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.d.ts.map +1 -1
  558. package/src/shade/renderer/postprocess/ssr/resolve/ssr_resolve_shader.js +4 -1
  559. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.d.ts.map +1 -1
  560. package/src/shade/renderer/postprocess/ssr/ssr_spatial_denoise_shader.js +4 -2
  561. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts.map +1 -1
  562. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.js +35 -39
  563. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.d.ts.map +1 -1
  564. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap_inv.js +20 -17
  565. package/src/shade/renderer/postprocess/taa/shader_taa.d.ts.map +1 -1
  566. package/src/shade/renderer/postprocess/taa/shader_taa.js +6 -3
  567. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  568. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +3 -1
  569. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +1 -1
  570. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_splat_slice.js +2 -2
  571. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +1 -1
  572. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.d.ts.map +1 -1
  573. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_integrate.js +92 -83
  574. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +1 -1
  575. package/src/shade/renderer/shader/ShaderDescriptor.d.ts.map +1 -1
  576. package/src/shade/renderer/shader/ShaderDescriptor.js +12 -4
  577. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.d.ts.map +1 -1
  578. package/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_cooperative.js +294 -286
  579. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_interpolate_probe_irradiance8.js +5 -5
  580. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.d.ts.map +1 -1
  581. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe.js +5 -3
  582. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.d.ts.map +1 -1
  583. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_mesh_interpolate_probe_irradiance.js +9 -6
  584. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.d.ts.map +1 -1
  585. package/src/shade/renderer/shader/chunk/light/lpv/chunk_lpv_sample_sh3_at.js +33 -38
  586. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.d.ts.map +1 -1
  587. package/src/shade/renderer/shader/resource/ShaderResourceSetDescriptor.js +690 -675
  588. package/src/shade/renderer/shader/type/WebGPUArray.d.ts +3 -0
  589. package/src/shade/renderer/shader/type/WebGPUArray.d.ts.map +1 -1
  590. package/src/shade/renderer/shader/type/WebGPUArray.js +185 -167
  591. package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
  592. package/src/shade/renderer/shader/type/WebGPUStruct.js +461 -455
  593. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.d.ts.map +1 -1
  594. package/src/shade/renderer/shader/type/serde/read_gpu_typed_buffer.js +335 -211
  595. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.d.ts.map +1 -1
  596. package/src/shade/renderer/shader/type/serde/write_gpu_typed_buffer.js +329 -221
  597. package/src/shade/renderer/shader/type/type_has_f16.d.ts +12 -0
  598. package/src/shade/renderer/shader/type/type_has_f16.d.ts.map +1 -0
  599. package/src/shade/renderer/shader/type/type_has_f16.js +66 -0
  600. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.d.ts.map +1 -1
  601. package/src/shade/renderer/volumetrics/shader_volumetrics_build_lighting.js +16 -2
  602. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts.map +1 -1
  603. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +5 -2
  604. package/src/shade/renderer/water/shader_water_avboit.js +1 -1
  605. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  606. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +260 -23
  607. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts +6 -7
  608. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  609. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +269 -69
  610. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  611. package/src/shade/wgsl/validate_wgsl_source.js +27 -1
  612. package/src/view/controller/controls/ListController.d.ts.map +1 -1
  613. package/src/view/controller/controls/ListController.js +118 -113
  614. package/src/view/controller/controls/Vector1Control.js +97 -97
  615. package/src/view/elements/image/SvgImageView.d.ts +1 -0
  616. package/src/view/elements/image/SvgImageView.d.ts.map +1 -1
  617. package/src/view/elements/image/SvgImageView.js +92 -90
  618. package/src/view/minimap/dom/MinimapTerrainView.d.ts +1 -0
  619. package/src/view/minimap/dom/MinimapTerrainView.d.ts.map +1 -1
  620. package/src/view/minimap/dom/MinimapTerrainView.js +151 -147
  621. package/src/view/tooltip/gml/TooltipParser.js +2 -2
  622. package/src/engine/network/PriorityFetch.d.ts +0 -59
  623. package/src/engine/network/PriorityFetch.d.ts.map +0 -1
  624. package/src/engine/network/PriorityFetch.js +0 -193
  625. package/src/generation/foliage/config/BranchLevelConfig.d.ts.map +0 -1
@@ -0,0 +1,361 @@
1
+ # GPU Wind Fluid Solver: Occupancy Analysis & Real-Time SotA Review (2026-10-26)
2
+
3
+ **Scope:** [`packages/meep-engine/src/shade/renderer/fluid/`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/) and [`GPUFluidSystem.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/engine/graphics3/GPUFluidSystem.js)
4
+ **Domain:** Space-filling atmospheric wind simulation (nested, player-centered 3D toroidal clipmap cascades with $2^c$ subcycling, MAC staggered velocity, geometric multigrid pressure projection, LBVH-culled obstacle/effector forcing, and `rgba16float` deviation atlas publishing).
5
+ **Related Specifications:** [`GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md), [`SHADER_F16_PROPOSAL_2026_10_24.md`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md), [`REVIEW_02_PLAN.md`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/engine/physics/fluid/REVIEW_02_PLAN.md)
6
+ **Reference Hardware & Device Floor:** NVIDIA GeForce RTX 4090 (Ada AD102: 128 SMs, 48 warps/SM = 1,536 threads/SM, 65,536 32-bit VGPRs/SM, up to 100 KB shared memory/SM) and AMD Radeon RDNA2/3 (64 KiB LDS/WGP, 65,536–131,072 VGPRs/SIMD). `shader-f16` (`enable f16;`), `subgroups`, and `texture-formats-tier1` (`r16float` storage textures) are required by [`SHADE_DEVICE_FLOOR`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/WebGPUDevice.js#L16-L35) and assumed throughout.
7
+
8
+ ---
9
+
10
+ ## 1. Executive Summary: Where the Time Goes and Why Occupancy Is Low
11
+
12
+ On an RTX 4090 at the default cascade resolution of `64×32×64` ($h_0 = 0.5\text{ m}$, 4 cascades), a single cascade step costs **`144.4 µs`** (`152.6 µs` with vorticity confinement), and a two-cascade tick (`c = 1, 0`) costs **`291.8 µs`** (`308.2 µs` with confinement) before scene forcing, plus **`34–88 µs`** for LBVH brick query and forcing application ([`GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md#L975-L1043), [`shader_fluid_cascade_ghosts.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js#L75-L80)).
13
+
14
+ Combining the measured RTX 4090 per-pass GPU timestamps with static analysis of the 19 compiled WGSL shaders reveals **six concrete occupancy and execution-efficiency bottlenecks** in the passes that dominate frame time:
15
+
16
+ | Pass Group | RTX 4090 Cost / Step (`64×32×64`) | Share of Step | Root Cause of Low GPU Occupancy / Execution Efficiency |
17
+ |---|---|---|---|
18
+ | **1. Multigrid Smoother & Restriction** ([`shader_fluid_mg_smooth`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js), [`shader_fluid_mg_residual_restrict`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js)) | `53 µs` + `18 µs` = **`71 µs`** | **`49.2%`** | **Unstaged coarse prolongation** (`600 × 8 = 4,800` global reads/WG for `144` unique coarse cells on up-sweeps); **redundant global re-read of `input`** after `grid_tile_f32_load`; **87.5% idle warps (`224/256` threads)** after barrier 1 in `residual_restrict` (`if (lane < 32u)`); **16 dead trailing `workgroupBarrier()`s/step** left over before `subgroup_atomic_add_u32`. |
19
+ | **2. MAC Advection** ([`shader_fluid_mac_advect_correct`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js), [`shader_fluid_mac_advect_predict`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.js)) | `27 µs` + `16 µs` = **`43 µs`** | **`29.8%`** | **Severe VGPR pressure & nested $8\times 8$ dynamic loops:** `mac_source_*` and `mac_forward_*` call `fluid_mac_ghost_*`, which still embeds a fallback call to `fluid_parent_face_*` — placing an **8-iteration dynamic loop inside an 8-iteration dynamic loop** (`select(0u, 8u, abs(position.x) < 1e30)`) across all 3 axes (`888` lines / `67` functions in `correct`). Plus **warp divergence on upper boundary tiles** (`u_end/v_end/w_end = 2`) and `r32float` (`4 B`/texel) velocity bandwidth instead of `r16float` (`2 B`/texel). |
20
+ | **3. Forcing Query & Apply** ([`shader_fluid_forcing_query`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/shader_fluid_forcing_query.js), [`shader_fluid_forcing_apply`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js)) | **`34–88 µs`** (per tick) | Additive (`+24–30%`) | **VGPR explosion + 2-warp (`64`-thread) workgroups:** `forcing_apply` (`825` lines, `4,724 B` LDS) copies 80 B `FluidObstacleRecord` and 64 B `mat4x4<f32>` structs by value into VGPRs and re-normalizes 3 matrix columns per thread × 24 obstacles; `57.8%` of brick threads diverge on 6-face effector loops; `forcing_query` executes `3` `workgroupBarrier()`s per BVH depth level with only 2 warps per workgroup. |
21
+ | **4. Cascade Ghosts** ([`shader_fluid_cascade_ghosts`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js)) | **`9.0 µs`** | **`6.2%`** | **Hollow bounding-box dispatch waste:** launches `4,800` WGs (`307,200` threads) over the filled `[77, 45, 77]` volume; **`53.66%` of threads (`164,851`) write nothing**, **`25.54%` of WGs (`1,226`) are 100% interior no-ops**, and `cell = id - 1` misaligns pressure ghosts through the velocity interior. |
22
+ | **5. Vorticity Confinement Curl** ([`shader_fluid_mac_curl`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.js)) | **`8.2 µs`** | **`5.4%`** (when on) | **LDS ceiling (`16,224 B` = `99.0%` of 16 KiB limit):** caps residency to 1–2 WGs/CU (`16.7%–33.3%` warp occupancy) by storing `3 × 1,152` velocities + `600` magnitudes as `f32` in LDS, and computes `fluid_curl_omega(local)` **twice** per interior thread. |
23
+ | **6. MAC Gradient & MG Weights** ([`shader_fluid_mac_gradient`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.js), `mg_*_weights`) | `4.1 µs` + `8.2 µs` = **`12.3 µs`** | **`8.5%`** | `mac_gradient` calls `grid_tile_f32_load` **twice in a row** (`2` `workgroupBarrier()`s, `2` unpack loops, `2,400 B` LDS to hold a 1-bit `solid` flag as `f32`); the `4` standalone MG weight dispatches (`level0_weights` + 3× `coarse_weights`) duplicate grid walks and `words` reads already performed by `mac_divergence` and `mg_residual_restrict`. |
24
+
25
+ ---
26
+
27
+ ## 2. Complete Quantitative Audit of All 19 Compute Shaders
28
+
29
+ All metrics below are extracted from the compiled WGSL (`shader.descriptor.source`) of the 19 [`ComputeShader`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/shader/ComputeShader.js) definitions in [`packages/meep-engine/src/shade/renderer/fluid/`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/).
30
+
31
+ | # | Shader Symbol & Label | WG Size (`Threads` / `Warps32`) | LDS (`var<workgroup>`) Bytes | Barriers (`Static` / `Dynamic`) | Bindings (`UBO` / `RO-SB` / `RW-SB` / `Tex` / `StTex`) | Compiled WGSL (`Lines` / `Fns`) | Primary Occupancy / Efficiency Bottleneck |
32
+ |---|---|---|---|---|---|---|---|
33
+ | 1 | [`shader_fluid_cascade_fill`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/coupling/shader_fluid_cascade_fill.js) (`Fluid / cascade fill`) | `4×4×4` (`64` / `2`) | `0 B` | `0 / 0` | `2 / 1 / 1 / 3 / 3` | `362 / 22` | Dynamic 8-corner `textureLoad` loops (`24` loads/thread, `z0/z1` `vec4f` live state); `cell == last` boundary divergence; 2-warp WG. |
34
+ | 2 | [`shader_fluid_cascade_ghosts`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js) (`Fluid / cascade ghosts`) | `4×4×4` (`64` / `2`) | `0 B` | `0 / 0` | `2 / 1 / 1 / 3 / 3` | `319 / 18` | **53.66% dead threads** (`164,851 / 307,200`) & **25.54% no-op WGs**; misaligned `cell = id - 1` pressure shell; 24 `textureLoad`s/thread. |
35
+ | 3 | [`shader_fluid_cascade_restrict`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/coupling/shader_fluid_cascade_restrict.js) (`Fluid / cascade restrict`) | `8×8×4` (`256` / `8`) | `0 B` | `0 / 0` | `1 / 0 / 0 / 3 / 3` | `152 / 13` | Clean, lightweight (`12` `textureLoad`s/thread); `r32float` bandwidth (`2×` `r16float`). |
36
+ | 4 | [`shader_fluid_mac_curl`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.js) (`Fluid / MAC curl`) | `8×8×4` (`256` / `8`) | **`16,224 B`** (`99.0%` of 16 KiB) | `2 / 2` | `1 / 1 / 1 / 3 / 0` | `260 / 19` | **16.2 KB `f32` LDS caps CU/SM residency to 1–2 WGs**; computes `fluid_curl_omega(local)` **twice** per interior thread (lines 142 & 164). |
37
+ | 5 | [`shader_fluid_mac_advect_predict`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.js) (`Fluid / MAC advect predict`) | `8×8×4` (`256` / `8`) | `0 B` | `0 / 0` | `2 / 1 / 0 / 9 / 3` | `576 / 43` | **High VGPR pressure:** nested `mac_source_* → fluid_mac_ghost_* → fluid_parent_face_*` 8×8 dynamic loops; `u_end/v_end/w_end` warp divergence. |
38
+ | 6 | [`shader_fluid_mac_advect_correct`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js) (`Fluid / MAC advect correct`) | `8×8×4` (`256` / `8`) | `0 B` | `0 / 0` | `2 / 3 / 0 / 12 / 3` | **`888 / 67`** | **Severe VGPR pressure:** 12 sampled textures + 3 storage textures + 3 storage buffers; 6× outer 8-corner loops + 6× nested parent 8-corner loops + 3× epilogue parent 8-corner loops + 6× bisection loops per thread. |
39
+ | 7 | [`shader_fluid_mac_divergence`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.js) (`Fluid / MAC divergence`) | `8×8×4` (`256` / `8`) | `0 B` | `0 / 0` | `1 / 1 / 1 / 3 / 0` | `135 / 12` | High occupancy (`2.0 µs` at `64×32×64`); direct texture reads beat LDS tiling 2× on RTX 4090. |
40
+ | 8 | [`shader_fluid_mac_gradient`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.js) (`Fluid / MAC gradient`) | `8×8×4` (`256` / `8`) | `4,800 B` (`2 × 2,400 B`) | `1 / 2` | `1 / 3 / 0 / 3 / 3` | `289 / 29` | **Calls `grid_tile_f32_load` twice in a row** → **2 serial `workgroupBarrier()`s** and 2 halo unpack loops; stores 1-bit `solid` as `f32` (`2,400 B`). |
41
+ | 9 | [`shader_fluid_mg_level0_weights`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_level0_weights.js) (`Fluid / pressure / level 0 weights`) | `8×8×4` (`256` / `8`) | `0 B` | `0 / 0` | `1 / 1 / 1 / 0 / 0` | `78 / 7` | Separate dispatch over the exact same `8×8×4` cell grid and `solid` buffer just traversed by `shader_fluid_mac_divergence`. |
42
+ | 10 | [`shader_fluid_mg_coarse_weights`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_coarse_weights.js) (`Fluid / pressure / coarse weights`) | `8×8×4` (`256` / `8`) | `0 B` | `0 / 0` | `1 / 1 / 1 / 0 / 0` | `79 / 6` | Separate dispatch reading the exact $2\times 2\times 2$ fine `words` already loaded by `shader_fluid_mg_residual_restrict`; at `L3` (`8×4×8`), `50%` of threads (`cell.y >= 4`) early-return. |
43
+ | 11 | [`shader_fluid_mg_smooth`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js) (`Fluid / pressure / smooth`) | `8×8×4` (`256` / `8`) | `2,400 B` | `2 / 5` | `1 / 5 / 2 / 0 / 0` | `359 / 28` | **Unstaged prolongation (`4,800` global reads/WG for `144` coarse cells)**; **redundant global re-read of `input`** at line 140; dead trailing `workgroupBarrier()` at line 169. |
44
+ | 12 | [`shader_fluid_mg_residual_restrict`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js) (`Fluid / pressure / residual + restrict`) | `8×8×4` (`256` / `8`) | `3,424 B` | `2 / 2` | `1 / 4 / 3 / 0 / 0` | `327 / 26` | **87.5% of threads (`224/256`) sit idle** during `if (lane < 32u)` restriction after barrier 1; redundant global re-read of `input` at line 114; dead trailing `workgroupBarrier()` at line 137. |
45
+ | 13 | [`shader_fluid_mg_coarsest`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_coarsest.js) (`Fluid / pressure / coarsest`) | `256×1×1` (`256` / `8`) | `1,024 B` | `2 / 17` | `1 / 3 / 2 / 0 / 0` | `245 / 18` | `17` serial `workgroupBarrier()`s (`8` red-black sweeps + dead trailing barrier at line 150 before `subgroup_atomic_add_u32`); `7.2 µs` on RTX 4090. |
46
+ | 14 | [`shader_fluid_forcing_extract`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/shader_fluid_forcing_extract.js) (`Fluid / forcing / extract leaves`) | `64×1×1` (`64` / `2`) | `512 B` | `1 / 1` | `1 / 3 / 3 / 0 / 0` | `410 / 15` | 2-warp WG; lightweight (`~1–2 µs`). |
47
+ | 15 | [`shader_fluid_forcing_query`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/shader_fluid_forcing_query.js) (`Fluid / forcing / brick query`) | `64×1×1` (`64` / `2`) | `2,580 B` | `4 / 2+3·d` | `1 / 2 / 6 / 0 / 0` | `540 / 26` | **3 `workgroupBarrier()`s per BVH level** inside a 2-warp (`64`-thread) WG (`chunk_bvh_query_aabb_frontier.js`); no independent warps inside the WG to hide barrier stalls. |
48
+ | 16 | [`shader_fluid_forcing_command`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/shader_fluid_forcing_command.js) (`Fluid / forcing / commands`) | `1×1×1` (`1` / `1`) | `0 B` | `0 / 0` | `0 / 2 / 1 / 0 / 0` | `32 / 3` | 1-thread dispatch (`1 µs`) between `query` and `apply`; can be folded into `query`. |
49
+ | 17 | [`shader_fluid_forcing_apply`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js) (`Fluid / forcing / apply`) | `4×4×4` (`64` / `2`) | `4,724 B` | `2 / 2` | `1 / 5 / 2 / 0 / 3` | **`825 / 45`** | **Extreme VGPR pressure + 2-warp WG:** copies 80 B `FluidObstacleRecord` + 64 B `mat4x4<f32>` + 48 B `FluidEffectorRecord` by value into VGPRs; re-normalizes 3 matrix columns per thread × 24 obstacles; 6-face effector divergence on `57.8%` of lanes. |
50
+ | 18 | [`shader_fluid_wind_publish`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/publish/shader_fluid_wind_publish.js) (`Fluid / wind publish`) | `4×4×4` (`64` / `2`) | `0 B` | `0 / 0` | `3 / 0 / 0 / 6 / 1` | `300 / 19` | 2-warp WG; skirt threads (`local == 0` or `local == size-1`) diverge to run `3 × 8 = 24` dynamic `textureLoad`s from parent (`chunk_fluid_cascade_parent.js`). |
51
+ | 19 | [`shader_fluid_query_gather`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/query/shader_fluid_query_gather.js) (`Fluid / query / gather`) | `64×1×1` (`64` / `2`) | `0 B` | `0 / 0` | `1 / 1 / 1 / 1 / 0` | `230 / 9` | Uses software 8-tap `textureLoad` loop on `wind_field_atlas` even though `wind_field_atlas` is **already `rgba16float`** and hardware-filterable via `textureSampleLevel`. |
52
+
53
+ ---
54
+
55
+ ## 3. Deep-Dive Technical Findings (Verified Line-by-Line)
56
+
57
+ ### F-01: Nested $8 \times 8$ Dynamic Corner Loops & VGPR Explosion in `shader_fluid_mac_advect_predict` and `shader_fluid_mac_advect_correct`
58
+ - **Location:** [`chunk_v3_mac_lattice_corners.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.js#L82-L185), [`chunk_fluid_mac_seams.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.js#L50-L189), [`chunk_fluid_cascade_parent.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js#L79-L162), [`shader_fluid_mac_advect_predict.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_predict.js#L118-L202), [`shader_fluid_mac_advect_correct.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_advect_correct.js#L139-L246).
59
+ - **Mechanism:**
60
+ 1. **The Hidden $8 \times 8$ Nested Loop Inside `v3_mac_source_corners_*` and `v3_mac_forward_corners_*`:**
61
+ Look at [`chunk_fluid_mac_seams.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.js#L55-L185):
62
+ - In `mac_carrier_u/v/w` (lines 123–145), an out-of-window read fetches `textureLoad(ghost_u, vec3<u32>(face + vec3<i32>(FLUID_MAC_GHOST_DEPTH)), 0).r` directly.
63
+ - However, in `mac_source_u/v/w` (lines 99–121) and `mac_forward_u/v/w` (lines 163–185), an out-of-window read calls `fluid_mac_ghost_u/v/w(face)` (lines 55–83):
64
+ ```wgsl
65
+ fn fluid_mac_ghost_u(face: vec3<i32>) -> f32 {
66
+ let texel = face + vec3<i32>(FLUID_MAC_GHOST_DEPTH);
67
+ if (all(texel >= vec3<i32>(0)) && all(texel < vec3<i32>(step.faces_u.size) + vec3<i32>(2 * FLUID_MAC_GHOST_DEPTH))) {
68
+ return textureLoad(ghost_u, vec3<u32>(texel), 0).r;
69
+ }
70
+ return fluid_parent_face_u(face, step.cells.corner - parent.origin);
71
+ }
72
+ ```
73
+ - Because `v3_mac_source_corners_u/v/w` and `v3_mac_forward_corners_u/v/w` ([`chunk_v3_mac_lattice_corners.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.js#L82-L185)) call `mac_source_u/v/w` or `mac_forward_u/v/w` inside their 8-corner loop, and `fluid_parent_face_u/v/w` ([`chunk_fluid_cascade_parent.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js#L79-L162)) is itself an 8-corner trilinear gather, **every outer 8-corner gather contains a nested 8-corner parent gather ($8 \times 8 = 64$ corner evaluations per trilinear tap)**!
74
+ - Because WGSL has no stack-called functions in DXIL, DXC inlines the entire call tree. When these loops were statically unrolled (`for (var i = 0u; i < 8u; i++)`), inlining $8 \times 8 = 64$ parent `textureLoad` blocks across 6 trilinear taps and 2 boundary faces ($768+$ `textureLoad` blocks) caused DXC compilation to stall.
75
+ - To prevent DXC from unrolling that $8 \times 8$ tree, both the outer loop and inner loop were given a runtime-opaque bound (`let n_corners = select(0u, 8u, abs(position.x) < 1e30);`) and a `vec4<f32>` mask-select accumulator (`z0`, `z1`):
76
+ ```wgsl
77
+ let n_corners = select(0u, 8u, abs(position.x) < 1e30);
78
+ var z0 = vec4<f32>(0.0);
79
+ var z1 = vec4<f32>(0.0);
80
+ for (var i = 0u; i < n_corners; i++) {
81
+ let pt = vec3<i32>(
82
+ select(lo.x, hi.x, (i & 1u) != 0u),
83
+ select(lo.y, hi.y, (i & 2u) != 0u),
84
+ select(lo.z, hi.z, (i & 4u) != 0u)
85
+ );
86
+ let v = vec4<f32>(mac_source_u(pt));
87
+ let mask = vec4<u32>(i & 3u) == vec4<u32>(0u, 1u, 2u, 3u);
88
+ z0 = select(z0, v, mask & vec4<bool>(i < 4u));
89
+ z1 = select(z1, v, mask & vec4<bool>(i >= 4u));
90
+ }
91
+ ```
92
+ 2. **Why This Cripples Runtime GPU Occupancy Even When 100% of Reads Hit `ghost_u/v/w`:**
93
+ - Even when `|v_far|·dt/h <= 1` (`|v_far| <= 20 m/s` at $h = 0.5\text{ m}, \Delta t = 25\text{ ms}$) so that every out-of-window tap hits `ghost_u/v/w` and never executes `fluid_parent_face_*` at runtime, the compiled shader still contains the **nested dynamic loop** inside the outer dynamic loop.
94
+ - Consequently, the register allocator must simultaneously keep live in VGPRs:
95
+ - Outer loop state (`i`, `n_corners`, `lo`, `hi`, `z0: vec4<f32>`, `z1: vec4<f32>`, `tap.weight`),
96
+ - Inner `fluid_parent_face_*` loop state (`i`, `n_corners`, `lattice`, `base`, `lo`, `hi`, `z0: vec4<f32>`, `z1: vec4<f32>`), and
97
+ - MacCormack / solid-bisection state (`start`, `travel`, `back`, `ahead`, `source`, `forward`).
98
+ - In addition, because the outer loop is dynamic (`i < n_corners`) and branches between `source_*` and `ghost_*` on every iteration, the GPU cannot issue the 8 corner `textureLoad`s in parallel; it serializes texture memory latency across 8 loop iterations.
99
+ 3. **Mathematical Proof That `fluid_parent_face_*` Never Needs to Be Inside the 8-Corner Loop:**
100
+ - In `v3_mac_source_corners_*` and `v3_mac_forward_corners_*`, the 8 corners span `tap.lo` to `tap.hi = tap.lo + vec3<i32>(1)`.
101
+ - Since `FLUID_MAC_GHOST_DEPTH = 6 >= 1`, if **any** corner of `[tap.lo, tap.hi]` lies outside the ghost shell `[-6, size + 6)`, then along that axis either `tap.lo <= -7` (so `tap.hi <= -6 < 0`) or `tap.hi >= size + 6` (so `tap.lo >= size + 5 >= size`).
102
+ - Because a 3D lattice point lies inside the child window `[0, size)` only if **all three** coordinates lie in `[0, size)`, whenever a tap exceeds the ghost shell on any axis, **all 8 corners of `[tap.lo, tap.hi]` are guaranteed to lie outside the child window**!
103
+ - Therefore, `fluid_parent_face_*` **never** needs to be called per corner inside `fluid_mac_ghost_*`. Checking `any(tap.lo < vec3<i32>(-FLUID_MAC_GHOST_DEPTH)) || any(tap.hi >= size + vec3<i32>(FLUID_MAC_GHOST_DEPTH))` **once before the 8-corner loop** and calling `fluid_parent_face_*` once outside the loop (while making `fluid_mac_ghost_*` an unconditional `textureLoad(ghost_*)` just like `mac_carrier_*`) preserves 100% exact storm-wind fallback behavior while completely eliminating the $8 \times 8$ nested loop!
104
+ 4. **Upper-Face Boundary Warp Divergence (`u_end`, `v_end`, `w_end`):**
105
+ In both `advect_predict` and `advect_correct`, threads at `cell.x == last.x`, `cell.y == last.y`, or `cell.z == last.z` run `for (var dx = 0; dx < u_end; dx++)` with `u_end = 2`. In every boundary workgroup (`8×8×4`), when `cell.x == 63`, **4 threads in each 32-thread warp (`12.5%` of the warp)** execute a second full MacCormack advection pass while the other **28 threads (`87.5%` of the warp)** sit masked off.
106
+
107
+ ---
108
+
109
+ ### F-02: Unstaged Prolongation (`33.3×` Read Amplification), Redundant Global Reads, `87.5%` Restrict Warp Idling, and 16 Dead Barriers in the Multigrid Solve
110
+ - **Location:** [`shader_fluid_mg_smooth.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js#L63-L171), [`shader_fluid_mg_residual_restrict.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js#L49-L142), [`shader_fluid_mg_coarsest.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_coarsest.js#L140-L153), [`chunk_fluid_mg_prolong.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/chunk_fluid_mg_prolong.js#L35-L62).
111
+ - **Mechanism:**
112
+ 1. **Unstaged Coarse Tile Prolongation (`4,800` global reads per workgroup for `144` unique coarse values):**
113
+ - On the up-leg of the V-cycle (`params.prolong != 0u`), [`shader_fluid_mg_smooth.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js#L66-L68) calls `fluid_mg_prolong` inside `grid_tile_f32_fetch_inside` for all **600 cells** of the `10×10×6` fine tile+halo (`3` load rounds × `256` threads).
114
+ - Each `fluid_mg_prolong` call ([`chunk_fluid_mg_prolong.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/chunk_fluid_mg_prolong.js#L45-L56)) executes **8 global buffer reads** from `coarse`, totaling **`600 × 8 = 4,800` global buffer reads per workgroup**.
115
+ - Yet a `10×10×6` fine halo tile (`[-1..8] × [-1..8] × [-1..4]` relative to the `8×8×4` tile base) touches at most **`6×6×4 = 144` unique coarse cells** (`coarse_cell = (fine_cell + 1) >> 1` for `fine_cell ∈ [-2..9]`, spanning `[-1..4]` on $x,y$ and `[-1..2]` on $z$).
116
+ - This `33.3×` global read amplification explains why the up-leg smoother is measured at **`19.5 µs` vs. `13.3 µs` (`+46.6%` slower)** than the down-leg smoother at `128×32×128` ([`GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md#L982-L983)).
117
+ 2. **Redundant Post-Barrier Global Re-Read of `held = input[...]`:**
118
+ - In [`shader_fluid_mg_smooth.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js#L125-L143):
119
+ ```wgsl
120
+ grid_tile_f32_load(&tile_p, params.source, fluid_mg_input_window(), workgroup_id, lane);
121
+ // ...
122
+ let held = input[fluid_mg_input_index(fluid_mg_input_storage(cell))];
123
+ var nonfinite_here = select(0u, 1u, !is_finite(held));
124
+ ```
125
+ - And identically in [`shader_fluid_mg_residual_restrict.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js#L103-L115):
126
+ ```wgsl
127
+ grid_tile_f32_load(&tile_p, params.source, fluid_mg_input_window(), workgroup_id, lane);
128
+ // ...
129
+ let held = input[fluid_mg_input_index(fluid_mg_input_storage(cell))];
130
+ let nonfinite_here = select(0u, 1u, !is_finite(held) || !is_finite(rhs_value));
131
+ ```
132
+ - Both kernels **already read `input[...]` for all 600 tile+halo cells inside `grid_tile_f32_load`**! Re-reading `input[...]` from global memory after the barrier issues `256` redundant global loads per workgroup (`131,072` redundant loads per `L0` dispatch) across all **14 smooth and restrict dispatches** per cascade step.
133
+ 3. **`87.5%` Warp Idling During Coarse Restriction (`if (lane < 32u)`):**
134
+ - In [`shader_fluid_mg_residual_restrict.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js#L120-L137), after writing `tile_r[lane] = residual;` and executing `workgroupBarrier()`, only `if (lane < 32u)` (Warp 0) executes `fluid_mg_restrict` (reading `8` values per thread from `tile_r`) while **Warps 1–7 (`224` of `256` threads = `87.5%`) sit completely idle**.
135
+ 4. **16 Dead Trailing `workgroupBarrier()`s per Cascade Step:**
136
+ - [`shader_fluid_mg_smooth.js:169`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js#L169), [`shader_fluid_mg_residual_restrict.js:137`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js#L137), and [`shader_fluid_mg_coarsest.js:150`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_coarsest.js#L150) each execute a `workgroupBarrier()` immediately before calling `subgroup_atomic_add_u32(&nonfinite[0], nonfinite_here);`.
137
+ - As verified in [`chunk_subgroup_atomic_add.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/shader/chunk/subgroup/chunk_subgroup_atomic_add.js#L19-L26), `subgroup_atomic_add_u32` uses only `subgroupAdd(value)`, `subgroupElect()`, and `atomicAdd(counter, total)` — it **never accesses `var<workgroup>` memory**! Those trailing barriers are leftover artifacts from when `nonfinite` used a workgroup shared-memory reduction tree, wasting 16 barrier synchronizations per cascade step.
138
+
139
+ ---
140
+
141
+ ### F-03: `shader_fluid_forcing_apply` & `shader_fluid_forcing_query` Register Bloat, 2-Warp Workgroups, and Redundant Matrix Normalizations
142
+ - **Location:** [`shader_fluid_forcing_apply.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js#L43-L162), [`chunk_fluid_forcing_cell.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_cell.js#L92-L148), [`chunk_fluid_obstacle_record.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/chunk_fluid_obstacle_record.js#L26-L70), [`shader_fluid_forcing_query.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/shader_fluid_forcing_query.js#L50-L152).
143
+ - **Mechanism:**
144
+ 1. **By-Value Struct Copies from LDS into Per-Lane VGPRs (`80 B` + `64 B` + `48 B`):**
145
+ In [`shader_fluid_forcing_apply.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js#L69-L77):
146
+ ```wgsl
147
+ fn fluid_forcing_read_obstacle(slot: u32) -> FluidObstacleRecord { return fluid_forcing_obstacles[slot]; }
148
+ fn fluid_forcing_read_obstacle_global(slot: u32) -> mat4x4<f32> { return fluid_forcing_globals[slot]; }
149
+ fn fluid_forcing_read_effector(slot: u32) -> FluidEffectorRecord { return fluid_forcing_effectors[slot]; }
150
+ ```
151
+ Inside [`chunk_fluid_forcing_cell.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_cell.js#L98-L115), every thread copies the entire `FluidObstacleRecord` (`20 × 4 B = 80 B`) and `mat4x4<f32>` (`16 × 4 B = 64 B`) by value out of LDS into VGPRs on every iteration of the `24`-obstacle loop, even though `linear_velocity` is only used if the cell is inside the obstacle and row 3 of `mat4x4<f32>` is always `(0, 0, 0, 1)`.
152
+ 2. **Redundant Per-Thread `mat4x4` Column Normalization (`64×` duplicate `inverseSqrt`s per obstacle):**
153
+ In [`chunk_fluid_obstacle_record.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/chunk_fluid_obstacle_record.js#L35-L42):
154
+ ```wgsl
155
+ let x = normalize(global[0].xyz);
156
+ let y = normalize(global[1].xyz);
157
+ let z = normalize(global[2].xyz);
158
+ let local = vec3<f32>(dot(offset, x), dot(offset, y), dot(offset, z));
159
+ ```
160
+ Every one of the `64` threads in the brick normalizes `global[0..2].xyz` for every obstacle in the brick (`up to 24 × 3 = 72` `normalize()` calls per thread), even though `fluid_forcing_globals[lane]` is cooperatively loaded into LDS once at lines 99–103 of `shader_fluid_forcing_apply.js`! Normalizing the 3 columns **once when loading into LDS** eliminates all 72 `normalize()` calls from the per-cell loop and shrinks `fluid_forcing_globals` from `24 × 64 B = 1,536 B` (`mat4x4<f32>`) to `24 × 48 B = 1,152 B` (`mat3x4<f32>`).
161
+ 3. **6-Face Effector Divergence on Brick Upper Faces (`57.8%` of brick lanes):**
162
+ In [`shader_fluid_forcing_apply.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js#L139-L161), threads on the $+x, +y, +z$ faces of the `4×4×4` brick (`local_id.x == 3`, `local_id.y == 3`, `local_id.z == 3` — which is $64 - 27 = 37$ of the $64$ threads) execute a second `fluid_forcing_face_deposit` loop (`up to 16` effectors) per boundary axis while interior lanes in the same warp sit masked off.
163
+ 4. **2-Warp Workgroups (`64` threads) Under Heavy Barrier & Register Load:**
164
+ Both `shader_fluid_forcing_query` (`@workgroup_size(64)`) and `shader_fluid_forcing_apply` (`@workgroup_size(4, 4, 4)`) have only **2 warps per workgroup**. In `shader_fluid_forcing_query`, [`chunk_bvh_query_aabb_frontier.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/shader/chunk/bvh/chunk_bvh_query_aabb_frontier.js) executes **3 `workgroupBarrier()`s per BVH level**. With only 2 warps per workgroup, each barrier drains the workgroup's instruction pipeline completely.
165
+
166
+ ---
167
+
168
+ ### F-04: `shader_fluid_cascade_ghosts` Hollow Bounding-Box Dispatch (`53.66%` Dead Threads) & Pressure Offset Misalignment
169
+ - **Location:** [`FluidMacPasses.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/FluidMacPasses.js#L178-L181), [`shader_fluid_cascade_ghosts.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js#L35-L58).
170
+ - **Exact Quantitative Accounting (at default `64×32×64`, `FLUID_CASCADE_GHOST_DEPTH = 6`):**
171
+ - `FluidMacPasses.js` dispatches `threads = [77, 45, 77]` in `4×4×4` workgroups → `20 × 12 × 20 = 4,800` workgroups = **`307,200` threads**.
172
+ - Across the `307,200` launched threads:
173
+ - **Active threads (writing at least one of `u, v, w, p`):** `142,349` (`46.34%`).
174
+ - **Completely dead threads (writing nothing):** **`164,851` (`53.66%`)**.
175
+ - **100% no-op workgroups (all 64 threads exit without writing anything):** **`1,226` of `4,800` workgroups (`25.54%`)**.
176
+ - **Per-branch active threads:** `u`: `124,368` (`40.48%`), `v`: `124,752` (`40.61%`), `w`: `124,368` (`40.48%`), `ghost_pressure`: **`17,032` (`5.54%` — `94.46%` of threads are dead on the pressure branch)**.
177
+ - **Coordinate Offset Misalignment (Lines 36 vs. 53):**
178
+ - Velocity ghosts use `let face = vec3<i32>(id) - vec3<i32>(6);` (line 36), so the interior velocity cutout is `id ∈ [6..70] × [6..38] × [6..70]`.
179
+ - Pressure ghosts use `let cell = vec3<i32>(id) - vec3<i32>(1);` (line 53), so the $+x, +y, +z$ faces of the pressure ghost shell lie at **`id.x = 65`, `id.y = 33`, `id.z = 65` — cutting straight through the interior velocity cutout `[6..70, 6..38, 6..70]`**!
180
+ - This wakes up `574` otherwise-empty interior workgroups so a single plane of `16` threads in the `4×4×4` workgroup can write `ghost_pressure` while the other `48` threads in the workgroup do nothing.
181
+
182
+ ---
183
+
184
+ ### F-05: `shader_fluid_mac_curl` `16,224 B` LDS Ceiling & Duplicate `fluid_curl_omega` Evaluation
185
+ - **Location:** [`shader_fluid_mac_curl.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.js#L35-L171).
186
+ - **Mechanism:**
187
+ 1. Allocates `3 × 1,152 × 4 B = 13,824 B` (`fluid_curl_u/v/w`) + `600 × 4 B = 2,400 B` (`fluid_curl_magnitude`) = **`16,224` bytes of `var<workgroup>` memory** (`99.0%` of the 16 KiB limit), restricting residency to 1–2 workgroups per CU/SM (`16.7%–33.3%` warp occupancy).
188
+ 2. Computes `fluid_curl_omega(local)` (`12` LDS reads + `6` subtractions) **twice** for every interior cell: once at line 142 (`fluid_curl_magnitude[index] = length(fluid_curl_omega(local))`) and a second time after the barrier at line 164 (`let omega = fluid_curl_omega(local)`).
189
+ 3. Changing the LDS arrays to `f16` (`enable f16;`, per [`SHADER_F16_PROPOSAL_2026_10_24.md`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md#L112) `F16-03`) immediately halves LDS from **`16,224 B` to `8,112 B`**, and keeping the interior thread's `omega: vec3<f16>` in registers across the second barrier allows `fluid_curl_magnitude` to alias `fluid_curl_u[0..599]`, dropping total LDS to **`6,912 B`** (`42%` of the 16 KiB limit) and eliminating `256` duplicate `fluid_curl_omega` evaluations per workgroup.
190
+
191
+ ---
192
+
193
+ ### F-06: `shader_fluid_mac_gradient` Redundant Double Halo Load & Double Barrier
194
+ - **Location:** [`shader_fluid_mac_gradient.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.js#L35-L120), [`chunk_grid_tile_halo_f32.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/shader/chunk/grid/chunk_grid_tile_halo_f32.js#L62-L89).
195
+ - **Mechanism:**
196
+ - Lines 115–116 of `shader_fluid_mac_gradient.js` call `grid_tile_f32_load` **twice in a row**:
197
+ ```wgsl
198
+ grid_tile_f32_load(&fluid_mac_tile_pressure, FLUID_MAC_TILE_SOURCE_PRESSURE, step.cells, workgroup_id, local_index);
199
+ grid_tile_f32_load(&fluid_mac_tile_solid, FLUID_MAC_TILE_SOURCE_SOLID, step.cells, workgroup_id, local_index);
200
+ ```
201
+ - Because `grid_tile_f32_load` contains its own 3-iteration `index_to_grid3d` unpack loop and ends with `workgroupBarrier()`, calling it twice executes **two `workgroupBarrier()`s** and **two coordinate-unpack loops** serially, while spending **`2,400 B` of LDS** (`fluid_mac_tile_solid: array<f32, 600>`) to store a 1-bit `solid` flag as a 32-bit `f32`.
202
+ - Since `fluid_mac_tile_pressure` is never read for a solid cell (line 93: `if (fluid_mac_tile_cell_solid(a) || fluid_mac_tile_cell_solid(b)) { return current; }`), encoding a solid cell as a sentinel value (`F32_MAX`) inside `fluid_mac_tile_pressure` **eliminates `fluid_mac_tile_solid` (`2,400 B` LDS) and the second `grid_tile_f32_load` call (1 loop + 1 `workgroupBarrier()`) completely**.
203
+
204
+ ---
205
+
206
+ ### F-07: Underutilization of `r16float` Velocity Textures, `f16` LDS Tiles, and Hardware `textureSampleLevel`
207
+ - **Location:** [`FluidMacVelocitySet.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/FluidMacVelocitySet.js), [`shader_fluid_query_gather.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/query/shader_fluid_query_gather.js#L21-L65), [`chunk_v3_mac_lattice_corners.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.js), [`chunk_fluid_cascade_parent.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js).
208
+ - **Mechanism:**
209
+ 1. **Unnecessary 8-Tap Software Gather on `wind_field_atlas` in `shader_fluid_query_gather`:**
210
+ External GPU consumers ([`chunk_wind_field_sample_cascades.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/wind/chunk_wind_field_sample_cascades.js#L57)) sample `wind_field_atlas` (`rgba16float`) using a single hardware `textureSampleLevel` instruction. Yet [`shader_fluid_query_gather.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/query/shader_fluid_query_gather.js#L21-L62), which reads **that exact same `rgba16float` `wind_field_atlas` texture**, binds it as `unfilterable-float` and executes a manual 8-iteration `textureLoad` loop (`16` `textureLoad`s per query point in the blend band instead of `2` hardware `textureSampleLevel`s).
211
+ 2. **`r32float` vs. `r16float` Internal Velocity & Ghost Textures:**
212
+ All internal velocity and ghost 3D textures (`u, v, w`, `forward_u/v/w`, `advected_u/v/w`, `ghost_u/v/w`) are `r32float` (`4 B`/texel, `unfilterable-float`), even though the published wind field is `rgba16float` (`2 B`/channel) and `r16float` supports both `STORAGE_BINDING` (`write-only`, via `texture-formats-tier1` in `SHADE_DEVICE_FLOOR`) and `TEXTURE_BINDING` (`filterable-float`).
213
+ - In [`GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md#L591-L606) (§10, D6), software `textureLoad` of the 8 corners was retained in `advect_correct` for two specific reasons: (a) MacCormack's limiter requires the 8-corner `min` and `max` of `source_u/v/w`, and (b) 8-bit hardware trilinear filter weights (`1/256` sub-texel quantization) would perturb the second-order correction $\tfrac{1}{2}(\phi^n - \tilde{\phi})$.
214
+ - However:
215
+ 1. Storing `u, v, w`, `forward_u/v/w`, `advected_u/v/w`, and `ghost_u/v/w` in **`r16float`** halves 3D texture memory footprint and cache bandwidth (`4 B → 2 B`/texel) across **every pass** (`fill`, `ghosts`, `restrict`, `curl`, `advect_predict`, `advect_correct`, `divergence`, `gradient`, `forcing_apply`, `wind_publish`) while still allowing `textureLoad` of the 8 corners in `advect_predict` and `advect_correct` with exact `f32` trilinear weights and exact 8-corner `min/max` bounds!
216
+ 2. Furthermore, parent cascade interpolation (`fluid_parent_face_u/v/w` in `cascade_fill`, `cascade_ghosts`, `advect_correct` epilogue, and `wind_publish`) has no MacCormack difference and no `min/max` limiter — on `r16float` parent textures, every interior parent read reduces from an 8-iteration `textureLoad` loop (`24` loads for $(u, v, w)$) to a single hardware `textureSampleLevel` (`3` loads for $(u, v, w)$).
217
+ 3. Finally, [`GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md#L600-L603) noted that LDS-tiling `advect_correct` was previously infeasible in `f32` because staging both $\phi^n$ and $\hat{\phi}$ required `29.6 KiB > 16 KiB`. With `enable f16;`, staging both fields in `f16` requires `14.8 KiB`, fitting within the `16 KiB` workgroup memory budget whenever CFL $\le 4$.
218
+
219
+ ---
220
+
221
+ ## 4. Comparison Against Real-Time SotA GPU Wind & Dense Eulerian Solvers
222
+
223
+ Because atmospheric wind is **space-filling** (ambient flow, gusts, and wakes occupy the entire domain around the camera/player), the relevant State-of-the-Art comparisons are **real-time dense/clipmap wind solvers and dense GPU Eulerian projection/transport architectures**:
224
+
225
+ | Dimension | **Meep `shade/renderer/fluid` (Current)** | **Frostbite / Battlefield Volumetric Wind Clipmaps** | **Ubisoft La Forge — Compact Poisson Filters (Rabbani et al., SIGGRAPH 2022)** | **AAA Dense GPU Eulerian Grids (UE5 Niagara Grid3D / Horizon / God of War Wind)** | **Academic Dense Grid SotA (McAdams 2010 GMG / Advection-Reflection / Covector)** | **Real-Time Aerodynamic LBM (HOME-LBM 2023 / Weakly-Compressible Wind)** |
226
+ |---|---|---|---|---|---|---|
227
+ | **Domain Topology** | Nested player-centered 3D toroidal clipmap cascades (`4 × 64×32×64`, $2^c$ subcycling). | Nested camera/player-centered 3D clipmap cascades (`64×32×64` or `128×32×128`). | Dense 3D wind volume / clipmap around player and obstacles. | Dense 3D world-aligned or camera-following grid (`64³–128³`). | Dense 3D MAC grid with harmonic/cut-cell face weights. | Dense 3D clipmap/nested lattice (`64³–128³` per level, $2^c$ acoustic subcycling). |
228
+ | **Velocity Storage & Precision** | Staggered MAC in **3× `r32float` 3D textures** + 3× `r32float` ghost textures; published to `rgba16float` atlas. | Collocated **`rgba16float`** (`vec4<f16>`) deviation from ambient wind field. | Collocated or staggered **`rgba16float` / `r16float`**. | Staggered **`r16float`** or collocated **`rgba16float`** 3D textures. | Staggered MAC (`r16float` velocity, `f32` pressure). | Moment-encoded **`f16` / `snorm16`** (`10` words/cell: $\rho, \mathbf{u}, \boldsymbol{\Pi}^{\text{neq}}$) instead of 19/27 DDFs. |
229
+ | **Trilinear Sampling** | **Software 8-tap `textureLoad` loops** internally; hardware `textureSampleLevel` only in `wind_field_sample`. | **Hardware `textureSampleLevel`** on `rgba16float` everywhere. | **Hardware `textureSampleLevel`** on `rgba16float` / `r16float`. | **Hardware `textureSampleLevel`** on `r16float` / `rgba16float`. | Hardware `textureSampleLevel` for parent/SL taps; 8-corner `r16float` `textureLoad` for MacCormack clamp. | Strictly local integer neighbor reads (`±1` cell); no trilinear interpolation. |
230
+ | **Advection & Vorticity** | **2-pass MacCormack** (`predict` + `correct`) with 4-step solid bisection + optional 2-barrier LDS `curl` pass. | 1-pass Semi-Lagrangian + analytical vortex/motor primitives. | 1-pass Semi-Lagrangian or MacCormack + analytical curl/vorticity injection. | 1-pass Semi-Lagrangian or BFECC/MacCormack + vorticity confinement. | **Advection-Reflection** (Zehnder 2018) or **Covector** (Nabizadeh 2022). | Inherent low-dissipation BGK/TRT/cumulant collision (advection is exact lattice streaming). |
231
+ | **Incompressibility / Projection** | **2 V-cycles of GMG** (`24` dispatches/step): 2-sweep Red-Black GS in `8×8×4` `f32` LDS tiles; harmonic 6-face `u32` weight words. | Approximate local divergence relaxation (2–4 Jacobi sweeps) or motor-only divergence-free primitives. | **Compact Poisson Filter (CPF):** 1–3 separable/blocked 3D convolution passes (`O(1)` dispatches, zero V-cycles!). | 1–2 V-cycles GMG with damped Jacobi / Red-Black GS, or 16–24 Jacobi sweeps. | **1–2 V-cycles GMG / MGPCG** with staged coarse prolongation in LDS and fused restriction/coarsening. | **Zero Poisson passes** (weakly-compressible equation of state $p = c_s^2 \rho$ handled locally in collision). |
232
+ | **Obstacle Coupling** | Per-frame LBVH → cooperative brick query (`4×4×4`) → SDF + moving-wall face pinning + 4-level MG harmonic weights. | Heightfield + coarse SDF wind-shadow mask. | Binary/smooth solid mask folded into filter weights. | SDF/collider stamp into grid solid mask and velocity. | Harmonic face weights restricted alongside residuals down the V-cycle. | Bounce-back or interpolated bounce-back boundary condition inside the single LBM pass. |
233
+ | **GPU Occupancy Profile** | **Low (`15%–35%` on heavy passes):** VGPR bloat from nested $8\times 8$ dynamic corner loops (`advect`), `16.2 KB` `f32` LDS (`curl`), unstaged MG prolongation, `64`-thread WGs (`forcing`, `ghosts`). | **High (`70%–90%`):** Simple hardware-filtered `rgba16float` kernels, no nested loops, minimal LDS. | **Very High (`80%–95%`):** Fixed-radius convolution kernels with `100%` active threads and zero barriers. | **Medium–High (`50%–80%`):** Hardware TMU filtering, `f16` textures, low register count. | **High (`65%–85%`):** Staged LDS tiles, no nested dynamic loops, fused restriction. | **Very High (`75%–95%`):** 1–2 fused passes per step, 100% coalesced reads, zero global reductions/V-cycles. |
234
+
235
+ ### Architectural Assessment
236
+
237
+ 1. **What the Current Meep Wind Solver Gets Right (Preserve):**
238
+ - **Staggered MAC Discretization with Moving-Wall Face Pinning & Harmonic Multigrid Weights:** As proven in [`REVIEW_02_PLAN.md`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/engine/physics/fluid/REVIEW_02_PLAN.md#L116-L120), MAC staggering eliminates the collocated checkerboard null-mode (`D ∘ G ≡ L`), achieves exact zero wall penetration, and stabilizes MacCormack velocity transport without energy pumping. The 30-bit harmonic face-weight word (`chunk_fluid_mg_coarse_word.js`) preserves thin 1-cell obstacles across coarse multigrid levels, and the finite-volume Dirichlet edge weight `2 / (1 + 2^-level)` (`FLUID_MG.js`) keeps the boundary ghost location consistent across levels.
239
+ - **Atmosphere Deviation Identity & $2^c$ Cascade Subcycling:** Tracking the exact far-field ODE integration (`keep = exp(-ΔΛ)`) and publishing `rgba16float` deviations (`v - v_far`) into the clipmap atlas ensures that uniform or gusting ambient wind is represented with zero numerical drift across all cascades.
240
+ - **LBVH-Culled $4\times 4\times 4$ Brick Forcing:** While the wind velocity/pressure grid itself is dense and space-filling, obstacles and effectors are spatially sparse. Culling $4\times 4\times 4$ bricks via the LBVH (`GPUFluidForcing`) avoids evaluating 24 obstacles × 16 effectors across empty air bricks.
241
+
242
+ 2. **Where the Current Implementation Loses Occupancy Against SotA:**
243
+ - **Nested $8 \times 8$ Dynamic Loops in Advection (`chunk_v3_mac_lattice_corners.js` + `chunk_fluid_mac_seams.js`):** No SotA GPU solver runs a dynamic loop (`select(0u, 8u, ...)`) containing a nested dynamic 8-corner parent loop inside every trilinear velocity tap.
244
+ - **Unstaged Prolongation, Redundant Global Reads, `87.5%` Restrict Warp Idling, and Dead Barriers in Multigrid:** Issuing `4,800` global reads per workgroup for a `144`-cell coarse neighborhood in `shader_fluid_mg_smooth`, re-reading `input` from global memory after loading `tile_p`, idling 7 of 8 warps during restriction, and executing 16 dead trailing `workgroupBarrier()`s directly inflate the `71 µs` smoother/restriction cost.
245
+ - **`f32` LDS Ceiling in `shader_fluid_mac_curl` and `r32float` Velocity Storage:** Allocating `16,224 B` of `f32` LDS in `mac_curl` caps residency to 1–2 workgroups per CU/SM, while storing all velocity and ghost textures in `r32float` doubles 3D texture memory bandwidth relative to `r16float`.
246
+ - **Hollow-Box Dispatch in `shader_fluid_cascade_ghosts` and Unfused Multigrid Weight Passes:** Launching `307,200` threads over a solid box to write a hollow shell (`53.66%` dead threads) and running 4 separate weight-building dispatches (`level0_weights` + 3× `coarse_weights`) over cells and `words` already traversed by `mac_divergence` and `mg_residual_restrict` waste GPU occupancy every step.
247
+
248
+ ---
249
+
250
+ ## 5. Prioritized Recommendations & Implementation Roadmap
251
+
252
+ All recommendations below preserve the solver's space-filling clipmap MAC architecture, respect the `1.25×` CPU quality gate ([`GPUFluidCascade.quality.slow.spec.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/GPUFluidCascade.quality.slow.spec.js)) and precision boundaries ([`SHADER_F16_PROPOSAL_2026_10_24.md`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md) `F16-03` & `NO-F16-09`), and leverage `enable f16;` (`shader-f16`) and `r16float` (`texture-formats-tier1`).
253
+
254
+ ---
255
+
256
+ ### Priority 1 — High-Leverage Occupancy & Execution Fixes in the Hot Passes (`mg_smooth`, `mg_restrict`, `advect`, `curl`, `gradient`, `ghosts`)
257
+
258
+ #### R-01: Hoist `fluid_parent_face_*` Out of `fluid_mac_ghost_*` to Eliminate the Nested $8\times 8$ Dynamic Loop & Use `vec4<f16>` Corner Accumulators
259
+ - **Target Files:** [`chunk_fluid_mac_seams.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/chunk_fluid_mac_seams.js#L50-L189), [`chunk_v3_mac_lattice_corners.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/chunk_v3_mac_lattice_corners.js#L82-L185).
260
+ - **Problem:** `mac_source_u/v/w` and `mac_forward_u/v/w` call `fluid_mac_ghost_u/v/w(face)`, which falls back to `fluid_parent_face_u/v/w` when `texel` is outside `[0, size + 2*depth)`. This single fallback forces DXC to inline an **8-iteration dynamic loop (`fluid_parent_face_*`) inside every iteration of the outer 8-iteration corner loops (`v3_mac_source_corners_*` and `v3_mac_forward_corners_*`)** in both `advect_predict` (`16 µs`) and `advect_correct` (`27 µs`), exploding live VGPR state (`2×` `z0/z1` `vec4<f32>` accumulators + loop counters + coordinate vectors across two loop levels).
261
+ - **Fix:**
262
+ 1. **Make `fluid_mac_ghost_u/v/w(face)` a pure `textureLoad` from `ghost_u/v/w` (matching `mac_carrier_u/v/w`):**
263
+ ```wgsl
264
+ fn fluid_mac_ghost_u(face: vec3<i32>) -> f32 {
265
+ let texel = clamp(
266
+ face + vec3<i32>(FLUID_MAC_GHOST_DEPTH),
267
+ vec3<i32>(0),
268
+ vec3<i32>(step.faces_u.size) + vec3<i32>(2 * FLUID_MAC_GHOST_DEPTH - 1)
269
+ );
270
+ return textureLoad(ghost_u, vec3<u32>(texel), 0).r;
271
+ }
272
+ ```
273
+ 2. **Hoist the storm-wind (`|v_far|·dt/h > 1`) parent fallback outside the 8-corner loop in `v3_mac_source_corners_*` and `v3_mac_forward_corners_*`:**
274
+ As proven in **F-01.3**, because `tap.hi == tap.lo + 1` and `FLUID_MAC_GHOST_DEPTH = 6 >= 1`, whenever `any(tap.lo < vec3<i32>(-FLUID_MAC_GHOST_DEPTH)) || any(tap.hi >= vec3<i32>(step.faces_u.size) + vec3<i32>(FLUID_MAC_GHOST_DEPTH))`, **all 8 corners of `tap` are guaranteed to lie outside the child window**. Evaluating `fluid_parent_face_*` in an `if` branch *before* the 8-corner loop preserves 100% exact storm-wind behavior while completely eliminating the $8 \times 8$ loop nesting!
275
+ 3. **Use `vec4<f16>` for `z0` and `z1` (`enable f16;`)**:
276
+ In `chunk_v3_mac_lattice_corners.js` and `chunk_fluid_cascade_parent.js`, store the 8 corner samples in `var z0: vec4<f16>; var z1: vec4<f16>;` (converting back to `vec4<f32>` for the trilinear weight dot product), cutting the live corner-accumulator VGPRs from `8 × 32-bit` to `4 × 32-bit` registers.
277
+ - **Impact:** Eliminates all nested $8\times 8$ dynamic `textureLoad` loops in `advect_predict` (`16 µs`) and `advect_correct` (`27 µs`) while preserving exact storm-wind fallback, substantially reducing VGPR pressure and increasing warp occupancy across `29.8%` of the step.
278
+
279
+ #### R-02: Stage the `6×6×4` Coarse Tile in LDS in `shader_fluid_mg_smooth`, Drop Redundant `held = input[...]` Global Reads, Parallelize Restriction, and Delete 16 Dead Trailing Barriers
280
+ - **Target Files:** [`shader_fluid_mg_smooth.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_smooth.js#L63-L171), [`shader_fluid_mg_residual_restrict.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js#L49-L142), [`shader_fluid_mg_coarsest.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_coarsest.js#L140-L153).
281
+ - **Problem:**
282
+ 1. Up-leg `shader_fluid_mg_smooth` (`params.prolong != 0u`) calls `fluid_mg_prolong` for all `600` halo cells, issuing **`600 × 8 = 4,800` global reads from `coarse`** per workgroup for a region that spans only **`6×6×4 = 144` unique coarse cells**.
283
+ 2. Both `shader_fluid_mg_smooth.js:140` and `shader_fluid_mg_residual_restrict.js:114` re-read `let held = input[fluid_mg_input_index(...)]` from global memory after `grid_tile_f32_load` has already fetched `input` for the entire tile into `tile_p`.
284
+ 3. All three pressure barrier kernels (`shader_fluid_mg_smooth.js:169`, `shader_fluid_mg_residual_restrict.js:137`, `shader_fluid_mg_coarsest.js:150`) execute a trailing `workgroupBarrier()` immediately before `subgroup_atomic_add_u32(&nonfinite[0], nonfinite_here);`, even though `subgroup_atomic_add_u32` uses only subgroup intrinsics and global atomics and **never touches `var<workgroup>` memory**.
285
+ 4. In `shader_fluid_mg_residual_restrict.js:128`, `if (lane < 32u)` uses only 1 warp (`32` threads) to sum 8 fine residuals per coarse cell while 7 warps (`224` threads = `87.5%`) sit idle.
286
+ - **Fix:**
287
+ 1. **Stage `144` coarse cells in LDS (`tile_coarse: array<f32, 144>`, `576 B`):** When `params.prolong != 0u`, lanes `0..143` load the `6×6×4` coarse neighborhood (`coarse_base = vec3<i32>(workgroup_id * vec3<u32>(4u, 4u, 2u)) - vec3<i32>(1)`) into `tile_coarse` (`144` global loads instead of `4,800`) before the halo load barrier, and `fluid_mg_prolong` reads its 8 trilinear corners from `tile_coarse`. Total LDS in `shader_fluid_mg_smooth` is `2,400 + 576 = 2,976 B` (`18.2%` of 16 KiB, preserving 5–6 WGs/SM = `83%–100%` occupancy on RTX 4090 and 100% `f32` precision per `NO-F16-09`).
288
+ 2. **Eliminate redundant `held = input[...]` global reads & call `subgroup_atomic_add_u32` immediately:** In `shader_fluid_mg_residual_restrict` (`prolong == 0u`), `tile_p` already holds the sanitized `input` (or record a 1-bit `nonfinite` flag during `grid_tile_f32_load`) and call `subgroup_atomic_add_u32(&nonfinite[0], nonfinite_here)` immediately after the load barrier so `nonfinite_here` does not occupy a live VGPR across the stencil sweeps.
289
+ 3. **Delete the 16 dead trailing `workgroupBarrier()`s** before `subgroup_atomic_add_u32` in `shader_fluid_mg_smooth.js:169`, `shader_fluid_mg_residual_restrict.js:137`, and `shader_fluid_mg_coarsest.js:150`.
290
+ 4. **Parallelize restriction in `shader_fluid_mg_residual_restrict`:** Have threads `0..127` (`4` warps) reduce pairs of $z$-layers in `tile_r` (`tile_r[lane] += tile_r[lane + 128u]`) or map the $2\times 2\times 2$ fine block to 8 consecutive lanes so `subgroupAdd` / `subgroupShuffleXor` computes the 8-child mean without 7 warps idling.
291
+ - **Impact:** Directly accelerates the **`71 µs` (`49.2%` of step)** multigrid smoother + restriction passes: cuts coarse prolongation global reads by **`33.3×` (`4,800 → 144`/WG)**, removes `256` redundant global loads per workgroup across 14 dispatches, and removes 16 dead `workgroupBarrier()`s per step while keeping full `f32` V-cycle precision (`NO-F16-09`).
292
+
293
+ #### R-03: Migrate `shader_fluid_mac_curl` LDS Tiles to `f16` (`enable f16;`) and Compute `fluid_curl_omega` Once per Thread (`16,224 B → 6,912 B` LDS)
294
+ - **Target Files:** [`shader_fluid_mac_curl.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_curl.js#L40-L171).
295
+ - **Problem:** `shader_fluid_mac_curl` uses **`16,224 B` of `f32` LDS** (`99.0%` of WebGPU's `16,384 B` limit), capping CU/SM residency to 1–2 workgroups (`16.7%–33.3%` occupancy) and computing `fluid_curl_omega(local)` twice per interior cell (lines 142 and 164).
296
+ - **Fix (aligned with [`SHADER_F16_PROPOSAL_2026_10_24.md`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md#L112) `F16-03`):**
297
+ 1. Enable `f16` (`shader_fluid_mac_curl.addExtension(WebGPUExtensionType.ShaderF16)`), declare `fluid_curl_u/v/w: array<f16, 1152>` (`3 × 2,304 B = 6,912 B`) and `fluid_curl_magnitude: array<f16, 600>` (`1,200 B`).
298
+ 2. Keep the interior cell's `let omega: vec3<f16> = fluid_curl_omega(vec3<i32>(local_id));` in a `vec3<f16>` register (`2` 32-bit VGPRs) across the second barrier instead of recomputing `fluid_curl_omega(local)` at line 164. Because `fluid_curl_u/v/w` is never read again after line 143 once `omega` is held in registers, `fluid_curl_magnitude` can also alias `fluid_curl_u[0..599]`, dropping total LDS from **`16,224 B` to `6,912 B` (`−57.4%`)**!
299
+ - **Impact:** Doubles or triples LDS-limited workgroup residency in `shader_fluid_mac_curl` (`1–2 WGs/CU → 4+ WGs/CU`) and eliminates `256` duplicate 12-tap curl evaluations per workgroup (`131,072` fewer LDS reads per `L0` dispatch).
300
+
301
+ #### R-04: Fuse `shader_fluid_mac_gradient`'s Double Halo Load & Sentinel-Encode `solid` (`2 Barriers → 1`, `4,800 B → 2,400 B` LDS)
302
+ - **Target Files:** [`shader_fluid_mac_gradient.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_gradient.js#L35-L120).
303
+ - **Problem:** `shader_fluid_mac_gradient` calls `grid_tile_f32_load` twice back-to-back (lines 115–116), executing **2 `workgroupBarrier()`s**, **2 halo coordinate-unpack loops**, and allocating **`2,400 B` of LDS** (`fluid_mac_tile_solid: array<f32, 600>`) for a 1-bit solid flag.
304
+ - **Fix:** Because a solid cell's pressure is never read (`if (fluid_mac_tile_cell_solid(a) || fluid_mac_tile_cell_solid(b)) { return current; }`), write a sentinel value (`F32_MAX` or `bitcast<f32>(0x7f7fffffu)`) into `fluid_mac_tile_pressure[index]` whenever `mac_cell_solid(cell)` is `true` during the single load loop!
305
+ - **Impact:** Deletes `fluid_mac_tile_solid` completely (`4,800 B → 2,400 B` LDS), deletes the second `grid_tile_f32_load` loop, and cuts `workgroupBarrier()` count in `shader_fluid_mac_gradient` from `2` to `1`.
306
+
307
+ #### R-05: Fix `shader_fluid_cascade_ghosts` Pressure Shell Offset & Eliminate Interior No-Op Workgroups
308
+ - **Target Files:** [`shader_fluid_cascade_ghosts.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/coupling/shader_fluid_cascade_ghosts.js#L35-L58), [`FluidMacPasses.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/FluidMacPasses.js#L178-L181).
309
+ - **Problem:** Dispatches `[20, 12, 20] = 4,800` workgroups (`307,200` threads) over the filled `[77, 45, 77]` box where `164,851` threads (`53.66%`) are dead and `1,226` workgroups (`25.54%`) are 100% interior no-ops. Worse, `cell = vec3<i32>(id) - vec3<i32>(1)` (line 53) places the $+x, +y, +z$ pressure ghost faces at `id = (65, 33, 65)` — **inside** the velocity interior `[6..70, 6..38, 6..70]`.
310
+ - **Fix:**
311
+ 1. **Align pressure ghosts with velocity ghosts:** Set `let cell = face;` (`vec3<i32>(id) - vec3<i32>(FLUID_CASCADE_GHOST_DEPTH)`) and `let p_id = vec3<u32>(cell + vec3<i32>(1));`. Now the pressure ghost shell `cell ∈ [-1..size]` lies on the inner skin of the velocity ghost shell (`id ∈ [0..5]` and `[size+6..size+12]`), so **zero interior workgroups (`id ∈ [6..69, 6..37, 6..69]`) are ever touched by pressure ghosts** (`1,800` interior workgroups become 100% empty instead of `1,226`).
312
+ 2. **Skip interior workgroups at dispatch:** Map a 1D/3D workgroup grid onto only the boundary workgroups of the `20×12×20` box (`4,800 - 1,800 = 3,000` workgroups at `64×32×64`), eliminating all `1,800` interior no-op workgroups (`115,200` dead threads).
313
+
314
+ ---
315
+
316
+ ### Priority 2 — Hardware `textureSampleLevel`, `r16float` Velocity Storage, Forcing VGPR Reduction, & Dynamic MG Weight Fusion
317
+
318
+ #### R-06: Use Hardware `textureSampleLevel` in `shader_fluid_query_gather` & Parent Seam Reads, and Migrate Velocity/Ghost 3D Textures to `r16float`
319
+ - **Target Files:** [`shader_fluid_query_gather.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/query/shader_fluid_query_gather.js#L21-L65), [`FluidMacVelocitySet.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/FluidMacVelocitySet.js), [`chunk_fluid_cascade_parent.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js), [`GPUFluidCascade.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/GPUFluidCascade.js).
320
+ - **Problem:**
321
+ 1. [`shader_fluid_query_gather.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/query/shader_fluid_query_gather.js#L21-L62) binds `wind_field_atlas` (`rgba16float`) as `unfilterable-float` and executes an 8-tap `textureLoad` loop (`16` loads in the blend band), whereas [`chunk_wind_field_sample_cascades.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/wind/chunk_wind_field_sample_cascades.js#L57) already samples `wind_field_atlas` with `1` hardware `textureSampleLevel`.
322
+ 2. Internal velocity and ghost textures (`u, v, w`, `forward_u/v/w`, `advected_u/v/w`, `ghost_u/v/w`) use `r32float` (`4 B`/texel, `unfilterable-float`) instead of `r16float` (`2 B`/texel, `filterable-float` + `write-only` storage texture via `texture-formats-tier1`).
323
+ - **Fix:**
324
+ 1. **Immediate win in `shader_fluid_query_gather.js`:** Bind `wind_field_atlas` with a linear clamp sampler (matching `chunk_wind_field_sample_cascades.js`) and replace the 8-tap `textureLoad` loop with `textureSampleLevel` (`8×` fewer texture instructions).
325
+ 2. **Migrate internal velocity and ghost 3D textures to `r16float`:** Because wind velocity deviations are clamped to $|v - v_{\text{far}}| \le 4 h / \Delta t = 80\text{ m/s}$ (`f16` ULP $\le 0.0625\text{ m/s}$ at peak storm speed and $< 0.004\text{ m/s}$ in normal winds) and published to `rgba16float`, storing `u, v, w`, `forward_u/v/w`, `advected_u/v/w`, and `ghost_u/v/w` in `r16float` halves 3D texture memory and L1/L2 cache bandwidth across all passes.
326
+ 3. **Preserve MacCormack `min/max` & `f32` weights in `advect_correct` while using `textureSampleLevel` for parent reads:** Keep the 8-corner `textureLoad` in `v3_mac_source_corners_*` and `v3_mac_forward_corners_*` (which now loads `r16float` texels at `2×` cache density while preserving `f32` trilinear weights and the 8-corner `min/max` MacCormack limiter per D6 of [`GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md#L591-L606)), and use hardware `textureSampleLevel` in `fluid_parent_face_u/v/w` (`cascade_fill`, `cascade_ghosts`, `advect_correct` epilogue, and `wind_publish`) whenever the parent tap does not straddle the toroidal wrap seam.
327
+
328
+ #### R-07: Pre-Normalize Obstacle Transforms in LDS & Eliminate By-Value Struct Copies in `shader_fluid_forcing_apply`
329
+ - **Target Files:** [`shader_fluid_forcing_apply.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/shader_fluid_forcing_apply.js#L62-L162), [`chunk_fluid_forcing_cell.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/chunk_fluid_forcing_cell.js#L92-L148), [`chunk_fluid_obstacle_record.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/chunk_fluid_obstacle_record.js#L26-L70), [`shader_fluid_forcing_command.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/forcing/shader_fluid_forcing_command.js).
330
+ - **Problem:** `shader_fluid_forcing_apply` (`@workgroup_size(4,4,4)` = 64 threads, `4,724 B` LDS) copies 80 B `FluidObstacleRecord`, 64 B `mat4x4<f32>`, and 48 B `FluidEffectorRecord` structs by value from LDS into VGPRs inside its loops, and every thread (`64` threads) re-normalizes `global[0..2].xyz` (`3 × inverseSqrt`) for each of the up to `24` obstacles (`72` `normalize()` calls per thread).
331
+ - **Fix:**
332
+ 1. **Normalize once on LDS load:** When threads `0..obstacle_count-1` load `fluid_forcing_globals[lane]` into LDS at lines 99–103 of `shader_fluid_forcing_apply.js`, normalize the 3 unit rotation columns right there before writing to LDS (storing them as `vec3<f16>` or `mat3x4<f32>`, saving `384–960 B` LDS and **`72` `normalize()` calls per thread**).
333
+ 2. **Index LDS in-place instead of copying structs by value:** Pass the LDS slot index `slot: u32` into the containment check and read `fluid_forcing_obstacles[slot].linear_velocity` **only when `distance <= obstacle.inflation`** (`true` for a small fraction of obstacle checks), avoiding materializing the 20-word struct in VGPRs on every loop iteration.
334
+ 3. **Fold `shader_fluid_forcing_command` (`1×1×1`) into `shader_fluid_forcing_query`:** Initialize `command` to `[0, 1, 1, 0, 1, 1]` and have `shader_fluid_forcing_query` atomically increment `command[0]` (and `command[3]`), removing the single-thread `shader_fluid_forcing_command` dispatch and its inter-dispatch barrier.
335
+
336
+ #### R-08: Dynamically Fuse `shader_fluid_mg_level0_weights` into `shader_fluid_mac_divergence` and `shader_fluid_mg_coarse_weights` into `shader_fluid_mg_residual_restrict`
337
+ - **Target Files:** [`shader_fluid_mac_divergence.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/mac/shader_fluid_mac_divergence.js), [`shader_fluid_mg_level0_weights.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_level0_weights.js), [`shader_fluid_mg_coarse_weights.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_coarse_weights.js), [`shader_fluid_mg_residual_restrict.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/shader_fluid_mg_residual_restrict.js), [`GPUFluidPressureSolve.js`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.js#L300-L326).
338
+ - **Problem:** Every cascade step executes `4` standalone weight-building dispatches (`shader_fluid_mg_level0_weights` + 3× `shader_fluid_mg_coarse_weights`, costing `8.2 µs` per step at `64×32×64`), plus at `L3` (`8×4×8`), `shader_fluid_mg_coarse_weights` launches `[1, 1, 2]` workgroups of `8×8×4` where `50%` of threads (`cell.y >= 4`) immediately early-return.
339
+ - **Observation — 100% of the Data and Grid Walks Already Exist in `mac_divergence` and `mg_residual_restrict`:**
340
+ 1. `shader_fluid_mac_divergence` and `shader_fluid_mg_level0_weights` both dispatch the exact same `8×8×4` workgroup grid over `step.cells.size` (`64×32×64`) right before the pressure solve and both bind `solid` (`array<u32>`, read-only).
341
+ 2. In [`GPUFluidPressureSolve.js:315-321`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.js#L315-L321), `levels[l + 1].words` ($l \in \{0, 1, 2\}$) is **never read until `this.#down[l + 1]`** (or `this.#coarsest` for $l + 1 = 3$), which executes **immediately after `this.#restrict[l]` (`shader_fluid_mg_residual_restrict`)** on the first V-cycle (`cycle === 0`).
342
+ 3. Furthermore, [`chunk_fluid_mg_coarse_word.js:29-47`](file:///H:/git/CompanyNamed/meep/packages/meep-engine/src/shade/renderer/fluid/pressure/chunk_fluid_mg_coarse_word.js#L29-L47) (`fluid_mg_coarse_word(coarse)`) is a **strictly block-local function of the $2\times 2\times 2 = 8$ fine child words `w0..w7`** (`2 * coarse + [0..1]^3`) — the exact same 8 fine cells whose `word = words[index]` is already loaded by `shader_fluid_mg_residual_restrict.js:111` and whose residuals are restricted into `coarse_cell`!
343
+ - **Fix (100% Dynamic Every Step, Zero CPU State Tracking):**
344
+ 1. **Fuse `level0_weights` into `shader_fluid_mac_divergence`:** Bind `levels[0].words` (`write-only` storage buffer) in `shader_fluid_mac_divergence` and write `words[idx] = fluid_mg_level0_word(vec3<i32>(id), step.cells.size);` alongside `rhs[idx]`.
345
+ 2. **Fuse `coarse_weights` into `shader_fluid_mg_residual_restrict` (on `cycle === 0`):** After the barrier in `shader_fluid_mg_residual_restrict`, while Warp 0 (`lane < 32u`) computes and writes `coarse_rhs[coarse_index]` and `coarse_error[coarse_index]` for the `4×4×2 = 32` coarse cells of the tile, have **Warp 1 (`lane ∈ [32..63]`, which is currently 100% idle after the barrier!)** compute `coarse_words[coarse_index] = fluid_mg_coarse_word(coarse_local)` from the tile's fine `words`!
346
+ - **Impact:** Unconditionally eliminates **all 4 weight-building dispatches (`shader_fluid_mg_level0_weights` and 3× `shader_fluid_mg_coarse_weights`, saving `4` dispatches and up to `8.2 µs` per step)** on **every single step** while remaining 100% dynamic and utilizing an otherwise-idle warp (`lane ∈ [32..63]`) inside `shader_fluid_mg_residual_restrict`.
347
+
348
+ ---
349
+
350
+ ## 6. Summary Impact Matrix
351
+
352
+ | ID | Recommendation | Target Shaders / Files | Measured Step Share Affected | Expected Occupancy & Cost Impact |
353
+ |---|---|---|---|---|
354
+ | **R-01** | Hoist `fluid_parent_face_*` out of `fluid_mac_ghost_*` (break nested $8\times 8$ loop while preserving storm-wind fallback + `vec4<f16>` corner accumulators) | `chunk_fluid_mac_seams.js`, `chunk_v3_mac_lattice_corners.js`, `chunk_fluid_cascade_parent.js` | **`43.0 µs`** (`29.8%` of step) | Eliminates nested $8\times 8$ dynamic `textureLoad` loops in `advect_predict` and `advect_correct`; major VGPR reduction and higher SM warp occupancy. |
355
+ | **R-02** | Stage `6×6×4` coarse tile in LDS (`4,800 → 144` reads/WG), drop redundant `held = input[...]` global read, delete 16 dead trailing barriers, parallelize restrict | `shader_fluid_mg_smooth.js`, `shader_fluid_mg_residual_restrict.js`, `shader_fluid_mg_coarsest.js` | **`71.0 µs`** (`49.2%` of step) | **`33.3×` fewer coarse global reads** on up-sweeps; removes `256` redundant global reads/WG across 14 dispatches; removes 16 dead barriers/step; eliminates `87.5%` warp idling in restrict while keeping full `f32` precision (`NO-F16-09`). |
356
+ | **R-03** | Migrate `mac_curl` LDS tiles to `f16` (`enable f16;`, `F16-03`) + hold `omega` in registers across barrier 2 | `shader_fluid_mac_curl.js` | **`8.2 µs`** (`5.4%` of step with curl) | Drops `mac_curl` LDS from `16,224 B` to **`6,912 B` (`−57.4%`)**, doubling/tripling CU/SM residency; eliminates `256` duplicate 12-tap curl evaluations/WG. |
357
+ | **R-04** | Fuse double `grid_tile_f32_load` in `mac_gradient` via sentinel-encoded `solid` | `shader_fluid_mac_gradient.js` | **`4.1 µs`** (`2.8%` of step) | Cuts `mac_gradient` LDS from `4,800 B` to `2,400 B`, removes 1 `workgroupBarrier()` and 1 halo unpack loop. |
358
+ | **R-05** | Align `cell = face` in `cascade_ghosts` + skip interior no-op workgroups | `shader_fluid_cascade_ghosts.js`, `FluidMacPasses.js` | **`9.0 µs`** (`6.2%` of step) | Eliminates `164,851` dead threads (`53.66%`) and `1,800` interior workgroups (`−37.5%` WGs launched). |
359
+ | **R-06** | Use hardware `textureSampleLevel` in `query_gather` (`rgba16float`) & parent seam reads, and migrate internal velocity/ghost 3D textures to `r16float` (`texture-formats-tier1`) | `shader_fluid_query_gather.js`, `FluidMacVelocitySet.js`, `chunk_fluid_cascade_parent.js` | **`52+ µs`** (`36%+` of step + queries) | Halves velocity texture bandwidth (`4 B → 2 B`/texel), preserves MacCormack 8-corner `min/max` & `f32` weights in `correct`, and replaces 8-tap parent/query software loops with 1-cycle hardware TMU taps. |
360
+ | **R-07** | Pre-normalize obstacle transforms in LDS, index records in-place (`forcing_apply`), and fold `1×1×1` `forcing_command` into `forcing_query` | `shader_fluid_forcing_apply.js`, `chunk_fluid_forcing_cell.js`, `chunk_fluid_obstacle_record.js`, `shader_fluid_forcing_query.js` | **`34–88 µs`** (forcing tick) | Saves `72` `normalize()` calls/thread; avoids copying `80 B + 64 B` structs into VGPRs; removes `1×1×1` command dispatch. |
361
+ | **R-08** | Dynamically fuse `level0_weights` into `mac_divergence` and `coarse_weights` into Warp 1 of `mg_residual_restrict` (`cycle === 0`) | `shader_fluid_mac_divergence.js`, `shader_fluid_mg_residual_restrict.js`, `GPUFluidPressureSolve.js` | **`8.2 µs`** (`5.7%` of step) | Unconditionally eliminates all `4` standalone weight dispatches (`24 → 20` MG dispatches/step) every step with zero CPU dirty tracking, while putting idle Warp 1 (`lane ∈ [32..63]`) in `mg_residual_restrict` to work. |
@@ -1 +1 @@
1
- {"version":3,"file":"chunk_fluid_cascade_parent.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js"],"names":[],"mappings":"AAsBA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,kDAFU,SAAS,CAoIjB;AAEF;;;;;;;;;;;;;;;GAeG;AACH,kDAFU,SAAS,CAmDjB;0BA3OwB,oCAAoC"}
1
+ {"version":3,"file":"chunk_fluid_cascade_parent.d.ts","sourceRoot":"","sources":["../../../../../../src/shade/renderer/fluid/coupling/chunk_fluid_cascade_parent.js"],"names":[],"mappings":"AAsBA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,kDAFU,SAAS,CAmMjB;AAEF;;;;;;;;;;;;;;;GAeG;AACH,kDAFU,SAAS,CAkFjB;0BAzUwB,oCAAoC"}