@woosh/meep-engine 3.29.0 → 3.31.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 (1766) hide show
  1. package/build/bundle-worker-image-decoder.js +1 -1
  2. package/build/bundle-worker-terrain.js +1 -1
  3. package/package.json +3 -1
  4. package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
  5. package/src/core/binary/BinaryBuffer.js +56 -16
  6. package/src/core/binary/BitImage2.d.ts.map +1 -1
  7. package/src/core/binary/BitImage2.js +2 -6
  8. package/src/core/binary/BitSet.js +5 -5
  9. package/src/core/binary/compression/chunks_to_stream.d.ts +24 -0
  10. package/src/core/binary/compression/chunks_to_stream.d.ts.map +1 -0
  11. package/src/core/binary/compression/chunks_to_stream.js +35 -0
  12. package/src/core/binary/compression/compress_bytes.d.ts +3 -4
  13. package/src/core/binary/compression/compress_bytes.d.ts.map +1 -1
  14. package/src/core/binary/compression/compress_bytes.js +6 -17
  15. package/src/core/binary/compression/decompress_bytes.d.ts +1 -2
  16. package/src/core/binary/compression/decompress_bytes.d.ts.map +1 -1
  17. package/src/core/binary/compression/decompress_bytes.js +4 -15
  18. package/src/core/binary/compression/decompress_bytes_into.d.ts.map +1 -1
  19. package/src/core/binary/compression/decompress_bytes_into.js +2 -13
  20. package/src/core/binary/ctz32.d.ts +12 -4
  21. package/src/core/binary/ctz32.d.ts.map +1 -1
  22. package/src/core/binary/ctz32.js +23 -41
  23. package/src/core/binary/lsb_32.d.ts +10 -2
  24. package/src/core/binary/lsb_32.d.ts.map +1 -1
  25. package/src/core/binary/lsb_32.js +17 -12
  26. package/src/core/binary/lz4/lz4_compress_block_hc.js +2 -2
  27. package/src/core/binary/type/DataTypeIndices.d.ts +39 -0
  28. package/src/core/binary/type/DataTypeIndices.d.ts.map +1 -1
  29. package/src/core/binary/type/DataTypeIndices.js +38 -1
  30. package/src/core/binary/type/Type.d.ts.map +1 -1
  31. package/src/core/binary/type/Type.js +6 -1
  32. package/src/core/bvh2/bvh3/BVH.d.ts.map +1 -1
  33. package/src/core/bvh2/bvh3/BVH.js +14 -1
  34. package/src/core/bvh2/bvh3/ebvh_optimize_treelet.js +3 -3
  35. package/src/core/bvh8/bvh8_geometry_validate.d.ts.map +1 -1
  36. package/src/core/bvh8/bvh8_geometry_validate.js +2 -88
  37. package/src/core/bvh8/bvh8_geometry_validate_bounds.d.ts +25 -0
  38. package/src/core/bvh8/bvh8_geometry_validate_bounds.d.ts.map +1 -0
  39. package/src/core/bvh8/bvh8_geometry_validate_bounds.js +105 -0
  40. package/src/core/bvh8/bvh8_geometry_validate_indirect.d.ts.map +1 -1
  41. package/src/core/bvh8/bvh8_geometry_validate_indirect.js +2 -91
  42. package/src/core/cache/FrequencySketch.d.ts +3 -1
  43. package/src/core/cache/FrequencySketch.d.ts.map +1 -1
  44. package/src/core/cache/FrequencySketch.js +10 -4
  45. package/src/core/cache/wtinylfu/CacheWTinylfu.d.ts.map +1 -1
  46. package/src/core/cache/wtinylfu/CacheWTinylfu.js +24 -2
  47. package/src/core/clipboard/obtainClipBoard.d.ts +4 -0
  48. package/src/core/clipboard/obtainClipBoard.d.ts.map +1 -1
  49. package/src/core/clipboard/obtainClipBoard.js +29 -8
  50. package/src/core/clipboard/safeClipboardReadText.d.ts.map +1 -1
  51. package/src/core/clipboard/safeClipboardReadText.js +73 -38
  52. package/src/core/clipboard/safeClipboardWriteText.d.ts.map +1 -1
  53. package/src/core/clipboard/safeClipboardWriteText.js +11 -9
  54. package/src/core/collection/array/iterator/ArrayIteratorRandom.d.ts.map +1 -1
  55. package/src/core/collection/array/iterator/ArrayIteratorRandom.js +6 -0
  56. package/src/core/collection/heap/IndexedFloatMinHeap.d.ts +6 -0
  57. package/src/core/collection/heap/IndexedFloatMinHeap.d.ts.map +1 -1
  58. package/src/core/collection/heap/IndexedFloatMinHeap.js +14 -0
  59. package/src/core/collection/list/FilteredListProjection.d.ts.map +1 -1
  60. package/src/core/collection/list/FilteredListProjection.js +7 -54
  61. package/src/core/collection/list/List.d.ts +4 -0
  62. package/src/core/collection/list/List.d.ts.map +1 -1
  63. package/src/core/collection/list/List.js +10 -52
  64. package/src/core/collection/list/SortedListProjection.d.ts +7 -0
  65. package/src/core/collection/list/SortedListProjection.d.ts.map +1 -1
  66. package/src/core/collection/list/SortedListProjection.js +12 -0
  67. package/src/core/collection/list/list_apply_ordered_diff.d.ts +37 -0
  68. package/src/core/collection/list/list_apply_ordered_diff.d.ts.map +1 -0
  69. package/src/core/collection/list/list_apply_ordered_diff.js +87 -0
  70. package/src/core/collection/map/BiMap.d.ts.map +1 -1
  71. package/src/core/collection/map/BiMap.js +19 -6
  72. package/src/core/collection/map/HashMap.d.ts.map +1 -1
  73. package/src/core/collection/map/HashMap.js +38 -11
  74. package/src/core/collection/queue/Deque.d.ts +2 -2
  75. package/src/core/collection/queue/Deque.d.ts.map +1 -1
  76. package/src/core/collection/queue/Deque.js +12 -1
  77. package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
  78. package/src/core/collection/table/RowFirstTable.js +15 -2
  79. package/src/core/collection/table/serializeRowFirstTable.d.ts.map +1 -1
  80. package/src/core/collection/table/serializeRowFirstTable.js +2 -3
  81. package/src/core/color/operations/color_lerp.d.ts.map +1 -1
  82. package/src/core/color/operations/color_lerp.js +77 -55
  83. package/src/core/color/sRGB/linear_to_sRGB.d.ts.map +1 -1
  84. package/src/core/color/sRGB/linear_to_sRGB.js +3 -1
  85. package/src/core/debug/matchers/AllOf.d.ts +2 -1
  86. package/src/core/debug/matchers/AllOf.d.ts.map +1 -1
  87. package/src/core/debug/matchers/AllOf.js +1 -1
  88. package/src/core/debug/matchers/AnyOf.d.ts +2 -1
  89. package/src/core/debug/matchers/AnyOf.d.ts.map +1 -1
  90. package/src/core/debug/matchers/AnyOf.js +1 -1
  91. package/src/core/debug/matchers/CombinableMatcher.d.ts +2 -1
  92. package/src/core/debug/matchers/CombinableMatcher.d.ts.map +1 -1
  93. package/src/core/debug/matchers/CombinableMatcher.js +1 -1
  94. package/src/core/debug/matchers/DescribeAs.d.ts +2 -1
  95. package/src/core/debug/matchers/DescribeAs.d.ts.map +1 -1
  96. package/src/core/debug/matchers/DescribeAs.js +2 -1
  97. package/src/core/debug/matchers/IsAnything.d.ts +2 -1
  98. package/src/core/debug/matchers/IsAnything.d.ts.map +1 -1
  99. package/src/core/debug/matchers/IsAnything.js +2 -1
  100. package/src/core/debug/matchers/IsEqual.d.ts +2 -1
  101. package/src/core/debug/matchers/IsEqual.d.ts.map +1 -1
  102. package/src/core/debug/matchers/IsEqual.js +2 -1
  103. package/src/core/debug/matchers/IsFinite.d.ts +2 -1
  104. package/src/core/debug/matchers/IsFinite.d.ts.map +1 -1
  105. package/src/core/debug/matchers/IsFinite.js +2 -1
  106. package/src/core/debug/matchers/IsIn.d.ts +2 -1
  107. package/src/core/debug/matchers/IsIn.d.ts.map +1 -1
  108. package/src/core/debug/matchers/IsIn.js +2 -1
  109. package/src/core/debug/matchers/IsInteger.d.ts +2 -1
  110. package/src/core/debug/matchers/IsInteger.d.ts.map +1 -1
  111. package/src/core/debug/matchers/IsInteger.js +2 -1
  112. package/src/core/debug/matchers/IsIterableContaining.d.ts +2 -1
  113. package/src/core/debug/matchers/IsIterableContaining.d.ts.map +1 -1
  114. package/src/core/debug/matchers/IsIterableContaining.js +1 -1
  115. package/src/core/debug/matchers/IsNot.d.ts +2 -1
  116. package/src/core/debug/matchers/IsNot.d.ts.map +1 -1
  117. package/src/core/debug/matchers/IsNot.js +2 -1
  118. package/src/core/debug/matchers/IsNull.d.ts +2 -1
  119. package/src/core/debug/matchers/IsNull.d.ts.map +1 -1
  120. package/src/core/debug/matchers/IsNull.js +2 -1
  121. package/src/core/debug/matchers/IsUndefined.d.ts +2 -1
  122. package/src/core/debug/matchers/IsUndefined.d.ts.map +1 -1
  123. package/src/core/debug/matchers/IsUndefined.js +2 -1
  124. package/src/core/events/signal/Signal.d.ts +15 -0
  125. package/src/core/events/signal/Signal.d.ts.map +1 -1
  126. package/src/core/events/signal/Signal.js +857 -820
  127. package/src/core/fsm/simple/SimpleStateMachineDescription.d.ts.map +1 -1
  128. package/src/core/fsm/simple/SimpleStateMachineDescription.js +4 -3
  129. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_bruteforce.d.ts.map +1 -1
  130. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_bruteforce.js +6 -1
  131. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts +1 -1
  132. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts.map +1 -1
  133. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js +6 -7
  134. package/src/core/geom/2d/hash-grid/SpatialHashGrid.d.ts.map +1 -1
  135. package/src/core/geom/2d/hash-grid/SpatialHashGrid.js +23 -6
  136. package/src/core/geom/2d/line/ray2_ray2_compute_intersection_array_2d.d.ts.map +1 -1
  137. package/src/core/geom/2d/line/ray2_ray2_compute_intersection_array_2d.js +13 -1
  138. package/src/core/geom/3d/aabb/aabb3_raycast_hit_point.d.ts.map +1 -1
  139. package/src/core/geom/3d/aabb/aabb3_raycast_hit_point.js +53 -32
  140. package/src/core/geom/3d/atlas/segment/atlas_chart_growth_cost.d.ts +40 -0
  141. package/src/core/geom/3d/atlas/segment/atlas_chart_growth_cost.d.ts.map +1 -0
  142. package/src/core/geom/3d/atlas/segment/atlas_chart_growth_cost.js +54 -0
  143. package/src/core/geom/3d/atlas/segment/atlas_segment_charts.d.ts +21 -3
  144. package/src/core/geom/3d/atlas/segment/atlas_segment_charts.d.ts.map +1 -1
  145. package/src/core/geom/3d/atlas/segment/atlas_segment_charts.js +24 -15
  146. package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.d.ts +6 -3
  147. package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.d.ts.map +1 -1
  148. package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.js +9 -15
  149. package/src/core/geom/3d/cone/cone_compute_plane_side.d.ts.map +1 -1
  150. package/src/core/geom/3d/cone/cone_compute_plane_side.js +31 -19
  151. package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.d.ts +11 -1
  152. package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.d.ts.map +1 -1
  153. package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.js +11 -1
  154. package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.d.ts +11 -1
  155. package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.d.ts.map +1 -1
  156. package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.js +11 -1
  157. package/src/core/geom/3d/frustum/frustum3_compute_closest_point.d.ts.map +1 -1
  158. package/src/core/geom/3d/frustum/frustum3_compute_closest_point.js +55 -0
  159. package/src/core/geom/3d/frustum/frustum_from_projection_matrix_array.d.ts +14 -0
  160. package/src/core/geom/3d/frustum/frustum_from_projection_matrix_array.d.ts.map +1 -1
  161. package/src/core/geom/3d/frustum/frustum_from_projection_matrix_array.js +17 -1
  162. package/src/core/geom/3d/gjk/gjk.d.ts +15 -0
  163. package/src/core/geom/3d/gjk/gjk.d.ts.map +1 -1
  164. package/src/core/geom/3d/gjk/gjk.js +15 -0
  165. package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts.map +1 -1
  166. package/src/core/geom/3d/gjk/gjk_epa_penetration.js +18 -0
  167. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts +32 -3
  168. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts.map +1 -1
  169. package/src/core/geom/3d/hash-grid/PointHashGrid3.js +36 -3
  170. package/src/core/geom/3d/morton/v3_morton_encode_lut.d.ts.map +1 -1
  171. package/src/core/geom/3d/morton/v3_morton_encode_lut.js +11 -4
  172. package/src/core/geom/3d/morton/v3_morton_encode_normalized.d.ts +16 -4
  173. package/src/core/geom/3d/morton/v3_morton_encode_normalized.d.ts.map +1 -1
  174. package/src/core/geom/3d/morton/v3_morton_encode_normalized.js +21 -8
  175. package/src/core/geom/3d/normal/spherical/encode_unit_to_spheremap.d.ts.map +1 -1
  176. package/src/core/geom/3d/normal/spherical/encode_unit_to_spheremap.js +17 -3
  177. package/src/core/geom/3d/octahedra/octahedral_direction_to_uv.d.ts +10 -0
  178. package/src/core/geom/3d/octahedra/octahedral_direction_to_uv.d.ts.map +1 -1
  179. package/src/core/geom/3d/octahedra/octahedral_direction_to_uv.js +46 -49
  180. package/src/core/geom/3d/octahedra/octahedral_uv_to_direction.d.ts +13 -1
  181. package/src/core/geom/3d/octahedra/octahedral_uv_to_direction.d.ts.map +1 -1
  182. package/src/core/geom/3d/octahedra/octahedral_uv_to_direction.js +36 -39
  183. package/src/core/geom/3d/quadric/quadric3_to_tensor_m3_inverse.d.ts +4 -1
  184. package/src/core/geom/3d/quadric/quadric3_to_tensor_m3_inverse.d.ts.map +1 -1
  185. package/src/core/geom/3d/quadric/quadric3_to_tensor_m3_inverse.js +22 -4
  186. package/src/core/geom/3d/quaternion/quat3_canonicalize_sign_run.d.ts +38 -0
  187. package/src/core/geom/3d/quaternion/quat3_canonicalize_sign_run.d.ts.map +1 -0
  188. package/src/core/geom/3d/quaternion/quat3_canonicalize_sign_run.js +76 -0
  189. package/src/core/geom/3d/quaternion/quat3_encode_to_uint32.d.ts +11 -0
  190. package/src/core/geom/3d/quaternion/quat3_encode_to_uint32.d.ts.map +1 -1
  191. package/src/core/geom/3d/quaternion/quat3_encode_to_uint32.js +14 -34
  192. package/src/core/geom/3d/shape/PosedShape3D.d.ts +9 -0
  193. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
  194. package/src/core/geom/3d/shape/PosedShape3D.js +43 -0
  195. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  196. package/src/core/geom/3d/shape/UnionShape3D.js +20 -3
  197. package/src/core/geom/3d/shape/json/type_adapters.d.ts +11 -2
  198. package/src/core/geom/3d/shape/json/type_adapters.d.ts.map +1 -1
  199. package/src/core/geom/3d/shape/json/type_adapters.js +36 -12
  200. package/src/core/geom/3d/sphere/harmonics/sh3_sample_irradiance_by_direction.d.ts +13 -0
  201. package/src/core/geom/3d/sphere/harmonics/sh3_sample_irradiance_by_direction.d.ts.map +1 -1
  202. package/src/core/geom/3d/sphere/harmonics/sh3_sample_irradiance_by_direction.js +17 -4
  203. package/src/core/geom/3d/tetrahedra/tetrahedral_flip_layouts.d.ts +88 -0
  204. package/src/core/geom/3d/tetrahedra/tetrahedral_flip_layouts.d.ts.map +1 -0
  205. package/src/core/geom/3d/tetrahedra/tetrahedral_flip_layouts.js +108 -0
  206. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.d.ts.map +1 -1
  207. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.js +13 -31
  208. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.d.ts.map +1 -1
  209. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.js +14 -22
  210. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts.map +1 -1
  211. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js +96 -26
  212. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts.map +1 -1
  213. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +17 -6
  214. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts +27 -0
  215. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts.map +1 -1
  216. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.js +101 -0
  217. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts +3 -0
  218. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts.map +1 -1
  219. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js +5 -57
  220. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts +20 -0
  221. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
  222. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +68 -35
  223. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts.map +1 -1
  224. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.js +2 -43
  225. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +72 -21
  226. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  227. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +452 -99
  228. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts.map +1 -1
  229. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js +4 -15
  230. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_mesh_split_pinched_vertices.d.ts.map +1 -1
  231. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_mesh_split_pinched_vertices.js +13 -1
  232. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.d.ts.map +1 -1
  233. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.js +3 -1
  234. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
  235. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +22 -3
  236. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts +25 -0
  237. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.d.ts.map +1 -0
  238. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_fold_limit.js +228 -0
  239. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts +13 -0
  240. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.d.ts.map +1 -1
  241. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_would_fold.js +10 -128
  242. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_count_faces.d.ts +17 -2
  243. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_count_faces.d.ts.map +1 -1
  244. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_count_faces.js +28 -4
  245. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.d.ts.map +1 -1
  246. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.js +8 -1
  247. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_edge_adjacent_faces_weighted.d.ts.map +1 -1
  248. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_edge_adjacent_faces_weighted.js +10 -2
  249. package/src/core/geom/3d/topology/struct/binary/query/bt_face_island_flood_fill.d.ts.map +1 -1
  250. package/src/core/geom/3d/topology/struct/binary/query/bt_face_island_flood_fill.js +2 -0
  251. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.d.ts.map +1 -1
  252. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.js +25 -5
  253. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.d.ts.map +1 -1
  254. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_face_bvh.js +11 -1
  255. package/src/core/geom/3d/triangle/tri3_compute_normal.d.ts +5 -1
  256. package/src/core/geom/3d/triangle/tri3_compute_normal.d.ts.map +1 -1
  257. package/src/core/geom/3d/triangle/tri3_compute_normal.js +8 -1
  258. package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts.map +1 -1
  259. package/src/core/geom/3d/triangle/tri3_ray_intersection.js +15 -3
  260. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric.d.ts +2 -1
  261. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric.d.ts.map +1 -1
  262. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric.js +2 -1
  263. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric_edge.d.ts +1 -1
  264. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric_edge.d.ts.map +1 -1
  265. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric_edge.js +8 -1
  266. package/src/core/geom/vec/vector_normalize.d.ts.map +1 -1
  267. package/src/core/geom/vec/vector_normalize.js +5 -1
  268. package/src/core/geom/vec3/v3_slerp.d.ts.map +1 -1
  269. package/src/core/geom/vec3/v3_slerp.js +69 -4
  270. package/src/core/geom/vec4/v4_max_axis.d.ts +28 -0
  271. package/src/core/geom/vec4/v4_max_axis.d.ts.map +1 -0
  272. package/src/core/geom/vec4/v4_max_axis.js +41 -0
  273. package/src/core/graph/coloring/colorizeGraph.js +10 -7
  274. package/src/core/graph/layout/graph_peel_topological_layer.d.ts.map +1 -1
  275. package/src/core/graph/layout/graph_peel_topological_layer.js +16 -2
  276. package/src/core/graph/mn_graph_collapse_weighted_edge.js +6 -6
  277. package/src/core/json/JsonUtils.d.ts.map +1 -1
  278. package/src/core/json/JsonUtils.js +6 -2
  279. package/src/core/json/abstractJSONSerializer.d.ts.map +1 -1
  280. package/src/core/json/abstractJSONSerializer.js +5 -1
  281. package/src/core/lang/reactive/ReactiveOperatorType.d.ts +20 -0
  282. package/src/core/lang/reactive/ReactiveOperatorType.d.ts.map +1 -1
  283. package/src/core/lang/reactive/ReactiveOperatorType.js +34 -12
  284. package/src/core/localization/LanguageMetadata.d.ts +2 -1
  285. package/src/core/localization/LanguageMetadata.d.ts.map +1 -1
  286. package/src/core/localization/LanguageMetadata.js +6 -0
  287. package/src/core/localization/Localization.d.ts.map +1 -1
  288. package/src/core/localization/Localization.js +23 -10
  289. package/src/core/localization/LocalizationEngine.d.ts.map +1 -1
  290. package/src/core/localization/LocalizationEngine.js +4 -0
  291. package/src/core/math/fract.d.ts.map +1 -1
  292. package/src/core/math/fract.js +4 -3
  293. package/src/core/math/hash/squirrel3.d.ts +10 -2
  294. package/src/core/math/hash/squirrel3.d.ts.map +1 -1
  295. package/src/core/math/hash/squirrel3.js +16 -8
  296. package/src/core/math/linalg/m2/m2_polar_decomp_noS.d.ts +7 -0
  297. package/src/core/math/linalg/m2/m2_polar_decomp_noS.d.ts.map +1 -1
  298. package/src/core/math/linalg/m2/m2_polar_decomp_noS.js +20 -1
  299. package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -1
  300. package/src/core/math/lookup/ParameterLookupTable.js +10 -5
  301. package/src/core/math/noise/sdnoise.d.ts.map +1 -1
  302. package/src/core/math/noise/sdnoise.js +16 -10
  303. package/src/core/math/physics/pdf/pdf_normal.d.ts +11 -3
  304. package/src/core/math/physics/pdf/pdf_normal.d.ts.map +1 -1
  305. package/src/core/math/physics/pdf/pdf_normal.js +25 -11
  306. package/src/core/math/solveQuadratic.d.ts.map +1 -1
  307. package/src/core/math/solveQuadratic.js +22 -3
  308. package/src/core/math/statistics/computeStatisticalPartialMedian.d.ts +9 -2
  309. package/src/core/math/statistics/computeStatisticalPartialMedian.d.ts.map +1 -1
  310. package/src/core/math/statistics/computeStatisticalPartialMedian.js +12 -6
  311. package/src/core/math/statistics/computeStatisticalPercentile.d.ts.map +1 -1
  312. package/src/core/math/statistics/computeStatisticalPercentile.js +9 -2
  313. package/src/core/math/statistics/gaussian_amplitude.d.ts +10 -1
  314. package/src/core/math/statistics/gaussian_amplitude.d.ts.map +1 -1
  315. package/src/core/math/statistics/gaussian_amplitude.js +20 -15
  316. package/src/core/model/BooleanVector3.d.ts.map +1 -1
  317. package/src/core/model/BooleanVector3.js +18 -2
  318. package/src/core/model/BoundedValue.d.ts +9 -0
  319. package/src/core/model/BoundedValue.d.ts.map +1 -1
  320. package/src/core/model/BoundedValue.js +30 -3
  321. package/src/core/model/ObservedBoolean.d.ts.map +1 -1
  322. package/src/core/model/ObservedBoolean.js +22 -2
  323. package/src/core/model/ObservedEnum.d.ts.map +1 -1
  324. package/src/core/model/ObservedEnum.js +6 -2
  325. package/src/core/model/node-graph/NodeGraph.d.ts +6 -1
  326. package/src/core/model/node-graph/NodeGraph.d.ts.map +1 -1
  327. package/src/core/model/node-graph/NodeGraph.js +22 -4
  328. package/src/core/model/node-graph/json/deserializeNodeGraphFromJSON.d.ts.map +1 -1
  329. package/src/core/model/node-graph/json/deserializeNodeGraphFromJSON.js +3 -1
  330. package/src/core/model/node-graph/json/serializeNodeGraphToJSON.d.ts.map +1 -1
  331. package/src/core/model/node-graph/json/serializeNodeGraphToJSON.js +5 -0
  332. package/src/core/model/node-graph/type/DataType.d.ts.map +1 -1
  333. package/src/core/model/node-graph/type/DataType.js +8 -0
  334. package/src/core/model/node-graph/type/ParametricDataType.d.ts.map +1 -1
  335. package/src/core/model/node-graph/type/ParametricDataType.js +19 -0
  336. package/src/core/model/node-graph/visual/NodeGraphVisualData.d.ts.map +1 -1
  337. package/src/core/model/node-graph/visual/NodeGraphVisualData.js +5 -0
  338. package/src/core/model/object/ImmutableObjectPool.d.ts.map +1 -1
  339. package/src/core/model/object/ImmutableObjectPool.js +17 -7
  340. package/src/core/model/reactive/js/compileReactiveToJS.d.ts +22 -0
  341. package/src/core/model/reactive/js/compileReactiveToJS.d.ts.map +1 -1
  342. package/src/core/model/reactive/js/compileReactiveToJS.js +113 -219
  343. package/src/core/model/reactive/model/ReactiveBinaryExpression.d.ts.map +1 -1
  344. package/src/core/model/reactive/model/ReactiveBinaryExpression.js +8 -2
  345. package/src/core/model/reactive/model/comparative/ReactiveEquals.d.ts.map +1 -1
  346. package/src/core/model/reactive/model/comparative/ReactiveEquals.js +3 -1
  347. package/src/core/model/reactive/model/comparative/ReactiveNotEquals.d.ts.map +1 -1
  348. package/src/core/model/reactive/model/comparative/ReactiveNotEquals.js +2 -1
  349. package/src/core/model/reactive/model/terminal/ReactiveLiteralString.d.ts.map +1 -1
  350. package/src/core/model/reactive/model/terminal/ReactiveLiteralString.js +4 -2
  351. package/src/core/model/stat/Stat.d.ts.map +1 -1
  352. package/src/core/model/stat/Stat.js +4 -0
  353. package/src/core/parser/seedVariablesIntoTemplateString.d.ts.map +1 -1
  354. package/src/core/parser/seedVariablesIntoTemplateString.js +5 -0
  355. package/src/core/parser/simple/readArrayLiteral.d.ts.map +1 -1
  356. package/src/core/parser/simple/readArrayLiteral.js +7 -0
  357. package/src/core/parser/simple/readHexToken.d.ts +3 -0
  358. package/src/core/parser/simple/readHexToken.d.ts.map +1 -1
  359. package/src/core/parser/simple/readHexToken.js +39 -106
  360. package/src/core/parser/simple/readNumberToken.d.ts.map +1 -1
  361. package/src/core/parser/simple/readNumberToken.js +13 -4
  362. package/src/core/parser/simple/readUnsignedIntegerToken.d.ts +2 -0
  363. package/src/core/parser/simple/readUnsignedIntegerToken.d.ts.map +1 -1
  364. package/src/core/parser/simple/readUnsignedIntegerToken.js +31 -71
  365. package/src/core/parser/simple/read_digits.d.ts +31 -0
  366. package/src/core/parser/simple/read_digits.d.ts.map +1 -0
  367. package/src/core/parser/simple/read_digits.js +74 -0
  368. package/src/core/primitives/numbers/number_format_by_thousands.d.ts.map +1 -1
  369. package/src/core/primitives/numbers/number_format_by_thousands.js +16 -1
  370. package/src/core/primitives/numbers/number_pretty_print.d.ts.map +1 -1
  371. package/src/core/primitives/numbers/number_pretty_print.js +6 -1
  372. package/src/core/process/executor/ConcurrentExecutor.d.ts +1 -5
  373. package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
  374. package/src/core/process/executor/ConcurrentExecutor.js +131 -1
  375. package/src/core/process/task/Task.d.ts +8 -0
  376. package/src/core/process/task/Task.d.ts.map +1 -1
  377. package/src/core/process/task/Task.js +12 -1
  378. package/src/core/process/task/TaskGroup.d.ts +6 -0
  379. package/src/core/process/task/TaskGroup.d.ts.map +1 -1
  380. package/src/core/process/task/TaskGroup.js +7 -1
  381. package/src/core/process/task/task_find_dependency_cycle.d.ts +17 -0
  382. package/src/core/process/task/task_find_dependency_cycle.d.ts.map +1 -0
  383. package/src/core/process/task/task_find_dependency_cycle.js +81 -0
  384. package/src/core/process/undo/ActionProcessor.d.ts +12 -0
  385. package/src/core/process/undo/ActionProcessor.d.ts.map +1 -1
  386. package/src/core/process/undo/ActionProcessor.js +41 -15
  387. package/src/core/process/worker/OnDemandWorkerManager.d.ts.map +1 -1
  388. package/src/core/process/worker/OnDemandWorkerManager.js +6 -1
  389. package/src/core/process/worker/WorkerBuilder.d.ts.map +1 -1
  390. package/src/core/process/worker/WorkerBuilder.js +27 -5
  391. package/src/core/wfc/WFCCellChoice.d.ts +17 -0
  392. package/src/core/wfc/WFCCellChoice.d.ts.map +1 -0
  393. package/src/core/wfc/WFCCellChoice.js +36 -0
  394. package/src/core/wfc/WFCLattice.d.ts +105 -0
  395. package/src/core/wfc/WFCLattice.d.ts.map +1 -0
  396. package/src/core/wfc/WFCLattice.js +235 -0
  397. package/src/core/wfc/WFCRuleTable.d.ts +172 -0
  398. package/src/core/wfc/WFCRuleTable.d.ts.map +1 -0
  399. package/src/core/wfc/WFCRuleTable.js +334 -0
  400. package/src/core/wfc/WFCState.d.ts +273 -0
  401. package/src/core/wfc/WFCState.d.ts.map +1 -0
  402. package/src/core/wfc/WFCState.js +552 -0
  403. package/src/core/wfc/WFCStatus.d.ts +11 -0
  404. package/src/core/wfc/WFCStatus.d.ts.map +1 -0
  405. package/src/core/wfc/WFCStatus.js +28 -0
  406. package/src/core/wfc/WFCTileWeights.d.ts +48 -0
  407. package/src/core/wfc/WFCTileWeights.d.ts.map +1 -0
  408. package/src/core/wfc/WFCTileWeights.js +86 -0
  409. package/src/core/wfc/WFC_UNRESOLVED.d.ts +12 -0
  410. package/src/core/wfc/WFC_UNRESOLVED.d.ts.map +1 -0
  411. package/src/core/wfc/WFC_UNRESOLVED.js +11 -0
  412. package/src/core/wfc/wfc_estimate_bytes.d.ts +24 -0
  413. package/src/core/wfc/wfc_estimate_bytes.d.ts.map +1 -0
  414. package/src/core/wfc/wfc_estimate_bytes.js +47 -0
  415. package/src/core/wfc/wfc_rule_table_tile_components.d.ts +27 -0
  416. package/src/core/wfc/wfc_rule_table_tile_components.d.ts.map +1 -0
  417. package/src/core/wfc/wfc_rule_table_tile_components.js +80 -0
  418. package/src/core/wfc/wfc_solve.d.ts +21 -0
  419. package/src/core/wfc/wfc_solve.d.ts.map +1 -0
  420. package/src/core/wfc/wfc_solve.js +154 -0
  421. package/src/core/wfc/wfc_state_apply_boundary.d.ts +18 -0
  422. package/src/core/wfc/wfc_state_apply_boundary.d.ts.map +1 -0
  423. package/src/core/wfc/wfc_state_apply_boundary.js +61 -0
  424. package/src/core/wfc/wfc_state_assign.d.ts +11 -0
  425. package/src/core/wfc/wfc_state_assign.d.ts.map +1 -0
  426. package/src/core/wfc/wfc_state_assign.js +36 -0
  427. package/src/core/wfc/wfc_state_ban_bits.d.ts +17 -0
  428. package/src/core/wfc/wfc_state_ban_bits.d.ts.map +1 -0
  429. package/src/core/wfc/wfc_state_ban_bits.js +81 -0
  430. package/src/core/wfc/wfc_state_collapse.d.ts +12 -0
  431. package/src/core/wfc/wfc_state_collapse.d.ts.map +1 -0
  432. package/src/core/wfc/wfc_state_collapse.js +73 -0
  433. package/src/core/wfc/wfc_state_flush_dirty.d.ts +12 -0
  434. package/src/core/wfc/wfc_state_flush_dirty.d.ts.map +1 -0
  435. package/src/core/wfc/wfc_state_flush_dirty.js +39 -0
  436. package/src/core/wfc/wfc_state_propagate.d.ts +14 -0
  437. package/src/core/wfc/wfc_state_propagate.d.ts.map +1 -0
  438. package/src/core/wfc/wfc_state_propagate.js +155 -0
  439. package/src/core/wfc/wfc_state_read.d.ts +11 -0
  440. package/src/core/wfc/wfc_state_read.d.ts.map +1 -0
  441. package/src/core/wfc/wfc_state_read.js +38 -0
  442. package/src/core/wfc/wfc_state_restrict.d.ts +18 -0
  443. package/src/core/wfc/wfc_state_restrict.d.ts.map +1 -0
  444. package/src/core/wfc/wfc_state_restrict.js +39 -0
  445. package/src/core/wfc/wfc_state_set_eligible.d.ts +24 -0
  446. package/src/core/wfc/wfc_state_set_eligible.d.ts.map +1 -0
  447. package/src/core/wfc/wfc_state_set_eligible.js +49 -0
  448. package/src/core/wfc/wfc_state_undo_to.d.ts +13 -0
  449. package/src/core/wfc/wfc_state_undo_to.d.ts.map +1 -0
  450. package/src/core/wfc/wfc_state_undo_to.js +84 -0
  451. package/src/core/wfc/wfc_words_per_cell.d.ts +11 -0
  452. package/src/core/wfc/wfc_words_per_cell.d.ts.map +1 -0
  453. package/src/core/wfc/wfc_words_per_cell.js +16 -0
  454. package/src/engine/Clock.d.ts.map +1 -1
  455. package/src/engine/Clock.js +11 -0
  456. package/src/engine/Engine.d.ts.map +1 -1
  457. package/src/engine/Engine.js +107 -6
  458. package/src/engine/achievements/AchievementManager.d.ts.map +1 -1
  459. package/src/engine/achievements/AchievementManager.js +16 -1
  460. package/src/engine/animation/clip/ecd_bind_animation_curve.d.ts.map +1 -1
  461. package/src/engine/animation/clip/ecd_bind_animation_curve.js +17 -6
  462. package/src/engine/animation/clip/hemisphere_align_quaternion_values.d.ts +19 -10
  463. package/src/engine/animation/clip/hemisphere_align_quaternion_values.d.ts.map +1 -1
  464. package/src/engine/animation/clip/hemisphere_align_quaternion_values.js +19 -23
  465. package/src/engine/animation/keyed2/AnimationTrackPlayback.d.ts +1 -1
  466. package/src/engine/animation/keyed2/AnimationTrackPlayback.d.ts.map +1 -1
  467. package/src/engine/animation/keyed2/AnimationTrackPlayback.js +21 -4
  468. package/src/engine/asset/AssetManager.d.ts.map +1 -1
  469. package/src/engine/asset/AssetManager.js +11 -3
  470. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +1 -0
  471. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
  472. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +28 -0
  473. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
  474. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +14 -0
  475. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +23 -2
  476. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
  477. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2122 -2078
  478. package/src/engine/ecs/Entity.d.ts.map +1 -1
  479. package/src/engine/ecs/Entity.js +43 -7
  480. package/src/engine/ecs/EntityBlueprint.d.ts.map +1 -1
  481. package/src/engine/ecs/EntityBlueprint.js +13 -4
  482. package/src/engine/ecs/EntityComponentDataset.d.ts +8 -0
  483. package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
  484. package/src/engine/ecs/EntityComponentDataset.js +132 -23
  485. package/src/engine/ecs/EntityManager.d.ts +16 -0
  486. package/src/engine/ecs/EntityManager.d.ts.map +1 -1
  487. package/src/engine/ecs/EntityManager.js +112 -37
  488. package/src/engine/ecs/EntityObserver.d.ts +7 -0
  489. package/src/engine/ecs/EntityObserver.d.ts.map +1 -1
  490. package/src/engine/ecs/EntityObserver.js +8 -1
  491. package/src/engine/ecs/System.d.ts +23 -0
  492. package/src/engine/ecs/System.d.ts.map +1 -1
  493. package/src/engine/ecs/System.js +25 -0
  494. package/src/engine/ecs/components/Tag.d.ts.map +1 -1
  495. package/src/engine/ecs/components/Tag.js +4 -1
  496. package/src/engine/ecs/computeComponentClassName.d.ts +13 -1
  497. package/src/engine/ecs/computeComponentClassName.d.ts.map +1 -1
  498. package/src/engine/ecs/computeComponentClassName.js +11 -1
  499. package/src/engine/ecs/dynamic_actions/DynamicActorSystem.d.ts.map +1 -1
  500. package/src/engine/ecs/dynamic_actions/DynamicActorSystem.js +11 -0
  501. package/src/engine/ecs/fow/FogOfWar.d.ts.map +1 -1
  502. package/src/engine/ecs/fow/FogOfWar.js +37 -11
  503. package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts +8 -1
  504. package/src/engine/ecs/fow/FogOfWarRevealerSystem.d.ts.map +1 -1
  505. package/src/engine/ecs/fow/FogOfWarRevealerSystem.js +37 -2
  506. package/src/engine/ecs/guid/UUID.d.ts.map +1 -1
  507. package/src/engine/ecs/guid/UUID.js +45 -17
  508. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.d.ts.map +1 -1
  509. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +3 -1
  510. package/src/engine/ecs/parent/EntityNode.d.ts.map +1 -1
  511. package/src/engine/ecs/parent/EntityNode.js +8 -0
  512. package/src/engine/ecs/speaker/VoiceSystem.d.ts.map +1 -1
  513. package/src/engine/ecs/speaker/VoiceSystem.js +9 -0
  514. package/src/engine/ecs/storage/binary/BinaryClassSerializationAdapter.d.ts +15 -0
  515. package/src/engine/ecs/storage/binary/BinaryClassSerializationAdapter.d.ts.map +1 -1
  516. package/src/engine/ecs/storage/binary/BinaryClassSerializationAdapter.js +18 -0
  517. package/src/engine/ecs/system/AbstractContextSystem.d.ts.map +1 -1
  518. package/src/engine/ecs/system/AbstractContextSystem.js +14 -4
  519. package/src/engine/ecs/system/SystemEntityContext.d.ts +12 -0
  520. package/src/engine/ecs/system/SystemEntityContext.d.ts.map +1 -1
  521. package/src/engine/ecs/system/SystemEntityContext.js +23 -0
  522. package/src/engine/ecs/system_validate_class.d.ts.map +1 -1
  523. package/src/engine/ecs/system_validate_class.js +6 -2
  524. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.d.ts.map +1 -1
  525. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +395 -360
  526. package/src/engine/ecs/terrain/tiles/TerrainTile.d.ts.map +1 -1
  527. package/src/engine/ecs/terrain/tiles/TerrainTile.js +45 -3
  528. package/src/engine/ecs/terrain/tiles/TerrainTileManager.d.ts.map +1 -1
  529. package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +5 -8
  530. package/src/engine/graphics/ecs/camera/pp/PerfectPanner.d.ts.map +1 -1
  531. package/src/engine/graphics/ecs/camera/pp/PerfectPanner.js +62 -7
  532. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.d.ts +9 -0
  533. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.d.ts.map +1 -1
  534. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js +13 -0
  535. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshAnimationControllerSystem.d.ts +11 -0
  536. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshAnimationControllerSystem.d.ts.map +1 -1
  537. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshAnimationControllerSystem.js +78 -13
  538. package/src/engine/graphics/ecs/path/tube/build/make_ring_vertices.d.ts.map +1 -1
  539. package/src/engine/graphics/ecs/path/tube/build/make_ring_vertices.js +22 -8
  540. package/src/engine/graphics/geometry/buffered/geometry_compute_vertex_normals_indexed.d.ts.map +1 -1
  541. package/src/engine/graphics/geometry/buffered/geometry_compute_vertex_normals_indexed.js +18 -2
  542. package/src/engine/graphics/geometry/geometry_construct_triangle_normal.d.ts +3 -1
  543. package/src/engine/graphics/geometry/geometry_construct_triangle_normal.d.ts.map +1 -1
  544. package/src/engine/graphics/geometry/geometry_construct_triangle_normal.js +3 -1
  545. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts +32 -0
  546. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts.map +1 -0
  547. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.js +53 -0
  548. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts +22 -2
  549. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
  550. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +1201 -1160
  551. package/src/engine/graphics/particles/particular/engine/simulator/SimulationStepCurlNoiseVelocity.d.ts +0 -1
  552. package/src/engine/graphics/particles/particular/engine/simulator/SimulationStepCurlNoiseVelocity.d.ts.map +1 -1
  553. package/src/engine/graphics/particles/particular/engine/simulator/SimulationStepCurlNoiseVelocity.js +10 -5
  554. package/src/engine/graphics/particles/particular/engine/simulator/update_parameters.d.ts.map +1 -1
  555. package/src/engine/graphics/particles/particular/engine/simulator/update_parameters.js +23 -0
  556. package/src/engine/graphics/particles/particular/group/itemSizeFromAttributeType.d.ts +1 -1
  557. package/src/engine/graphics/sh3/path_tracer/texture/apply_texture_clamping_to_coordinate.d.ts.map +1 -1
  558. package/src/engine/graphics/sh3/path_tracer/texture/apply_texture_clamping_to_coordinate.js +6 -1
  559. package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.d.ts.map +1 -1
  560. package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.js +20 -0
  561. package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts +1 -0
  562. package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts.map +1 -1
  563. package/src/engine/graphics/texture/atlas/TextureAtlas.js +24 -5
  564. package/src/engine/graphics/texture/sampler/Sampler2D.d.ts.map +1 -1
  565. package/src/engine/graphics/texture/sampler/Sampler2D.js +14 -1
  566. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.d.ts.map +1 -1
  567. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_linear.js +24 -10
  568. package/src/engine/graphics/texture/sampler/sampler2d_sub_copy_same_item_size.d.ts.map +1 -1
  569. package/src/engine/graphics/texture/sampler/sampler2d_sub_copy_same_item_size.js +16 -5
  570. package/src/engine/graphics/texture/sampler/sampler2d_to_uint8_RGBA.d.ts.map +1 -1
  571. package/src/engine/graphics/texture/sampler/sampler2d_to_uint8_RGBA.js +29 -8
  572. package/src/engine/graphics/texture/sampler/serialization/TextureBinaryBufferSerializer.d.ts.map +1 -1
  573. package/src/engine/graphics/texture/sampler/serialization/TextureBinaryBufferSerializer.js +8 -3
  574. package/src/engine/graphics3/DecalSystem.d.ts +5 -4
  575. package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
  576. package/src/engine/graphics3/DecalSystem.js +5 -4
  577. package/src/engine/graphics3/GraphicsEngine.d.ts +40 -7
  578. package/src/engine/graphics3/GraphicsEngine.d.ts.map +1 -1
  579. package/src/engine/graphics3/GraphicsEngine.js +92 -7
  580. package/src/engine/graphics3/MeshSystem.d.ts +7 -0
  581. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  582. package/src/engine/graphics3/MeshSystem.js +681 -661
  583. package/src/engine/graphics3/ParticleEmitterSystem.d.ts +1 -0
  584. package/src/engine/graphics3/ParticleEmitterSystem.d.ts.map +1 -1
  585. package/src/engine/graphics3/ParticleEmitterSystem.js +1 -0
  586. package/src/engine/graphics3/TerrainSystem.d.ts +10 -40
  587. package/src/engine/graphics3/TerrainSystem.d.ts.map +1 -1
  588. package/src/engine/graphics3/TerrainSystem.js +186 -185
  589. package/src/engine/graphics3/Trail3DSystem.d.ts +28 -19
  590. package/src/engine/graphics3/Trail3DSystem.d.ts.map +1 -1
  591. package/src/engine/graphics3/Trail3DSystem.js +57 -64
  592. package/src/engine/graphics3/debug/gizmo_write_geometry.d.ts.map +1 -1
  593. package/src/engine/graphics3/debug/gizmo_write_geometry.js +7 -59
  594. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts.map +1 -1
  595. package/src/engine/graphics3/decal/GPUDecalRenderer.js +23 -7
  596. package/src/engine/graphics3/decal/shader_cluster_assign_decals.d.ts.map +1 -1
  597. package/src/engine/graphics3/decal/shader_cluster_assign_decals.js +29 -6
  598. package/src/engine/graphics3/path/tube_stream_write_geometry.d.ts.map +1 -1
  599. package/src/engine/graphics3/path/tube_stream_write_geometry.js +7 -56
  600. package/src/engine/graphics3/register_instance_animation.d.ts +3 -3
  601. package/src/engine/graphics3/register_instance_animation.js +3 -3
  602. package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.d.ts.map +1 -1
  603. package/src/engine/graphics3/terrain/TERRAIN_MATERIAL_TEMPLATE.d.ts +77 -0
  604. package/src/engine/graphics3/terrain/TERRAIN_MATERIAL_TEMPLATE.d.ts.map +1 -0
  605. package/src/engine/graphics3/terrain/TERRAIN_MATERIAL_TEMPLATE.js +485 -0
  606. package/src/engine/graphics3/terrain/TerrainShadeMaterial.d.ts +103 -0
  607. package/src/engine/graphics3/terrain/TerrainShadeMaterial.d.ts.map +1 -0
  608. package/src/engine/graphics3/terrain/TerrainShadeMaterial.js +130 -0
  609. package/src/engine/graphics3/terrain/chunk_terrain_material_surface.d.ts +23 -0
  610. package/src/engine/graphics3/terrain/chunk_terrain_material_surface.d.ts.map +1 -0
  611. package/src/engine/graphics3/terrain/chunk_terrain_material_surface.js +68 -0
  612. package/src/engine/graphics3/trail/trail_tube_write_geometry.d.ts.map +1 -1
  613. package/src/engine/graphics3/trail/trail_tube_write_geometry.js +8 -59
  614. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
  615. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.js +24 -5
  616. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts.map +1 -1
  617. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.js +10 -0
  618. package/src/engine/input/devices/PointerDevice.d.ts.map +1 -1
  619. package/src/engine/input/devices/PointerDevice.js +58 -5
  620. package/src/engine/input/ecs/ism/InputMapProgram.d.ts.map +1 -1
  621. package/src/engine/input/ecs/ism/InputMapProgram.js +13 -0
  622. package/src/engine/input/ecs/systems/InputControllerSystem.d.ts +1 -0
  623. package/src/engine/input/ecs/systems/InputControllerSystem.d.ts.map +1 -1
  624. package/src/engine/input/ecs/systems/InputControllerSystem.js +52 -2
  625. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts.map +1 -1
  626. package/src/engine/intelligence/behavior/composite/ParallelBehavior.js +8 -0
  627. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.d.ts.map +1 -1
  628. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.js +7 -0
  629. package/src/engine/intelligence/behavior/decorator/RepeatUntilSuccessBehavior.d.ts.map +1 -1
  630. package/src/engine/intelligence/behavior/decorator/RepeatUntilSuccessBehavior.js +14 -0
  631. package/src/engine/intelligence/behavior/ecs/BehaviorSystem.d.ts.map +1 -1
  632. package/src/engine/intelligence/behavior/ecs/BehaviorSystem.js +13 -0
  633. package/src/engine/interpolation/Interpoland.d.ts +7 -1
  634. package/src/engine/interpolation/Interpoland.d.ts.map +1 -1
  635. package/src/engine/interpolation/Interpoland.js +8 -1
  636. package/src/engine/interpolation/InterpolationLog.d.ts +51 -4
  637. package/src/engine/interpolation/InterpolationLog.d.ts.map +1 -1
  638. package/src/engine/interpolation/InterpolationLog.js +132 -2
  639. package/src/engine/interpolation/InterpolationSystem.d.ts +113 -35
  640. package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
  641. package/src/engine/interpolation/InterpolationSystem.js +677 -50
  642. package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts +5 -3
  643. package/src/engine/interpolation/TransformPoseSerializationAdapter.d.ts.map +1 -1
  644. package/src/engine/interpolation/TransformPoseSerializationAdapter.js +14 -3
  645. package/src/engine/interpolation/pose_interpoland.d.ts.map +1 -1
  646. package/src/engine/interpolation/pose_interpoland.js +2 -0
  647. package/src/engine/network/NetworkSession.d.ts +176 -47
  648. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  649. package/src/engine/network/NetworkSession.js +1462 -272
  650. package/src/engine/network/README.md +106 -3
  651. package/src/engine/network/SMOOTHNESS_DESIGN.md +392 -0
  652. package/src/engine/network/adapters/PoseCorrection.d.ts +50 -0
  653. package/src/engine/network/adapters/PoseCorrection.d.ts.map +1 -0
  654. package/src/engine/network/adapters/PoseCorrection.js +211 -0
  655. package/src/engine/network/adapters/TransformReplicationAdapter.d.ts +1 -0
  656. package/src/engine/network/adapters/TransformReplicationAdapter.d.ts.map +1 -1
  657. package/src/engine/network/adapters/TransformReplicationAdapter.js +17 -0
  658. package/src/engine/network/adapters/VelocityCorrection.d.ts +31 -0
  659. package/src/engine/network/adapters/VelocityCorrection.d.ts.map +1 -0
  660. package/src/engine/network/adapters/VelocityCorrection.js +71 -0
  661. package/src/engine/network/adapters/replicate_transform64.d.ts +13 -0
  662. package/src/engine/network/adapters/replicate_transform64.d.ts.map +1 -0
  663. package/src/engine/network/adapters/replicate_transform64.js +18 -0
  664. package/src/engine/network/adapters/rigid_body_of.d.ts +22 -0
  665. package/src/engine/network/adapters/rigid_body_of.d.ts.map +1 -0
  666. package/src/engine/network/adapters/rigid_body_of.js +33 -0
  667. package/src/engine/network/correction/Correction.d.ts +120 -0
  668. package/src/engine/network/correction/Correction.d.ts.map +1 -0
  669. package/src/engine/network/correction/Correction.js +143 -0
  670. package/src/engine/network/ecs/NetworkSystem.d.ts +36 -7
  671. package/src/engine/network/ecs/NetworkSystem.d.ts.map +1 -1
  672. package/src/engine/network/ecs/NetworkSystem.js +49 -7
  673. package/src/engine/network/orchestrator/NetworkPeer.d.ts +50 -1
  674. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  675. package/src/engine/network/orchestrator/NetworkPeer.js +158 -20
  676. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +38 -2
  677. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
  678. package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +58 -10
  679. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts +68 -2
  680. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
  681. package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +299 -18
  682. package/src/engine/network/replication/Replicator.d.ts +8 -1
  683. package/src/engine/network/replication/Replicator.d.ts.map +1 -1
  684. package/src/engine/network/replication/Replicator.js +50 -6
  685. package/src/engine/network/sim/ActionLog.d.ts +5 -2
  686. package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
  687. package/src/engine/network/sim/ActionLog.js +5 -2
  688. package/src/engine/network/sim/RewindEngine.d.ts.map +1 -1
  689. package/src/engine/network/sim/RewindEngine.js +6 -0
  690. package/src/engine/network/sim/SimActionExecutor.d.ts +48 -3
  691. package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
  692. package/src/engine/network/sim/SimActionExecutor.js +152 -6
  693. package/src/engine/network/sim/SmoothingState.d.ts +54 -2
  694. package/src/engine/network/sim/SmoothingState.d.ts.map +1 -1
  695. package/src/engine/network/sim/SmoothingState.js +107 -3
  696. package/src/engine/network/state/MutationLedger.d.ts.map +1 -1
  697. package/src/engine/network/state/MutationLedger.js +18 -2
  698. package/src/engine/network/state/PredictionHistory.d.ts +67 -0
  699. package/src/engine/network/state/PredictionHistory.d.ts.map +1 -0
  700. package/src/engine/network/state/PredictionHistory.js +145 -0
  701. package/src/engine/network/time/RenderPlayout.d.ts +2 -1
  702. package/src/engine/network/time/RenderPlayout.d.ts.map +1 -1
  703. package/src/engine/network/time/RenderPlayout.js +174 -163
  704. package/src/engine/network/transport/DeferredTransport.d.ts +57 -0
  705. package/src/engine/network/transport/DeferredTransport.d.ts.map +1 -0
  706. package/src/engine/network/transport/DeferredTransport.js +143 -0
  707. package/src/engine/network/transport/LoopbackTransport.d.ts +8 -0
  708. package/src/engine/network/transport/LoopbackTransport.d.ts.map +1 -1
  709. package/src/engine/network/transport/LoopbackTransport.js +12 -1
  710. package/src/engine/network/transport/ReliableCommandPipeline.d.ts.map +1 -1
  711. package/src/engine/network/transport/ReliableCommandPipeline.js +20 -0
  712. package/src/engine/network/transport/adapters/NodeUDPTransport.d.ts.map +1 -1
  713. package/src/engine/network/transport/adapters/NodeUDPTransport.js +11 -2
  714. package/src/engine/network/transport/adapters/WebTransportTransport.d.ts.map +1 -1
  715. package/src/engine/network/transport/adapters/WebTransportTransport.js +8 -1
  716. package/src/engine/network/transport/fragments/FragmentAssembler.d.ts +2 -1
  717. package/src/engine/network/transport/fragments/FragmentAssembler.d.ts.map +1 -1
  718. package/src/engine/network/transport/fragments/FragmentAssembler.js +67 -3
  719. package/src/engine/network/transport/fragments/fragment_send.d.ts +8 -0
  720. package/src/engine/network/transport/fragments/fragment_send.d.ts.map +1 -1
  721. package/src/engine/network/transport/fragments/fragment_send.js +17 -7
  722. package/src/engine/network/transport/fragments/packet_size.d.ts +6 -0
  723. package/src/engine/network/transport/fragments/packet_size.d.ts.map +1 -1
  724. package/src/engine/network/transport/fragments/packet_size.js +6 -0
  725. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  726. package/src/engine/physics/ccd/linear_sweep.js +19 -1
  727. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +7 -3
  728. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  729. package/src/engine/physics/cloth/ecs/ClothWorld.js +51 -4
  730. package/src/engine/physics/cloth/solver/cloth_self_find.js +17 -0
  731. package/src/engine/physics/contact/ManifoldStore.d.ts +20 -1
  732. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
  733. package/src/engine/physics/contact/ManifoldStore.js +24 -2
  734. package/src/engine/physics/ecs/PhysicsSystem.d.ts +51 -88
  735. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  736. package/src/engine/physics/ecs/PhysicsSystem.js +82 -217
  737. package/src/engine/physics/ecs/is_sensor.d.ts +24 -0
  738. package/src/engine/physics/ecs/is_sensor.d.ts.map +1 -1
  739. package/src/engine/physics/ecs/is_sensor.js +39 -0
  740. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +18 -4
  741. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -1
  742. package/src/engine/physics/fluid/ecs/FluidComponent.js +29 -8
  743. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  744. package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts +8 -0
  745. package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts.map +1 -1
  746. package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +8 -0
  747. package/src/engine/physics/fluid/solver/NOTES.md +46 -0
  748. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.js +1 -1
  749. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +1 -1
  750. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +1 -1
  751. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.js +1 -1
  752. package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.js +1 -1
  753. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.d.ts.map +1 -1
  754. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.js +8 -0
  755. package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.d.ts.map +1 -1
  756. package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.js +8 -0
  757. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -1
  758. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +8 -0
  759. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.d.ts +5 -0
  760. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.d.ts.map +1 -1
  761. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.js +5 -0
  762. package/src/engine/physics/integration/integrate_velocity.d.ts +15 -0
  763. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
  764. package/src/engine/physics/integration/integrate_velocity.js +15 -0
  765. package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -1
  766. package/src/engine/physics/island/IslandBuilder.js +6 -7
  767. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
  768. package/src/engine/physics/mls-mpm/MLS_MPM.js +36 -6
  769. package/src/engine/physics/mls-mpm/mls_mpm_demo_scene.d.ts +29 -0
  770. package/src/engine/physics/mls-mpm/mls_mpm_demo_scene.d.ts.map +1 -0
  771. package/src/engine/physics/mls-mpm/mls_mpm_demo_scene.js +44 -0
  772. package/src/engine/physics/mls-mpm/testMLS_MPM.js +3 -3
  773. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  774. package/src/engine/physics/narrowphase/narrowphase_step.js +74 -11
  775. package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -1
  776. package/src/engine/physics/queries/overlap_shape.js +92 -45
  777. package/src/engine/physics/queries/raycast.d.ts.map +1 -1
  778. package/src/engine/physics/queries/raycast.js +55 -43
  779. package/src/engine/physics/queries/shape_cast.d.ts.map +1 -1
  780. package/src/engine/physics/queries/shape_cast.js +185 -174
  781. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
  782. package/src/engine/physics/solver/solve_contacts.js +42 -19
  783. package/src/engine/plugin/EnginePluginManager.d.ts +10 -0
  784. package/src/engine/plugin/EnginePluginManager.d.ts.map +1 -1
  785. package/src/engine/plugin/EnginePluginManager.js +54 -1
  786. package/src/engine/plugin/PluginReferenceContext.d.ts.map +1 -1
  787. package/src/engine/plugin/PluginReferenceContext.js +7 -3
  788. package/src/engine/reference/v2/Reference.d.ts +9 -0
  789. package/src/engine/reference/v2/Reference.d.ts.map +1 -1
  790. package/src/engine/reference/v2/Reference.js +39 -2
  791. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  792. package/src/engine/simulation/Ticker.js +20 -1
  793. package/src/engine/sound/ecs/SoundListenerSystem.d.ts +27 -0
  794. package/src/engine/sound/ecs/SoundListenerSystem.d.ts.map +1 -1
  795. package/src/engine/sound/ecs/SoundListenerSystem.js +82 -21
  796. package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts.map +1 -1
  797. package/src/engine/sound/ecs/audio/LiveEmitterSet.js +394 -356
  798. package/src/engine/sound/material/concrete/SoundMaterialComposition.d.ts.map +1 -1
  799. package/src/engine/sound/material/concrete/SoundMaterialComposition.js +54 -17
  800. package/src/engine/sound/material/detector/terrain/TerrainSoundMaterialSurfaceDetector.d.ts.map +1 -1
  801. package/src/engine/sound/material/detector/terrain/TerrainSoundMaterialSurfaceDetector.js +34 -3
  802. package/src/engine/sound/simulation/core/AcousticSolution.d.ts +5 -0
  803. package/src/engine/sound/simulation/core/AcousticSolution.d.ts.map +1 -1
  804. package/src/engine/sound/simulation/core/AcousticSolution.js +5 -0
  805. package/src/engine/sound/simulation/definition/AcousticMaterial.d.ts +8 -0
  806. package/src/engine/sound/simulation/definition/AcousticMaterial.d.ts.map +1 -1
  807. package/src/engine/sound/simulation/definition/AcousticMaterial.js +8 -0
  808. package/src/engine/sound/simulation/probe/probe_visibility_augment.d.ts +6 -4
  809. package/src/engine/sound/simulation/probe/probe_visibility_augment.d.ts.map +1 -1
  810. package/src/engine/sound/simulation/probe/probe_visibility_augment.js +19 -7
  811. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts +39 -0
  812. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts.map +1 -1
  813. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +130 -1
  814. package/src/engine/sound/simulation/render/ProbeReverbRenderer.d.ts +3 -2
  815. package/src/engine/sound/simulation/render/ProbeReverbRenderer.d.ts.map +1 -1
  816. package/src/engine/sound/simulation/render/ProbeReverbRenderer.js +15 -1
  817. package/src/engine/sound/sopra/SopraEngine.d.ts +10 -0
  818. package/src/engine/sound/sopra/SopraEngine.d.ts.map +1 -1
  819. package/src/engine/sound/sopra/SopraEngine.js +486 -440
  820. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts +2 -1
  821. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.d.ts.map +1 -1
  822. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +1 -1
  823. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts +1 -0
  824. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.d.ts.map +1 -1
  825. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts +1 -0
  826. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.d.ts.map +1 -1
  827. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts +2 -1
  828. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.d.ts.map +1 -1
  829. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +12 -3
  830. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts +1 -0
  831. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.d.ts.map +1 -1
  832. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +1 -0
  833. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
  834. package/src/engine/sound/sopra/runtime/BusGraph.d.ts +29 -0
  835. package/src/engine/sound/sopra/runtime/BusGraph.d.ts.map +1 -1
  836. package/src/engine/sound/sopra/runtime/BusGraph.js +69 -2
  837. package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
  838. package/src/engine/sound/sopra/runtime/EventInstance.js +134 -10
  839. package/src/engine/ui/GUIEngine.d.ts +14 -0
  840. package/src/engine/ui/GUIEngine.d.ts.map +1 -1
  841. package/src/engine/ui/GUIEngine.js +52 -4
  842. package/src/format/image/avif/api/apply_transformations.d.ts +2 -1
  843. package/src/format/image/avif/api/apply_transformations.d.ts.map +1 -1
  844. package/src/format/image/avif/api/apply_transformations.js +129 -120
  845. package/src/format/image/avif/api/convert_to_rgba.d.ts.map +1 -1
  846. package/src/format/image/avif/api/convert_to_rgba.js +35 -2
  847. package/src/format/image/avif/api/decode_image_item.d.ts +2 -1
  848. package/src/format/image/avif/api/decode_image_item.d.ts.map +1 -1
  849. package/src/format/image/avif/api/decode_image_item.js +322 -234
  850. package/src/format/image/avif/av1/decode/decode_av1_still.js +329 -309
  851. package/src/format/image/avif/av1/decode/decode_coefficients.d.ts.map +1 -1
  852. package/src/format/image/avif/av1/decode/decode_coefficients.js +248 -259
  853. package/src/format/image/avif/av1/decode/read_golomb.d.ts +21 -0
  854. package/src/format/image/avif/av1/decode/read_golomb.d.ts.map +1 -0
  855. package/src/format/image/avif/av1/decode/read_golomb.js +49 -0
  856. package/src/format/image/avif/av1/encode/encode_tile.js +2349 -2331
  857. package/src/format/image/avif/av1/entropy/symbol_cost.d.ts.map +1 -1
  858. package/src/format/image/avif/av1/entropy/symbol_cost.js +86 -76
  859. package/src/format/image/avif/av1/filter/loop_restoration.js +461 -451
  860. package/src/format/image/avif/av1/util/round2.d.ts +19 -2
  861. package/src/format/image/avif/av1/util/round2.d.ts.map +1 -1
  862. package/src/format/image/avif/av1/util/round2.js +51 -27
  863. package/src/format/image/avif/heif/AvifFile.d.ts +11 -0
  864. package/src/format/image/avif/heif/AvifFile.d.ts.map +1 -1
  865. package/src/format/image/avif/heif/AvifFile.js +154 -142
  866. package/src/format/image/avif/heif/find_item_properties.d.ts +23 -0
  867. package/src/format/image/avif/heif/find_item_properties.d.ts.map +1 -0
  868. package/src/format/image/avif/heif/find_item_properties.js +36 -0
  869. package/src/format/image/avif/heif/parse_avif_file.js +30 -3
  870. package/src/format/image/avif/heif/read_item_data.d.ts.map +1 -1
  871. package/src/format/image/avif/heif/read_item_data.js +131 -97
  872. package/src/format/image/jpeg/decodeScan.d.ts.map +1 -1
  873. package/src/format/image/jpeg/decodeScan.js +17 -0
  874. package/src/format/scene/gltf/gltf_parse_container.d.ts.map +1 -1
  875. package/src/format/scene/gltf/gltf_parse_container.js +61 -41
  876. package/src/format/scene/gltf/gltf_read_accessor.d.ts +21 -0
  877. package/src/format/scene/gltf/gltf_read_accessor.d.ts.map +1 -1
  878. package/src/format/scene/gltf/gltf_read_accessor.js +37 -0
  879. package/src/format/scene/usd/usd_compose_transform.d.ts.map +1 -1
  880. package/src/format/scene/usd/usd_compose_transform.js +56 -6
  881. package/src/format/texture/basis/transcode/fit_endpoints.d.ts +6 -0
  882. package/src/format/texture/basis/transcode/fit_endpoints.d.ts.map +1 -1
  883. package/src/format/texture/basis/transcode/fit_endpoints.js +33 -39
  884. package/src/generation/filtering/numeric/CellFilterCache.d.ts +17 -0
  885. package/src/generation/filtering/numeric/CellFilterCache.d.ts.map +1 -1
  886. package/src/generation/filtering/numeric/CellFilterCache.js +36 -3
  887. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.d.ts +9 -0
  888. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.d.ts.map +1 -1
  889. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.js +37 -6
  890. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.d.ts.map +1 -1
  891. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.js +8 -21
  892. package/src/generation/grid/actions/grid_obstacle_write_grid_point.d.ts +28 -0
  893. package/src/generation/grid/actions/grid_obstacle_write_grid_point.d.ts.map +1 -0
  894. package/src/generation/grid/actions/grid_obstacle_write_grid_point.js +41 -0
  895. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.d.ts +15 -1
  896. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.d.ts.map +1 -1
  897. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.js +17 -3
  898. package/src/generation/markers/actions/MarkerNodeProcessingRuleSet.d.ts.map +1 -1
  899. package/src/generation/markers/actions/MarkerNodeProcessingRuleSet.js +16 -1
  900. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.d.ts.map +1 -1
  901. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.js +8 -1
  902. package/src/generation/theme/TerrainTheme.d.ts.map +1 -1
  903. package/src/generation/theme/TerrainTheme.js +20 -1
  904. package/src/shade/RENDERER_CONTRACT.md +48 -6
  905. package/src/shade/descriptor/texture/format/gpu_texture_formats_copy_compatible.d.ts +23 -0
  906. package/src/shade/descriptor/texture/format/gpu_texture_formats_copy_compatible.d.ts.map +1 -0
  907. package/src/shade/descriptor/texture/format/gpu_texture_formats_copy_compatible.js +28 -0
  908. package/src/shade/descriptor/texture/format/gpu_texture_formats_view_compatible.d.ts +25 -0
  909. package/src/shade/descriptor/texture/format/gpu_texture_formats_view_compatible.d.ts.map +1 -0
  910. package/src/shade/descriptor/texture/format/gpu_texture_formats_view_compatible.js +42 -0
  911. package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
  912. package/src/shade/device/ShadeGPUCommandContext.js +874 -857
  913. package/src/shade/device/mock/SoftwareGPUBindGroup.d.ts +38 -1
  914. package/src/shade/device/mock/SoftwareGPUBindGroup.d.ts.map +1 -1
  915. package/src/shade/device/mock/SoftwareGPUBindGroup.js +73 -1
  916. package/src/shade/device/mock/SoftwareGPUBuffer.d.ts.map +1 -1
  917. package/src/shade/device/mock/SoftwareGPUBuffer.js +5 -0
  918. package/src/shade/device/mock/SoftwareGPUCommandBuffer.d.ts +34 -0
  919. package/src/shade/device/mock/SoftwareGPUCommandBuffer.d.ts.map +1 -1
  920. package/src/shade/device/mock/SoftwareGPUCommandBuffer.js +71 -1
  921. package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts +15 -0
  922. package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts.map +1 -1
  923. package/src/shade/device/mock/SoftwareGPUCommandEncoder.js +109 -1
  924. package/src/shade/device/mock/SoftwareGPUComputePassEncoder.d.ts.map +1 -1
  925. package/src/shade/device/mock/SoftwareGPUComputePassEncoder.js +51 -0
  926. package/src/shade/device/mock/SoftwareGPUDevice.d.ts +5 -1
  927. package/src/shade/device/mock/SoftwareGPUDevice.d.ts.map +1 -1
  928. package/src/shade/device/mock/SoftwareGPUDevice.js +58 -1
  929. package/src/shade/device/mock/SoftwareGPUPipeline.d.ts +1 -0
  930. package/src/shade/device/mock/SoftwareGPUPipeline.d.ts.map +1 -1
  931. package/src/shade/device/mock/SoftwareGPUPipeline.js +17 -11
  932. package/src/shade/device/mock/SoftwareGPUQueue.d.ts.map +1 -1
  933. package/src/shade/device/mock/SoftwareGPUQueue.js +41 -0
  934. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts.map +1 -1
  935. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.js +24 -0
  936. package/src/shade/device/mock/SoftwareGPUTexture.d.ts +11 -1
  937. package/src/shade/device/mock/SoftwareGPUTexture.d.ts.map +1 -1
  938. package/src/shade/device/mock/SoftwareGPUTexture.js +45 -8
  939. package/src/shade/device/mock/SoftwareGPUTextureView.d.ts +20 -1
  940. package/src/shade/device/mock/SoftwareGPUTextureView.d.ts.map +1 -1
  941. package/src/shade/device/mock/SoftwareGPUTextureView.js +28 -1
  942. package/src/shade/device/mock/recorded_binding_kind_mismatches.d.ts +20 -0
  943. package/src/shade/device/mock/recorded_binding_kind_mismatches.d.ts.map +1 -0
  944. package/src/shade/device/mock/recorded_binding_kind_mismatches.js +84 -0
  945. package/src/shade/device/mock/texture_copy.d.ts.map +1 -1
  946. package/src/shade/device/mock/texture_copy.js +41 -3
  947. package/src/shade/device/mock/texture_view_resource.d.ts +26 -0
  948. package/src/shade/device/mock/texture_view_resource.d.ts.map +1 -0
  949. package/src/shade/device/mock/texture_view_resource.js +47 -0
  950. package/src/shade/device/timing/GPUTimer.d.ts.map +1 -1
  951. package/src/shade/device/timing/GPUTimer.js +35 -21
  952. package/src/shade/playground/caldera/caldera_format.d.ts +28 -1
  953. package/src/shade/playground/caldera/caldera_format.d.ts.map +1 -1
  954. package/src/shade/playground/caldera/caldera_format.js +37 -0
  955. package/src/shade/playground/caldera/main.js +12 -2
  956. package/src/shade/playground/frame_rate_meter.d.ts +92 -0
  957. package/src/shade/playground/frame_rate_meter.d.ts.map +1 -0
  958. package/src/shade/playground/frame_rate_meter.js +147 -0
  959. package/src/shade/playground/particle_ecs/main.js +53 -7
  960. package/src/shade/playground/particle_ecs/moonlit_environment.js +2 -2
  961. package/src/shade/playground/particle_stats_readback.d.ts +58 -0
  962. package/src/shade/playground/particle_stats_readback.d.ts.map +1 -0
  963. package/src/shade/playground/particle_stats_readback.js +83 -0
  964. package/src/shade/playground/particle_system/main.js +378 -325
  965. package/src/shade/playground/skinned_blas_refit/main.d.ts.map +1 -1
  966. package/src/shade/playground/skinned_blas_refit/main.js +7 -2
  967. package/src/shade/playground/sponza_path_trace/main.d.ts.map +1 -1
  968. package/src/shade/playground/sponza_path_trace/main.js +398 -393
  969. package/src/shade/playground/volumetrics_froxel/main.d.ts.map +1 -1
  970. package/src/shade/playground/volumetrics_froxel/main.js +941 -936
  971. package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
  972. package/src/shade/renderer/GraphicsContext.js +7 -2
  973. package/src/shade/renderer/Renderer.d.ts +47 -1
  974. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  975. package/src/shade/renderer/Renderer.js +224 -27
  976. package/src/shade/renderer/animation/ANIMATION_CLIP_STATE_STRUCT.d.ts +4 -7
  977. package/src/shade/renderer/animation/ANIMATION_CLIP_STATE_STRUCT.d.ts.map +1 -1
  978. package/src/shade/renderer/animation/ANIMATION_CLIP_STATE_STRUCT.js +19 -16
  979. package/src/shade/renderer/animation/ANIMATION_CURVE_HEADER_STRUCT.js +11 -11
  980. package/src/shade/renderer/animation/ANIMATION_DATABASE_SPEC.d.ts +14 -18
  981. package/src/shade/renderer/animation/ANIMATION_DATABASE_SPEC.d.ts.map +1 -1
  982. package/src/shade/renderer/animation/ANIMATION_DATABASE_SPEC.js +95 -24
  983. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_STRUCT.d.ts +5 -4
  984. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_STRUCT.d.ts.map +1 -1
  985. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_STRUCT.js +7 -4
  986. package/src/shade/renderer/animation/ANIMATION_SKIN_STRUCT.d.ts +6 -12
  987. package/src/shade/renderer/animation/ANIMATION_SKIN_STRUCT.d.ts.map +1 -1
  988. package/src/shade/renderer/animation/ANIMATION_SKIN_STRUCT.js +9 -16
  989. package/src/shade/renderer/animation/ANIMATION_TRACK_BINDING_STRUCT.d.ts +6 -5
  990. package/src/shade/renderer/animation/ANIMATION_TRACK_BINDING_STRUCT.d.ts.map +1 -1
  991. package/src/shade/renderer/animation/ANIMATION_TRACK_BINDING_STRUCT.js +12 -5
  992. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +80 -95
  993. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  994. package/src/shade/renderer/animation/GPUAnimationManager.js +371 -606
  995. package/src/shade/renderer/animation/chunk_animation_curve_evaluate.d.ts +10 -14
  996. package/src/shade/renderer/animation/chunk_animation_curve_evaluate.d.ts.map +1 -1
  997. package/src/shade/renderer/animation/chunk_animation_curve_evaluate.js +40 -67
  998. package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts.map +1 -1
  999. package/src/shade/renderer/animation/chunk_pose_accumulator.js +13 -4
  1000. package/src/shade/renderer/animation/shader_animation_apply.d.ts +14 -8
  1001. package/src/shade/renderer/animation/shader_animation_apply.d.ts.map +1 -1
  1002. package/src/shade/renderer/animation/shader_animation_apply.js +129 -128
  1003. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +2 -2
  1004. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts +3 -2
  1005. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts.map +1 -1
  1006. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.js +3 -2
  1007. package/src/shade/renderer/animation/skinning/shader_skin_matrix_prep.d.ts +12 -7
  1008. package/src/shade/renderer/animation/skinning/shader_skin_matrix_prep.d.ts.map +1 -1
  1009. package/src/shade/renderer/animation/skinning/shader_skin_matrix_prep.js +107 -104
  1010. package/src/shade/renderer/binding/BindingResource.d.ts +36 -1
  1011. package/src/shade/renderer/binding/BindingResource.d.ts.map +1 -1
  1012. package/src/shade/renderer/binding/BindingResource.js +36 -3
  1013. package/src/shade/renderer/binding/BufferBinding.d.ts +8 -0
  1014. package/src/shade/renderer/binding/BufferBinding.d.ts.map +1 -1
  1015. package/src/shade/renderer/binding/BufferBinding.js +21 -0
  1016. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts +19 -0
  1017. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
  1018. package/src/shade/renderer/buffer/table/GPUDatabase.js +114 -1
  1019. package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.d.ts +132 -1
  1020. package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.d.ts.map +1 -1
  1021. package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.js +384 -1
  1022. package/src/shade/renderer/buffer/table/GPUDatabaseReadback.d.ts.map +1 -1
  1023. package/src/shade/renderer/buffer/table/GPUDatabaseReadback.js +1332 -1323
  1024. package/src/shade/renderer/buffer/table/GPUTableLink.d.ts +67 -0
  1025. package/src/shade/renderer/buffer/table/GPUTableLink.d.ts.map +1 -0
  1026. package/src/shade/renderer/buffer/table/GPUTableLink.js +76 -0
  1027. package/src/shade/renderer/buffer/table/GPUTableRange.d.ts +72 -0
  1028. package/src/shade/renderer/buffer/table/GPUTableRange.d.ts.map +1 -0
  1029. package/src/shade/renderer/buffer/table/GPUTableRange.js +82 -0
  1030. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts +106 -5
  1031. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  1032. package/src/shade/renderer/buffer/table/GPUTypedTable.js +458 -28
  1033. package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.d.ts.map +1 -1
  1034. package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.js +28 -5
  1035. package/src/shade/renderer/buffer/table/GPU_DATABASE_NULL.d.ts +14 -0
  1036. package/src/shade/renderer/buffer/table/GPU_DATABASE_NULL.d.ts.map +1 -0
  1037. package/src/shade/renderer/buffer/table/GPU_DATABASE_NULL.js +13 -0
  1038. package/src/shade/renderer/buffer/table/gpu_database_check_links.d.ts +80 -0
  1039. package/src/shade/renderer/buffer/table/gpu_database_check_links.d.ts.map +1 -0
  1040. package/src/shade/renderer/buffer/table/gpu_database_check_links.js +456 -0
  1041. package/src/shade/renderer/buffer/table/gpu_table_field_word.d.ts +17 -0
  1042. package/src/shade/renderer/buffer/table/gpu_table_field_word.d.ts.map +1 -0
  1043. package/src/shade/renderer/buffer/table/gpu_table_field_word.js +111 -0
  1044. package/src/shade/renderer/buffer/table/gpu_table_range_well_formed.d.ts +20 -0
  1045. package/src/shade/renderer/buffer/table/gpu_table_range_well_formed.d.ts.map +1 -0
  1046. package/src/shade/renderer/buffer/table/gpu_table_range_well_formed.js +27 -0
  1047. package/src/shade/renderer/camera/CameraManager.d.ts +11 -0
  1048. package/src/shade/renderer/camera/CameraManager.d.ts.map +1 -1
  1049. package/src/shade/renderer/camera/CameraManager.js +18 -0
  1050. package/src/shade/renderer/create_frame_loop.d.ts +16 -0
  1051. package/src/shade/renderer/create_frame_loop.d.ts.map +1 -1
  1052. package/src/shade/renderer/create_frame_loop.js +16 -0
  1053. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct.d.ts +23 -0
  1054. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct.d.ts.map +1 -1
  1055. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct.js +27 -32
  1056. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_heavy.d.ts +9 -7
  1057. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_heavy.d.ts.map +1 -1
  1058. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_heavy.js +16 -108
  1059. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts +135 -0
  1060. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts.map +1 -0
  1061. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.js +296 -0
  1062. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts +2 -2
  1063. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts.map +1 -1
  1064. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.js +10 -131
  1065. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.d.ts.map +1 -1
  1066. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +185 -167
  1067. package/src/shade/renderer/dynamic/GPUDynamicMeshResidencyTable.d.ts +49 -0
  1068. package/src/shade/renderer/dynamic/GPUDynamicMeshResidencyTable.d.ts.map +1 -0
  1069. package/src/shade/renderer/dynamic/GPUDynamicMeshResidencyTable.js +185 -0
  1070. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts +24 -0
  1071. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts.map +1 -0
  1072. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.js +49 -0
  1073. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts +18 -0
  1074. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts.map +1 -0
  1075. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.js +54 -0
  1076. package/src/shade/renderer/dynamic/dynamic_mesh_live_bounds.d.ts +26 -0
  1077. package/src/shade/renderer/dynamic/dynamic_mesh_live_bounds.d.ts.map +1 -0
  1078. package/src/shade/renderer/dynamic/dynamic_mesh_live_bounds.js +96 -0
  1079. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts +102 -0
  1080. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts.map +1 -0
  1081. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.js +364 -0
  1082. package/src/shade/renderer/dynamic/shader_dynamic_mesh.d.ts.map +1 -1
  1083. package/src/shade/renderer/dynamic/shader_dynamic_mesh.js +153 -177
  1084. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts +20 -0
  1085. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts.map +1 -0
  1086. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.js +136 -0
  1087. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_occupancy.d.ts +20 -0
  1088. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_occupancy.d.ts.map +1 -0
  1089. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_occupancy.js +106 -0
  1090. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts +32 -0
  1091. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts.map +1 -0
  1092. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +163 -0
  1093. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +13 -2
  1094. package/src/shade/renderer/fow/GPUFogOfWarRenderer.d.ts.map +1 -1
  1095. package/src/shade/renderer/fow/GPUFogOfWarRenderer.js +5 -14
  1096. package/src/shade/renderer/fow/fow_obtain_mask.d.ts +17 -0
  1097. package/src/shade/renderer/fow/fow_obtain_mask.d.ts.map +1 -0
  1098. package/src/shade/renderer/fow/fow_obtain_mask.js +41 -0
  1099. package/src/shade/renderer/frame_jitter_applies.d.ts +21 -0
  1100. package/src/shade/renderer/frame_jitter_applies.d.ts.map +1 -0
  1101. package/src/shade/renderer/frame_jitter_applies.js +23 -0
  1102. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  1103. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +128 -3
  1104. package/src/shade/renderer/geometry/geometry_obtain_attribute.d.ts +42 -0
  1105. package/src/shade/renderer/geometry/geometry_obtain_attribute.d.ts.map +1 -0
  1106. package/src/shade/renderer/geometry/geometry_obtain_attribute.js +83 -0
  1107. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +12 -0
  1108. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  1109. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +65 -0
  1110. package/src/shade/renderer/geometry/meshlet/build/geometry_to_meshlets_greedy.d.ts.map +1 -1
  1111. package/src/shade/renderer/geometry/meshlet/build/geometry_to_meshlets_greedy.js +4 -1
  1112. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  1113. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +4 -1
  1114. package/src/shade/renderer/geometry/normals/encode_normals_to_octahedral_u32.d.ts.map +1 -1
  1115. package/src/shade/renderer/geometry/normals/encode_normals_to_octahedral_u32.js +4 -1
  1116. package/src/shade/renderer/geometry/normals/geometry_build_tangents.d.ts.map +1 -1
  1117. package/src/shade/renderer/geometry/normals/geometry_build_tangents.js +39 -1
  1118. package/src/shade/renderer/geometry/util/geometry_merge.d.ts.map +1 -1
  1119. package/src/shade/renderer/geometry/util/geometry_merge.js +18 -2
  1120. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +93 -12
  1121. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +91 -1
  1122. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts +0 -13
  1123. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.d.ts.map +1 -1
  1124. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +0 -15
  1125. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_collect_geometries.d.ts.map +1 -1
  1126. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_collect_geometries.js +31 -2
  1127. package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.d.ts +18 -0
  1128. package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.d.ts.map +1 -1
  1129. package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.js +19 -0
  1130. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.d.ts +8 -0
  1131. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.d.ts.map +1 -1
  1132. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.js +9 -0
  1133. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.d.ts.map +1 -1
  1134. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +15 -6
  1135. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.d.ts.map +1 -1
  1136. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.js +4 -0
  1137. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.d.ts.map +1 -1
  1138. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.js +12 -0
  1139. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts +11 -1
  1140. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.d.ts.map +1 -1
  1141. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_DEFAULT_ATTRIBUTE_WEIGHT_RATIOS.js +11 -1
  1142. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts +18 -9
  1143. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.d.ts.map +1 -1
  1144. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_compute_vertex_normals.js +20 -26
  1145. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts +1 -3
  1146. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.d.ts.map +1 -1
  1147. package/src/shade/renderer/geometry/virtual/build/mesh/vgeo_normalize_source.js +2 -5
  1148. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +1 -1
  1149. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  1150. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +10 -1
  1151. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +21 -0
  1152. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  1153. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +33 -1
  1154. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -1
  1155. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +63 -2
  1156. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.d.ts.map +1 -1
  1157. package/src/shade/renderer/geometry/virtual/runtime/VGeoResidency.js +14 -1
  1158. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +17 -0
  1159. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -1
  1160. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +39 -0
  1161. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  1162. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +7 -0
  1163. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_decode.d.ts.map +1 -1
  1164. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_decode.js +23 -2
  1165. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_decode_from_storage.d.ts.map +1 -1
  1166. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_decode_from_storage.js +22 -1
  1167. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_encode.d.ts.map +1 -1
  1168. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_encode.js +23 -2
  1169. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_encode_to_storage.d.ts.map +1 -1
  1170. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_encode_to_storage.js +22 -1
  1171. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.d.ts +2 -1
  1172. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.d.ts.map +1 -1
  1173. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.js +12 -53
  1174. package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.d.ts.map +1 -1
  1175. package/src/shade/renderer/global_illumination/probe/octahedral/GPUProbeAtlas.js +12 -3
  1176. package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lvp_atlas_to_sh.d.ts.map +1 -1
  1177. package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lvp_atlas_to_sh.js +2 -1
  1178. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_patch_texel_coord.d.ts +17 -0
  1179. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_patch_texel_coord.d.ts.map +1 -0
  1180. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_patch_texel_coord.js +38 -0
  1181. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_read_patch_texel.d.ts.map +1 -1
  1182. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_read_patch_texel.js +16 -10
  1183. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts +1 -1
  1184. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts.map +1 -1
  1185. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.js +25 -14
  1186. package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +94 -0
  1187. package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.d.ts +10 -7
  1188. package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.d.ts.map +1 -1
  1189. package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.js +10 -7
  1190. package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
  1191. package/src/shade/renderer/light/GPULightCollection.js +22 -1
  1192. package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.d.ts.map +1 -1
  1193. package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.js +26 -0
  1194. package/src/shade/renderer/light/cluster/chunk_cluster_keep_smallest.d.ts +21 -0
  1195. package/src/shade/renderer/light/cluster/chunk_cluster_keep_smallest.d.ts.map +1 -0
  1196. package/src/shade/renderer/light/cluster/chunk_cluster_keep_smallest.js +47 -0
  1197. package/src/shade/renderer/light/cluster/shader_cluster_assign_lights.d.ts.map +1 -1
  1198. package/src/shade/renderer/light/cluster/shader_cluster_assign_lights.js +12 -8
  1199. package/src/shade/renderer/light/environment/equirectangular_zenith_first_direction_to_uv.d.ts +36 -0
  1200. package/src/shade/renderer/light/environment/equirectangular_zenith_first_direction_to_uv.d.ts.map +1 -0
  1201. package/src/shade/renderer/light/environment/equirectangular_zenith_first_direction_to_uv.js +41 -0
  1202. package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts.map +1 -1
  1203. package/src/shade/renderer/light/environment/execute_filter_environment_map.js +17 -1
  1204. package/src/shade/renderer/light/environment/octahedral_uv_to_direction.d.ts +5 -13
  1205. package/src/shade/renderer/light/environment/octahedral_uv_to_direction.d.ts.map +1 -1
  1206. package/src/shade/renderer/light/environment/octahedral_uv_to_direction.js +10 -30
  1207. package/src/shade/renderer/light/environment/octahedral_z_pole_uv_to_direction.d.ts +31 -0
  1208. package/src/shade/renderer/light/environment/octahedral_z_pole_uv_to_direction.d.ts.map +1 -0
  1209. package/src/shade/renderer/light/environment/octahedral_z_pole_uv_to_direction.js +45 -0
  1210. package/src/shade/renderer/light/environment/resample_cube_to_octahedral.js +2 -2
  1211. package/src/shade/renderer/light/environment/resample_equirectangular_to_octahedral.d.ts.map +1 -1
  1212. package/src/shade/renderer/light/environment/resample_equirectangular_to_octahedral.js +11 -8
  1213. package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.d.ts.map +1 -1
  1214. package/src/shade/renderer/light/environment/rgbe/RGBE_ReadPixels_RLE.js +7 -1
  1215. package/src/shade/renderer/light/model/SpotLight.d.ts +10 -1
  1216. package/src/shade/renderer/light/model/SpotLight.d.ts.map +1 -1
  1217. package/src/shade/renderer/light/model/SpotLight.js +11 -3
  1218. package/src/shade/renderer/light/model/io/light_record_directional.d.ts.map +1 -1
  1219. package/src/shade/renderer/light/model/io/light_record_directional.js +3 -1
  1220. package/src/shade/renderer/light/model/io/light_record_point.d.ts.map +1 -1
  1221. package/src/shade/renderer/light/model/io/light_record_point.js +3 -1
  1222. package/src/shade/renderer/light/model/io/light_record_spot.d.ts.map +1 -1
  1223. package/src/shade/renderer/light/model/io/light_record_spot.js +3 -1
  1224. package/src/shade/renderer/lightmap/GPULightMap.d.ts.map +1 -1
  1225. package/src/shade/renderer/lightmap/GPULightMap.js +349 -336
  1226. package/src/shade/renderer/loader/gltf/gltf_base_url.d.ts +20 -0
  1227. package/src/shade/renderer/loader/gltf/gltf_base_url.d.ts.map +1 -0
  1228. package/src/shade/renderer/loader/gltf/gltf_base_url.js +27 -0
  1229. package/src/shade/renderer/loader/gltf/gltf_create_material.d.ts.map +1 -1
  1230. package/src/shade/renderer/loader/gltf/gltf_create_material.js +50 -10
  1231. package/src/shade/renderer/loader/gltf/load_gltf.d.ts +4 -0
  1232. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  1233. package/src/shade/renderer/loader/gltf/load_gltf.js +1109 -1128
  1234. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  1235. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts.map +1 -1
  1236. package/src/shade/renderer/loader/gltf/tiny-gltf.js +843 -843
  1237. package/src/shade/renderer/material/GPUMaterialContext.d.ts +63 -26
  1238. package/src/shade/renderer/material/GPUMaterialContext.d.ts.map +1 -1
  1239. package/src/shade/renderer/material/GPUMaterialContext.js +255 -390
  1240. package/src/shade/renderer/material/GPUMaterialManager.d.ts +51 -1
  1241. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  1242. package/src/shade/renderer/material/GPUMaterialManager.js +345 -91
  1243. package/src/shade/renderer/material/ShadeMaterial.d.ts +21 -0
  1244. package/src/shade/renderer/material/ShadeMaterial.d.ts.map +1 -1
  1245. package/src/shade/renderer/material/ShadeMaterial.js +31 -0
  1246. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  1247. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +25 -6
  1248. package/src/shade/renderer/material/standard/SHADING_MATERIAL_RESOURCE_GROUP.d.ts +10 -0
  1249. package/src/shade/renderer/material/standard/SHADING_MATERIAL_RESOURCE_GROUP.d.ts.map +1 -1
  1250. package/src/shade/renderer/material/standard/SHADING_MATERIAL_RESOURCE_GROUP.js +14 -2
  1251. package/src/shade/renderer/material/standard/STANDARD_MATERIAL_TEMPLATE.d.ts +12 -0
  1252. package/src/shade/renderer/material/standard/STANDARD_MATERIAL_TEMPLATE.d.ts.map +1 -0
  1253. package/src/shade/renderer/material/standard/STANDARD_MATERIAL_TEMPLATE.js +166 -0
  1254. package/src/shade/renderer/material/standard/VT_MATERIAL_TEMPLATE.d.ts +10 -0
  1255. package/src/shade/renderer/material/standard/VT_MATERIAL_TEMPLATE.d.ts.map +1 -0
  1256. package/src/shade/renderer/material/standard/VT_MATERIAL_TEMPLATE.js +141 -0
  1257. package/src/shade/renderer/material/standard/chunk_standard_material_surface.d.ts +29 -0
  1258. package/src/shade/renderer/material/standard/chunk_standard_material_surface.d.ts.map +1 -0
  1259. package/src/shade/renderer/material/standard/chunk_standard_material_surface.js +92 -0
  1260. package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts +74 -28
  1261. package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts.map +1 -1
  1262. package/src/shade/renderer/material/standard/fragment_gbuffer.js +165 -67
  1263. package/src/shade/renderer/material/standard/fragment_gbuffer_vt.d.ts +27 -18
  1264. package/src/shade/renderer/material/standard/fragment_gbuffer_vt.d.ts.map +1 -1
  1265. package/src/shade/renderer/material/standard/fragment_gbuffer_vt.js +70 -91
  1266. package/src/shade/renderer/material/standard/material_gbuffer_vertex.d.ts +9 -6
  1267. package/src/shade/renderer/material/standard/material_gbuffer_vertex.d.ts.map +1 -1
  1268. package/src/shade/renderer/material/standard/material_gbuffer_vertex.js +13 -14
  1269. package/src/shade/renderer/material/template/GPUMaterialServices.d.ts +73 -0
  1270. package/src/shade/renderer/material/template/GPUMaterialServices.d.ts.map +1 -0
  1271. package/src/shade/renderer/material/template/GPUMaterialServices.js +79 -0
  1272. package/src/shade/renderer/material/template/ShadeMaterialTemplate.d.ts +170 -0
  1273. package/src/shade/renderer/material/template/ShadeMaterialTemplate.d.ts.map +1 -0
  1274. package/src/shade/renderer/material/template/ShadeMaterialTemplate.js +234 -0
  1275. package/src/shade/renderer/material/template/chunk_material_surface.d.ts +47 -0
  1276. package/src/shade/renderer/material/template/chunk_material_surface.d.ts.map +1 -0
  1277. package/src/shade/renderer/material/template/chunk_material_surface.js +116 -0
  1278. package/src/shade/renderer/material/template/flat_material_template_spec_support.d.ts +22 -0
  1279. package/src/shade/renderer/material/template/flat_material_template_spec_support.d.ts.map +1 -0
  1280. package/src/shade/renderer/material/template/flat_material_template_spec_support.js +78 -0
  1281. package/src/shade/renderer/material/template/material_metadata_neutral.d.ts +15 -0
  1282. package/src/shade/renderer/material/template/material_metadata_neutral.d.ts.map +1 -0
  1283. package/src/shade/renderer/material/template/material_metadata_neutral.js +46 -0
  1284. package/src/shade/renderer/material/template/material_template_of.d.ts +10 -0
  1285. package/src/shade/renderer/material/template/material_template_of.d.ts.map +1 -0
  1286. package/src/shade/renderer/material/template/material_template_of.js +20 -0
  1287. package/src/shade/renderer/object_property/chunk_write_object_property.d.ts +5 -0
  1288. package/src/shade/renderer/object_property/chunk_write_object_property.d.ts.map +1 -1
  1289. package/src/shade/renderer/object_property/chunk_write_object_property.js +7 -1
  1290. package/src/shade/renderer/object_property/chunk_write_object_property_node3d.d.ts +7 -1
  1291. package/src/shade/renderer/object_property/chunk_write_object_property_node3d.d.ts.map +1 -1
  1292. package/src/shade/renderer/object_property/chunk_write_object_property_node3d.js +9 -2
  1293. package/src/shade/renderer/particles/DESIGN.md +21 -5
  1294. package/src/shade/renderer/particles/GPUParticleSystem.d.ts +25 -10
  1295. package/src/shade/renderer/particles/GPUParticleSystem.d.ts.map +1 -1
  1296. package/src/shade/renderer/particles/GPUParticleSystem.js +182 -38
  1297. package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.d.ts.map +1 -1
  1298. package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.js +81 -68
  1299. package/src/shade/renderer/particles/graph/groups/simplex_reference.d.ts.map +1 -1
  1300. package/src/shade/renderer/particles/graph/groups/simplex_reference.js +16 -10
  1301. package/src/shade/renderer/particles/graph_particles.d.ts +4 -2
  1302. package/src/shade/renderer/particles/graph_particles.d.ts.map +1 -1
  1303. package/src/shade/renderer/particles/graph_particles.js +8 -2
  1304. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts +22 -3
  1305. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts.map +1 -1
  1306. package/src/shade/renderer/particles/isa/ParticleVMISA.js +30 -3
  1307. package/src/shade/renderer/particles/isa/particle_assembly.js +41 -1
  1308. package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts +7 -1
  1309. package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts.map +1 -1
  1310. package/src/shade/renderer/particles/optimizer/particle_program_analysis.js +23 -17
  1311. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.d.ts.map +1 -1
  1312. package/src/shade/renderer/particles/optimizer/particle_vm_semantics.js +8 -2
  1313. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.js +1 -1
  1314. package/src/shade/renderer/particles/optimizer/pass_fold_constants.d.ts.map +1 -1
  1315. package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +20 -13
  1316. package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts.map +1 -1
  1317. package/src/shade/renderer/particles/optimizer/pass_inline_constants.js +4 -3
  1318. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.d.ts.map +1 -1
  1319. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.js +1 -1
  1320. package/src/shade/renderer/particles/optimizer/pass_pack_registers.d.ts.map +1 -1
  1321. package/src/shade/renderer/particles/optimizer/pass_pack_registers.js +12 -4
  1322. package/src/shade/renderer/particles/optimizer/pass_peephole.d.ts.map +1 -1
  1323. package/src/shade/renderer/particles/optimizer/pass_peephole.js +11 -10
  1324. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.d.ts.map +1 -1
  1325. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.js +12 -10
  1326. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.d.ts.map +1 -1
  1327. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.js +12 -4
  1328. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
  1329. package/src/shade/renderer/particles/runtime/ParticleEmitter.js +7 -0
  1330. package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.d.ts +4 -0
  1331. package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.d.ts.map +1 -1
  1332. package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.js +47 -88
  1333. package/src/shade/renderer/particles/shaders/shader_particle_avboit_occupancy.d.ts.map +1 -1
  1334. package/src/shade/renderer/particles/shaders/shader_particle_avboit_occupancy.js +22 -68
  1335. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts.map +1 -1
  1336. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.js +5 -3
  1337. package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts +31 -0
  1338. package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.d.ts.map +1 -0
  1339. package/src/shade/renderer/particles/shaders/shader_particle_init_free_list.js +62 -0
  1340. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts +13 -0
  1341. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
  1342. package/src/shade/renderer/particles/vm/ParticleVMReference.js +112 -18
  1343. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.d.ts.map +1 -1
  1344. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.js +12 -2
  1345. package/src/shade/renderer/postprocess/TemporalJitterSequence.d.ts +44 -0
  1346. package/src/shade/renderer/postprocess/TemporalJitterSequence.d.ts.map +1 -0
  1347. package/src/shade/renderer/postprocess/TemporalJitterSequence.js +104 -0
  1348. package/src/shade/renderer/postprocess/chunk_find_nearest_depth.d.ts +25 -0
  1349. package/src/shade/renderer/postprocess/chunk_find_nearest_depth.d.ts.map +1 -0
  1350. package/src/shade/renderer/postprocess/chunk_find_nearest_depth.js +74 -0
  1351. package/src/shade/renderer/postprocess/denoise/shader_temporal_reprojection_luma.d.ts.map +1 -1
  1352. package/src/shade/renderer/postprocess/denoise/shader_temporal_reprojection_luma.js +19 -4
  1353. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_recombine.d.ts.map +1 -1
  1354. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_recombine.js +12 -1
  1355. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts.map +1 -1
  1356. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.js +8 -0
  1357. package/src/shade/renderer/postprocess/eye/shader_autoexposure_adapt.d.ts.map +1 -1
  1358. package/src/shade/renderer/postprocess/eye/shader_autoexposure_adapt.js +18 -3
  1359. package/src/shade/renderer/postprocess/eye/shader_autoexposure_read_histogram.d.ts.map +1 -1
  1360. package/src/shade/renderer/postprocess/eye/shader_autoexposure_read_histogram.js +17 -4
  1361. package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.d.ts +29 -0
  1362. package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.d.ts.map +1 -0
  1363. package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.js +69 -0
  1364. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts +4 -16
  1365. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
  1366. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +10 -52
  1367. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts +0 -16
  1368. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
  1369. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +23 -55
  1370. package/src/shade/renderer/postprocess/motion_blur/MotionBlur.d.ts +4 -1
  1371. package/src/shade/renderer/postprocess/motion_blur/MotionBlur.d.ts.map +1 -1
  1372. package/src/shade/renderer/postprocess/motion_blur/MotionBlur.js +4 -1
  1373. package/src/shade/renderer/postprocess/motion_blur/chunk_motion_blur_resolution.d.ts +18 -0
  1374. package/src/shade/renderer/postprocess/motion_blur/chunk_motion_blur_resolution.d.ts.map +1 -0
  1375. package/src/shade/renderer/postprocess/motion_blur/chunk_motion_blur_resolution.js +43 -0
  1376. package/src/shade/renderer/postprocess/motion_blur/graph_postprocess_motion_blur.d.ts +5 -1
  1377. package/src/shade/renderer/postprocess/motion_blur/graph_postprocess_motion_blur.d.ts.map +1 -1
  1378. package/src/shade/renderer/postprocess/motion_blur/graph_postprocess_motion_blur.js +12 -2
  1379. package/src/shade/renderer/postprocess/motion_blur/shader_motion_blur_reconstruct.d.ts.map +1 -1
  1380. package/src/shade/renderer/postprocess/motion_blur/shader_motion_blur_reconstruct.js +33 -6
  1381. package/src/shade/renderer/postprocess/nss/NSS.d.ts +16 -8
  1382. package/src/shade/renderer/postprocess/nss/NSS.d.ts.map +1 -1
  1383. package/src/shade/renderer/postprocess/nss/NSS.js +37 -35
  1384. package/src/shade/renderer/postprocess/nss/chunk_nss_find_nearest_depth.d.ts +2 -2
  1385. package/src/shade/renderer/postprocess/nss/chunk_nss_find_nearest_depth.d.ts.map +1 -1
  1386. package/src/shade/renderer/postprocess/nss/chunk_nss_find_nearest_depth.js +28 -61
  1387. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
  1388. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +296 -291
  1389. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.d.ts.map +1 -1
  1390. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +13 -0
  1391. package/src/shade/renderer/postprocess/ssr/SSR.d.ts.map +1 -1
  1392. package/src/shade/renderer/postprocess/ssr/SSR.js +9 -7
  1393. package/src/shade/renderer/postprocess/ssr/depth_max_shader.d.ts +14 -0
  1394. package/src/shade/renderer/postprocess/ssr/depth_max_shader.d.ts.map +1 -1
  1395. package/src/shade/renderer/postprocess/ssr/depth_max_shader.js +53 -25
  1396. package/src/shade/renderer/postprocess/ssr/graph_build_depth_max_pyramid.d.ts +11 -1
  1397. package/src/shade/renderer/postprocess/ssr/graph_build_depth_max_pyramid.d.ts.map +1 -1
  1398. package/src/shade/renderer/postprocess/ssr/graph_build_depth_max_pyramid.js +11 -1
  1399. package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +46 -0
  1400. package/src/shade/renderer/postprocess/ssr/prefilter/shader_ssr_prefilter.d.ts.map +1 -1
  1401. package/src/shade/renderer/postprocess/ssr/prefilter/shader_ssr_prefilter.js +7 -0
  1402. package/src/shade/renderer/postprocess/ssr/shader/chunk_ssr_depth_thickness.d.ts +32 -0
  1403. package/src/shade/renderer/postprocess/ssr/shader/chunk_ssr_depth_thickness.d.ts.map +1 -0
  1404. package/src/shade/renderer/postprocess/ssr/shader/chunk_ssr_depth_thickness.js +41 -0
  1405. package/src/shade/renderer/postprocess/ssr/ssr_trace_shader.d.ts.map +1 -1
  1406. package/src/shade/renderer/postprocess/ssr/ssr_trace_shader.js +11 -6
  1407. package/src/shade/renderer/postprocess/taa/TAA.d.ts +13 -4
  1408. package/src/shade/renderer/postprocess/taa/TAA.d.ts.map +1 -1
  1409. package/src/shade/renderer/postprocess/taa/TAA.js +29 -48
  1410. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts +11 -0
  1411. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts.map +1 -1
  1412. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.js +25 -4
  1413. package/src/shade/renderer/postprocess/taa/shader_depth_occlusion_clip.d.ts +8 -0
  1414. package/src/shade/renderer/postprocess/taa/shader_depth_occlusion_clip.d.ts.map +1 -1
  1415. package/src/shade/renderer/postprocess/taa/shader_depth_occlusion_clip.js +14 -42
  1416. package/src/shade/renderer/rasterize/RasterizationJob.d.ts +4 -2
  1417. package/src/shade/renderer/rasterize/RasterizationJob.d.ts.map +1 -1
  1418. package/src/shade/renderer/rasterize/RasterizationJob.js +3 -1
  1419. package/src/shade/renderer/rasterize/TemplatePassDescriptor.d.ts +57 -0
  1420. package/src/shade/renderer/rasterize/TemplatePassDescriptor.d.ts.map +1 -0
  1421. package/src/shade/renderer/rasterize/TemplatePassDescriptor.js +133 -0
  1422. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts.map +1 -1
  1423. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.js +17 -0
  1424. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  1425. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +30 -4
  1426. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +21 -0
  1427. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -0
  1428. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +28 -0
  1429. package/src/shade/renderer/rasterize/bucket/shader_count_meshlets_by_material.d.ts.map +1 -1
  1430. package/src/shade/renderer/rasterize/bucket/shader_count_meshlets_by_material.js +74 -68
  1431. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
  1432. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +11 -1
  1433. package/src/shade/renderer/rasterize/bucket/shader_sort_meshlets_by_material.d.ts.map +1 -1
  1434. package/src/shade/renderer/rasterize/bucket/shader_sort_meshlets_by_material.js +70 -64
  1435. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way.d.ts.map +1 -1
  1436. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way.js +3 -4
  1437. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
  1438. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +8 -2
  1439. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.d.ts.map +1 -1
  1440. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.js +3 -4
  1441. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  1442. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +7 -5
  1443. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.d.ts.map +1 -1
  1444. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js +3 -4
  1445. package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.d.ts.map +1 -1
  1446. package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.js +3 -4
  1447. package/src/shade/renderer/rasterize/expand/mesh/shader_prefix_sum_to_command.d.ts.map +1 -1
  1448. package/src/shade/renderer/rasterize/expand/mesh/shader_prefix_sum_to_command.js +5 -2
  1449. package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.d.ts.map +1 -1
  1450. package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.js +3 -4
  1451. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
  1452. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +19 -2
  1453. package/src/shade/renderer/rasterize/forward/SHADING_SCENE_RESOURCE_GROUP.d.ts +20 -0
  1454. package/src/shade/renderer/rasterize/forward/SHADING_SCENE_RESOURCE_GROUP.d.ts.map +1 -1
  1455. package/src/shade/renderer/rasterize/forward/SHADING_SCENE_RESOURCE_GROUP.js +25 -0
  1456. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.d.ts.map +1 -1
  1457. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.js +2 -1
  1458. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.d.ts.map +1 -1
  1459. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.js +2 -1
  1460. package/src/shade/renderer/rasterize/forward/forward_template_pipeline.d.ts +40 -0
  1461. package/src/shade/renderer/rasterize/forward/forward_template_pipeline.d.ts.map +1 -0
  1462. package/src/shade/renderer/rasterize/forward/forward_template_pipeline.js +86 -0
  1463. package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.d.ts +11 -0
  1464. package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.d.ts.map +1 -1
  1465. package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.js +13 -2
  1466. package/src/shade/renderer/rasterize/native/alpha_tested_pass_resources.d.ts +59 -1
  1467. package/src/shade/renderer/rasterize/native/alpha_tested_pass_resources.d.ts.map +1 -1
  1468. package/src/shade/renderer/rasterize/native/alpha_tested_pass_resources.js +109 -7
  1469. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +16 -1
  1470. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  1471. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +13 -1
  1472. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +247 -0
  1473. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +20 -2
  1474. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +1 -1
  1475. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_coverage.d.ts +17 -0
  1476. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_coverage.d.ts.map +1 -0
  1477. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_coverage.js +25 -0
  1478. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_fold_pairs.d.ts +4 -5
  1479. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_fold_pairs.d.ts.map +1 -1
  1480. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_fold_pairs.js +7 -6
  1481. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_mark.d.ts +17 -0
  1482. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_mark.d.ts.map +1 -0
  1483. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_mark.js +51 -0
  1484. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_premultiplied_contribution.d.ts +23 -0
  1485. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_premultiplied_contribution.d.ts.map +1 -0
  1486. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_premultiplied_contribution.js +77 -0
  1487. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  1488. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +16 -20
  1489. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.d.ts +8 -2
  1490. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.d.ts.map +1 -1
  1491. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.js +57 -43
  1492. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.d.ts +8 -2
  1493. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.d.ts.map +1 -1
  1494. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.js +57 -43
  1495. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_occupancy.d.ts.map +1 -1
  1496. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_occupancy.js +8 -2
  1497. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.d.ts +7 -2
  1498. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.d.ts.map +1 -1
  1499. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +67 -58
  1500. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.d.ts +8 -2
  1501. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.d.ts.map +1 -1
  1502. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.js +186 -156
  1503. package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.d.ts +2 -2
  1504. package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.d.ts.map +1 -1
  1505. package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.js +36 -28
  1506. package/src/shade/renderer/rasterize/native/material_draw_indirect.d.ts +14 -12
  1507. package/src/shade/renderer/rasterize/native/material_draw_indirect.d.ts.map +1 -1
  1508. package/src/shade/renderer/rasterize/native/material_draw_indirect.js +29 -23
  1509. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts.map +1 -1
  1510. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +16 -22
  1511. package/src/shade/renderer/rasterize/native/oit/oit_resolve_fragment_body.d.ts +33 -0
  1512. package/src/shade/renderer/rasterize/native/oit/oit_resolve_fragment_body.d.ts.map +1 -0
  1513. package/src/shade/renderer/rasterize/native/oit/oit_resolve_fragment_body.js +123 -0
  1514. package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.d.ts +7 -2
  1515. package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.d.ts.map +1 -1
  1516. package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.js +227 -218
  1517. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.d.ts +8 -2
  1518. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.d.ts.map +1 -1
  1519. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.js +112 -180
  1520. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.d.ts +8 -2
  1521. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.d.ts.map +1 -1
  1522. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.js +110 -178
  1523. package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.d.ts +7 -2
  1524. package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.d.ts.map +1 -1
  1525. package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.js +242 -204
  1526. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
  1527. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +19 -2
  1528. package/src/shade/renderer/restir/reservoir/shader.d.ts.map +1 -1
  1529. package/src/shade/renderer/restir/reservoir/shader.js +27 -1
  1530. package/src/shade/renderer/scene/GPUSceneContext.d.ts +2 -1
  1531. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  1532. package/src/shade/renderer/scene/GPUSceneContext.js +11 -9
  1533. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +22 -0
  1534. package/src/shade/renderer/scene/SceneManager.d.ts +10 -0
  1535. package/src/shade/renderer/scene/SceneManager.d.ts.map +1 -1
  1536. package/src/shade/renderer/scene/SceneManager.js +17 -0
  1537. package/src/shade/renderer/scene/rows/GPUEntityBoundsReadback.d.ts.map +1 -1
  1538. package/src/shade/renderer/scene/rows/GPUEntityBoundsReadback.js +164 -144
  1539. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts +10 -0
  1540. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
  1541. package/src/shade/renderer/scene/rows/GPUSceneRows.js +14 -0
  1542. package/src/shade/renderer/scene/serialization/serialize_scene.d.ts.map +1 -1
  1543. package/src/shade/renderer/scene/serialization/serialize_scene.js +2 -6
  1544. package/src/shade/renderer/shader/ComputeShader.d.ts +5 -0
  1545. package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
  1546. package/src/shade/renderer/shader/ComputeShader.js +358 -353
  1547. package/src/shade/renderer/shader/chunk/atmosphere/chunk_integrate_scattering.d.ts.map +1 -1
  1548. package/src/shade/renderer/shader/chunk/atmosphere/chunk_integrate_scattering.js +15 -1
  1549. package/src/shade/renderer/shader/chunk/binary/chunk_encode_f16.d.ts +11 -2
  1550. package/src/shade/renderer/shader/chunk/binary/chunk_encode_f16.d.ts.map +1 -1
  1551. package/src/shade/renderer/shader/chunk/binary/chunk_encode_f16.js +33 -13
  1552. package/src/shade/renderer/shader/chunk/brdf/chunk_D_GGX.d.ts.map +1 -1
  1553. package/src/shade/renderer/shader/chunk/brdf/chunk_D_GGX.js +31 -3
  1554. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_decode32_morton2.d.ts +10 -1
  1555. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_decode32_morton2.d.ts.map +1 -1
  1556. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_decode32_morton2.js +23 -8
  1557. package/src/shade/renderer/shader/chunk/camera/chunk_pixel_radius_to_world.d.ts +8 -1
  1558. package/src/shade/renderer/shader/chunk/camera/chunk_pixel_radius_to_world.d.ts.map +1 -1
  1559. package/src/shade/renderer/shader/chunk/camera/chunk_pixel_radius_to_world.js +12 -5
  1560. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray.d.ts +15 -1
  1561. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray.d.ts.map +1 -1
  1562. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray.js +24 -28
  1563. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray_v2.d.ts +5 -0
  1564. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray_v2.d.ts.map +1 -1
  1565. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray_v2.js +18 -13
  1566. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_intersects_ray.d.ts.map +1 -1
  1567. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_intersects_ray.js +1 -47
  1568. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast.d.ts +10 -0
  1569. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast.d.ts.map +1 -1
  1570. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast.js +23 -8
  1571. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast_positive.d.ts +7 -0
  1572. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast_positive.d.ts.map +1 -1
  1573. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast_positive.js +12 -25
  1574. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_slab_span.d.ts +32 -0
  1575. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_slab_span.d.ts.map +1 -0
  1576. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_slab_span.js +52 -0
  1577. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_view_depth_range.d.ts +20 -0
  1578. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_view_depth_range.d.ts.map +1 -0
  1579. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_view_depth_range.js +42 -0
  1580. package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_octahedral_uv_wrap.d.ts +10 -1
  1581. package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_octahedral_uv_wrap.d.ts.map +1 -1
  1582. package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_octahedral_uv_wrap.js +18 -3
  1583. package/src/shade/renderer/shader/chunk/geometry/quaternion/chunk_quat_encode_u32.d.ts.map +1 -1
  1584. package/src/shade/renderer/shader/chunk/geometry/quaternion/chunk_quat_encode_u32.js +8 -4
  1585. package/src/shade/renderer/shader/chunk/grid/chunk_folded_workgroup_index.d.ts +24 -0
  1586. package/src/shade/renderer/shader/chunk/grid/chunk_folded_workgroup_index.d.ts.map +1 -0
  1587. package/src/shade/renderer/shader/chunk/grid/chunk_folded_workgroup_index.js +36 -0
  1588. package/src/shade/renderer/shader/chunk/grid/chunk_grid3d_to_index.d.ts +6 -0
  1589. package/src/shade/renderer/shader/chunk/grid/chunk_grid3d_to_index.d.ts.map +1 -1
  1590. package/src/shade/renderer/shader/chunk/grid/chunk_grid3d_to_index.js +6 -0
  1591. package/src/shade/renderer/shader/chunk/light/INCIDENT_LIGHT_STRUCT.d.ts.map +1 -1
  1592. package/src/shade/renderer/shader/chunk/light/INCIDENT_LIGHT_STRUCT.js +6 -1
  1593. package/src/shade/renderer/shader/chunk/light/io/chunk_get_spot_light_info.d.ts.map +1 -1
  1594. package/src/shade/renderer/shader/chunk/light/io/chunk_get_spot_light_info.js +6 -1
  1595. package/src/shade/renderer/shader/chunk/material/chunk_albedo_unpremultiply.d.ts +24 -0
  1596. package/src/shade/renderer/shader/chunk/material/chunk_albedo_unpremultiply.d.ts.map +1 -0
  1597. package/src/shade/renderer/shader/chunk/material/chunk_albedo_unpremultiply.js +31 -0
  1598. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg2d.js +2 -2
  1599. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg3d16.js +1 -1
  1600. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg4d.js +1 -1
  1601. package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_validate_hit.d.ts.map +1 -1
  1602. package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_validate_hit.js +8 -4
  1603. package/src/shade/renderer/shader/chunk/sdf/chunk_mesh_sdf_soft_shadow.d.ts.map +1 -1
  1604. package/src/shade/renderer/shader/chunk/sdf/chunk_mesh_sdf_soft_shadow.js +17 -3
  1605. package/src/shade/renderer/shader/graph/compute/graph_compute_indirect_pass.d.ts +4 -0
  1606. package/src/shade/renderer/shader/graph/compute/graph_compute_indirect_pass.d.ts.map +1 -1
  1607. package/src/shade/renderer/shader/graph/compute/graph_compute_indirect_pass.js +4 -0
  1608. package/src/shade/renderer/shader/pass/RenderPassDescriptor.d.ts +8 -0
  1609. package/src/shade/renderer/shader/pass/RenderPassDescriptor.d.ts.map +1 -1
  1610. package/src/shade/renderer/shader/pass/RenderPassDescriptor.js +203 -192
  1611. package/src/shade/renderer/shader/resource/ShaderResourceGroupDescriptor.d.ts.map +1 -1
  1612. package/src/shade/renderer/shader/resource/ShaderResourceGroupDescriptor.js +12 -0
  1613. package/src/shade/renderer/shader/type/WebGPUArray.d.ts.map +1 -1
  1614. package/src/shade/renderer/shader/type/WebGPUArray.js +25 -1
  1615. package/src/shade/renderer/shader/type/WebGPUStruct.d.ts.map +1 -1
  1616. package/src/shade/renderer/shader/type/WebGPUStruct.js +12 -0
  1617. package/src/shade/renderer/shader/type/queue_typed_buffer_update.d.ts.map +1 -1
  1618. package/src/shade/renderer/shader/type/queue_typed_buffer_update.js +15 -0
  1619. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  1620. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +10 -9
  1621. package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.d.ts +12 -2
  1622. package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.d.ts.map +1 -1
  1623. package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.js +210 -196
  1624. package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.d.ts +10 -3
  1625. package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.d.ts.map +1 -1
  1626. package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.js +219 -194
  1627. package/src/shade/renderer/shadow/map/shadowmap_budget_carry_over.d.ts +32 -0
  1628. package/src/shade/renderer/shadow/map/shadowmap_budget_carry_over.d.ts.map +1 -0
  1629. package/src/shade/renderer/shadow/map/shadowmap_budget_carry_over.js +47 -0
  1630. package/src/shade/renderer/shadow/vsm/VirtualShadowMap.d.ts.map +1 -1
  1631. package/src/shade/renderer/shadow/vsm/VirtualShadowMap.js +11 -1
  1632. package/src/shade/renderer/texture/ShadeTexture.d.ts +16 -0
  1633. package/src/shade/renderer/texture/ShadeTexture.d.ts.map +1 -1
  1634. package/src/shade/renderer/texture/ShadeTexture.js +17 -0
  1635. package/src/shade/renderer/texture/TextureManager.d.ts +22 -5
  1636. package/src/shade/renderer/texture/TextureManager.d.ts.map +1 -1
  1637. package/src/shade/renderer/texture/TextureManager.js +109 -6
  1638. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts.map +1 -1
  1639. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.js +8 -2
  1640. package/src/shade/renderer/texture/download_texture_data.d.ts.map +1 -1
  1641. package/src/shade/renderer/texture/download_texture_data.js +12 -4
  1642. package/src/shade/renderer/texture/encode/shader_texture_encode_astc_4x4.d.ts.map +1 -1
  1643. package/src/shade/renderer/texture/encode/shader_texture_encode_astc_4x4.js +66 -63
  1644. package/src/shade/renderer/texture/encode/shader_texture_encode_bc1.d.ts.map +1 -1
  1645. package/src/shade/renderer/texture/encode/shader_texture_encode_bc1.js +63 -60
  1646. package/src/shade/renderer/texture/encode/shader_texture_encode_bc4.d.ts.map +1 -1
  1647. package/src/shade/renderer/texture/encode/shader_texture_encode_bc4.js +79 -76
  1648. package/src/shade/renderer/texture/encode/shader_texture_encode_bc4_snorm.d.ts.map +1 -1
  1649. package/src/shade/renderer/texture/encode/shader_texture_encode_bc4_snorm.js +67 -64
  1650. package/src/shade/renderer/texture/encode/shader_texture_encode_bc5.d.ts.map +1 -1
  1651. package/src/shade/renderer/texture/encode/shader_texture_encode_bc5.js +70 -67
  1652. package/src/shade/renderer/texture/encode/shader_texture_encode_bc5_snorm.d.ts.map +1 -1
  1653. package/src/shade/renderer/texture/encode/shader_texture_encode_bc5_snorm.js +66 -63
  1654. package/src/shade/renderer/texture/encode/shader_texture_encode_bc6h.d.ts.map +1 -1
  1655. package/src/shade/renderer/texture/encode/shader_texture_encode_bc6h.js +65 -62
  1656. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts.map +1 -1
  1657. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.js +61 -58
  1658. package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts +7 -1
  1659. package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts.map +1 -1
  1660. package/src/shade/renderer/texture/format/texture_format_from_shade_image.js +100 -95
  1661. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts +8 -2
  1662. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts.map +1 -1
  1663. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +99 -73
  1664. package/src/shade/renderer/texture/mipmaps/filters/mipmap_shader_code_wronski2021.d.ts +30 -1
  1665. package/src/shade/renderer/texture/mipmaps/filters/mipmap_shader_code_wronski2021.d.ts.map +1 -1
  1666. package/src/shade/renderer/texture/mipmaps/filters/mipmap_shader_code_wronski2021.js +37 -20
  1667. package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.js +73 -73
  1668. package/src/shade/renderer/view/ViewManager.d.ts +8 -0
  1669. package/src/shade/renderer/view/ViewManager.d.ts.map +1 -1
  1670. package/src/shade/renderer/view/ViewManager.js +15 -0
  1671. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  1672. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +516 -507
  1673. package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.d.ts.map +1 -1
  1674. package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.js +272 -260
  1675. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts.map +1 -1
  1676. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +160 -134
  1677. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts +3 -0
  1678. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  1679. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +2564 -2356
  1680. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  1681. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +110 -7
  1682. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  1683. package/src/shade/wgsl/validate_wgsl_source.js +57 -0
  1684. package/src/view/asset/AssetLoaderStatusView.d.ts.map +1 -1
  1685. package/src/view/asset/AssetLoaderStatusView.js +8 -0
  1686. package/src/view/common/LabelView.d.ts.map +1 -1
  1687. package/src/view/common/LabelView.js +4 -0
  1688. package/src/view/common/ListView.d.ts +6 -2
  1689. package/src/view/common/ListView.d.ts.map +1 -1
  1690. package/src/view/common/ListView.js +27 -7
  1691. package/src/view/common/TabbedView.d.ts.map +1 -1
  1692. package/src/view/common/TabbedView.js +8 -0
  1693. package/src/view/common/VirtualListView.d.ts.map +1 -1
  1694. package/src/view/common/VirtualListView.js +17 -1
  1695. package/src/view/common/dnd/DropTarget.d.ts.map +1 -1
  1696. package/src/view/common/dnd/DropTarget.js +18 -0
  1697. package/src/view/elements/DropDownSelectionView.d.ts.map +1 -1
  1698. package/src/view/elements/DropDownSelectionView.js +8 -0
  1699. package/src/view/elements/image/SvgImageView.d.ts.map +1 -1
  1700. package/src/view/elements/image/SvgImageView.js +8 -0
  1701. package/src/view/elements/navigation/ViewStack.d.ts.map +1 -1
  1702. package/src/view/elements/navigation/ViewStack.js +4 -0
  1703. package/src/view/elements/notify/NotificationView.d.ts.map +1 -1
  1704. package/src/view/elements/notify/NotificationView.js +4 -0
  1705. package/src/view/elements/progress/segmented/SegmentedResourceBarView.d.ts.map +1 -1
  1706. package/src/view/elements/progress/segmented/SegmentedResourceBarView.js +8 -0
  1707. package/src/view/elements/radial/RadialMenu.d.ts.map +1 -1
  1708. package/src/view/elements/radial/RadialMenu.js +4 -0
  1709. package/src/view/minimap/Minimap.d.ts.map +1 -1
  1710. package/src/view/minimap/Minimap.js +8 -0
  1711. package/src/view/minimap/MinimapCanvasView.d.ts.map +1 -1
  1712. package/src/view/minimap/MinimapCanvasView.js +21 -1
  1713. package/src/view/minimap/dom/MinimapCameraView.d.ts.map +1 -1
  1714. package/src/view/minimap/dom/MinimapCameraView.js +232 -220
  1715. package/src/view/minimap/dom/MinimapMarkerView.d.ts.map +1 -1
  1716. package/src/view/minimap/dom/MinimapMarkerView.js +8 -0
  1717. package/src/view/minimap/minimap_focus_area.d.ts +5 -0
  1718. package/src/view/minimap/minimap_focus_area.d.ts.map +1 -1
  1719. package/src/view/minimap/minimap_focus_area.js +22 -0
  1720. package/src/view/tooltip/DomTooltipManager.d.ts +7 -0
  1721. package/src/view/tooltip/DomTooltipManager.d.ts.map +1 -1
  1722. package/src/view/tooltip/DomTooltipManager.js +22 -0
  1723. package/src/view/tooltip/DomTooltipObserver.d.ts.map +1 -1
  1724. package/src/view/tooltip/DomTooltipObserver.js +13 -3
  1725. package/src/view/tooltip/TooltipManager.d.ts.map +1 -1
  1726. package/src/view/tooltip/TooltipManager.js +16 -4
  1727. package/src/core/geom/3d/atlas/atlas_bench_lib.js +0 -315
  1728. package/src/engine/graphics/ecs/mesh/MeshEvents.d.ts +0 -6
  1729. package/src/engine/graphics/ecs/mesh/MeshEvents.d.ts.map +0 -1
  1730. package/src/engine/graphics/ecs/mesh/MeshEvents.js +0 -16
  1731. package/src/engine/graphics/ecs/mesh/commonObject3DFastMatrixUpdate.d.ts +0 -2
  1732. package/src/engine/graphics/ecs/mesh/commonObject3DFastMatrixUpdate.d.ts.map +0 -1
  1733. package/src/engine/graphics/ecs/mesh/commonObject3DFastMatrixUpdate.js +0 -37
  1734. package/src/engine/graphics/ecs/mesh/copyToVector3.d.ts +0 -8
  1735. package/src/engine/graphics/ecs/mesh/copyToVector3.d.ts.map +0 -1
  1736. package/src/engine/graphics/ecs/mesh/copyToVector3.js +0 -18
  1737. package/src/engine/graphics/ecs/mesh/object3DFastMatrixUpdate.d.ts +0 -6
  1738. package/src/engine/graphics/ecs/mesh/object3DFastMatrixUpdate.d.ts.map +0 -1
  1739. package/src/engine/graphics/ecs/mesh/object3DFastMatrixUpdate.js +0 -18
  1740. package/src/engine/graphics/ecs/mesh/rootObject3DFastMatrixUpdate.d.ts +0 -6
  1741. package/src/engine/graphics/ecs/mesh/rootObject3DFastMatrixUpdate.d.ts.map +0 -1
  1742. package/src/engine/graphics/ecs/mesh/rootObject3DFastMatrixUpdate.js +0 -14
  1743. package/src/engine/graphics/ecs/mesh/setMesh.d.ts +0 -16
  1744. package/src/engine/graphics/ecs/mesh/setMesh.d.ts.map +0 -1
  1745. package/src/engine/graphics/ecs/mesh/setMesh.js +0 -55
  1746. package/src/engine/graphics/ecs/mesh/skeleton/BoneMapping.d.ts +0 -13
  1747. package/src/engine/graphics/ecs/mesh/skeleton/BoneMapping.d.ts.map +0 -1
  1748. package/src/engine/graphics/ecs/mesh/skeleton/BoneMapping.js +0 -99
  1749. package/src/engine/graphics/ecs/mesh/skeleton/HumanoidBoneType.d.ts +0 -25
  1750. package/src/engine/graphics/ecs/mesh/skeleton/HumanoidBoneType.d.ts.map +0 -1
  1751. package/src/engine/graphics/ecs/mesh/skeleton/HumanoidBoneType.js +0 -29
  1752. package/src/engine/graphics/ecs/mesh/updateMeshTransform.d.ts +0 -6
  1753. package/src/engine/graphics/ecs/mesh/updateMeshTransform.d.ts.map +0 -1
  1754. package/src/engine/graphics/ecs/mesh/updateMeshTransform.js +0 -15
  1755. package/src/engine/graphics/ecs/mesh/updateNodeByTransformAndBBB.d.ts +0 -8
  1756. package/src/engine/graphics/ecs/mesh/updateNodeByTransformAndBBB.d.ts.map +0 -1
  1757. package/src/engine/graphics/ecs/mesh/updateNodeByTransformAndBBB.js +0 -14
  1758. package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.js +0 -481
  1759. package/src/engine/graphics3/terrain/pack_terrain_row_table.js +0 -48
  1760. package/src/engine/graphics3/terrain/shader_terrain_splat.js +0 -215
  1761. package/src/shade/renderer/animation/ANIMATION_BOUND_TRACK_GROUP_STRUCT.js +0 -57
  1762. package/src/shade/renderer/animation/ANIMATION_KEYFRAME_BLOCK_STRUCT.js +0 -50
  1763. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_BLOCK_STRUCT.js +0 -62
  1764. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.d.ts +0 -46
  1765. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.d.ts.map +0 -1
  1766. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.js +0 -45
@@ -1,2356 +1,2564 @@
1
- import { assert } from "../../../core/assert.js";
2
- import LineBuilder from "../../../core/codegen/LineBuilder.js";
3
-
4
- // =========================================================================
5
- // Type representation
6
- // =========================================================================
7
-
8
- /**
9
- * @typedef {object} WgslType
10
- * @property {'primitive' | 'vec' | 'mat' | 'array' | 'struct' | 'texture_2d' | 'sampler' | 'atomic' | 'unknown'} kind
11
- * @property {string} [name]
12
- * @property {number} [size]
13
- * @property {number} [cols]
14
- * @property {number} [rows]
15
- * @property {string} [scalar]
16
- * @property {WgslType} [element]
17
- * @property {number} [count]
18
- */
19
-
20
- const T_UNKNOWN = Object.freeze({ kind: 'unknown' });
21
- const T_I32 = Object.freeze({ kind: 'primitive', name: 'i32' });
22
-
23
- const VECTOR_ALIASES = {
24
- vec2i: { size: 2, scalar: 'i32' },
25
- vec3i: { size: 3, scalar: 'i32' },
26
- vec4i: { size: 4, scalar: 'i32' },
27
- vec2u: { size: 2, scalar: 'u32' },
28
- vec3u: { size: 3, scalar: 'u32' },
29
- vec4u: { size: 4, scalar: 'u32' },
30
- vec2f: { size: 2, scalar: 'f32' },
31
- vec3f: { size: 3, scalar: 'f32' },
32
- vec4f: { size: 4, scalar: 'f32' },
33
- vec2h: { size: 2, scalar: 'f16' },
34
- vec3h: { size: 3, scalar: 'f16' },
35
- vec4h: { size: 4, scalar: 'f16' },
36
- };
37
-
38
- const PRIMITIVE_NAMES = new Set(['i32', 'u32', 'f32', 'f16', 'bool']);
39
-
40
- const SWIZZLE_LETTERS = new Set(['x', 'y', 'z', 'w', 'r', 'g', 'b', 'a']);
41
-
42
- const SWIZZLE_INDEX = { x: 0, y: 1, z: 2, w: 3, r: 0, g: 1, b: 2, a: 3 };
43
-
44
- /**
45
- * Build a vec type alias name (e.g., {size:3, scalar:'f32'} → 'vec3f').
46
- */
47
- function vecAliasName(size, scalar) {
48
- const suffix = { i32: 'i', u32: 'u', f32: 'f', f16: 'h' }[scalar] || 'f';
49
- return `vec${size}${suffix}`;
50
- }
51
-
52
- // =========================================================================
53
- // Scope (symbol table) — tracks variable types for accurate codegen
54
- // =========================================================================
55
-
56
- class Scope {
57
- constructor(parent = null) {
58
- this.parent = parent;
59
- /** @type {Map<string, WgslType>} */
60
- this.symbols = new Map();
61
- }
62
-
63
- declare(name, type) {
64
- this.symbols.set(name, type || T_UNKNOWN);
65
- }
66
-
67
- /** @returns {WgslType} */
68
- lookup(name) {
69
- if (this.symbols.has(name)) return this.symbols.get(name);
70
- if (this.parent) return this.parent.lookup(name);
71
- return T_UNKNOWN;
72
- }
73
-
74
- push() {
75
- return new Scope(this);
76
- }
77
- }
78
-
79
- // =========================================================================
80
- // Tree-sitter helpers
81
- // =========================================================================
82
-
83
- /**
84
- * Return only the named children of a node (filters out punctuation tokens).
85
- */
86
- function namedChildren(node) {
87
- return node.namedChildren;
88
- }
89
-
90
- /**
91
- * First named child by type, or null.
92
- */
93
- function namedChildByType(node, type) {
94
- for (const c of node.namedChildren) {
95
- if (c.type === type) return c;
96
- }
97
- return null;
98
- }
99
-
100
- /**
101
- * All named children with the given type.
102
- */
103
- function namedChildrenByType(node, type) {
104
- return node.namedChildren.filter(c => c.type === type);
105
- }
106
-
107
- /**
108
- * Extract the source-text slice of `parent` that lies between the end of `left` and the start
109
- * of `right`. tree-sitter-web's `node.children` does not include unnamed tokens, so this is the
110
- * reliable way to read operator characters that sit between two named children.
111
- *
112
- * @param {Node} parent
113
- * @param {Node} left
114
- * @param {Node} right
115
- * @returns {string}
116
- */
117
- function textBetween(parent, left, right) {
118
- const left_offset = (left.endIndex - parent.startIndex);
119
- const right_offset = (right.startIndex - parent.startIndex);
120
- return parent.text.slice(left_offset, right_offset);
121
- }
122
-
123
- /**
124
- * Extract any leading source text in `parent` that precedes its first named child. Used for
125
- * unary operators (e.g. `-x`, `!cond`) where the operator is an unnamed token.
126
- *
127
- * @param {Node} parent
128
- * @returns {string}
129
- */
130
- function textBeforeFirstNamed(parent) {
131
- if (parent.namedChildCount === 0) return '';
132
- const first = parent.namedChildren[0];
133
- const offset = first.startIndex - parent.startIndex;
134
- return parent.text.slice(0, offset);
135
- }
136
-
137
- /**
138
- * Strip wrapper nodes that have a single named child of an expression-passthrough type.
139
- * The WGSL grammar has a long precedence chain: expression > relational > shift > additive > ...
140
- * When an expression is "simple" each level just wraps the next.
141
- */
142
- function unwrapExpression(node) {
143
- const PASSTHROUGH = new Set([
144
- 'expression',
145
- 'relational_expression',
146
- 'shift_expression',
147
- 'additive_expression',
148
- 'multiplicative_expression',
149
- 'unary_expression',
150
- 'singular_expression',
151
- 'primary_expression',
152
- ]);
153
- while (PASSTHROUGH.has(node.type) && node.namedChildren.length === 1) {
154
- // `unary_expression` keeps its operator as an unnamed token before the operand. If there
155
- // is one, don't unwrap — the caller needs to see the unary node so it can apply the op.
156
- if (node.type === 'unary_expression' && textBeforeFirstNamed(node).trim() !== '') {
157
- break;
158
- }
159
- node = node.namedChildren[0];
160
- }
161
- return node;
162
- }
163
-
164
- // =========================================================================
165
- // Type parsing (from `type_specifier` nodes or raw text)
166
- // =========================================================================
167
-
168
- /**
169
- * Parse a `type_specifier` tree-sitter node.
170
- * @param {Node} node
171
- * @returns {WgslType}
172
- */
173
- function parseTypeSpecifier(node) {
174
- if (node === null || node === undefined) return T_UNKNOWN;
175
- if (node.type === 'type_specifier') {
176
- return parseTypeSpecifier(node.namedChildren[0]);
177
- }
178
- if (node.type === 'template_elaborated_ident') {
179
- const ident = namedChildByType(node, 'ident');
180
- const ident_text = ident ? ident.text : node.text;
181
- const template = namedChildByType(node, 'template_list');
182
- const args = template ? extractTemplateArgs(template) : [];
183
- return classifyType(ident_text, args, template);
184
- }
185
- return T_UNKNOWN;
186
- }
187
-
188
- /**
189
- * Pull the textual template arguments from a `template_list` node, e.g. `<f32, 256>` → ['f32', '256'].
190
- */
191
- function extractTemplateArgs(template_list_node) {
192
- const out = [];
193
- const comma_list = namedChildByType(template_list_node, 'template_arg_comma_list');
194
- if (comma_list === null) return out;
195
- for (const c of comma_list.namedChildren) {
196
- if (c.type === 'template_arg_expression') {
197
- out.push(c.text.trim());
198
- }
199
- }
200
- return out;
201
- }
202
-
203
- /**
204
- * @param {string} ident
205
- * @param {string[]} args — textual template args (may be types or numbers)
206
- * @param {Node | null} template_list_node — the original node, for parsing nested array element types
207
- * @returns {WgslType}
208
- */
209
- function classifyType(ident, args, template_list_node) {
210
- if (PRIMITIVE_NAMES.has(ident)) {
211
- return { kind: 'primitive', name: ident };
212
- }
213
- if (VECTOR_ALIASES.hasOwnProperty(ident)) {
214
- const a = VECTOR_ALIASES[ident];
215
- return { kind: 'vec', size: a.size, scalar: a.scalar };
216
- }
217
- if (ident === 'vec2' || ident === 'vec3' || ident === 'vec4') {
218
- const size = parseInt(ident.slice(3));
219
- const scalar = args.length > 0 ? args[0] : 'f32';
220
- return { kind: 'vec', size, scalar };
221
- }
222
- {
223
- const m = ident.match(/^mat(\d)x(\d)([ifh]?)$/);
224
- if (m !== null) {
225
- const cols = parseInt(m[1]);
226
- const rows = parseInt(m[2]);
227
- const suffix = m[3];
228
- let scalar;
229
- if (suffix === 'f') scalar = 'f32';
230
- else if (suffix === 'i') scalar = 'i32';
231
- else if (suffix === 'h') scalar = 'f16';
232
- else scalar = (args.length > 0 ? args[0] : 'f32');
233
- return { kind: 'mat', cols, rows, scalar };
234
- }
235
- }
236
- if (ident === 'array') {
237
- // template arg 0 is the element type (sub-template), arg 1 is the count
238
- let element = T_UNKNOWN;
239
- let count = -1;
240
- if (template_list_node !== null) {
241
- const comma_list = namedChildByType(template_list_node, 'template_arg_comma_list');
242
- if (comma_list !== null) {
243
- const arg_nodes = namedChildrenByType(comma_list, 'template_arg_expression');
244
- if (arg_nodes.length > 0) {
245
- // Walk down to find the inner type ident
246
- const inner_expr = unwrapExpression(arg_nodes[0].namedChildren[0]);
247
- element = parseTypeSpecifier(inner_expr);
248
- }
249
- if (arg_nodes.length > 1) {
250
- const c = parseInt(arg_nodes[1].text.trim());
251
- if (!isNaN(c)) count = c;
252
- }
253
- }
254
- }
255
- return { kind: 'array', element, count };
256
- }
257
- if (ident === 'atomic') {
258
- const inner = args.length > 0 ? args[0] : 'i32';
259
- return { kind: 'atomic', scalar: inner };
260
- }
261
- // Texture types - 1D / 2D / 3D, sampled and storage variants. We
262
- // collapse all of them to a single kind because the intrinsics in
263
- // WGSLLanguageCore dispatch on the bound CPUBitmapData's
264
- // `dimensionality`, not on the static WGSL type. (The 'texture_2d'
265
- // kind label is preserved for backward compatibility with any
266
- // downstream consumer that may grep for it.)
267
- if (
268
- ident === 'texture_2d' || ident === 'texture_storage_2d'
269
- || ident === 'texture_1d' || ident === 'texture_storage_1d'
270
- || ident === 'texture_3d' || ident === 'texture_storage_3d'
271
- || ident === 'texture_2d_array'
272
- ) {
273
- const scalar = args.length > 0 ? args[0] : 'f32';
274
- return { kind: 'texture_2d', scalar };
275
- }
276
- if (ident === 'sampler') {
277
- return { kind: 'sampler' };
278
- }
279
- if (ident === 'ptr') {
280
- // Pointer — peel off the address space and read the inner type.
281
- if (template_list_node !== null) {
282
- const comma_list = namedChildByType(template_list_node, 'template_arg_comma_list');
283
- if (comma_list !== null) {
284
- const arg_nodes = namedChildrenByType(comma_list, 'template_arg_expression');
285
- if (arg_nodes.length >= 2) {
286
- const inner_expr = unwrapExpression(arg_nodes[1].namedChildren[0]);
287
- return parseTypeSpecifier(inner_expr);
288
- }
289
- }
290
- }
291
- return T_UNKNOWN;
292
- }
293
- // Otherwise: assume it's a struct name.
294
- return { kind: 'struct', name: ident };
295
- }
296
-
297
- // =========================================================================
298
- // Literal handling — strip WGSL type suffixes for JS
299
- // =========================================================================
300
-
301
- /**
302
- * Convert a WGSL literal token (e.g. `7u`, `1.0f`, `true`) to its JS equivalent.
303
- *
304
- * Stripping the type suffix is shape-sensitive: integer literals only carry `u`/`i`, and float
305
- * literals only carry `f`/`h`. Crucially, a hex int like `0x0300f00f` ends in a hex digit `f`
306
- * that must NOT be treated as a suffix — only an `f` after a decimal-format float counts.
307
- */
308
- function literalToJs(text) {
309
- const t = text.trim();
310
- if (t === 'true' || t === 'false') return t;
311
-
312
- // Hex int literals: `0xNN[ui]?`. Only `u`/`i` are real suffixes here; trailing `f`/`h` are
313
- // hex digits.
314
- if (/^0[xX]/.test(t)) {
315
- return t.replace(/[ui]$/, '');
316
- }
317
-
318
- // Decimal int / float. Float forms have a `.`, `e`/`E`, or end in `f`/`h`. Int forms don't.
319
- if (/[.eE]/.test(t)) {
320
- return t.replace(/[fh]$/, '');
321
- }
322
-
323
- // Plain integer (no `.`, no exponent): strip `u`/`i`/`f`/`h` (the latter two appear only on
324
- // forms like `1f` which WGSL allows as a float written without a decimal point).
325
- return t.replace(/[uifh]$/, '');
326
- }
327
-
328
- /**
329
- * The tracked type of a literal token, as far as its own spelling settles it.
330
- *
331
- * Only an explicit suffix is honoured. A bare `2043` is WGSL's AbstractInt, which takes its
332
- * concrete type from context this compiler does not track, so it stays unknown rather than being
333
- * guessed at.
334
- *
335
- * The suffix matters because operator selection reads these types. `index / 2043u` is truncating
336
- * integer division in WGSL and plain division in JavaScript, and the two differ for every pair
337
- * where the divisor does not divide the dividend — which is what a paged table's
338
- * `index / elements_per_page` is. Left untyped, the generated code returned a fractional page
339
- * index, indexed the page-address table with it, and read `undefined` back as zero: every record
340
- * past the first page slot came out of the emulator zero-filled, with nothing to say it had.
341
- *
342
- * @param {string} text
343
- * @returns {WgslType}
344
- */
345
- function literalType(text) {
346
- const t = text.trim();
347
-
348
- if (t === 'true' || t === 'false') {
349
- return { kind: 'primitive', name: 'bool' };
350
- }
351
-
352
- if (/[ui]$/.test(t)) {
353
- return { kind: 'primitive', name: t.endsWith('u') ? 'u32' : 'i32' };
354
- }
355
-
356
- // `f`/`h` are only suffixes on a decimal-format literal; on a hex int they are digits.
357
- if (!/^0[xX]/.test(t) && /[fh]$/.test(t)) {
358
- return { kind: 'primitive', name: t.endsWith('f') ? 'f32' : 'f16' };
359
- }
360
-
361
- if (/[.eE]/.test(t) && !/^0[xX]/.test(t)) {
362
- return { kind: 'primitive', name: 'f32' };
363
- }
364
-
365
- return T_UNKNOWN;
366
- }
367
-
368
- // =========================================================================
369
- // Operator handling
370
- // =========================================================================
371
-
372
- /**
373
- * Map a WGSL binary operator to a `wgsl.*` runtime helper or to a raw JS operator.
374
- * Arithmetic must go through wgsl.* so vectors are handled element-wise.
375
- */
376
- const ARITHMETIC_OP = {
377
- '+': 'add',
378
- '-': 'sub',
379
- '*': 'mul',
380
- '/': 'div',
381
- '%': 'rem',
382
- };
383
-
384
- const RAW_BINARY_OPS = new Set(['<', '>', '<=', '>=', '==', '!=', '&&', '||', '&', '|', '^', '<<', '>>']);
385
-
386
- /**
387
- * Arithmetic operators that wrap at 32 bits when WGSL types the result as an integer. Mapped to the
388
- * helper-name prefix; the scalar type (`u32` / `i32`) is appended at the call site.
389
- */
390
- const INTEGER_WRAPPING_OP = {
391
- '+': 'add',
392
- '-': 'sub',
393
- '*': 'mul',
394
- };
395
-
396
- // =========================================================================
397
- // Compiler context — central state during compilation
398
- // =========================================================================
399
-
400
- class Compiler {
401
- constructor() {
402
- /** @type {LineBuilder} */
403
- this.out = new LineBuilder();
404
-
405
- /** @type {Scope} */
406
- this.scope = new Scope();
407
-
408
- /** @type {Map<string, { name: string, fields: Array<{ name: string, type: WgslType }> }>} */
409
- this.structs = new Map();
410
-
411
- /** @type {Map<string, { name: string, returnType: WgslType, params: Array<{ name: string, type: WgslType }> }>} */
412
- this.functions = new Map();
413
-
414
- /** @type {Array<{ name: string, type: WgslType, group: number, binding: number, addressSpace: string | null, accessMode: string | null }>} */
415
- this.globalBindings = [];
416
-
417
- /** @type {Array<{ name: string, type: WgslType }>} */
418
- this.workgroupVars = [];
419
-
420
- /**
421
- * Module-scope `var<private>` and `const` declarations, in declaration order.
422
- * Each entry is `{ name, kind: 'let' | 'const', code, init }` — `code` is the JS line
423
- * emitted verbatim; `name` and `kind` are also tracked so the returned module object can
424
- * expose them as getter/setter (or read-only) properties for testing, and `init` is the
425
- * initializer expression on its own, which the private-state reset re-emits for the `let`
426
- * ones (a `const` cannot be reassigned, and no invocation can disturb it).
427
- * @type {Array<{ name: string, kind: 'let' | 'const', code: string, init: string }>}
428
- */
429
- this.privateGlobals = [];
430
-
431
- /** @type {{ name: string, params: Array<{ name: string, type: WgslType, builtin: string | null }>, workgroup_size: number[] } | null} */
432
- this.entry = null;
433
-
434
- /**
435
- * Label of the enclosing `loop` body block when that loop has a `continuing`
436
- * block: WGSL `continue` must transfer control INTO the continuing block, so it
437
- * is emitted as `break <label>` out of the labeled body block. `null` when the
438
- * nearest enclosing loop has no continuing block (plain JS `continue` suffices).
439
- * Loop emitters save/clear/restore this around nested loop bodies.
440
- * @type {string | null}
441
- */
442
- this.continue_label = null;
443
-
444
- /**
445
- * Monotonic counter used to generate unique loop-body labels.
446
- * @type {number}
447
- */
448
- this.loop_label_counter = 0;
449
- }
450
-
451
- error(node, message) {
452
- throw new Error(`WGSL compiler: ${message} (at ${node ? node.type : '<unknown>'} : ${node ? JSON.stringify(node.text.slice(0, 60)) : ''})`);
453
- }
454
- }
455
-
456
- // =========================================================================
457
- // Top-level compile entry point
458
- // =========================================================================
459
-
460
- export class WGSLJavaScriptCompiler {
461
-
462
- /**
463
- * Compile a tree-sitter WGSL parse tree to a JS source string.
464
- *
465
- * The output is a JavaScript expression: a function `factory(wgsl)` that returns
466
- * a shader module object. The shape depends on what the WGSL declared:
467
- *
468
- * - **Always present:** every top-level user function (e.g. `module.random()`),
469
- * every struct class (e.g. `module.Foo`), a getter/setter property for each
470
- * `var<private>` and getter for each module-scope `const`, and `reset_private()`,
471
- * which returns every `var<private>` to its start-of-invocation value.
472
- * - **Compute-shader fields (only when a `@compute` entry is present):**
473
- * ```
474
- * {
475
- * entry_name: string,
476
- * workgroup_size: [x, y, z],
477
- * param_names: string[],
478
- * entry: (bindings, workgroup, ...args) => void,
479
- * create_workgroup_state: () => object,
480
- * }
481
- * ```
482
- *
483
- * Without a `@compute` entry the result is a "library" module — useful for testing
484
- * pure WGSL helper code chunks (hashes, packing, math) one function at a time.
485
- *
486
- * @param {Tree} ast — tree-sitter WGSL AST (returned by `WGSLParser.parse`)
487
- * @returns {string}
488
- */
489
- compile(ast) {
490
- const c = new Compiler();
491
- compileTranslationUnit(c, ast.rootNode);
492
- return c.out.build();
493
- }
494
- }
495
-
496
- // =========================================================================
497
- // Translation unit (root)
498
- // =========================================================================
499
-
500
- /**
501
- * @param {Compiler} c
502
- * @param {Node} root
503
- */
504
- function compileTranslationUnit(c, root) {
505
- assert.equal(root.type, 'translation_unit', 'root must be translation_unit');
506
-
507
- // First pass — collect top-level decls so forward references and global scope resolve.
508
- for (const node of root.namedChildren) {
509
- switch (node.type) {
510
- case 'struct_decl':
511
- collectStruct(c, node);
512
- break;
513
- case 'function_decl':
514
- collectFunction(c, node);
515
- break;
516
- case 'global_variable_decl':
517
- collectGlobalVariable(c, node);
518
- break;
519
- case 'global_value_decl':
520
- collectGlobalValue(c, node);
521
- break;
522
- }
523
- }
524
-
525
- // Emit the wrapper: `(wgsl) => { ... }`
526
- c.out.add('(wgsl) => {');
527
- c.out.indent();
528
-
529
- // 1) Struct classes — must be defined before any user fn that references them or before
530
- // the workgroup state factory (which may need to construct struct instances).
531
- for (const node of root.namedChildren) {
532
- if (node.type === 'struct_decl') emitStruct(c, node);
533
- }
534
-
535
- // 2) Module-scope `let` slots for bindings and workgroup vars. The entry wrapper assigns
536
- // these on each dispatch so that user functions see them via their enclosing closure
537
- // — WGSL functions can read globals freely.
538
- for (const b of c.globalBindings) {
539
- c.out.add(`let ${b.name} = undefined;`);
540
- }
541
- for (const wv of c.workgroupVars) {
542
- c.out.add(`let ${wv.name} = undefined;`);
543
- }
544
-
545
- // 3) Module-scope `var<private>` and `const` declarations.
546
- for (const g of c.privateGlobals) {
547
- c.out.add(g.code);
548
- }
549
-
550
- // 4) User-defined functions (including the @compute entry, if any).
551
- for (const node of root.namedChildren) {
552
- if (node.type === 'function_decl') emitFunction(c, node);
553
- }
554
-
555
- // 5) The private-state reset. Emitted for every module, library ones included: a
556
- // `var<private>` is per-invocation state on the GPU, and the JS `let` above outlives the
557
- // dispatch that wrote it, so something has to put the initial values back.
558
- emitPrivateStateReset(c);
559
-
560
- // 6) Entry-stage support code: the dispatch wrapper for any entry, plus a workgroup-state
561
- // factory for @compute entries (fragment shaders have no var<workgroup>). Skipped entirely
562
- // in library mode (no entry attribute) so the resulting module is just a bag of pure
563
- // functions and globals.
564
- if (c.entry !== null) {
565
- if (c.entry.stage === 'compute') {
566
- emitWorkgroupStateFactory(c);
567
- }
568
- emitEntryWrapper(c);
569
- }
570
-
571
- // 7) Build and return the module object.
572
- emitModuleReturn(c);
573
-
574
- c.out.dedent();
575
- c.out.add('}');
576
- }
577
-
578
- /**
579
- * Emit the `return { ... }` block of the factory. Every top-level user function and struct
580
- * class is exposed by name; module-scope `var<private>` slots become getter/setter properties
581
- * (so tests can inspect or seed RNG state etc.), and module-scope `const`s become read-only
582
- * getters. `reset_private` is always included. When the WGSL had a `@compute` entry, the dispatch
583
- * trio (`entry_name`, `workgroup_size`, `param_names`, `entry`, `create_workgroup_state`) is
584
- * included too.
585
- */
586
- function emitModuleReturn(c) {
587
- c.out.add('const __module__ = {};');
588
-
589
- for (const fn_name of c.functions.keys()) {
590
- c.out.add(`__module__.${fn_name} = ${fn_name};`);
591
- }
592
- for (const struct_name of c.structs.keys()) {
593
- c.out.add(`__module__.${struct_name} = ${struct_name};`);
594
- }
595
-
596
- for (const g of c.privateGlobals) {
597
- if (g.kind === 'let') {
598
- c.out.add(`Object.defineProperty(__module__, ${JSON.stringify(g.name)}, { get: () => ${g.name}, set: (v) => { ${g.name} = v; } });`);
599
- } else {
600
- c.out.add(`Object.defineProperty(__module__, ${JSON.stringify(g.name)}, { get: () => ${g.name} });`);
601
- }
602
- }
603
-
604
- c.out.add('__module__.reset_private = __reset_private__;');
605
-
606
- if (c.entry !== null) {
607
- c.out.add(`__module__.entry_name = ${JSON.stringify(c.entry.name)};`);
608
- c.out.add(`__module__.stage = ${JSON.stringify(c.entry.stage)};`);
609
- c.out.add(`__module__.param_names = [${c.entry.params.map(p => JSON.stringify(p.name)).join(', ')}];`);
610
- c.out.add(`__module__.entry = __entry__;`);
611
- if (c.entry.stage === 'compute') {
612
- c.out.add(`__module__.workgroup_size = [${c.entry.workgroup_size.join(', ')}];`);
613
- c.out.add(`__module__.create_workgroup_state = __create_workgroup_state__;`);
614
- }
615
- }
616
-
617
- c.out.add('return __module__;');
618
- }
619
-
620
- // =========================================================================
621
- // Struct collection + emission
622
- // =========================================================================
623
-
624
- /**
625
- * @param {Compiler} c
626
- * @param {Node} node
627
- */
628
- function collectStruct(c, node) {
629
- const ident = namedChildByType(node, 'ident');
630
- const name = ident.text;
631
-
632
- const body = namedChildByType(node, 'struct_body_decl');
633
- const members = namedChildrenByType(body, 'struct_member');
634
-
635
- /** @type {Array<{ name: string, type: WgslType }>} */
636
- const fields = [];
637
-
638
- for (const m of members) {
639
- const member_ident = namedChildByType(m, 'member_ident');
640
- const type_spec = namedChildByType(m, 'type_specifier');
641
- fields.push({
642
- name: member_ident.text,
643
- type: parseTypeSpecifier(type_spec),
644
- });
645
- }
646
-
647
- c.structs.set(name, { name, fields });
648
- }
649
-
650
- /**
651
- * @param {Compiler} c
652
- * @param {Node} node
653
- */
654
- function emitStruct(c, node) {
655
- const ident = namedChildByType(node, 'ident');
656
- const name = ident.text;
657
- const info = c.structs.get(name);
658
-
659
- c.out.add(`class ${name} {`);
660
- c.out.indent();
661
- c.out.add('constructor() {');
662
- c.out.indent();
663
- for (const f of info.fields) {
664
- c.out.add(`this.${f.name} = ${defaultValueForType(f.type)};`);
665
- }
666
- c.out.dedent();
667
- c.out.add('}');
668
- c.out.dedent();
669
- c.out.add('}');
670
- }
671
-
672
- /**
673
- * Initialiser expression for a fresh value of the given type.
674
- * @param {WgslType} type
675
- * @returns {string}
676
- */
677
- function defaultValueForType(type) {
678
- if (type === undefined || type === null) return 'undefined';
679
- switch (type.kind) {
680
- case 'primitive':
681
- return type.name === 'bool' ? 'false' : '0';
682
- case 'vec':
683
- return `wgsl.${vecAliasName(type.size, type.scalar)}()`;
684
- case 'mat':
685
- return `new Float32Array(${type.cols * type.rows})`;
686
- case 'array': {
687
- if (type.count > 0) {
688
- if (type.element.kind === 'primitive') {
689
- const ctor = arrayCtorForScalar(type.element.name);
690
- return `new ${ctor}(${type.count})`;
691
- }
692
- // For non-primitive elements (vec / mat / struct / nested array) build the
693
- // array eagerly so `out[i]` is a fresh, mutable element rather than `undefined`.
694
- return `Array.from({ length: ${type.count} }, () => ${defaultValueForType(type.element)})`;
695
- }
696
- return '[]';
697
- }
698
- case 'struct':
699
- return `new ${type.name}()`;
700
- case 'atomic':
701
- return '{ value: 0 }';
702
- default:
703
- return 'undefined';
704
- }
705
- }
706
-
707
- function arrayCtorForScalar(name) {
708
- switch (name) {
709
- case 'f32':
710
- return 'Float32Array';
711
- case 'f16':
712
- return 'Float16Array';
713
- case 'i32':
714
- return 'Int32Array';
715
- case 'u32':
716
- return 'Uint32Array';
717
- default:
718
- return 'Array';
719
- }
720
- }
721
-
722
- // =========================================================================
723
- // Function collection + emission
724
- // =========================================================================
725
-
726
- /**
727
- * @param {Compiler} c
728
- * @param {Node} node
729
- */
730
- function collectFunction(c, node) {
731
- const header = namedChildByType(node, 'function_header');
732
- const ident = namedChildByType(header, 'ident');
733
- const name = ident.text;
734
-
735
- const param_list_node = namedChildByType(header, 'param_list');
736
- /** @type {Array<{ name: string, type: WgslType, builtin: string | null }>} */
737
- const params = [];
738
- if (param_list_node !== null) {
739
- const param_nodes = namedChildrenByType(param_list_node, 'param');
740
- for (const p of param_nodes) {
741
- const p_ident = namedChildByType(p, 'ident');
742
- const p_type = namedChildByType(p, 'type_specifier');
743
- const builtin = extractBuiltin(p);
744
- params.push({
745
- name: p_ident.text,
746
- type: parseTypeSpecifier(p_type),
747
- builtin,
748
- });
749
- }
750
- }
751
-
752
- // Optional return type — `template_elaborated_ident` directly under the header.
753
- let returnType = T_UNKNOWN;
754
- for (const child of header.namedChildren) {
755
- if (child.type === 'template_elaborated_ident') {
756
- returnType = parseTypeSpecifier(child);
757
- }
758
- }
759
-
760
- c.functions.set(name, { name, returnType, params: params.map(p => ({ name: p.name, type: p.type })) });
761
-
762
- // Detect the entry attribute (@compute, @fragment, or @vertex) and capture stage-specific
763
- // metadata. The emulator supports compute and fragment entries; vertex is rejected because
764
- // ImageShader testing in the emulator skips the vertex phase intentionally.
765
- const attrs = namedChildrenByType(node, 'attribute');
766
- let stage = null;
767
- let workgroup_size = [1, 1, 1];
768
- for (const a of attrs) {
769
- const inner = a.namedChildren[0];
770
- if (inner.type === 'compute_attr') {
771
- stage = 'compute';
772
- } else if (inner.type === 'fragment_attr') {
773
- stage = 'fragment';
774
- } else if (inner.type === 'vertex_attr') {
775
- throw new Error(`WGSL compiler: @vertex stage is not supported by the emulator (function '${name}'). For ImageShader testing the vertex phase is skipped — invoke the @fragment entry directly.`);
776
- } else if (inner.type === 'workgroup_size_attr') {
777
- const sizes = namedChildrenByType(inner, 'expression').map(e => parseInt(e.text.trim()) | 0);
778
- for (let i = 0; i < sizes.length && i < 3; i++) {
779
- workgroup_size[i] = sizes[i];
780
- }
781
- }
782
- }
783
-
784
- if (stage !== null) {
785
- if (c.entry !== null) {
786
- throw new Error(`WGSL compiler: multiple @${stage} entry functions found ('${c.entry.name}' and '${name}')`);
787
- }
788
- c.entry = { name, params, stage, workgroup_size };
789
- }
790
- }
791
-
792
- /**
793
- * Pull the `@builtin(name)` attribute name from a function param node, if present.
794
- */
795
- function extractBuiltin(param_node) {
796
- for (const a of namedChildrenByType(param_node, 'attribute')) {
797
- const inner = a.namedChildren[0];
798
- if (inner.type === 'builtin_attr') {
799
- const name_node = namedChildByType(inner, 'builtin_value_name');
800
- if (name_node !== null) return name_node.text;
801
- }
802
- }
803
- return null;
804
- }
805
-
806
- /**
807
- * @param {Compiler} c
808
- * @param {Node} node
809
- */
810
- function emitFunction(c, node) {
811
- const header = namedChildByType(node, 'function_header');
812
- const ident = namedChildByType(header, 'ident');
813
- const name = ident.text;
814
- const info = c.functions.get(name);
815
-
816
- const param_list_node = namedChildByType(header, 'param_list');
817
- const param_nodes = param_list_node !== null ? namedChildrenByType(param_list_node, 'param') : [];
818
-
819
- const param_names = param_nodes.map(p => namedChildByType(p, 'ident').text);
820
-
821
- c.out.add(`function ${name}(${param_names.join(', ')}) {`);
822
- c.out.indent();
823
-
824
- c.scope = c.scope.push();
825
- for (let i = 0; i < param_nodes.length; i++) {
826
- c.scope.declare(param_names[i], info.params[i].type);
827
- }
828
-
829
- const body = namedChildByType(node, 'compound_statement');
830
- emitCompoundStatementBody(c, body);
831
-
832
- c.scope = c.scope.parent;
833
-
834
- c.out.dedent();
835
- c.out.add('}');
836
- }
837
-
838
- // =========================================================================
839
- // Globals — bindings, workgroup vars, private/const
840
- // =========================================================================
841
-
842
- /**
843
- * Inspect a `global_variable_decl` and record its metadata.
844
- * @param {Compiler} c
845
- * @param {Node} node
846
- */
847
- function collectGlobalVariable(c, node) {
848
- const var_decl = namedChildByType(node, 'variable_decl');
849
- if (var_decl === null) {
850
- collectGlobalValue(c, node);
851
- return;
852
- }
853
-
854
- const template = namedChildByType(var_decl, 'template_list');
855
- const opt_ident = namedChildByType(var_decl, 'optionally_typed_ident');
856
- const var_ident = namedChildByType(opt_ident, 'ident');
857
- const type_spec = namedChildByType(opt_ident, 'type_specifier');
858
- const name = var_ident.text;
859
- const type = parseTypeSpecifier(type_spec);
860
-
861
- let address_space = null;
862
- let access_mode = null;
863
- if (template !== null) {
864
- const args = extractTemplateArgs(template);
865
- address_space = args[0] || null;
866
- access_mode = args[1] || null;
867
- }
868
-
869
- let group = null;
870
- let binding = null;
871
- for (const a of namedChildrenByType(node, 'attribute')) {
872
- const inner = a.namedChildren[0];
873
- if (inner.type === 'group_attr') {
874
- const expr = namedChildByType(inner, 'expression');
875
- group = parseInt(expr.text.trim());
876
- } else if (inner.type === 'binding_attr') {
877
- const expr = namedChildByType(inner, 'expression');
878
- binding = parseInt(expr.text.trim());
879
- }
880
- }
881
-
882
- c.scope.declare(name, type);
883
-
884
- // `var<immediate>` carries neither attribute — immediate data is part of the shader interface
885
- // but is not a bound resource, so WGSL gives it no @group/@binding. It still arrives from
886
- // outside the shader, so it is a binding as far as the emulator is concerned, and binding here
887
- // is what keeps it out of the `privateGlobals` branch below. Falling through to that branch
888
- // would default-initialise it and every spec reading it would quietly see zeroes.
889
- const is_immediate = address_space === 'immediate';
890
-
891
- if (is_immediate || (group !== null && binding !== null)) {
892
- c.globalBindings.push({
893
- name, type, group, binding, addressSpace: address_space, accessMode: access_mode,
894
- });
895
- return;
896
- }
897
-
898
- if (address_space === 'workgroup') {
899
- c.workgroupVars.push({ name, type });
900
- return;
901
- }
902
-
903
- // Private / module-scope `var<private>`. If the WGSL has an explicit initializer
904
- // (e.g. `var<private> rnd_state: u32 = 2891336453u`), use it; otherwise fall back
905
- // to the type's default value.
906
- const initializer_node = namedChildByType(node, 'expression');
907
- const init_code = initializer_node !== null
908
- ? compileExpression(c, initializer_node).code
909
- : defaultValueForType(type);
910
- c.privateGlobals.push({
911
- name,
912
- kind: 'let',
913
- code: `let ${name} = ${init_code};`,
914
- init: init_code,
915
- });
916
- }
917
-
918
- /**
919
- * Inspect a `global_value_decl` (`const x = …;` / `let x = …;` at module scope) and record it.
920
- * @param {Compiler} c
921
- * @param {Node} node
922
- */
923
- function collectGlobalValue(c, node) {
924
- let ident = null;
925
- let value_node = null;
926
- let type_node = null;
927
- for (const child of node.namedChildren) {
928
- if (child.type === 'optionally_typed_ident') {
929
- ident = namedChildByType(child, 'ident');
930
- type_node = namedChildByType(child, 'type_specifier');
931
- } else if (child.type === 'expression') {
932
- value_node = child;
933
- }
934
- }
935
- if (ident === null || value_node === null) return;
936
- const name = ident.text;
937
- let type = type_node !== null ? parseTypeSpecifier(type_node) : T_UNKNOWN;
938
-
939
- const expr = compileExpression(c, value_node);
940
-
941
- // Infer the type from the RHS when there's no explicit annotation (mirrors the local
942
- // `let`/`var` path). Without this a `const M = mat3x3<f32>(...)` is left T_UNKNOWN, so a
943
- // later `M * v` can't tell M is a matrix and emits a vector multiply → length mismatch.
944
- if (type === T_UNKNOWN || type.kind === 'unknown') {
945
- type = expr.type;
946
- }
947
-
948
- c.scope.declare(name, type);
949
- c.privateGlobals.push({
950
- name,
951
- kind: 'const',
952
- code: `const ${name} = ${expr.code};`,
953
- init: expr.code,
954
- });
955
- }
956
-
957
- // =========================================================================
958
- // Workgroup state factory + entry wrapper
959
- // =========================================================================
960
-
961
- /**
962
- * Emit `__reset_private__()`, which restores every module-scope `var<private>` to the value it
963
- * would have at the start of a WGSL invocation — its declared initializer, or the type's zero
964
- * value when it was declared without one.
965
- *
966
- * This is the private-address-space counterpart of {@link emitWorkgroupStateFactory}. The
967
- * generated module keeps its private slots in `let` bindings that live as long as the module, so
968
- * without this a second dispatch would start from whatever the first one left behind — state the
969
- * GPU never carries.
970
- *
971
- * Module-scope `const`s are skipped: they are immutable in the generated JS and no invocation can
972
- * disturb them.
973
- *
974
- * @param {Compiler} c
975
- */
976
- function emitPrivateStateReset(c) {
977
- c.out.add('function __reset_private__() {');
978
- c.out.indent();
979
- for (const g of c.privateGlobals) {
980
- if (g.kind !== 'let') continue;
981
- c.out.add(`${g.name} = ${g.init};`);
982
- }
983
- c.out.dedent();
984
- c.out.add('}');
985
- }
986
-
987
- function emitWorkgroupStateFactory(c) {
988
- c.out.add('function __create_workgroup_state__() {');
989
- c.out.indent();
990
- c.out.add('return {');
991
- c.out.indent();
992
- for (const wv of c.workgroupVars) {
993
- c.out.add(`${wv.name}: ${defaultValueForType(wv.type)},`);
994
- }
995
- c.out.dedent();
996
- c.out.add('};');
997
- c.out.dedent();
998
- c.out.add('}');
999
- }
1000
-
1001
- function emitEntryWrapper(c) {
1002
- const param_names = c.entry.params.map(p => p.name);
1003
- const is_compute = c.entry.stage === 'compute';
1004
- // Compute entries take a per-dispatch workgroup-state object; fragment entries don't have
1005
- // var<workgroup> at all, so the wrapper signature drops it.
1006
- const fixed_args = is_compute ? '__bindings__, __workgroup__' : '__bindings__';
1007
- const all_args = param_names.length > 0 ? `${fixed_args}, ${param_names.join(', ')}` : fixed_args;
1008
-
1009
- c.out.add(`function __entry__(${all_args}) {`);
1010
- c.out.indent();
1011
-
1012
- // Refresh each module-scope binding/workgroup slot before invoking the user's main.
1013
- // User functions read these via their enclosing closure, so this assignment makes the
1014
- // current dispatch's bindings visible to every helper they may call.
1015
- for (const b of c.globalBindings) {
1016
- c.out.add(`${b.name} = __bindings__.${b.name};`);
1017
- }
1018
- if (is_compute) {
1019
- for (const wv of c.workgroupVars) {
1020
- c.out.add(`${wv.name} = __workgroup__.${wv.name};`);
1021
- }
1022
- }
1023
-
1024
- if (is_compute && c.workgroupVars.length > 0) {
1025
- // The lanes of one workgroup are dispatched one call at a time, and a scalar
1026
- // `var<workgroup>` a lane assigns lives in the module-scope slot above — a copy of the
1027
- // state object's field, not the field. Writing it back is what lets the next lane see it,
1028
- // which is the whole point of workgroup memory (an array slot already persists, since the
1029
- // slot holds a reference and the lane mutates it in place).
1030
- c.out.add(`const __result__ = ${c.entry.name}(${param_names.join(', ')});`);
1031
- for (const wv of c.workgroupVars) {
1032
- c.out.add(`__workgroup__.${wv.name} = ${wv.name};`);
1033
- }
1034
- c.out.add('return __result__;');
1035
- } else {
1036
- c.out.add(`return ${c.entry.name}(${param_names.join(', ')});`);
1037
- }
1038
-
1039
- c.out.dedent();
1040
- c.out.add('}');
1041
- }
1042
-
1043
- // =========================================================================
1044
- // Statements
1045
- // =========================================================================
1046
-
1047
- /**
1048
- * Emit only the inside of a compound_statement (no `{` / `}`).
1049
- * @param {Compiler} c
1050
- * @param {Node} node — `compound_statement`
1051
- */
1052
- function emitCompoundStatementBody(c, node) {
1053
- for (const child of node.namedChildren) {
1054
- if (child.type === 'statement') {
1055
- emitStatement(c, child);
1056
- }
1057
- }
1058
- }
1059
-
1060
- function emitCompoundStatement(c, node) {
1061
- c.out.add('{');
1062
- c.out.indent();
1063
- c.scope = c.scope.push();
1064
- emitCompoundStatementBody(c, node);
1065
- c.scope = c.scope.parent;
1066
- c.out.dedent();
1067
- c.out.add('}');
1068
- }
1069
-
1070
- /**
1071
- * Emit a single `statement` node (its child is the actual statement kind).
1072
- * @param {Compiler} c
1073
- * @param {Node} node
1074
- */
1075
- function emitStatement(c, node) {
1076
- const inner = node.namedChildren[0];
1077
- switch (inner.type) {
1078
- case 'variable_or_value_statement':
1079
- emitVariableOrValueStatement(c, inner);
1080
- break;
1081
- case 'variable_updating_statement':
1082
- emitVariableUpdatingStatement(c, inner);
1083
- break;
1084
- case 'return_statement':
1085
- emitReturnStatement(c, inner);
1086
- break;
1087
- case 'if_statement':
1088
- emitIfStatement(c, inner);
1089
- break;
1090
- case 'for_statement':
1091
- emitForStatement(c, inner);
1092
- break;
1093
- case 'while_statement':
1094
- emitWhileStatement(c, inner);
1095
- break;
1096
- case 'loop_statement':
1097
- emitLoopStatement(c, inner);
1098
- break;
1099
- case 'switch_statement':
1100
- emitSwitchStatement(c, inner);
1101
- break;
1102
- case 'break_statement':
1103
- c.out.add('break;');
1104
- break;
1105
- case 'continue_statement':
1106
- // Inside a `loop` with a `continuing` block, `continue` must run the
1107
- // continuing block: it is emitted as a break out of the labeled body block
1108
- // (the continuing code follows that block inside the same `while`).
1109
- if (c.continue_label !== null) {
1110
- c.out.add(`break ${c.continue_label};`);
1111
- } else {
1112
- c.out.add('continue;');
1113
- }
1114
- break;
1115
- case 'discard_statement':
1116
- c.out.add('return;');
1117
- break;
1118
- case 'compound_statement':
1119
- emitCompoundStatement(c, inner);
1120
- break;
1121
- case 'func_call_statement':
1122
- emitFunctionCallStatement(c, inner);
1123
- break;
1124
- case 'const_assert_statement':
1125
- // Skipped at runtime.
1126
- break;
1127
- default:
1128
- c.error(inner, `unsupported statement: ${inner.type}`);
1129
- }
1130
- }
1131
-
1132
- /**
1133
- * `let x = expr;` or `var x: T = expr;` or `var x: T;`
1134
- */
1135
- function emitVariableOrValueStatement(c, node) {
1136
- const var_decl = namedChildByType(node, 'variable_decl');
1137
- const opt_ident_direct = namedChildByType(node, 'optionally_typed_ident');
1138
- const expr_node = namedChildByType(node, 'expression');
1139
-
1140
- /** @type {'let' | 'const'} */
1141
- let kind = 'let';
1142
- let opt_ident = null;
1143
- let template = null;
1144
-
1145
- if (var_decl !== null) {
1146
- // WGSL `var` is the mutable form → JS `let`.
1147
- kind = 'let';
1148
- opt_ident = namedChildByType(var_decl, 'optionally_typed_ident');
1149
- template = namedChildByType(var_decl, 'template_list');
1150
- } else {
1151
- // WGSL `let` and `const` are both immutable bindings → JS `const`.
1152
- // Tree-sitter exposes the keyword as an unnamed leading token; read it from the source.
1153
- kind = 'const';
1154
- opt_ident = opt_ident_direct;
1155
- }
1156
-
1157
- const ident = namedChildByType(opt_ident, 'ident');
1158
- const type_spec = namedChildByType(opt_ident, 'type_specifier');
1159
- const name = ident.text;
1160
- let type = type_spec !== null ? parseTypeSpecifier(type_spec) : T_UNKNOWN;
1161
-
1162
- if (expr_node !== null) {
1163
- const expr = compileExpression(c, expr_node);
1164
- // Infer the type from the RHS when no explicit annotation is present. A bare integer
1165
- // literal concretises to i32 here, as WGSL does for `let x = 3;`.
1166
- if (type === T_UNKNOWN || type.kind === 'unknown') {
1167
- type = expr.abstract_int === true ? T_I32 : expr.type;
1168
- }
1169
- c.scope.declare(name, type);
1170
- c.out.add(`${kind} ${name} = ${expr.code};`);
1171
- } else {
1172
- c.scope.declare(name, type);
1173
- c.out.add(`${kind} ${name} = ${defaultValueForType(type)};`);
1174
- }
1175
- }
1176
-
1177
- /**
1178
- * Assignment / compound assignment / increment / decrement.
1179
- */
1180
- function emitVariableUpdatingStatement(c, node) {
1181
- const inner = node.namedChildren[0];
1182
- if (inner.type === 'assignment_statement') {
1183
- const lhs = namedChildByType(inner, 'lhs_expression');
1184
- const expr = namedChildByType(inner, 'expression');
1185
-
1186
- // The compound assignment operator sits between the LHS and the RHS as an unnamed token.
1187
- const op_text = textBetween(inner, lhs, expr).trim();
1188
-
1189
- const lhs_compiled = compileLhs(c, lhs);
1190
- const rhs_compiled = compileExpression(c, expr);
1191
-
1192
- if (op_text === '=' || op_text === '') {
1193
- c.out.add(emitWriteStatement(lhs_compiled, rhs_compiled.code));
1194
- return;
1195
- }
1196
-
1197
- const arith = {
1198
- '+=': 'add', '-=': 'sub', '*=': 'mul', '/=': 'div', '%=': 'rem',
1199
- };
1200
- if (arith.hasOwnProperty(op_text)) {
1201
- c.out.add(emitWriteStatement(lhs_compiled, `wgsl.${arith[op_text]}(${lhs_compiled.code}, ${rhs_compiled.code})`));
1202
- return;
1203
- }
1204
-
1205
- // Bitwise / shift compound assignment, routed like the binary operators: through the
1206
- // element-wise helpers for a vec/mat or bool LHS (raw JS coerces a typed array to NaN and
1207
- // a bool to 0/1), and for `>>=` on u32 (JS `>>` sign-extends).
1208
- const bitwise_helper = BITWISE_HELPER[op_text.slice(0, -1)];
1209
- if (bitwise_helper !== undefined && (
1210
- isContainerType(lhs_compiled.type)
1211
- || isScalarBool(lhs_compiled.type)
1212
- || (op_text === '>>=' && (isScalarUnsigned(lhs_compiled.type) || isScalarUnsigned(rhs_compiled.type)))
1213
- )) {
1214
- c.out.add(emitWriteStatement(lhs_compiled, `wgsl.${bitwise_helper}(${lhs_compiled.code}, ${rhs_compiled.code})`));
1215
- return;
1216
- }
1217
- c.out.add(`${lhs_compiled.code} ${op_text} ${rhs_compiled.code};`);
1218
- return;
1219
- }
1220
- if (inner.type === 'increment_statement') {
1221
- const lhs = namedChildByType(inner, 'lhs_expression');
1222
- const lhs_compiled = compileLhs(c, lhs);
1223
- c.out.add(emitWriteStatement(lhs_compiled, `wgsl.add(${lhs_compiled.code}, 1)`));
1224
- return;
1225
- }
1226
- if (inner.type === 'decrement_statement') {
1227
- const lhs = namedChildByType(inner, 'lhs_expression');
1228
- const lhs_compiled = compileLhs(c, lhs);
1229
- c.out.add(emitWriteStatement(lhs_compiled, `wgsl.sub(${lhs_compiled.code}, 1)`));
1230
- return;
1231
- }
1232
- c.error(inner, `unsupported variable_updating_statement: ${inner.type}`);
1233
- }
1234
-
1235
- /**
1236
- * Emit a write to an LHS. Most LHS expressions are plain JS LValues (`x`, `arr[i]`, `obj.f`) and
1237
- * are written with `=`. Mat-column LHS — `m[i]` for a mat — is special: the compiler emits it as
1238
- * `wgsl.mat_col(m, i, rows)`, which is a typed-array view (a function call result, not assignable).
1239
- * To write through the view we use `Float32Array.prototype.set(rhs)` instead, which copies into
1240
- * the underlying matrix storage in place.
1241
- *
1242
- * @param {{ code: string }} lhs_compiled
1243
- * @param {string} rhs_code
1244
- * @returns {string}
1245
- */
1246
- function emitWriteStatement(lhs_compiled, rhs_code) {
1247
- // Only the bare `wgsl.mat_col(...)` form (no chained `[i]` / `.x`) needs `.set()` — that's a
1248
- // typed-array view, an unassignable function-call result. Anything chained off it (e.g.
1249
- // `wgsl.mat_col(...)[3]` or `wgsl.mat_col(...).x` becoming `[i]`) is a scalar slot and must
1250
- // use plain `=`.
1251
- if (lhs_compiled.code.startsWith('wgsl.mat_col(') && lhs_compiled.code.endsWith(')')) {
1252
- return `${lhs_compiled.code}.set(${rhs_code});`;
1253
- }
1254
- // `*p = v` has to reach the caller's object; assigning would only rebind the parameter.
1255
- if (lhs_compiled.through_pointer === true) {
1256
- return `${lhs_compiled.code} = wgsl.store_ptr(${lhs_compiled.code}, ${rhs_code});`;
1257
- }
1258
- return `${lhs_compiled.code} = ${rhs_code};`;
1259
- }
1260
-
1261
- function emitReturnStatement(c, node) {
1262
- const expr = namedChildByType(node, 'expression');
1263
- if (expr === null) {
1264
- c.out.add('return;');
1265
- } else {
1266
- const e = compileExpression(c, expr);
1267
- c.out.add(`return ${e.code};`);
1268
- }
1269
- }
1270
-
1271
- function emitIfStatement(c, node) {
1272
- const if_clause = namedChildByType(node, 'if_clause');
1273
- const cond = namedChildByType(if_clause, 'expression');
1274
- const if_body = namedChildByType(if_clause, 'compound_statement');
1275
-
1276
- const cond_compiled = compileExpression(c, cond);
1277
- c.out.add(`if (${cond_compiled.code}) {`);
1278
- c.out.indent();
1279
- c.scope = c.scope.push();
1280
- emitCompoundStatementBody(c, if_body);
1281
- c.scope = c.scope.parent;
1282
- c.out.dedent();
1283
- c.out.add('}');
1284
-
1285
- // else-if and else clauses.
1286
- for (const child of node.namedChildren) {
1287
- if (child.type === 'else_if_clause') {
1288
- const eif_cond = namedChildByType(child, 'expression');
1289
- const eif_body = namedChildByType(child, 'compound_statement');
1290
- const eif_compiled = compileExpression(c, eif_cond);
1291
- c.out.add(`else if (${eif_compiled.code}) {`);
1292
- c.out.indent();
1293
- c.scope = c.scope.push();
1294
- emitCompoundStatementBody(c, eif_body);
1295
- c.scope = c.scope.parent;
1296
- c.out.dedent();
1297
- c.out.add('}');
1298
- } else if (child.type === 'else_clause') {
1299
- const else_body = namedChildByType(child, 'compound_statement');
1300
- // else_body may instead be an if_statement (else-if shorthand).
1301
- const nested_if = namedChildByType(child, 'if_statement');
1302
- if (else_body !== null) {
1303
- c.out.add('else {');
1304
- c.out.indent();
1305
- c.scope = c.scope.push();
1306
- emitCompoundStatementBody(c, else_body);
1307
- c.scope = c.scope.parent;
1308
- c.out.dedent();
1309
- c.out.add('}');
1310
- } else if (nested_if !== null) {
1311
- c.out.add('else');
1312
- emitIfStatement(c, nested_if);
1313
- }
1314
- }
1315
- }
1316
- }
1317
-
1318
- function emitForStatement(c, node) {
1319
- const for_header = namedChildByType(node, 'for_header');
1320
- const for_init = namedChildByType(for_header, 'for_init');
1321
- const cond_expr = namedChildByType(for_header, 'expression');
1322
- const for_update = namedChildByType(for_header, 'for_update');
1323
- const body = namedChildByType(node, 'compound_statement');
1324
-
1325
- c.scope = c.scope.push();
1326
-
1327
- // Init / cond / update parts.
1328
- let init_str = '';
1329
- if (for_init !== null) {
1330
- // Tree-sitter wraps it in a variable_or_value_statement; capture the emission as text.
1331
- const sub = new Compiler();
1332
- sub.scope = c.scope;
1333
- sub.structs = c.structs;
1334
- sub.functions = c.functions;
1335
- const inner = for_init.namedChildren[0];
1336
- emitForInitInline(sub, inner);
1337
- init_str = sub.out.build().trimEnd();
1338
- if (init_str.endsWith(';')) init_str = init_str.slice(0, -1);
1339
- }
1340
-
1341
- const cond_str = cond_expr !== null ? compileExpression(c, cond_expr).code : '';
1342
-
1343
- let update_str = '';
1344
- if (for_update !== null) {
1345
- const inner = for_update.namedChildren[0];
1346
- update_str = emitForUpdateInline(c, inner);
1347
- }
1348
-
1349
- c.out.add(`for (${init_str}; ${cond_str}; ${update_str}) {`);
1350
- c.out.indent();
1351
- // `continue` inside this loop targets this loop, not an outer `loop`'s continuing block
1352
- const saved_continue_label = c.continue_label;
1353
- c.continue_label = null;
1354
- emitCompoundStatementBody(c, body);
1355
- c.continue_label = saved_continue_label;
1356
- c.out.dedent();
1357
- c.out.add('}');
1358
-
1359
- c.scope = c.scope.parent;
1360
- }
1361
-
1362
- /**
1363
- * Emit a `variable_or_value_statement` inline (as a single line with no trailing newline structure).
1364
- * Used by `for(init; ...)`.
1365
- */
1366
- function emitForInitInline(c, node) {
1367
- if (node.type === 'variable_or_value_statement') {
1368
- const var_decl = node.namedChildren[0] && node.namedChildren[0].type === 'variable_decl'
1369
- ? node.namedChildren[0]
1370
- : null;
1371
- const opt_ident = namedChildByType(var_decl !== null ? var_decl : node, 'optionally_typed_ident');
1372
- const expr_node = namedChildByType(node, 'expression');
1373
- const ident = namedChildByType(opt_ident, 'ident');
1374
- const type_spec = namedChildByType(opt_ident, 'type_specifier');
1375
- const name = ident.text;
1376
- const init = expr_node !== null ? compileExpression(c, expr_node) : null;
1377
- let type = type_spec !== null ? parseTypeSpecifier(type_spec) : T_UNKNOWN;
1378
- if (type.kind === 'unknown' && init !== null) {
1379
- // `for (var i = 0; ...)`: a bare integer literal concretises to i32, as in a `let`
1380
- type = init.abstract_int === true ? T_I32 : init.type;
1381
- }
1382
- c.scope.declare(name, type);
1383
- const value = init !== null ? init.code : defaultValueForType(type);
1384
- // `var i = …` (mutable, common in `for (var i = 0; ...; i = i + 1)`) → JS `let`.
1385
- // `let i = …` / `const i = …` (immutable) → JS `const`.
1386
- const kind = var_decl !== null ? 'let' : 'const';
1387
- c.out.add(`${kind} ${name} = ${value};`);
1388
- return;
1389
- }
1390
- if (node.type === 'variable_updating_statement') {
1391
- emitVariableUpdatingStatement(c, node);
1392
- return;
1393
- }
1394
- if (node.type === 'func_call_statement') {
1395
- emitFunctionCallStatement(c, node);
1396
- return;
1397
- }
1398
- }
1399
-
1400
- /**
1401
- * @returns {string} JS update expression (no semicolon).
1402
- */
1403
- function emitForUpdateInline(c, node) {
1404
- if (node.type === 'variable_updating_statement') {
1405
- const inner = node.namedChildren[0];
1406
- if (inner.type === 'assignment_statement') {
1407
- const lhs = namedChildByType(inner, 'lhs_expression');
1408
- const expr = namedChildByType(inner, 'expression');
1409
- const op_text = textBetween(inner, lhs, expr).trim();
1410
- const lhs_compiled = compileLhs(c, lhs);
1411
- const rhs_compiled = compileExpression(c, expr);
1412
- if (op_text === '=' || op_text === '') {
1413
- if (lhs_compiled.through_pointer === true) {
1414
- return `${lhs_compiled.code} = wgsl.store_ptr(${lhs_compiled.code}, ${rhs_compiled.code})`;
1415
- }
1416
- return `${lhs_compiled.code} = ${rhs_compiled.code}`;
1417
- }
1418
- const arith = { '+=': 'add', '-=': 'sub', '*=': 'mul', '/=': 'div', '%=': 'rem' };
1419
- if (arith.hasOwnProperty(op_text)) {
1420
- if (lhs_compiled.through_pointer === true) {
1421
- return `${lhs_compiled.code} = wgsl.store_ptr(${lhs_compiled.code}, wgsl.${arith[op_text]}(${lhs_compiled.code}, ${rhs_compiled.code}))`;
1422
- }
1423
- return `${lhs_compiled.code} = wgsl.${arith[op_text]}(${lhs_compiled.code}, ${rhs_compiled.code})`;
1424
- }
1425
- return `${lhs_compiled.code} ${op_text} ${rhs_compiled.code}`;
1426
- }
1427
- if (inner.type === 'increment_statement') {
1428
- const lhs = namedChildByType(inner, 'lhs_expression');
1429
- const lhs_compiled = compileLhs(c, lhs);
1430
- return `${lhs_compiled.code} = wgsl.add(${lhs_compiled.code}, 1)`;
1431
- }
1432
- if (inner.type === 'decrement_statement') {
1433
- const lhs = namedChildByType(inner, 'lhs_expression');
1434
- const lhs_compiled = compileLhs(c, lhs);
1435
- return `${lhs_compiled.code} = wgsl.sub(${lhs_compiled.code}, 1)`;
1436
- }
1437
- }
1438
- return '';
1439
- }
1440
-
1441
- function emitWhileStatement(c, node) {
1442
- const cond = namedChildByType(node, 'expression');
1443
- const body = namedChildByType(node, 'compound_statement');
1444
- const cc = compileExpression(c, cond);
1445
- c.out.add(`while (${cc.code}) {`);
1446
- c.out.indent();
1447
- c.scope = c.scope.push();
1448
- // `continue` inside this loop targets this loop, not an outer `loop`'s continuing block
1449
- const saved_continue_label = c.continue_label;
1450
- c.continue_label = null;
1451
- emitCompoundStatementBody(c, body);
1452
- c.continue_label = saved_continue_label;
1453
- c.scope = c.scope.parent;
1454
- c.out.dedent();
1455
- c.out.add('}');
1456
- }
1457
-
1458
- function emitLoopStatement(c, node) {
1459
- // NOTE: the grammar puts the loop's `statement` children and the optional
1460
- // `continuing_statement` directly on the `loop_statement` node (no
1461
- // `compound_statement` wrapper); emitCompoundStatementBody visits only the
1462
- // `statement` children, which is exactly the loop body.
1463
- const body = node;
1464
- const continuing = namedChildByType(node, 'continuing_statement');
1465
-
1466
- const saved_continue_label = c.continue_label;
1467
-
1468
- c.out.add('while (true) {');
1469
- c.out.indent();
1470
- c.scope = c.scope.push();
1471
-
1472
- if (continuing === null) {
1473
-
1474
- // no continuing block: JS `continue` already has the right semantics
1475
- c.continue_label = null;
1476
- emitCompoundStatementBody(c, body);
1477
-
1478
- } else {
1479
-
1480
- // WGSL `continue` transfers control INTO the `continuing` block. Emit the loop
1481
- // body inside a labeled block: `continue` becomes `break <label>`, which lands on
1482
- // the continuing code that follows the block (still inside the `while`).
1483
- const label = `loop_body_${c.loop_label_counter++}`;
1484
- c.continue_label = label;
1485
-
1486
- c.out.add(`${label}: {`);
1487
- c.out.indent();
1488
- emitCompoundStatementBody(c, body);
1489
- c.out.dedent();
1490
- c.out.add('}');
1491
-
1492
- c.continue_label = null;
1493
-
1494
- const cont_body = namedChildByType(continuing, 'continuing_compound_statement');
1495
- if (cont_body !== null) {
1496
- emitCompoundStatementBody(c, cont_body);
1497
-
1498
- // `break if expr;` — only legal as the trailing statement of a continuing block.
1499
- // It is a direct named child of the continuing compound (not wrapped in `statement`),
1500
- // so emitCompoundStatementBody does not visit it.
1501
- const break_if = namedChildByType(cont_body, 'break_if_statement');
1502
- if (break_if !== null) {
1503
- const break_expr = namedChildByType(break_if, 'expression');
1504
- const bc = compileExpression(c, break_expr);
1505
- c.out.add(`if (${bc.code}) { break; }`);
1506
- }
1507
- }
1508
-
1509
- }
1510
-
1511
- c.continue_label = saved_continue_label;
1512
- c.scope = c.scope.parent;
1513
- c.out.dedent();
1514
- c.out.add('}');
1515
- }
1516
-
1517
- /**
1518
- * Emit a WGSL `switch`.
1519
- *
1520
- * Grammar (tree-sitter-wgsl): `switch_statement { expression, switch_body { switch_clause* } }`,
1521
- * where each `switch_clause` wraps either a `case_clause { case_selectors { case_selector+ },
1522
- * compound_statement }` or a `default_alone_clause { compound_statement }`. A `case_selector` holds
1523
- * either an `expression` (a case value) or the `default` keyword.
1524
- *
1525
- * WGSL switch has no fall-through — each selected clause runs its body and stops — so we terminate
1526
- * every clause body with `break;`. Multiple selectors on one clause become stacked JS `case` labels
1527
- * over a shared body.
1528
- */
1529
- function emitSwitchStatement(c, node) {
1530
- const expr = namedChildByType(node, 'expression');
1531
- const ec = compileExpression(c, expr);
1532
- c.out.add(`switch (${ec.code}) {`);
1533
- c.out.indent();
1534
-
1535
- const body = namedChildByType(node, 'switch_body');
1536
- if (body) {
1537
- for (const clause of namedChildrenByType(body, 'switch_clause')) {
1538
- const case_clause = namedChildByType(clause, 'case_clause');
1539
- const default_clause = namedChildByType(clause, 'default_alone_clause');
1540
- const inner = case_clause ?? default_clause;
1541
- if (!inner) {
1542
- continue;
1543
- }
1544
-
1545
- if (case_clause) {
1546
- const case_selectors = namedChildByType(case_clause, 'case_selectors');
1547
- if (case_selectors) {
1548
- for (const sel of namedChildrenByType(case_selectors, 'case_selector')) {
1549
- const sel_expr = namedChildByType(sel, 'expression');
1550
- if (sel_expr) {
1551
- c.out.add(`case ${compileExpression(c, sel_expr).code}:`);
1552
- } else {
1553
- // a bare `default` used within a case_selectors list
1554
- c.out.add('default:');
1555
- }
1556
- }
1557
- }
1558
- } else {
1559
- c.out.add('default:');
1560
- }
1561
-
1562
- // Wrap each clause body in its own JS block. WGSL case clauses are independent scopes,
1563
- // but JS switch clauses share the switch's block scope — without the braces, `let`
1564
- // temporaries declared in two clauses collide ("Identifier already declared").
1565
- const case_body = namedChildByType(inner, 'compound_statement');
1566
- c.out.add('{');
1567
- c.out.indent();
1568
- c.scope = c.scope.push();
1569
- if (case_body) {
1570
- emitCompoundStatementBody(c, case_body);
1571
- }
1572
- c.out.add('break;');
1573
- c.scope = c.scope.parent;
1574
- c.out.dedent();
1575
- c.out.add('}');
1576
- }
1577
- }
1578
-
1579
- c.out.dedent();
1580
- c.out.add('}');
1581
- }
1582
-
1583
- function emitFunctionCallStatement(c, node) {
1584
- const call_phrase = namedChildByType(node, 'call_phrase');
1585
- const r = compileCallPhraseTyped(c, call_phrase);
1586
- c.out.add(`${r.code};`);
1587
- }
1588
-
1589
- // =========================================================================
1590
- // Expressions
1591
- // =========================================================================
1592
-
1593
- /**
1594
- * Compile an expression node (any wrapper or specific kind).
1595
- * @param {Compiler} c
1596
- * @param {Node} node
1597
- * @returns {{ code: string, type: WgslType }}
1598
- */
1599
- function compileExpression(c, node) {
1600
- const u = unwrapExpression(node);
1601
-
1602
- // Binary operations
1603
- switch (u.type) {
1604
- case 'expression':
1605
- // tree-sitter-wgsl can leave `&&` / `||` directly under an `expression` node — i.e.
1606
- // the operator wraps two operands without a more specific short_circuit_*_expression
1607
- // wrapper around it. With 2 named children the unnamed operator sits between them.
1608
- return compileBinaryExpression(c, u, '__shortcircuit_unused__', 'raw');
1609
- case 'relational_expression':
1610
- return compileBinaryExpression(c, u, 'relational_operator', 'raw');
1611
- case 'shift_expression':
1612
- return compileBinaryExpression(c, u, 'shift_operator', 'raw');
1613
- case 'additive_expression':
1614
- return compileBinaryExpression(c, u, 'additive_operator', 'arith');
1615
- case 'multiplicative_expression':
1616
- return compileBinaryExpression(c, u, 'multiplicative_operator', 'arith');
1617
- case 'short_circuit_and_expression':
1618
- case 'short_circuit_or_expression':
1619
- return compileBinaryExpression(c, u, '__shortcircuit_unused__', 'raw');
1620
- case 'bitwise_expression':
1621
- // Top-level WGSL `^` / `&` / `|` operator. The operator is an unnamed token between
1622
- // the two named operands; compileBinaryExpression's 2-named-children path picks it up.
1623
- return compileBinaryExpression(c, u, '__bitwise_unused__', 'raw');
1624
- case 'binary_and_expression':
1625
- case 'binary_or_expression':
1626
- case 'binary_xor_expression':
1627
- // Inner chain nodes from the WGSL grammar (e.g. `a ^ b ^ c` nests as
1628
- // `binary_xor_expression(binary_xor_expression(a, b), c)`). When 2 named children
1629
- // appear, the unnamed operator sits between them; the 1-child case is a passthrough.
1630
- return compileBinaryExpression(c, u, '__bitwise_unused__', 'raw');
1631
- }
1632
-
1633
- // Unary
1634
- if (u.type === 'unary_expression') {
1635
- return compileUnaryExpression(c, u);
1636
- }
1637
-
1638
- // Singular (primary + chained component access)
1639
- if (u.type === 'singular_expression') {
1640
- return compileSingularExpression(c, u);
1641
- }
1642
-
1643
- // Primary subkinds
1644
- if (u.type === 'literal' || u.type === 'int_literal' || u.type === 'float_literal' || u.type === 'bool_literal') {
1645
- // A bare integer literal is WGSL's AbstractInt. Its concrete type comes from context this
1646
- // compiler does not track, so the type stays unknown, but operator selection still needs
1647
- // to know it is an integer: see integerDivision().
1648
- return { code: literalToJs(u.text), type: literalType(u.text), abstract_int: isBareIntLiteral(u.text) };
1649
- }
1650
- if (u.type === 'paren_expression') {
1651
- const inner = namedChildByType(u, 'expression');
1652
- const e = compileExpression(c, inner);
1653
- return { code: `(${e.code})`, type: e.type, abstract_int: e.abstract_int };
1654
- }
1655
- if (u.type === 'call_expression') {
1656
- const call_phrase = namedChildByType(u, 'call_phrase');
1657
- return compileCallPhraseTyped(c, call_phrase);
1658
- }
1659
- if (u.type === 'template_elaborated_ident') {
1660
- const ident = namedChildByType(u, 'ident');
1661
- const name = ident !== null ? ident.text : u.text;
1662
- return { code: name, type: c.scope.lookup(name) };
1663
- }
1664
- if (u.type === 'ident') {
1665
- return { code: u.text, type: c.scope.lookup(u.text) };
1666
- }
1667
-
1668
- c.error(u, `unsupported expression: ${u.type}`);
1669
- }
1670
-
1671
- /**
1672
- * Compile a binary expression node. Two grammar shapes are supported:
1673
- * - 3 named children where the middle child has type `op_type` — used for additive / multiplicative
1674
- * where the operator is an explicit named node (`additive_operator`, `multiplicative_operator`).
1675
- * - 2 named children with an unnamed operator token between them — used for relational / shift,
1676
- * where the operator (e.g. `<`, `>=`, `<<`) is a raw token.
1677
- *
1678
- * Mode:
1679
- * - `'arith'` → use `wgsl.add/sub/mul/div/rem` (handles vectors)
1680
- * - `'raw'` → emit raw JS operator
1681
- */
1682
- function compileBinaryExpression(c, node, op_type, mode) {
1683
- const named = node.namedChildren;
1684
- if (named.length === 1) {
1685
- return compileExpression(c, named[0]);
1686
- }
1687
-
1688
- let op_text = null;
1689
- let left_node;
1690
- let right_node;
1691
-
1692
- if (named.length === 3 && named[1].type === op_type) {
1693
- op_text = named[1].text;
1694
- left_node = named[0];
1695
- right_node = named[2];
1696
- } else if (named.length === 2) {
1697
- left_node = named[0];
1698
- right_node = named[1];
1699
- // tree-sitter-web doesn't surface unnamed children in `node.children`. Extract the
1700
- // operator by slicing the original text using the operands' source positions.
1701
- op_text = textBetween(node, left_node, right_node).trim();
1702
- } else {
1703
- return { code: node.text, type: T_UNKNOWN };
1704
- }
1705
-
1706
- const left = compileExpression(c, left_node);
1707
- const right = compileExpression(c, right_node);
1708
-
1709
- if (mode === 'arith') {
1710
- const helper = ARITHMETIC_OP[op_text];
1711
- if (helper !== undefined) {
1712
- // `*` on matrix/vector operands has WGSL-specific algebra (dot-products and
1713
- // accumulation) that the element-wise `wgsl.mul` doesn't capture. Route to a
1714
- // dedicated `mNxR_multiply_*` helper when at least one side is a matrix.
1715
- if (op_text === '*') {
1716
- const dispatched = dispatchMatrixMul(left, right);
1717
- if (dispatched !== null) return dispatched;
1718
- }
1719
- // WGSL `/` on integer types is truncated integer division. Route through the
1720
- // integer-truncating helper when WGSL would type the division as integer;
1721
- // otherwise use float div.
1722
- let actual_helper = helper;
1723
- if (op_text === '/' && integerDivision(left, right)) {
1724
- actual_helper = 'idiv';
1725
- }
1726
- // WGSL `+` / `-` / `*` on integer types wrap at 32 bits. JS numbers don't, and the bits
1727
- // an overflowing f64 drops are the low ones — which silently ruins hashes and PRNGs
1728
- // (see the wrapping helpers in WGSLLanguageCore.js). Route to the wrapping variant only
1729
- // when the result type is *known* to be an integer, so anything untyped or float keeps
1730
- // the plain helper.
1731
- const arith_type = inferBinaryArithResultType(left.type, right.type);
1732
- const wrapping = INTEGER_WRAPPING_OP[op_text];
1733
- if (wrapping !== undefined && isIntegerType(arith_type)) {
1734
- actual_helper = `${wrapping}_${integerScalarName(arith_type)}`;
1735
- }
1736
- return {
1737
- code: `wgsl.${actual_helper}(${left.code}, ${right.code})`,
1738
- type: arith_type,
1739
- // arithmetic on two AbstractInts is still AbstractInt: `(1 + 2) / 2` is 1
1740
- abstract_int: left.abstract_int === true && right.abstract_int === true,
1741
- };
1742
- }
1743
- }
1744
-
1745
- // Bitwise (`&` / `|` / `^`) and shift (`<<` / `>>`) operators. Routed through element-wise
1746
- // helpers for vec/mat operands (JS raw operators coerce typed arrays to NaN), for bool
1747
- // operands (raw JS yields 0/1 where WGSL yields a bool), AND for `>>` on u32 scalars — JS's
1748
- // signed `>>` sign-extends, but WGSL u32 shift is logical.
1749
- const bitwise_helper = BITWISE_HELPER[op_text];
1750
- if (bitwise_helper !== undefined) {
1751
- if (isContainerType(left.type) || isContainerType(right.type)
1752
- || isScalarBool(left.type) || isScalarBool(right.type)) {
1753
- return {
1754
- code: `wgsl.${bitwise_helper}(${left.code}, ${right.code})`,
1755
- type: inferRawBinaryResultType(left.type, right.type, op_text),
1756
- };
1757
- }
1758
- // For `>>` specifically: any u32-typed scalar operand must use the unsigned shift helper.
1759
- if (op_text === '>>' && (isScalarUnsigned(left.type) || isScalarUnsigned(right.type))) {
1760
- return {
1761
- code: `wgsl.shr(${left.code}, ${right.code})`,
1762
- type: inferRawBinaryResultType(left.type, right.type, op_text),
1763
- };
1764
- }
1765
- }
1766
-
1767
- // Comparison operators. JS's raw `==` etc. compare TypedArrays by reference; for WGSL
1768
- // `vec<T>` operands we need element-wise comparison returning a `vec<bool>`.
1769
- const cmp_helper = COMPARISON_HELPER[op_text];
1770
- if (cmp_helper !== undefined && (isContainerType(left.type) || isContainerType(right.type))) {
1771
- return {
1772
- code: `wgsl.${cmp_helper}(${left.code}, ${right.code})`,
1773
- type: inferRawBinaryResultType(left.type, right.type, op_text),
1774
- };
1775
- }
1776
-
1777
- return {
1778
- code: `${left.code} ${op_text} ${right.code}`,
1779
- type: inferRawBinaryResultType(left.type, right.type, op_text),
1780
- };
1781
- }
1782
-
1783
- /** Map WGSL bitwise/shift operators to language-core element-wise helper names. */
1784
- const BITWISE_HELPER = {
1785
- '&': 'bit_and',
1786
- '|': 'bit_or',
1787
- '^': 'bit_xor',
1788
- '<<': 'shl',
1789
- '>>': 'shr',
1790
- };
1791
-
1792
- /** Map WGSL comparison operators to language-core element-wise helper names. */
1793
- const COMPARISON_HELPER = {
1794
- '==': 'eq',
1795
- '!=': 'ne',
1796
- '<': 'lt',
1797
- '>': 'gt',
1798
- '<=': 'le',
1799
- '>=': 'ge',
1800
- };
1801
-
1802
- /** True if `t` is a vector or matrix — operand types that need element-wise dispatch. */
1803
- function isContainerType(t) {
1804
- return t && (t.kind === 'vec' || t.kind === 'mat');
1805
- }
1806
-
1807
- /** True if `t` is a u32 scalar — needed to route `>>` through the unsigned-shift helper. */
1808
- function isScalarUnsigned(t) {
1809
- return t && t.kind === 'primitive' && t.name === 'u32';
1810
- }
1811
-
1812
- /** True if `t` is a bool scalar — WGSL `&` / `|` / `^` on bools are logical and stay bool. */
1813
- function isScalarBool(t) {
1814
- return t && t.kind === 'primitive' && t.name === 'bool';
1815
- }
1816
-
1817
- /** The scalar name (`u32` / `i32`) of an integer type, for picking a wrapping arithmetic helper. */
1818
- function integerScalarName(t) {
1819
- if (t.kind === 'primitive') return t.name;
1820
- return t.scalar;
1821
- }
1822
-
1823
- /** True if `t` is an integer type (scalar or vec/mat of i32/u32). */
1824
- function isIntegerType(t) {
1825
- if (!t) return false;
1826
- if (t.kind === 'primitive') return t.name === 'i32' || t.name === 'u32';
1827
- if (t.kind === 'vec' || t.kind === 'mat') return t.scalar === 'i32' || t.scalar === 'u32';
1828
- return false;
1829
- }
1830
-
1831
- /** True if the literal's spelling is a bare integer: no suffix, no fraction, no exponent. */
1832
- function isBareIntLiteral(text) {
1833
- return /^(0[xX][0-9a-fA-F]+|[0-9]+)$/.test(text.trim());
1834
- }
1835
-
1836
- /**
1837
- * True if WGSL evaluates `left / right` as integer division. Both operands integer-typed is the
1838
- * obvious case. A bare literal is AbstractInt and takes the other operand's integer type, so
1839
- * `index / 3` truncates; two bare literals divide as AbstractInt, so `7 / 2` is 3 even where an
1840
- * f32 is expected. Negation and parentheses keep a literal abstract: `index / -3` and
1841
- * `index / (3)` truncate too.
1842
- */
1843
- function integerDivision(left, right) {
1844
- const isInt = (operand) => isIntegerType(operand.type) || operand.abstract_int === true;
1845
- return isInt(left) && isInt(right);
1846
- }
1847
-
1848
- /**
1849
- * Dispatch a WGSL `*` expression to the appropriate matrix/vector helper in the language
1850
- * core when at least one operand is a matrix. Returns `null` to indicate "fall through to the
1851
- * element-wise multiply" — used for scalar×scalar, vec×scalar, vec×vec (Hadamard product),
1852
- * matrix×scalar, etc., which `wgsl.mul` already handles correctly.
1853
- *
1854
- * Naming includes the scalar type suffix (`f` / `i` / `u` / `h`), e.g.
1855
- * `m4x4f_multiply_v4f`, `v3f_multiply_m3x3f`, `m4x4f_multiply_m4x4f`. Unsupported
1856
- * shapes (e.g. mat3x4 × vec3) produce a runtime `TypeError: wgsl.<name> is not a function`
1857
- * — adding support is a single new function in WGSLLanguageCore.js.
1858
- *
1859
- * @param {{ code: string, type: WgslType }} left
1860
- * @param {{ code: string, type: WgslType }} right
1861
- * @returns {{ code: string, type: WgslType } | null}
1862
- */
1863
- function dispatchMatrixMul(left, right) {
1864
- const lt = left.type;
1865
- const rt = right.type;
1866
- const isVec = (t) => t && t.kind === 'vec';
1867
- const isMat = (t) => t && t.kind === 'mat';
1868
-
1869
- // mat × mat → mat(b.cols, a.rows). Multiplication is defined only when a.cols == b.rows.
1870
- if (isMat(lt) && isMat(rt)) {
1871
- const lh = `m${lt.cols}x${lt.rows}${scalarTypeSuffix(lt.scalar)}`;
1872
- const rh = `m${rt.cols}x${rt.rows}${scalarTypeSuffix(rt.scalar)}`;
1873
- return {
1874
- code: `wgsl.${lh}_multiply_${rh}(${left.code}, ${right.code})`,
1875
- type: { kind: 'mat', cols: rt.cols, rows: lt.rows, scalar: lt.scalar },
1876
- };
1877
- }
1878
-
1879
- // mat × vec → vec(rows). Vec must have length == cols.
1880
- if (isMat(lt) && isVec(rt)) {
1881
- const lh = `m${lt.cols}x${lt.rows}${scalarTypeSuffix(lt.scalar)}`;
1882
- const rh = `v${rt.size}${scalarTypeSuffix(rt.scalar)}`;
1883
- return {
1884
- code: `wgsl.${lh}_multiply_${rh}(${left.code}, ${right.code})`,
1885
- type: { kind: 'vec', size: lt.rows, scalar: lt.scalar },
1886
- };
1887
- }
1888
-
1889
- // vec × mat → vec(cols). Vec acts as a row vector; vec.length must equal rows.
1890
- if (isVec(lt) && isMat(rt)) {
1891
- const lh = `v${lt.size}${scalarTypeSuffix(lt.scalar)}`;
1892
- const rh = `m${rt.cols}x${rt.rows}${scalarTypeSuffix(rt.scalar)}`;
1893
- return {
1894
- code: `wgsl.${lh}_multiply_${rh}(${left.code}, ${right.code})`,
1895
- type: { kind: 'vec', size: rt.cols, scalar: rt.scalar },
1896
- };
1897
- }
1898
-
1899
- return null;
1900
- }
1901
-
1902
- /** Scalar type → suffix character used in matrix/vector helper names: f / i / u / h. */
1903
- function scalarTypeSuffix(scalar) {
1904
- return { f32: 'f', i32: 'i', u32: 'u', f16: 'h' }[scalar] || 'f';
1905
- }
1906
-
1907
- /**
1908
- * Pick the result type of an element-wise arithmetic op given the operand types.
1909
- * Vec wins over scalar; matrix wins over scalar; scalar otherwise.
1910
- */
1911
- function inferBinaryArithResultType(a, b) {
1912
- const isVec = (t) => t && t.kind === 'vec';
1913
- const isMat = (t) => t && t.kind === 'mat';
1914
- const isPrim = (t) => t && t.kind === 'primitive';
1915
-
1916
- if (isVec(a)) return a;
1917
- if (isVec(b)) return b;
1918
- if (isMat(a)) return a;
1919
- if (isMat(b)) return b;
1920
- if (isPrim(a)) return a;
1921
- if (isPrim(b)) return b;
1922
- return T_UNKNOWN;
1923
- }
1924
-
1925
- /**
1926
- * Pick the result type of a non-arithmetic binary op (comparison / logical / bitwise / shift).
1927
- * Comparisons return bool; bitwise and shift preserve the leftmost known integer operand type.
1928
- */
1929
- function inferRawBinaryResultType(a, b, op) {
1930
- const COMPARISON = new Set(['==', '!=', '<', '>', '<=', '>=']);
1931
- const LOGICAL = new Set(['&&', '||']);
1932
- if (COMPARISON.has(op) || LOGICAL.has(op)) {
1933
- return { kind: 'primitive', name: 'bool' };
1934
- }
1935
- // Bitwise / shift: propagate the first known integer-ish operand type. This lets `bitcast`
1936
- // and other downstream consumers see u32/i32 even when the literal on one side is untyped.
1937
- if (a && a.kind === 'primitive') return a;
1938
- if (b && b.kind === 'primitive') return b;
1939
- if (a && a.kind === 'vec') return a;
1940
- if (b && b.kind === 'vec') return b;
1941
- return T_UNKNOWN;
1942
- }
1943
-
1944
- function compileUnaryExpression(c, node) {
1945
- const named = node.namedChildren;
1946
- const prefix = textBeforeFirstNamed(node).trim();
1947
-
1948
- if (prefix === '') {
1949
- return compileExpression(c, named[0]);
1950
- }
1951
-
1952
- const operand = compileExpression(c, named[named.length - 1]);
1953
-
1954
- if (prefix === '-') return { code: `wgsl.neg(${operand.code})`, type: operand.type, abstract_int: operand.abstract_int };
1955
- if (prefix === '!') return { code: `!${operand.code}`, type: operand.type };
1956
- if (prefix === '~') return { code: `wgsl.not(${operand.code})`, type: operand.type };
1957
- if (prefix === '*' || prefix === '&') return { code: operand.code, type: operand.type };
1958
-
1959
- return { code: `${prefix}${operand.code}`, type: operand.type };
1960
- }
1961
-
1962
- function compileSingularExpression(c, node) {
1963
- const named = node.namedChildren;
1964
- const head = named[0];
1965
- const head_result = head.type === 'primary_expression'
1966
- ? compileExpression(c, unwrapExpression(head))
1967
- : compileExpression(c, head);
1968
-
1969
- let code = head_result.code;
1970
- let type = head_result.type;
1971
-
1972
- for (let i = 1; i < named.length; i++) {
1973
- const spec = named[i];
1974
- if (spec.type !== 'component_or_swizzle_specifier') break;
1975
- const next = applyAccessSpecifier(c, spec, code, type);
1976
- code = next.code;
1977
- type = next.type;
1978
- }
1979
-
1980
- // a bare literal reached through a singular expression is still AbstractInt; anything with an
1981
- // access specifier on it is not a literal
1982
- return { code, type, abstract_int: named.length === 1 ? head_result.abstract_int : undefined };
1983
- }
1984
-
1985
- /**
1986
- * Apply a `.member`, `.swizzle`, or `[index]` access to an expression that has already been
1987
- * compiled to `lhs_code` of type `lhs_type`.
1988
- */
1989
- function applyAccessSpecifier(c, node, lhs_code, lhs_type) {
1990
- // tree-sitter-wgsl groups chained access like `[i].x` (or `.foo[i]`) as a SINGLE outer
1991
- // `component_or_swizzle_specifier` whose first named child is the immediate access (an
1992
- // `expression` for `[]` or a `member_ident` for `.field`) and whose second named child
1993
- // is a NESTED `component_or_swizzle_specifier` for the rest of the chain. We apply the
1994
- // immediate access first, then recurse into any nested specifier.
1995
- let code = lhs_code;
1996
- let type = lhs_type;
1997
-
1998
- const member_ident = namedChildByType(node, 'member_ident');
1999
- if (member_ident !== null) {
2000
- const r = applyMemberAccess(c, member_ident.text, code, type);
2001
- code = r.code;
2002
- type = r.type;
2003
- } else {
2004
- const expr = namedChildByType(node, 'expression');
2005
- if (expr !== null) {
2006
- const e = compileExpression(c, expr);
2007
- // Matrices are stored as flat column-major typed arrays, so the bare `m[i]`
2008
- // would index a scalar — route through `wgsl.mat_col` to get the column as a vec.
2009
- if (type && type.kind === 'mat') {
2010
- code = `wgsl.mat_col(${code}, ${e.code}, ${type.rows})`;
2011
- type = { kind: 'vec', size: type.rows, scalar: type.scalar };
2012
- } else {
2013
- code = `${code}[${e.code}]`;
2014
- if (type && type.kind === 'array') type = type.element;
2015
- else if (type && type.kind === 'vec') type = { kind: 'primitive', name: type.scalar };
2016
- else type = T_UNKNOWN;
2017
- }
2018
- }
2019
- }
2020
-
2021
- const nested = namedChildByType(node, 'component_or_swizzle_specifier');
2022
- if (nested !== null) {
2023
- const r = applyAccessSpecifier(c, nested, code, type);
2024
- code = r.code;
2025
- type = r.type;
2026
- }
2027
-
2028
- return { code, type };
2029
- }
2030
-
2031
- /** Apply a `.field` / `.swizzle` access to an already-compiled expression of `lhs_type`. */
2032
- function applyMemberAccess(c, name, lhs_code, lhs_type) {
2033
- if (lhs_type !== null && lhs_type !== undefined && lhs_type.kind === 'vec' && isSwizzlePattern(name)) {
2034
- if (name.length === 1) {
2035
- return {
2036
- code: `${lhs_code}[${SWIZZLE_INDEX[name]}]`,
2037
- type: { kind: 'primitive', name: lhs_type.scalar },
2038
- };
2039
- }
2040
- const new_size = name.length;
2041
- const ctor = vecAliasName(new_size, lhs_type.scalar);
2042
- const elements = Array.from(name).map(ch => `${lhs_code}[${SWIZZLE_INDEX[ch]}]`);
2043
- return {
2044
- code: `wgsl.${ctor}(${elements.join(', ')})`,
2045
- type: { kind: 'vec', size: new_size, scalar: lhs_type.scalar },
2046
- };
2047
- }
2048
- if (lhs_type !== null && lhs_type !== undefined && lhs_type.kind === 'struct') {
2049
- const struct_info = c.structs.get(lhs_type.name);
2050
- if (struct_info !== undefined) {
2051
- const field = struct_info.fields.find(f => f.name === name);
2052
- if (field !== undefined) {
2053
- return { code: `${lhs_code}.${name}`, type: field.type };
2054
- }
2055
- }
2056
- }
2057
- return { code: `${lhs_code}.${name}`, type: T_UNKNOWN };
2058
- }
2059
-
2060
- function isSwizzlePattern(name) {
2061
- if (name.length === 0 || name.length > 4) return false;
2062
- for (const ch of name) {
2063
- if (!SWIZZLE_LETTERS.has(ch)) return false;
2064
- }
2065
- return true;
2066
- }
2067
-
2068
- /**
2069
- * Compile a `call_phrase` and return both the JS code and the inferred result type.
2070
- *
2071
- * Special cases:
2072
- * - `vec3<f32>(a, b, c)` → `wgsl.vec3f(a, b, c)` (vec result)
2073
- * - `f32(x)` → `wgsl.f32(x)` (scalar result)
2074
- * - WGSL builtin (mix, clamp, dot, length, ...) → `wgsl.<name>(...)` (best-effort type)
2075
- * - User function → `name(...)` (uses declared return type)
2076
- *
2077
- * @returns {{ code: string, type: WgslType }}
2078
- */
2079
- function compileCallPhraseTyped(c, node) {
2080
- const ident_node = namedChildByType(node, 'template_elaborated_ident');
2081
- const arg_list = namedChildByType(node, 'argument_expression_list');
2082
-
2083
- const ident_inner = namedChildByType(ident_node, 'ident');
2084
- const callee_name = ident_inner.text;
2085
- const template = namedChildByType(ident_node, 'template_list');
2086
-
2087
- /** @type {Array<{ code: string, type: WgslType }>} */
2088
- const arg_results = [];
2089
- if (arg_list !== null) {
2090
- const comma_list = namedChildByType(arg_list, 'expression_comma_list');
2091
- if (comma_list !== null) {
2092
- for (const arg of namedChildrenByType(comma_list, 'expression')) {
2093
- arg_results.push(compileExpression(c, arg));
2094
- }
2095
- }
2096
- }
2097
- const args = arg_results.map(a => a.code);
2098
-
2099
- // 1) Vec aliases: vec3f, vec4i, vec2h, etc.
2100
- if (VECTOR_ALIASES.hasOwnProperty(callee_name)) {
2101
- const a = VECTOR_ALIASES[callee_name];
2102
- return {
2103
- code: `wgsl.${callee_name}(${args.join(', ')})`,
2104
- type: { kind: 'vec', size: a.size, scalar: a.scalar },
2105
- };
2106
- }
2107
- // 2) Templated vec: vec3<f32>(...).
2108
- if (callee_name === 'vec2' || callee_name === 'vec3' || callee_name === 'vec4') {
2109
- const size = parseInt(callee_name.slice(3));
2110
- let scalar;
2111
- if (template !== null) {
2112
- const targs = extractTemplateArgs(template);
2113
- if (targs.length > 0) scalar = targs[0];
2114
- }
2115
- if (scalar === undefined) {
2116
- // No explicit template — infer the component type from the arguments, mirroring
2117
- // WGSL's overload resolution. e.g. `vec4(some_u32)` is `vec4<u32>`, not `vec4<f32>`.
2118
- for (const a of arg_results) {
2119
- const t = a.type;
2120
- if (t && t.kind === 'primitive' && t.name !== 'bool') { scalar = t.name; break; }
2121
- if (t && (t.kind === 'vec' || t.kind === 'mat')) { scalar = t.scalar; break; }
2122
- }
2123
- if (scalar === undefined) scalar = 'f32';
2124
- }
2125
- return {
2126
- code: `wgsl.${vecAliasName(size, scalar)}(${args.join(', ')})`,
2127
- type: { kind: 'vec', size, scalar },
2128
- };
2129
- }
2130
- // 3) Matrix constructors.
2131
- {
2132
- const m = callee_name.match(/^mat(\d)x(\d)([ifh]?)$/);
2133
- if (m !== null) {
2134
- const cols = parseInt(m[1]);
2135
- const rows = parseInt(m[2]);
2136
- const suffix = m[3];
2137
- let scalar;
2138
- if (suffix === 'f') scalar = 'f32';
2139
- else if (suffix === 'i') scalar = 'i32';
2140
- else if (suffix === 'h') scalar = 'f16';
2141
- else if (template !== null) {
2142
- const targs = extractTemplateArgs(template);
2143
- scalar = targs[0] || 'f32';
2144
- } else {
2145
- scalar = 'f32';
2146
- }
2147
- const fn_suffix = suffix !== '' ? '' : ({ f32: 'f', i32: 'i', f16: 'h' }[scalar] || 'f');
2148
- return {
2149
- code: `wgsl.${callee_name}${fn_suffix}(${args.join(', ')})`,
2150
- type: { kind: 'mat', cols, rows, scalar },
2151
- };
2152
- }
2153
- }
2154
-
2155
- // 4) Scalar casts: f32(x), i32(x), u32(x), f16(x), bool(x).
2156
- if (PRIMITIVE_NAMES.has(callee_name)) {
2157
- return {
2158
- code: `wgsl.${callee_name}(${args.join(', ')})`,
2159
- type: { kind: 'primitive', name: callee_name },
2160
- };
2161
- }
2162
-
2163
- // 5) `bitcast<T>(x)` — JS can't tell a u32 from an f32 by value alone, so we emit the
2164
- // source type alongside the target. The compiler infers source from the argument's tracked
2165
- // type; if that's unknown the runtime falls back to a heuristic.
2166
- if (callee_name === 'bitcast') {
2167
- let target = 'f32';
2168
- if (template !== null) {
2169
- const targs = extractTemplateArgs(template);
2170
- if (targs.length > 0) target = targs[0];
2171
- }
2172
- const arg_type = arg_results[0] !== undefined ? arg_results[0].type : null;
2173
- let source = null;
2174
- if (arg_type) {
2175
- if (arg_type.kind === 'primitive') source = arg_type.name;
2176
- else if (arg_type.kind === 'vec') source = arg_type.scalar;
2177
- }
2178
- const source_arg = source !== null ? `, ${JSON.stringify(source)}` : '';
2179
- // Parse the target string: `vec3<u32>` etc. become a vec type so that downstream
2180
- // swizzle/component access compiles correctly. Bare `f32` / `u32` / `i32` stay primitive.
2181
- let resultType;
2182
- const vec_match = target.match(/^vec(\d)<([^>]+)>$/);
2183
- if (vec_match !== null) {
2184
- resultType = { kind: 'vec', size: parseInt(vec_match[1]), scalar: vec_match[2] };
2185
- } else {
2186
- resultType = { kind: 'primitive', name: target };
2187
- }
2188
- return {
2189
- code: `wgsl.bitcast(${args[0]}, ${JSON.stringify(target)}${source_arg})`,
2190
- type: resultType,
2191
- };
2192
- }
2193
-
2194
- // 6) array / array<T, N> constructor.
2195
- if (callee_name === 'array') {
2196
- return { code: `[${args.join(', ')}]`, type: T_UNKNOWN };
2197
- }
2198
-
2199
- // 7) Struct constructor.
2200
- if (c.structs.has(callee_name)) {
2201
- const info = c.structs.get(callee_name);
2202
- const parts = [`(() => { const __s__ = new ${callee_name}();`];
2203
- for (let i = 0; i < info.fields.length && i < args.length; i++) {
2204
- parts.push(`__s__.${info.fields[i].name} = ${args[i]};`);
2205
- }
2206
- parts.push(`return __s__; })()`);
2207
- return { code: parts.join(' '), type: { kind: 'struct', name: callee_name } };
2208
- }
2209
-
2210
- // 8) User-defined function.
2211
- if (c.functions.has(callee_name)) {
2212
- return {
2213
- code: `${callee_name}(${args.join(', ')})`,
2214
- type: c.functions.get(callee_name).returnType,
2215
- };
2216
- }
2217
-
2218
- // 9) WGSL builtins — best-effort type inference for common helpers.
2219
- return {
2220
- code: `wgsl.${callee_name}(${args.join(', ')})`,
2221
- type: inferBuiltinReturnType(callee_name, arg_results),
2222
- };
2223
- }
2224
-
2225
- /**
2226
- * Best-effort return type for WGSL builtins commonly used in compute shaders.
2227
- * Handles the cases needed for accurate swizzle / member-access codegen downstream.
2228
- */
2229
- function inferBuiltinReturnType(name, args) {
2230
- // Element-wise vector-preserving math: result follows the first vector argument.
2231
- const ELEMENT_WISE = new Set([
2232
- 'abs', 'sign', 'floor', 'ceil', 'round', 'trunc', 'fract', 'sqrt', 'inverseSqrt',
2233
- 'exp', 'exp2', 'log', 'log2', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan',
2234
- 'pow', 'atan2', 'min', 'max', 'step', 'clamp', 'saturate', 'mix', 'smoothstep',
2235
- 'normalize', 'reflect', 'fma',
2236
- // not math, but the same shape: the result has the type of its one argument
2237
- 'subgroupBroadcastFirst',
2238
- ]);
2239
- if (ELEMENT_WISE.has(name)) {
2240
- for (const a of args) {
2241
- if (a.type && (a.type.kind === 'vec' || a.type.kind === 'mat')) return a.type;
2242
- }
2243
- if (args[0] && args[0].type) return args[0].type;
2244
- return T_UNKNOWN;
2245
- }
2246
- if (name === 'length' || name === 'distance' || name === 'dot' || name === 'determinant') {
2247
- return { kind: 'primitive', name: 'f32' };
2248
- }
2249
- if (name === 'cross') {
2250
- return args[0] && args[0].type && args[0].type.kind === 'vec'
2251
- ? args[0].type
2252
- : { kind: 'vec', size: 3, scalar: 'f32' };
2253
- }
2254
- if (name === 'all' || name === 'any') return { kind: 'primitive', name: 'bool' };
2255
- if (name === 'select') {
2256
- if (args[0] && args[0].type) return args[0].type;
2257
- if (args[1] && args[1].type) return args[1].type;
2258
- return T_UNKNOWN;
2259
- }
2260
- if (name === 'textureLoad' || name === 'textureSampleLevel' || name === 'textureSample' || name === 'textureSampleGrad') {
2261
- return { kind: 'vec', size: 4, scalar: 'f32' };
2262
- }
2263
- // Both gathers return the four texels of a 2x2 footprint. Saying so here matters more than
2264
- // for most builtins: the shadow chunks immediately swizzle the result (`samples.wzxy`), and
2265
- // an unknown type degrades swizzle codegen downstream.
2266
- if (name === 'textureGather' || name === 'textureGatherCompare') {
2267
- return { kind: 'vec', size: 4, scalar: 'f32' };
2268
- }
2269
- if (name === 'textureDimensions') {
2270
- return { kind: 'vec', size: 2, scalar: 'u32' };
2271
- }
2272
- if (name === 'atomicLoad') return { kind: 'primitive', name: 'i32' };
2273
- if (name === 'unpack2x16unorm' || name === 'unpack2x16snorm' || name === 'unpack2x16float') {
2274
- return { kind: 'vec', size: 2, scalar: 'f32' };
2275
- }
2276
- if (name === 'unpack4x8unorm' || name === 'unpack4x8snorm') {
2277
- return { kind: 'vec', size: 4, scalar: 'f32' };
2278
- }
2279
- if (name === 'pack2x16unorm' || name === 'pack2x16snorm' || name === 'pack2x16float'
2280
- || name === 'pack4x8unorm' || name === 'pack4x8snorm') {
2281
- return { kind: 'primitive', name: 'u32' };
2282
- }
2283
- // extractBits/insertBits return the integer type (scalar or vector) of their first operand.
2284
- if (name === 'extractBits' || name === 'insertBits') {
2285
- return args[0] && args[0].type ? args[0].type : T_UNKNOWN;
2286
- }
2287
- return T_UNKNOWN;
2288
- }
2289
-
2290
- // =========================================================================
2291
- // LHS expressions (for assignments)
2292
- // =========================================================================
2293
-
2294
- function compileLhs(c, node) {
2295
- if (node.type !== 'lhs_expression') {
2296
- return compileExpression(c, node);
2297
- }
2298
-
2299
- // Pointer deref / address-of: `*lhs` / `&lhs`. The emulator models pointers as values, so
2300
- // both collapse to the operand's value. The grammar puts the `*` / `&` as an unnamed leading
2301
- // token with a nested `lhs_expression` named child.
2302
- //
2303
- // A whole-value store through a deref (`*p = v`, with nothing selected out of it) is flagged
2304
- // so {@link emitWriteStatement} writes through the reference rather than rebinding the local
2305
- // — see `wgsl.store_ptr`. A store into part of the pointee (`(*p).x`, `(*p)[i]`) already
2306
- // lands on the shared object and needs no such treatment.
2307
- const prefix = textBeforeFirstNamed(node).trim();
2308
- if (prefix === '*' || prefix === '&') {
2309
- const nested_lhs = namedChildByType(node, 'lhs_expression');
2310
- if (nested_lhs !== null) {
2311
- const inner = compileLhs(c, nested_lhs);
2312
-
2313
- const selects_part = node.namedChildren.some(
2314
- child => child.type === 'component_or_swizzle_specifier'
2315
- );
2316
-
2317
- return {
2318
- ...inner,
2319
- through_pointer: prefix === '*' && !selects_part,
2320
- };
2321
- }
2322
- }
2323
-
2324
- const core = namedChildByType(node, 'core_lhs_expression');
2325
- let code;
2326
- let type;
2327
- if (core !== null) {
2328
- const ident = namedChildByType(core, 'ident');
2329
- if (ident !== null) {
2330
- code = ident.text;
2331
- type = c.scope.lookup(ident.text);
2332
- } else {
2333
- const nested = namedChildByType(core, 'lhs_expression');
2334
- if (nested !== null) {
2335
- const r = compileLhs(c, nested);
2336
- code = `(${r.code})`;
2337
- type = r.type;
2338
- } else {
2339
- code = core.text;
2340
- type = T_UNKNOWN;
2341
- }
2342
- }
2343
- } else {
2344
- code = node.text;
2345
- type = T_UNKNOWN;
2346
- }
2347
-
2348
- for (const child of node.namedChildren) {
2349
- if (child.type === 'component_or_swizzle_specifier') {
2350
- const next = applyAccessSpecifier(c, child, code, type);
2351
- code = next.code;
2352
- type = next.type;
2353
- }
2354
- }
2355
- return { code, type };
2356
- }
1
+ import { assert } from "../../../core/assert.js";
2
+ import LineBuilder from "../../../core/codegen/LineBuilder.js";
3
+
4
+ // =========================================================================
5
+ // Type representation
6
+ // =========================================================================
7
+
8
+ /**
9
+ * @typedef {object} WgslType
10
+ * @property {'primitive' | 'vec' | 'mat' | 'array' | 'struct' | 'texture_2d' | 'sampler' | 'atomic' | 'unknown'} kind
11
+ * @property {string} [name]
12
+ * @property {number} [size]
13
+ * @property {number} [cols]
14
+ * @property {number} [rows]
15
+ * @property {string} [scalar]
16
+ * @property {WgslType} [element]
17
+ * @property {number} [count]
18
+ */
19
+
20
+ const T_UNKNOWN = Object.freeze({ kind: 'unknown' });
21
+ const T_I32 = Object.freeze({ kind: 'primitive', name: 'i32' });
22
+
23
+ const VECTOR_ALIASES = {
24
+ vec2i: { size: 2, scalar: 'i32' },
25
+ vec3i: { size: 3, scalar: 'i32' },
26
+ vec4i: { size: 4, scalar: 'i32' },
27
+ vec2u: { size: 2, scalar: 'u32' },
28
+ vec3u: { size: 3, scalar: 'u32' },
29
+ vec4u: { size: 4, scalar: 'u32' },
30
+ vec2f: { size: 2, scalar: 'f32' },
31
+ vec3f: { size: 3, scalar: 'f32' },
32
+ vec4f: { size: 4, scalar: 'f32' },
33
+ vec2h: { size: 2, scalar: 'f16' },
34
+ vec3h: { size: 3, scalar: 'f16' },
35
+ vec4h: { size: 4, scalar: 'f16' },
36
+ };
37
+
38
+ const PRIMITIVE_NAMES = new Set(['i32', 'u32', 'f32', 'f16', 'bool']);
39
+
40
+ const SWIZZLE_LETTERS = new Set(['x', 'y', 'z', 'w', 'r', 'g', 'b', 'a']);
41
+
42
+ const SWIZZLE_INDEX = { x: 0, y: 1, z: 2, w: 3, r: 0, g: 1, b: 2, a: 3 };
43
+
44
+ /**
45
+ * Build a vec type alias name (e.g., {size:3, scalar:'f32'} → 'vec3f').
46
+ */
47
+ function vecAliasName(size, scalar) {
48
+ const suffix = { i32: 'i', u32: 'u', f32: 'f', f16: 'h' }[scalar] || 'f';
49
+ return `vec${size}${suffix}`;
50
+ }
51
+
52
+ // =========================================================================
53
+ // Scope (symbol table) — tracks variable types for accurate codegen
54
+ // =========================================================================
55
+
56
+ class Scope {
57
+ constructor(parent = null) {
58
+ this.parent = parent;
59
+ /** @type {Map<string, WgslType>} */
60
+ this.symbols = new Map();
61
+ }
62
+
63
+ declare(name, type) {
64
+ this.symbols.set(name, type || T_UNKNOWN);
65
+ }
66
+
67
+ /** @returns {WgslType} */
68
+ lookup(name) {
69
+ if (this.symbols.has(name)) return this.symbols.get(name);
70
+ if (this.parent) return this.parent.lookup(name);
71
+ return T_UNKNOWN;
72
+ }
73
+
74
+ push() {
75
+ return new Scope(this);
76
+ }
77
+ }
78
+
79
+ // =========================================================================
80
+ // Tree-sitter helpers
81
+ // =========================================================================
82
+
83
+ /**
84
+ * Return only the named children of a node (filters out punctuation tokens).
85
+ */
86
+ function namedChildren(node) {
87
+ return node.namedChildren;
88
+ }
89
+
90
+ /**
91
+ * First named child by type, or null.
92
+ */
93
+ function namedChildByType(node, type) {
94
+ for (const c of node.namedChildren) {
95
+ if (c.type === type) return c;
96
+ }
97
+ return null;
98
+ }
99
+
100
+ /**
101
+ * All named children with the given type.
102
+ */
103
+ function namedChildrenByType(node, type) {
104
+ return node.namedChildren.filter(c => c.type === type);
105
+ }
106
+
107
+ /**
108
+ * Extract the source-text slice of `parent` that lies between the end of `left` and the start
109
+ * of `right`. tree-sitter-web's `node.children` does not include unnamed tokens, so this is the
110
+ * reliable way to read operator characters that sit between two named children.
111
+ *
112
+ * @param {Node} parent
113
+ * @param {Node} left
114
+ * @param {Node} right
115
+ * @returns {string}
116
+ */
117
+ function textBetween(parent, left, right) {
118
+ const left_offset = (left.endIndex - parent.startIndex);
119
+ const right_offset = (right.startIndex - parent.startIndex);
120
+ return parent.text.slice(left_offset, right_offset);
121
+ }
122
+
123
+ /**
124
+ * Extract any leading source text in `parent` that precedes its first named child. Used for
125
+ * unary operators (e.g. `-x`, `!cond`) where the operator is an unnamed token.
126
+ *
127
+ * @param {Node} parent
128
+ * @returns {string}
129
+ */
130
+ function textBeforeFirstNamed(parent) {
131
+ if (parent.namedChildCount === 0) return '';
132
+ const first = parent.namedChildren[0];
133
+ const offset = first.startIndex - parent.startIndex;
134
+ return parent.text.slice(0, offset);
135
+ }
136
+
137
+ /**
138
+ * Strip wrapper nodes that have a single named child of an expression-passthrough type.
139
+ * The WGSL grammar has a long precedence chain: expression > relational > shift > additive > ...
140
+ * When an expression is "simple" each level just wraps the next.
141
+ */
142
+ function unwrapExpression(node) {
143
+ const PASSTHROUGH = new Set([
144
+ 'expression',
145
+ 'relational_expression',
146
+ 'shift_expression',
147
+ 'additive_expression',
148
+ 'multiplicative_expression',
149
+ 'unary_expression',
150
+ 'singular_expression',
151
+ 'primary_expression',
152
+ ]);
153
+ while (PASSTHROUGH.has(node.type) && node.namedChildren.length === 1) {
154
+ // `unary_expression` keeps its operator as an unnamed token before the operand. If there
155
+ // is one, don't unwrap — the caller needs to see the unary node so it can apply the op.
156
+ if (node.type === 'unary_expression' && textBeforeFirstNamed(node).trim() !== '') {
157
+ break;
158
+ }
159
+ node = node.namedChildren[0];
160
+ }
161
+ return node;
162
+ }
163
+
164
+ // =========================================================================
165
+ // Type parsing (from `type_specifier` nodes or raw text)
166
+ // =========================================================================
167
+
168
+ /**
169
+ * Parse a `type_specifier` tree-sitter node.
170
+ * @param {Node} node
171
+ * @returns {WgslType}
172
+ */
173
+ function parseTypeSpecifier(node) {
174
+ if (node === null || node === undefined) return T_UNKNOWN;
175
+ if (node.type === 'type_specifier') {
176
+ return parseTypeSpecifier(node.namedChildren[0]);
177
+ }
178
+ if (node.type === 'template_elaborated_ident') {
179
+ const ident = namedChildByType(node, 'ident');
180
+ const ident_text = ident ? ident.text : node.text;
181
+ const template = namedChildByType(node, 'template_list');
182
+ const args = template ? extractTemplateArgs(template) : [];
183
+ return classifyType(ident_text, args, template);
184
+ }
185
+ return T_UNKNOWN;
186
+ }
187
+
188
+ /**
189
+ * Pull the textual template arguments from a `template_list` node, e.g. `<f32, 256>` → ['f32', '256'].
190
+ */
191
+ function extractTemplateArgs(template_list_node) {
192
+ const out = [];
193
+ const comma_list = namedChildByType(template_list_node, 'template_arg_comma_list');
194
+ if (comma_list === null) return out;
195
+ for (const c of comma_list.namedChildren) {
196
+ if (c.type === 'template_arg_expression') {
197
+ out.push(c.text.trim());
198
+ }
199
+ }
200
+ return out;
201
+ }
202
+
203
+ /**
204
+ * @param {string} ident
205
+ * @param {string[]} args — textual template args (may be types or numbers)
206
+ * @param {Node | null} template_list_node — the original node, for parsing nested array element types
207
+ * @returns {WgslType}
208
+ */
209
+ function classifyType(ident, args, template_list_node) {
210
+ if (PRIMITIVE_NAMES.has(ident)) {
211
+ return { kind: 'primitive', name: ident };
212
+ }
213
+ if (VECTOR_ALIASES.hasOwnProperty(ident)) {
214
+ const a = VECTOR_ALIASES[ident];
215
+ return { kind: 'vec', size: a.size, scalar: a.scalar };
216
+ }
217
+ if (ident === 'vec2' || ident === 'vec3' || ident === 'vec4') {
218
+ const size = parseInt(ident.slice(3));
219
+ const scalar = args.length > 0 ? args[0] : 'f32';
220
+ return { kind: 'vec', size, scalar };
221
+ }
222
+ {
223
+ const m = ident.match(/^mat(\d)x(\d)([ifh]?)$/);
224
+ if (m !== null) {
225
+ const cols = parseInt(m[1]);
226
+ const rows = parseInt(m[2]);
227
+ const suffix = m[3];
228
+ let scalar;
229
+ if (suffix === 'f') scalar = 'f32';
230
+ else if (suffix === 'i') scalar = 'i32';
231
+ else if (suffix === 'h') scalar = 'f16';
232
+ else scalar = (args.length > 0 ? args[0] : 'f32');
233
+ return { kind: 'mat', cols, rows, scalar };
234
+ }
235
+ }
236
+ if (ident === 'array') {
237
+ // template arg 0 is the element type (sub-template), arg 1 is the count
238
+ let element = T_UNKNOWN;
239
+ let count = -1;
240
+ if (template_list_node !== null) {
241
+ const comma_list = namedChildByType(template_list_node, 'template_arg_comma_list');
242
+ if (comma_list !== null) {
243
+ const arg_nodes = namedChildrenByType(comma_list, 'template_arg_expression');
244
+ if (arg_nodes.length > 0) {
245
+ // Walk down to find the inner type ident
246
+ const inner_expr = unwrapExpression(arg_nodes[0].namedChildren[0]);
247
+ element = parseTypeSpecifier(inner_expr);
248
+ }
249
+ if (arg_nodes.length > 1) {
250
+ const c = parseInt(arg_nodes[1].text.trim());
251
+ if (!isNaN(c)) count = c;
252
+ }
253
+ }
254
+ }
255
+ return { kind: 'array', element, count };
256
+ }
257
+ if (ident === 'atomic') {
258
+ const inner = args.length > 0 ? args[0] : 'i32';
259
+ return { kind: 'atomic', scalar: inner };
260
+ }
261
+ // Texture types - 1D / 2D / 3D, sampled and storage variants. We
262
+ // collapse all of them to a single kind because the intrinsics in
263
+ // WGSLLanguageCore dispatch on the bound CPUBitmapData's
264
+ // `dimensionality`, not on the static WGSL type. (The 'texture_2d'
265
+ // kind label is preserved for backward compatibility with any
266
+ // downstream consumer that may grep for it.)
267
+ if (
268
+ ident === 'texture_2d' || ident === 'texture_storage_2d'
269
+ || ident === 'texture_1d' || ident === 'texture_storage_1d'
270
+ || ident === 'texture_3d' || ident === 'texture_storage_3d'
271
+ || ident === 'texture_2d_array'
272
+ ) {
273
+ const scalar = args.length > 0 ? args[0] : 'f32';
274
+ return { kind: 'texture_2d', scalar };
275
+ }
276
+ if (ident === 'sampler') {
277
+ return { kind: 'sampler' };
278
+ }
279
+ if (ident === 'ptr') {
280
+ // Pointer — peel off the address space and read the inner type.
281
+ if (template_list_node !== null) {
282
+ const comma_list = namedChildByType(template_list_node, 'template_arg_comma_list');
283
+ if (comma_list !== null) {
284
+ const arg_nodes = namedChildrenByType(comma_list, 'template_arg_expression');
285
+ if (arg_nodes.length >= 2) {
286
+ const inner_expr = unwrapExpression(arg_nodes[1].namedChildren[0]);
287
+ return parseTypeSpecifier(inner_expr);
288
+ }
289
+ }
290
+ }
291
+ return T_UNKNOWN;
292
+ }
293
+ // Otherwise: assume it's a struct name.
294
+ return { kind: 'struct', name: ident };
295
+ }
296
+
297
+ // =========================================================================
298
+ // Literal handling — strip WGSL type suffixes for JS
299
+ // =========================================================================
300
+
301
+ /**
302
+ * Convert a WGSL literal token (e.g. `7u`, `1.0f`, `true`) to its JS equivalent.
303
+ *
304
+ * Stripping the type suffix is shape-sensitive: integer literals only carry `u`/`i`, and float
305
+ * literals only carry `f`/`h`. Crucially, a hex int like `0x0300f00f` ends in a hex digit `f`
306
+ * that must NOT be treated as a suffix — only an `f` after a decimal-format float counts.
307
+ */
308
+ function literalToJs(text) {
309
+ const t = text.trim();
310
+ if (t === 'true' || t === 'false') return t;
311
+
312
+ // Hex int literals: `0xNN[ui]?`. Only `u`/`i` are real suffixes here; trailing `f`/`h` are
313
+ // hex digits.
314
+ if (/^0[xX]/.test(t)) {
315
+ return t.replace(/[ui]$/, '');
316
+ }
317
+
318
+ // Decimal int / float. Float forms have a `.`, `e`/`E`, or end in `f`/`h`. Int forms don't.
319
+ if (/[.eE]/.test(t)) {
320
+ return t.replace(/[fh]$/, '');
321
+ }
322
+
323
+ // Plain integer (no `.`, no exponent): strip `u`/`i`/`f`/`h` (the latter two appear only on
324
+ // forms like `1f` which WGSL allows as a float written without a decimal point).
325
+ return t.replace(/[uifh]$/, '');
326
+ }
327
+
328
+ /**
329
+ * The tracked type of a literal token, as far as its own spelling settles it.
330
+ *
331
+ * Only an explicit suffix is honoured. A bare `2043` is WGSL's AbstractInt, which takes its
332
+ * concrete type from context this compiler does not track, so it stays unknown rather than being
333
+ * guessed at.
334
+ *
335
+ * The suffix matters because operator selection reads these types. `index / 2043u` is truncating
336
+ * integer division in WGSL and plain division in JavaScript, and the two differ for every pair
337
+ * where the divisor does not divide the dividend — which is what a paged table's
338
+ * `index / elements_per_page` is. Left untyped, the generated code returned a fractional page
339
+ * index, indexed the page-address table with it, and read `undefined` back as zero: every record
340
+ * past the first page slot came out of the emulator zero-filled, with nothing to say it had.
341
+ *
342
+ * @param {string} text
343
+ * @returns {WgslType}
344
+ */
345
+ function literalType(text) {
346
+ const t = text.trim();
347
+
348
+ if (t === 'true' || t === 'false') {
349
+ return { kind: 'primitive', name: 'bool' };
350
+ }
351
+
352
+ if (/[ui]$/.test(t)) {
353
+ return { kind: 'primitive', name: t.endsWith('u') ? 'u32' : 'i32' };
354
+ }
355
+
356
+ // `f`/`h` are only suffixes on a decimal-format literal; on a hex int they are digits.
357
+ if (!/^0[xX]/.test(t) && /[fh]$/.test(t)) {
358
+ return { kind: 'primitive', name: t.endsWith('f') ? 'f32' : 'f16' };
359
+ }
360
+
361
+ if (/[.eE]/.test(t) && !/^0[xX]/.test(t)) {
362
+ return { kind: 'primitive', name: 'f32' };
363
+ }
364
+
365
+ return T_UNKNOWN;
366
+ }
367
+
368
+ // =========================================================================
369
+ // Identifiers — WGSL names JavaScript cannot bind verbatim
370
+ // =========================================================================
371
+
372
+ /**
373
+ * Names a WGSL identifier cannot keep in the generated JavaScript. {@link identToJs} renames them.
374
+ *
375
+ * - JavaScript's reserved words, strict-mode ones included. A struct becomes a class and a class
376
+ * body is strict code, so `struct private` fails to load even though sloppy code would accept it.
377
+ * - `arguments` and `eval`, which strict code refuses as bindings. Inside a function, `arguments`
378
+ * also means the call's arguments object, so a function reading a module-scope one got that
379
+ * object instead of the WGSL value.
380
+ * - The free names the generated code refers to: the `wgsl` runtime and the globals it builds
381
+ * values with. A WGSL `struct Object` shadowed the `Object` whose `defineProperty` exports the
382
+ * module's state, and the module failed to load. Any global that new emitted code refers to
383
+ * belongs here too.
384
+ *
385
+ * WGSL reserves most of these itself, so a device rejects them. The tree-sitter grammar does not,
386
+ * so any of them can reach this compiler. `in` is the one real shaders use, as the parameter of a
387
+ * fragment entry: `fn fs_main(in : VertexOut)`.
388
+ *
389
+ * @type {Set<string>}
390
+ */
391
+ const JS_RESERVED_NAMES = new Set([
392
+ // reserved words
393
+ 'await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger', 'default', 'delete',
394
+ 'do', 'else', 'enum', 'export', 'extends', 'false', 'finally', 'for', 'function', 'if', 'import',
395
+ 'in', 'instanceof', 'new', 'null', 'return', 'super', 'switch', 'this', 'throw', 'true', 'try',
396
+ 'typeof', 'var', 'void', 'while', 'with', 'yield',
397
+ // reserved in strict code
398
+ 'implements', 'interface', 'let', 'package', 'private', 'protected', 'public', 'static',
399
+ // refused as bindings in strict code
400
+ 'arguments', 'eval',
401
+ // referred to by the generated code
402
+ 'wgsl', 'undefined', 'Object', 'Array', 'Float32Array', 'Float16Array', 'Int32Array', 'Uint32Array',
403
+ ]);
404
+
405
+ /**
406
+ * The JavaScript binding a WGSL identifier is emitted as: the identifier itself, or the identifier
407
+ * with a `$` suffix when it is one of {@link JS_RESERVED_NAMES} (`in` becomes `in$`).
408
+ *
409
+ * The suffix cannot collide with anything. The WGSL grammar has no `$` in an identifier, so a
410
+ * source that spells one does not parse. None of the compiler's own names (`wgsl`, `__entry__`, …)
411
+ * contain one. Appending it to two different names leaves them different.
412
+ *
413
+ * Every declaration of, and reference to, a function, parameter, local, module-scope variable or
414
+ * struct type goes through this. Struct members do not: a member is a property, and `x.in` is
415
+ * legal JavaScript. Nothing a caller sees is renamed either. The module exports everything under
416
+ * its WGSL name, `entry_name` and `param_names` hold WGSL names, and bindings and workgroup
417
+ * variables are keyed by their WGSL names.
418
+ *
419
+ * @param {string} name a WGSL identifier
420
+ * @returns {string}
421
+ */
422
+ function identToJs(name) {
423
+ return JS_RESERVED_NAMES.has(name) ? `${name}$` : name;
424
+ }
425
+
426
+ // =========================================================================
427
+ // Operator handling
428
+ // =========================================================================
429
+
430
+ /**
431
+ * Map a WGSL binary operator to a `wgsl.*` runtime helper or to a raw JS operator.
432
+ * Arithmetic must go through wgsl.* so vectors are handled element-wise.
433
+ */
434
+ const ARITHMETIC_OP = {
435
+ '+': 'add',
436
+ '-': 'sub',
437
+ '*': 'mul',
438
+ '/': 'div',
439
+ '%': 'rem',
440
+ };
441
+
442
+ const RAW_BINARY_OPS = new Set(['<', '>', '<=', '>=', '==', '!=', '&&', '||', '&', '|', '^', '<<', '>>']);
443
+
444
+ /**
445
+ * Arithmetic operators that wrap at 32 bits when WGSL types the result as an integer. Mapped to the
446
+ * helper-name prefix; the scalar type (`u32` / `i32`) is appended at the call site.
447
+ */
448
+ const INTEGER_WRAPPING_OP = {
449
+ '+': 'add',
450
+ '-': 'sub',
451
+ '*': 'mul',
452
+ };
453
+
454
+ /**
455
+ * Scalar arithmetic that has to round to f32, by operator.
456
+ *
457
+ * A vector's lanes always rounded — they are written into a Float32Array — and the scalar path did
458
+ * not, so one function ran at two precisions and the scalar one was more accurate than the device.
459
+ * @type {Object<string, string>}
460
+ */
461
+ const F32_SCALAR_OP = {
462
+ '+': 'add_f32',
463
+ '-': 'sub_f32',
464
+ '*': 'mul_f32',
465
+ '/': 'div_f32',
466
+ };
467
+
468
+ // =========================================================================
469
+ // Compiler context — central state during compilation
470
+ // =========================================================================
471
+
472
+ class Compiler {
473
+ constructor() {
474
+ /** @type {LineBuilder} */
475
+ this.out = new LineBuilder();
476
+
477
+ /** @type {Scope} */
478
+ this.scope = new Scope();
479
+
480
+ /** @type {Map<string, { name: string, fields: Array<{ name: string, type: WgslType }> }>} */
481
+ this.structs = new Map();
482
+
483
+ /** @type {Map<string, { name: string, returnType: WgslType, params: Array<{ name: string, type: WgslType }> }>} */
484
+ this.functions = new Map();
485
+
486
+ /** @type {Array<{ name: string, type: WgslType, group: number, binding: number, addressSpace: string | null, accessMode: string | null }>} */
487
+ this.globalBindings = [];
488
+
489
+ /** @type {Array<{ name: string, type: WgslType }>} */
490
+ this.workgroupVars = [];
491
+
492
+ /**
493
+ * Module-scope `var<private>` and `const` declarations, in declaration order.
494
+ * Each entry is `{ name, kind: 'let' | 'const', code, init }` — `code` is the JS line
495
+ * emitted verbatim; `name` and `kind` are also tracked so the returned module object can
496
+ * expose them as getter/setter (or read-only) properties for testing, and `init` is the
497
+ * initializer expression on its own, which the private-state reset re-emits for the `let`
498
+ * ones (a `const` cannot be reassigned, and no invocation can disturb it).
499
+ * @type {Array<{ name: string, kind: 'let' | 'const', code: string, init: string }>}
500
+ */
501
+ this.privateGlobals = [];
502
+
503
+ /** @type {{ name: string, params: Array<{ name: string, type: WgslType, builtin: string | null }>, workgroup_size: number[] } | null} */
504
+ this.entry = null;
505
+
506
+ /**
507
+ * Name of the function whose body is being emitted, `null` outside one. `discard` reads it:
508
+ * it compiles to a `return`, which only ends the invocation from inside the entry.
509
+ * @type {string | null}
510
+ */
511
+ this.function_name = null;
512
+
513
+ /**
514
+ * Label of the enclosing `loop` body block when that loop has a `continuing`
515
+ * block: WGSL `continue` must transfer control INTO the continuing block, so it
516
+ * is emitted as `break <label>` out of the labeled body block. `null` when the
517
+ * nearest enclosing loop has no continuing block (plain JS `continue` suffices).
518
+ * Loop emitters save/clear/restore this around nested loop bodies.
519
+ * @type {string | null}
520
+ */
521
+ this.continue_label = null;
522
+
523
+ /**
524
+ * Monotonic counter used to generate unique loop-body labels.
525
+ * @type {number}
526
+ */
527
+ this.loop_label_counter = 0;
528
+ }
529
+
530
+ error(node, message) {
531
+ throw new Error(`WGSL compiler: ${message} (at ${node ? node.type : '<unknown>'} : ${node ? JSON.stringify(node.text.slice(0, 60)) : ''})`);
532
+ }
533
+ }
534
+
535
+ // =========================================================================
536
+ // Top-level compile entry point
537
+ // =========================================================================
538
+
539
+ export class WGSLJavaScriptCompiler {
540
+
541
+ /**
542
+ * Compile a tree-sitter WGSL parse tree to a JS source string.
543
+ *
544
+ * The output is a JavaScript expression: a function `factory(wgsl)` that returns
545
+ * a shader module object. The shape depends on what the WGSL declared:
546
+ *
547
+ * - **Always present:** every top-level user function (e.g. `module.random()`),
548
+ * every struct class (e.g. `module.Foo`), a getter/setter property for each
549
+ * `var<private>` and getter for each module-scope `const`, and `reset_private()`,
550
+ * which returns every `var<private>` to its start-of-invocation value.
551
+ * - **Compute-shader fields (only when a `@compute` entry is present):**
552
+ * ```
553
+ * {
554
+ * entry_name: string,
555
+ * workgroup_size: [x, y, z],
556
+ * param_names: string[],
557
+ * entry: (bindings, workgroup, ...args) => void,
558
+ * create_workgroup_state: () => object,
559
+ * }
560
+ * ```
561
+ *
562
+ * Without a `@compute` entry the result is a "library" module — useful for testing
563
+ * pure WGSL helper code chunks (hashes, packing, math) one function at a time.
564
+ *
565
+ * Every name on the module is the WGSL one, including where the generated JavaScript had to
566
+ * bind it under another (a parameter `in` is bound as `in$`; see {@link identToJs}).
567
+ *
568
+ * @param {Tree} ast — tree-sitter WGSL AST (returned by `WGSLParser.parse`)
569
+ * @returns {string}
570
+ */
571
+ compile(ast) {
572
+ const c = new Compiler();
573
+ compileTranslationUnit(c, ast.rootNode);
574
+ return c.out.build();
575
+ }
576
+ }
577
+
578
+ // =========================================================================
579
+ // Translation unit (root)
580
+ // =========================================================================
581
+
582
+ /**
583
+ * @param {Compiler} c
584
+ * @param {Node} root
585
+ */
586
+ function compileTranslationUnit(c, root) {
587
+ assert.equal(root.type, 'translation_unit', 'root must be translation_unit');
588
+
589
+ // First pass — collect top-level decls so forward references and global scope resolve.
590
+ for (const node of root.namedChildren) {
591
+ switch (node.type) {
592
+ case 'struct_decl':
593
+ collectStruct(c, node);
594
+ break;
595
+ case 'function_decl':
596
+ collectFunction(c, node);
597
+ break;
598
+ case 'global_variable_decl':
599
+ collectGlobalVariable(c, node);
600
+ break;
601
+ case 'global_value_decl':
602
+ collectGlobalValue(c, node);
603
+ break;
604
+ }
605
+ }
606
+
607
+ // Emit the wrapper: `(wgsl) => { ... }`
608
+ c.out.add('(wgsl) => {');
609
+ c.out.indent();
610
+
611
+ // 1) Struct classes — must be defined before any user fn that references them or before
612
+ // the workgroup state factory (which may need to construct struct instances).
613
+ for (const node of root.namedChildren) {
614
+ if (node.type === 'struct_decl') emitStruct(c, node);
615
+ }
616
+
617
+ // 2) Module-scope `let` slots for bindings and workgroup vars. The entry wrapper assigns
618
+ // these on each dispatch so that user functions see them via their enclosing closure
619
+ // — WGSL functions can read globals freely.
620
+ for (const b of c.globalBindings) {
621
+ c.out.add(`let ${identToJs(b.name)} = undefined;`);
622
+ }
623
+ for (const wv of c.workgroupVars) {
624
+ c.out.add(`let ${identToJs(wv.name)} = undefined;`);
625
+ }
626
+
627
+ // 3) Module-scope `var<private>` and `const` declarations.
628
+ for (const g of c.privateGlobals) {
629
+ c.out.add(g.code);
630
+ }
631
+
632
+ // 4) User-defined functions (including the @compute entry, if any).
633
+ for (const node of root.namedChildren) {
634
+ if (node.type === 'function_decl') emitFunction(c, node);
635
+ }
636
+
637
+ // 5) The private-state reset. Emitted for every module, library ones included: a
638
+ // `var<private>` is per-invocation state on the GPU, and the JS `let` above outlives the
639
+ // dispatch that wrote it, so something has to put the initial values back.
640
+ emitPrivateStateReset(c);
641
+
642
+ // 6) Entry-stage support code: the dispatch wrapper for any entry, plus a workgroup-state
643
+ // factory for @compute entries (fragment shaders have no var<workgroup>). Skipped entirely
644
+ // in library mode (no entry attribute) so the resulting module is just a bag of pure
645
+ // functions and globals.
646
+ if (c.entry !== null) {
647
+ if (c.entry.stage === 'compute') {
648
+ emitWorkgroupStateFactory(c);
649
+ }
650
+ emitEntryWrapper(c);
651
+ }
652
+
653
+ // 7) Build and return the module object.
654
+ emitModuleReturn(c);
655
+
656
+ c.out.dedent();
657
+ c.out.add('}');
658
+ }
659
+
660
+ /**
661
+ * Emit the `return { ... }` block of the factory. Every top-level user function and struct
662
+ * class is exposed by its WGSL name; module-scope `var<private>` slots become getter/setter
663
+ * properties (so tests can inspect or seed RNG state etc.), and module-scope `const`s become
664
+ * read-only getters. `reset_private` is always included. When the WGSL had a `@compute` entry, the
665
+ * dispatch trio (`entry_name`, `workgroup_size`, `param_names`, `entry`, `create_workgroup_state`)
666
+ * is included too.
667
+ */
668
+ function emitModuleReturn(c) {
669
+ c.out.add('const __module__ = {};');
670
+
671
+ for (const fn_name of c.functions.keys()) {
672
+ c.out.add(`__module__.${fn_name} = ${identToJs(fn_name)};`);
673
+ }
674
+ for (const struct_name of c.structs.keys()) {
675
+ c.out.add(`__module__.${struct_name} = ${identToJs(struct_name)};`);
676
+ }
677
+
678
+ for (const g of c.privateGlobals) {
679
+ const js_name = identToJs(g.name);
680
+
681
+ if (g.kind === 'let') {
682
+ // The setter's parameter uses a name WGSL cannot spell. When it was `v`, a
683
+ // `var<private> v` compiled to `v = v`, which assigned the parameter to itself and
684
+ // left the variable untouched.
685
+ c.out.add(`Object.defineProperty(__module__, ${JSON.stringify(g.name)}, { get: () => ${js_name}, set: (__value__) => { ${js_name} = __value__; } });`);
686
+ } else {
687
+ c.out.add(`Object.defineProperty(__module__, ${JSON.stringify(g.name)}, { get: () => ${js_name} });`);
688
+ }
689
+ }
690
+
691
+ c.out.add('__module__.reset_private = __reset_private__;');
692
+
693
+ if (c.entry !== null) {
694
+ c.out.add(`__module__.entry_name = ${JSON.stringify(c.entry.name)};`);
695
+ c.out.add(`__module__.stage = ${JSON.stringify(c.entry.stage)};`);
696
+ c.out.add(`__module__.param_names = [${c.entry.params.map(p => JSON.stringify(p.name)).join(', ')}];`);
697
+ c.out.add(`__module__.entry = __entry__;`);
698
+ if (c.entry.stage === 'compute') {
699
+ c.out.add(`__module__.workgroup_size = [${c.entry.workgroup_size.join(', ')}];`);
700
+ c.out.add(`__module__.create_workgroup_state = __create_workgroup_state__;`);
701
+ }
702
+ }
703
+
704
+ c.out.add('return __module__;');
705
+ }
706
+
707
+ // =========================================================================
708
+ // Struct collection + emission
709
+ // =========================================================================
710
+
711
+ /**
712
+ * @param {Compiler} c
713
+ * @param {Node} node
714
+ */
715
+ function collectStruct(c, node) {
716
+ const ident = namedChildByType(node, 'ident');
717
+ const name = ident.text;
718
+
719
+ const body = namedChildByType(node, 'struct_body_decl');
720
+ const members = namedChildrenByType(body, 'struct_member');
721
+
722
+ /** @type {Array<{ name: string, type: WgslType }>} */
723
+ const fields = [];
724
+
725
+ for (const m of members) {
726
+ const member_ident = namedChildByType(m, 'member_ident');
727
+ const type_spec = namedChildByType(m, 'type_specifier');
728
+ fields.push({
729
+ name: member_ident.text,
730
+ type: parseTypeSpecifier(type_spec),
731
+ });
732
+ }
733
+
734
+ c.structs.set(name, { name, fields });
735
+ }
736
+
737
+ /**
738
+ * @param {Compiler} c
739
+ * @param {Node} node
740
+ */
741
+ function emitStruct(c, node) {
742
+ const ident = namedChildByType(node, 'ident');
743
+ const name = ident.text;
744
+ const info = c.structs.get(name);
745
+
746
+ c.out.add(`class ${identToJs(name)} {`);
747
+ c.out.indent();
748
+ c.out.add('constructor() {');
749
+ c.out.indent();
750
+ for (const f of info.fields) {
751
+ c.out.add(`this.${f.name} = ${defaultValueForType(f.type)};`);
752
+ }
753
+ c.out.dedent();
754
+ c.out.add('}');
755
+ c.out.dedent();
756
+ c.out.add('}');
757
+ }
758
+
759
+ /**
760
+ * Initialiser expression for a fresh value of the given type.
761
+ * @param {WgslType} type
762
+ * @returns {string}
763
+ */
764
+ function defaultValueForType(type) {
765
+ if (type === undefined || type === null) return 'undefined';
766
+ switch (type.kind) {
767
+ case 'primitive':
768
+ return type.name === 'bool' ? 'false' : '0';
769
+ case 'vec':
770
+ return `wgsl.${vecAliasName(type.size, type.scalar)}()`;
771
+ case 'mat':
772
+ return `new Float32Array(${type.cols * type.rows})`;
773
+ case 'array': {
774
+ if (type.count > 0) {
775
+ if (type.element.kind === 'primitive') {
776
+ const ctor = arrayCtorForScalar(type.element.name);
777
+ return `new ${ctor}(${type.count})`;
778
+ }
779
+ // For non-primitive elements (vec / mat / struct / nested array) build the
780
+ // array eagerly so `out[i]` is a fresh, mutable element rather than `undefined`.
781
+ return `Array.from({ length: ${type.count} }, () => ${defaultValueForType(type.element)})`;
782
+ }
783
+ return '[]';
784
+ }
785
+ case 'struct':
786
+ return `new ${identToJs(type.name)}()`;
787
+ case 'atomic':
788
+ return '{ value: 0 }';
789
+ default:
790
+ return 'undefined';
791
+ }
792
+ }
793
+
794
+ function arrayCtorForScalar(name) {
795
+ switch (name) {
796
+ case 'f32':
797
+ return 'Float32Array';
798
+ case 'f16':
799
+ return 'Float16Array';
800
+ case 'i32':
801
+ return 'Int32Array';
802
+ case 'u32':
803
+ return 'Uint32Array';
804
+ default:
805
+ return 'Array';
806
+ }
807
+ }
808
+
809
+ // =========================================================================
810
+ // Function collection + emission
811
+ // =========================================================================
812
+
813
+ /**
814
+ * @param {Compiler} c
815
+ * @param {Node} node
816
+ */
817
+ function collectFunction(c, node) {
818
+ const header = namedChildByType(node, 'function_header');
819
+ const ident = namedChildByType(header, 'ident');
820
+ const name = ident.text;
821
+
822
+ const param_list_node = namedChildByType(header, 'param_list');
823
+ /** @type {Array<{ name: string, type: WgslType, builtin: string | null }>} */
824
+ const params = [];
825
+ if (param_list_node !== null) {
826
+ const param_nodes = namedChildrenByType(param_list_node, 'param');
827
+ for (const p of param_nodes) {
828
+ const p_ident = namedChildByType(p, 'ident');
829
+ const p_type = namedChildByType(p, 'type_specifier');
830
+ const builtin = extractBuiltin(p);
831
+ params.push({
832
+ name: p_ident.text,
833
+ type: parseTypeSpecifier(p_type),
834
+ builtin,
835
+ });
836
+ }
837
+ }
838
+
839
+ // Optional return type — `template_elaborated_ident` directly under the header.
840
+ let returnType = T_UNKNOWN;
841
+ for (const child of header.namedChildren) {
842
+ if (child.type === 'template_elaborated_ident') {
843
+ returnType = parseTypeSpecifier(child);
844
+ }
845
+ }
846
+
847
+ c.functions.set(name, { name, returnType, params: params.map(p => ({ name: p.name, type: p.type })) });
848
+
849
+ // Detect the entry attribute (@compute, @fragment, or @vertex) and capture stage-specific
850
+ // metadata. The emulator supports compute and fragment entries; vertex is rejected because
851
+ // ImageShader testing in the emulator skips the vertex phase intentionally.
852
+ const attrs = namedChildrenByType(node, 'attribute');
853
+ let stage = null;
854
+ let workgroup_size = [1, 1, 1];
855
+ for (const a of attrs) {
856
+ const inner = a.namedChildren[0];
857
+ if (inner.type === 'compute_attr') {
858
+ stage = 'compute';
859
+ } else if (inner.type === 'fragment_attr') {
860
+ stage = 'fragment';
861
+ } else if (inner.type === 'vertex_attr') {
862
+ throw new Error(`WGSL compiler: @vertex stage is not supported by the emulator (function '${name}'). For ImageShader testing the vertex phase is skipped — invoke the @fragment entry directly.`);
863
+ } else if (inner.type === 'workgroup_size_attr') {
864
+ const sizes = namedChildrenByType(inner, 'expression').map(e => parseInt(e.text.trim()) | 0);
865
+ for (let i = 0; i < sizes.length && i < 3; i++) {
866
+ workgroup_size[i] = sizes[i];
867
+ }
868
+ }
869
+ }
870
+
871
+ if (stage !== null) {
872
+ if (c.entry !== null) {
873
+ throw new Error(`WGSL compiler: multiple @${stage} entry functions found ('${c.entry.name}' and '${name}')`);
874
+ }
875
+ c.entry = { name, params, stage, workgroup_size };
876
+ }
877
+ }
878
+
879
+ /**
880
+ * Pull the `@builtin(name)` attribute name from a function param node, if present.
881
+ */
882
+ function extractBuiltin(param_node) {
883
+ for (const a of namedChildrenByType(param_node, 'attribute')) {
884
+ const inner = a.namedChildren[0];
885
+ if (inner.type === 'builtin_attr') {
886
+ const name_node = namedChildByType(inner, 'builtin_value_name');
887
+ if (name_node !== null) return name_node.text;
888
+ }
889
+ }
890
+ return null;
891
+ }
892
+
893
+ /**
894
+ * @param {Compiler} c
895
+ * @param {Node} node
896
+ */
897
+ function emitFunction(c, node) {
898
+ const header = namedChildByType(node, 'function_header');
899
+ const ident = namedChildByType(header, 'ident');
900
+ const name = ident.text;
901
+ const info = c.functions.get(name);
902
+
903
+ const param_list_node = namedChildByType(header, 'param_list');
904
+ const param_nodes = param_list_node !== null ? namedChildrenByType(param_list_node, 'param') : [];
905
+
906
+ const param_names = param_nodes.map(p => namedChildByType(p, 'ident').text);
907
+
908
+ c.out.add(`function ${identToJs(name)}(${param_names.map(identToJs).join(', ')}) {`);
909
+ c.out.indent();
910
+
911
+ c.scope = c.scope.push();
912
+ for (let i = 0; i < param_nodes.length; i++) {
913
+ c.scope.declare(param_names[i], info.params[i].type);
914
+ }
915
+
916
+ const body = namedChildByType(node, 'compound_statement');
917
+ c.function_name = name;
918
+ emitCompoundStatementBody(c, body);
919
+ c.function_name = null;
920
+
921
+ c.scope = c.scope.parent;
922
+
923
+ c.out.dedent();
924
+ c.out.add('}');
925
+ }
926
+
927
+ // =========================================================================
928
+ // Globals — bindings, workgroup vars, private/const
929
+ // =========================================================================
930
+
931
+ /**
932
+ * Inspect a `global_variable_decl` and record its metadata.
933
+ * @param {Compiler} c
934
+ * @param {Node} node
935
+ */
936
+ function collectGlobalVariable(c, node) {
937
+ const var_decl = namedChildByType(node, 'variable_decl');
938
+ if (var_decl === null) {
939
+ collectGlobalValue(c, node);
940
+ return;
941
+ }
942
+
943
+ const template = namedChildByType(var_decl, 'template_list');
944
+ const opt_ident = namedChildByType(var_decl, 'optionally_typed_ident');
945
+ const var_ident = namedChildByType(opt_ident, 'ident');
946
+ const type_spec = namedChildByType(opt_ident, 'type_specifier');
947
+ const name = var_ident.text;
948
+ const type = parseTypeSpecifier(type_spec);
949
+
950
+ let address_space = null;
951
+ let access_mode = null;
952
+ if (template !== null) {
953
+ const args = extractTemplateArgs(template);
954
+ address_space = args[0] || null;
955
+ access_mode = args[1] || null;
956
+ }
957
+
958
+ let group = null;
959
+ let binding = null;
960
+ for (const a of namedChildrenByType(node, 'attribute')) {
961
+ const inner = a.namedChildren[0];
962
+ if (inner.type === 'group_attr') {
963
+ const expr = namedChildByType(inner, 'expression');
964
+ group = parseInt(expr.text.trim());
965
+ } else if (inner.type === 'binding_attr') {
966
+ const expr = namedChildByType(inner, 'expression');
967
+ binding = parseInt(expr.text.trim());
968
+ }
969
+ }
970
+
971
+ c.scope.declare(name, type);
972
+
973
+ // `var<immediate>` carries neither attribute — immediate data is part of the shader interface
974
+ // but is not a bound resource, so WGSL gives it no @group/@binding. It still arrives from
975
+ // outside the shader, so it is a binding as far as the emulator is concerned, and binding here
976
+ // is what keeps it out of the `privateGlobals` branch below. Falling through to that branch
977
+ // would default-initialise it and every spec reading it would quietly see zeroes.
978
+ const is_immediate = address_space === 'immediate';
979
+
980
+ if (is_immediate || (group !== null && binding !== null)) {
981
+ c.globalBindings.push({
982
+ name, type, group, binding, addressSpace: address_space, accessMode: access_mode,
983
+ });
984
+ return;
985
+ }
986
+
987
+ if (address_space === 'workgroup') {
988
+ c.workgroupVars.push({ name, type });
989
+ return;
990
+ }
991
+
992
+ // Private / module-scope `var<private>`. If the WGSL has an explicit initializer
993
+ // (e.g. `var<private> rnd_state: u32 = 2891336453u`), use it; otherwise fall back
994
+ // to the type's default value.
995
+ const initializer_node = namedChildByType(node, 'expression');
996
+ const init_code = initializer_node !== null
997
+ ? compileExpression(c, initializer_node).code
998
+ : defaultValueForType(type);
999
+ c.privateGlobals.push({
1000
+ name,
1001
+ kind: 'let',
1002
+ code: `let ${identToJs(name)} = ${init_code};`,
1003
+ init: init_code,
1004
+ });
1005
+ }
1006
+
1007
+ /**
1008
+ * Inspect a `global_value_decl` (`const x = …;` / `let x = …;` at module scope) and record it.
1009
+ * @param {Compiler} c
1010
+ * @param {Node} node
1011
+ */
1012
+ function collectGlobalValue(c, node) {
1013
+ let ident = null;
1014
+ let value_node = null;
1015
+ let type_node = null;
1016
+ for (const child of node.namedChildren) {
1017
+ if (child.type === 'optionally_typed_ident') {
1018
+ ident = namedChildByType(child, 'ident');
1019
+ type_node = namedChildByType(child, 'type_specifier');
1020
+ } else if (child.type === 'expression') {
1021
+ value_node = child;
1022
+ }
1023
+ }
1024
+ if (ident === null || value_node === null) return;
1025
+ const name = ident.text;
1026
+ let type = type_node !== null ? parseTypeSpecifier(type_node) : T_UNKNOWN;
1027
+
1028
+ const expr = compileExpression(c, value_node);
1029
+
1030
+ // Infer the type from the RHS when there's no explicit annotation (mirrors the local
1031
+ // `let`/`var` path). Without this a `const M = mat3x3<f32>(...)` is left T_UNKNOWN, so a
1032
+ // later `M * v` can't tell M is a matrix and emits a vector multiply → length mismatch.
1033
+ if (type === T_UNKNOWN || type.kind === 'unknown') {
1034
+ type = expr.type;
1035
+ }
1036
+
1037
+ c.scope.declare(name, type);
1038
+ c.privateGlobals.push({
1039
+ name,
1040
+ kind: 'const',
1041
+ code: `const ${identToJs(name)} = ${expr.code};`,
1042
+ init: expr.code,
1043
+ });
1044
+ }
1045
+
1046
+ // =========================================================================
1047
+ // Workgroup state factory + entry wrapper
1048
+ // =========================================================================
1049
+
1050
+ /**
1051
+ * Emit `__reset_private__()`, which restores every module-scope `var<private>` to the value it
1052
+ * would have at the start of a WGSL invocation — its declared initializer, or the type's zero
1053
+ * value when it was declared without one.
1054
+ *
1055
+ * This is the private-address-space counterpart of {@link emitWorkgroupStateFactory}. The
1056
+ * generated module keeps its private slots in `let` bindings that live as long as the module, so
1057
+ * without this a second dispatch would start from whatever the first one left behind — state the
1058
+ * GPU never carries.
1059
+ *
1060
+ * Module-scope `const`s are skipped: they are immutable in the generated JS and no invocation can
1061
+ * disturb them.
1062
+ *
1063
+ * @param {Compiler} c
1064
+ */
1065
+ function emitPrivateStateReset(c) {
1066
+ c.out.add('function __reset_private__() {');
1067
+ c.out.indent();
1068
+ for (const g of c.privateGlobals) {
1069
+ if (g.kind !== 'let') continue;
1070
+ c.out.add(`${identToJs(g.name)} = ${g.init};`);
1071
+ }
1072
+ c.out.dedent();
1073
+ c.out.add('}');
1074
+ }
1075
+
1076
+ function emitWorkgroupStateFactory(c) {
1077
+ c.out.add('function __create_workgroup_state__() {');
1078
+ c.out.indent();
1079
+ c.out.add('return {');
1080
+ c.out.indent();
1081
+ for (const wv of c.workgroupVars) {
1082
+ c.out.add(`${wv.name}: ${defaultValueForType(wv.type)},`);
1083
+ }
1084
+ c.out.dedent();
1085
+ c.out.add('};');
1086
+ c.out.dedent();
1087
+ c.out.add('}');
1088
+ }
1089
+
1090
+ function emitEntryWrapper(c) {
1091
+ // The wrapper refers to the entry function and to every binding and workgroup slot, all by
1092
+ // name, so its own parameters use names WGSL cannot spell. When they took the entry's WGSL
1093
+ // parameter names, `fn main(main: vec4<f32>)` wrapped to `main(main)`, which called the
1094
+ // argument. A parameter that shared a binding's name was assigned the binding in place of its
1095
+ // argument, and the binding's slot, which the entry's helpers read, stayed unset.
1096
+ const arg_names = c.entry.params.map((_, i) => `__arg${i}__`);
1097
+ const entry_fn = identToJs(c.entry.name);
1098
+ const is_compute = c.entry.stage === 'compute';
1099
+ // Compute entries take a per-dispatch workgroup-state object; fragment entries don't have
1100
+ // var<workgroup> at all, so the wrapper signature drops it.
1101
+ const fixed_args = is_compute ? '__bindings__, __workgroup__' : '__bindings__';
1102
+ const all_args = arg_names.length > 0 ? `${fixed_args}, ${arg_names.join(', ')}` : fixed_args;
1103
+
1104
+ c.out.add(`function __entry__(${all_args}) {`);
1105
+ c.out.indent();
1106
+
1107
+ // Refresh each module-scope binding/workgroup slot before invoking the user's main.
1108
+ // User functions read these via their enclosing closure, so this assignment makes the
1109
+ // current dispatch's bindings visible to every helper they may call. The caller keys both
1110
+ // objects by WGSL name; only the slot takes the JS name.
1111
+ for (const b of c.globalBindings) {
1112
+ c.out.add(`${identToJs(b.name)} = __bindings__.${b.name};`);
1113
+ }
1114
+ if (is_compute) {
1115
+ for (const wv of c.workgroupVars) {
1116
+ c.out.add(`${identToJs(wv.name)} = __workgroup__.${wv.name};`);
1117
+ }
1118
+ }
1119
+
1120
+ if (is_compute && c.workgroupVars.length > 0) {
1121
+ // The lanes of one workgroup are dispatched one call at a time, and a scalar
1122
+ // `var<workgroup>` a lane assigns lives in the module-scope slot above — a copy of the
1123
+ // state object's field, not the field. Writing it back is what lets the next lane see it,
1124
+ // which is the whole point of workgroup memory (an array slot already persists, since the
1125
+ // slot holds a reference and the lane mutates it in place).
1126
+ c.out.add(`const __result__ = ${entry_fn}(${arg_names.join(', ')});`);
1127
+ for (const wv of c.workgroupVars) {
1128
+ c.out.add(`__workgroup__.${wv.name} = ${identToJs(wv.name)};`);
1129
+ }
1130
+ c.out.add('return __result__;');
1131
+ } else {
1132
+ c.out.add(`return ${entry_fn}(${arg_names.join(', ')});`);
1133
+ }
1134
+
1135
+ c.out.dedent();
1136
+ c.out.add('}');
1137
+ }
1138
+
1139
+ // =========================================================================
1140
+ // Statements
1141
+ // =========================================================================
1142
+
1143
+ /**
1144
+ * Emit only the inside of a compound_statement (no `{` / `}`).
1145
+ * @param {Compiler} c
1146
+ * @param {Node} node — `compound_statement`
1147
+ */
1148
+ function emitCompoundStatementBody(c, node) {
1149
+ for (const child of node.namedChildren) {
1150
+ if (child.type === 'statement') {
1151
+ emitStatement(c, child);
1152
+ }
1153
+ }
1154
+ }
1155
+
1156
+ function emitCompoundStatement(c, node) {
1157
+ c.out.add('{');
1158
+ c.out.indent();
1159
+ c.scope = c.scope.push();
1160
+ emitCompoundStatementBody(c, node);
1161
+ c.scope = c.scope.parent;
1162
+ c.out.dedent();
1163
+ c.out.add('}');
1164
+ }
1165
+
1166
+ /**
1167
+ * Emit a single `statement` node (its child is the actual statement kind).
1168
+ * @param {Compiler} c
1169
+ * @param {Node} node
1170
+ */
1171
+ function emitStatement(c, node) {
1172
+ const inner = node.namedChildren[0];
1173
+ if (inner === undefined) {
1174
+ emitBareStatement(c, node);
1175
+ return;
1176
+ }
1177
+ switch (inner.type) {
1178
+ case 'variable_or_value_statement':
1179
+ emitVariableOrValueStatement(c, inner);
1180
+ break;
1181
+ case 'variable_updating_statement':
1182
+ emitVariableUpdatingStatement(c, inner);
1183
+ break;
1184
+ case 'return_statement':
1185
+ emitReturnStatement(c, inner);
1186
+ break;
1187
+ case 'if_statement':
1188
+ emitIfStatement(c, inner);
1189
+ break;
1190
+ case 'for_statement':
1191
+ emitForStatement(c, inner);
1192
+ break;
1193
+ case 'while_statement':
1194
+ emitWhileStatement(c, inner);
1195
+ break;
1196
+ case 'loop_statement':
1197
+ emitLoopStatement(c, inner);
1198
+ break;
1199
+ case 'switch_statement':
1200
+ emitSwitchStatement(c, inner);
1201
+ break;
1202
+ case 'break_statement':
1203
+ c.out.add('break;');
1204
+ break;
1205
+ case 'continue_statement':
1206
+ // Inside a `loop` with a `continuing` block, `continue` must run the
1207
+ // continuing block: it is emitted as a break out of the labeled body block
1208
+ // (the continuing code follows that block inside the same `while`).
1209
+ if (c.continue_label !== null) {
1210
+ c.out.add(`break ${c.continue_label};`);
1211
+ } else {
1212
+ c.out.add('continue;');
1213
+ }
1214
+ break;
1215
+ case 'compound_statement':
1216
+ emitCompoundStatement(c, inner);
1217
+ break;
1218
+ case 'func_call_statement':
1219
+ emitFunctionCallStatement(c, inner);
1220
+ break;
1221
+ case 'const_assert_statement':
1222
+ // Skipped at runtime.
1223
+ break;
1224
+ default:
1225
+ c.error(inner, `unsupported statement: ${inner.type}`);
1226
+ }
1227
+ }
1228
+
1229
+ /**
1230
+ * A `statement` with no named child. tree-sitter-wgsl builds `discard;` and the empty statement
1231
+ * `;` from anonymous tokens alone — `(statement)` — so there is no child type to switch on, and
1232
+ * they are told apart by their text.
1233
+ * @param {Compiler} c
1234
+ * @param {Node} node
1235
+ */
1236
+ function emitBareStatement(c, node) {
1237
+ switch (node.text.replace(/\s+/g, '')) {
1238
+ case ';':
1239
+ break;
1240
+ case 'discard;':
1241
+ // The fragment has no output, so `dispatch` returns undefined. That takes a return from
1242
+ // the entry itself: in a helper it would only hand control back to the caller, and the
1243
+ // fragment would carry on and write its colour.
1244
+ if (c.entry === null || c.function_name !== c.entry.name) {
1245
+ c.error(node, `discard is only supported in the entry function, not in '${c.function_name}'`);
1246
+ }
1247
+ c.out.add('return;');
1248
+ break;
1249
+ default:
1250
+ c.error(node, 'unsupported statement');
1251
+ }
1252
+ }
1253
+
1254
+ /**
1255
+ * `let x = expr;` or `var x: T = expr;` or `var x: T;`
1256
+ */
1257
+ function emitVariableOrValueStatement(c, node) {
1258
+ const var_decl = namedChildByType(node, 'variable_decl');
1259
+ const opt_ident_direct = namedChildByType(node, 'optionally_typed_ident');
1260
+ const expr_node = namedChildByType(node, 'expression');
1261
+
1262
+ /** @type {'let' | 'const'} */
1263
+ let kind = 'let';
1264
+ let opt_ident = null;
1265
+ let template = null;
1266
+
1267
+ if (var_decl !== null) {
1268
+ // WGSL `var` is the mutable form → JS `let`.
1269
+ kind = 'let';
1270
+ opt_ident = namedChildByType(var_decl, 'optionally_typed_ident');
1271
+ template = namedChildByType(var_decl, 'template_list');
1272
+ } else {
1273
+ // WGSL `let` and `const` are both immutable bindings → JS `const`.
1274
+ // Tree-sitter exposes the keyword as an unnamed leading token; read it from the source.
1275
+ kind = 'const';
1276
+ opt_ident = opt_ident_direct;
1277
+ }
1278
+
1279
+ const ident = namedChildByType(opt_ident, 'ident');
1280
+ const type_spec = namedChildByType(opt_ident, 'type_specifier');
1281
+ const name = ident.text;
1282
+ let type = type_spec !== null ? parseTypeSpecifier(type_spec) : T_UNKNOWN;
1283
+
1284
+ if (expr_node !== null) {
1285
+ const expr = compileExpression(c, expr_node);
1286
+ // Infer the type from the RHS when no explicit annotation is present. A bare integer
1287
+ // literal concretises to i32 here, as WGSL does for `let x = 3;`.
1288
+ if (type === T_UNKNOWN || type.kind === 'unknown') {
1289
+ type = expr.abstract_int === true ? T_I32 : expr.type;
1290
+ }
1291
+ c.scope.declare(name, type);
1292
+ c.out.add(`${kind} ${identToJs(name)} = ${expr.code};`);
1293
+ } else {
1294
+ c.scope.declare(name, type);
1295
+ c.out.add(`${kind} ${identToJs(name)} = ${defaultValueForType(type)};`);
1296
+ }
1297
+ }
1298
+
1299
+ /**
1300
+ * The `wgsl.*` helper a compound arithmetic assignment has to go through.
1301
+ *
1302
+ * The same selection the binary operators make, made again here off the LHS type — a compound
1303
+ * assignment's result type IS the LHS type. Without it `x *= y` on a u32 computed the product in
1304
+ * f64 and left the truncation to the write, and a 32-bit product passes 2^53 as soon as both
1305
+ * factors are large: the low bits fall off, which is precisely the part an integer hash keeps.
1306
+ * `hash_lowbias32`, written with `*=`, then disagreed with the CPU twin every CPU-built hash table
1307
+ * is probed with.
1308
+ *
1309
+ * @param {string} helper the untyped helper name
1310
+ * @param {string} op_text the compound operator, e.g. `*=`
1311
+ * @param {WgslType} lhs_type
1312
+ * @returns {string}
1313
+ */
1314
+ function compoundArithmeticHelper(helper, op_text, lhs_compiled, rhs_compiled) {
1315
+ const binary_op = op_text.slice(0, -1);
1316
+
1317
+ const arith_type = inferBinaryArithResultType(lhs_compiled.type, rhs_compiled.type);
1318
+
1319
+ const wrapping = INTEGER_WRAPPING_OP[binary_op];
1320
+
1321
+ if (wrapping !== undefined && isIntegerType(arith_type)) {
1322
+ return `${wrapping}_${integerScalarName(arith_type)}`;
1323
+ }
1324
+
1325
+ if (op_text === '/=' && integerDivision(lhs_compiled, rhs_compiled)) {
1326
+ // WGSL `/` on integers is truncated integer division, as at the binary site
1327
+ return 'idiv';
1328
+ }
1329
+
1330
+ const f32_scalar = F32_SCALAR_OP[binary_op];
1331
+
1332
+ if (f32_scalar !== undefined && isScalarF32(arith_type)) {
1333
+ return f32_scalar;
1334
+ }
1335
+
1336
+ return helper;
1337
+ }
1338
+
1339
+ /**
1340
+ * Assignment / compound assignment / increment / decrement.
1341
+ */
1342
+ function emitVariableUpdatingStatement(c, node) {
1343
+ const inner = node.namedChildren[0];
1344
+ if (inner.type === 'assignment_statement') {
1345
+ const lhs = namedChildByType(inner, 'lhs_expression');
1346
+ const expr = namedChildByType(inner, 'expression');
1347
+
1348
+ // The compound assignment operator sits between the LHS and the RHS as an unnamed token.
1349
+ const op_text = textBetween(inner, lhs, expr).trim();
1350
+
1351
+ const lhs_compiled = compileLhs(c, lhs);
1352
+ const rhs_compiled = compileExpression(c, expr);
1353
+
1354
+ if (op_text === '=' || op_text === '') {
1355
+ c.out.add(emitWriteStatement(lhs_compiled, rhs_compiled.code));
1356
+ return;
1357
+ }
1358
+
1359
+ const arith = {
1360
+ '+=': 'add', '-=': 'sub', '*=': 'mul', '/=': 'div', '%=': 'rem',
1361
+ };
1362
+ if (arith.hasOwnProperty(op_text)) {
1363
+ const helper = compoundArithmeticHelper(arith[op_text], op_text, lhs_compiled, rhs_compiled);
1364
+
1365
+ c.out.add(emitWriteStatement(lhs_compiled, `wgsl.${helper}(${lhs_compiled.code}, ${rhs_compiled.code})`));
1366
+ return;
1367
+ }
1368
+
1369
+ // Bitwise / shift compound assignment, routed exactly like the binary operators above:
1370
+ // through the element-wise helpers for a vec/mat or bool LHS, and for any u32 operand. The
1371
+ // WGSL idiom for a hash is `x ^= x >> 16u`, so this is the spelling that matters most.
1372
+ const bitwise_helper = BITWISE_HELPER[op_text.slice(0, -1)];
1373
+ if (bitwise_helper !== undefined && (
1374
+ isContainerType(lhs_compiled.type)
1375
+ || isScalarBool(lhs_compiled.type)
1376
+ || isScalarUnsigned(lhs_compiled.type)
1377
+ || isScalarUnsigned(rhs_compiled.type)
1378
+ )) {
1379
+ c.out.add(emitWriteStatement(lhs_compiled, `wgsl.${bitwise_helper}(${lhs_compiled.code}, ${rhs_compiled.code})`));
1380
+ return;
1381
+ }
1382
+ c.out.add(`${lhs_compiled.code} ${op_text} ${rhs_compiled.code};`);
1383
+ return;
1384
+ }
1385
+ if (inner.type === 'increment_statement') {
1386
+ const lhs = namedChildByType(inner, 'lhs_expression');
1387
+ const lhs_compiled = compileLhs(c, lhs);
1388
+ c.out.add(emitWriteStatement(lhs_compiled, `wgsl.add(${lhs_compiled.code}, 1)`));
1389
+ return;
1390
+ }
1391
+ if (inner.type === 'decrement_statement') {
1392
+ const lhs = namedChildByType(inner, 'lhs_expression');
1393
+ const lhs_compiled = compileLhs(c, lhs);
1394
+ c.out.add(emitWriteStatement(lhs_compiled, `wgsl.sub(${lhs_compiled.code}, 1)`));
1395
+ return;
1396
+ }
1397
+ c.error(inner, `unsupported variable_updating_statement: ${inner.type}`);
1398
+ }
1399
+
1400
+ /**
1401
+ * Emit a write to an LHS. Most LHS expressions are plain JS LValues (`x`, `arr[i]`, `obj.f`) and
1402
+ * are written with `=`. Mat-column LHS — `m[i]` for a mat — is special: the compiler emits it as
1403
+ * `wgsl.mat_col(m, i, rows)`, which is a typed-array view (a function call result, not assignable).
1404
+ * To write through the view we use `Float32Array.prototype.set(rhs)` instead, which copies into
1405
+ * the underlying matrix storage in place.
1406
+ *
1407
+ * @param {{ code: string }} lhs_compiled
1408
+ * @param {string} rhs_code
1409
+ * @returns {string}
1410
+ */
1411
+ function emitWriteStatement(lhs_compiled, rhs_code) {
1412
+ // Only the bare `wgsl.mat_col(...)` form (no chained `[i]` / `.x`) needs `.set()` — that's a
1413
+ // typed-array view, an unassignable function-call result. Anything chained off it (e.g.
1414
+ // `wgsl.mat_col(...)[3]` or `wgsl.mat_col(...).x` becoming `[i]`) is a scalar slot and must
1415
+ // use plain `=`.
1416
+ if (lhs_compiled.code.startsWith('wgsl.mat_col(') && lhs_compiled.code.endsWith(')')) {
1417
+ return `${lhs_compiled.code}.set(${rhs_code});`;
1418
+ }
1419
+ // `*p = v` has to reach the caller's object; assigning would only rebind the parameter.
1420
+ if (lhs_compiled.through_pointer === true) {
1421
+ return `${lhs_compiled.code} = wgsl.store_ptr(${lhs_compiled.code}, ${rhs_code});`;
1422
+ }
1423
+ return `${lhs_compiled.code} = ${rhs_code};`;
1424
+ }
1425
+
1426
+ function emitReturnStatement(c, node) {
1427
+ const expr = namedChildByType(node, 'expression');
1428
+ if (expr === null) {
1429
+ c.out.add('return;');
1430
+ } else {
1431
+ const e = compileExpression(c, expr);
1432
+ c.out.add(`return ${e.code};`);
1433
+ }
1434
+ }
1435
+
1436
+ function emitIfStatement(c, node) {
1437
+ const if_clause = namedChildByType(node, 'if_clause');
1438
+ const cond = namedChildByType(if_clause, 'expression');
1439
+ const if_body = namedChildByType(if_clause, 'compound_statement');
1440
+
1441
+ const cond_compiled = compileExpression(c, cond);
1442
+ c.out.add(`if (${cond_compiled.code}) {`);
1443
+ c.out.indent();
1444
+ c.scope = c.scope.push();
1445
+ emitCompoundStatementBody(c, if_body);
1446
+ c.scope = c.scope.parent;
1447
+ c.out.dedent();
1448
+ c.out.add('}');
1449
+
1450
+ // else-if and else clauses.
1451
+ for (const child of node.namedChildren) {
1452
+ if (child.type === 'else_if_clause') {
1453
+ const eif_cond = namedChildByType(child, 'expression');
1454
+ const eif_body = namedChildByType(child, 'compound_statement');
1455
+ const eif_compiled = compileExpression(c, eif_cond);
1456
+ c.out.add(`else if (${eif_compiled.code}) {`);
1457
+ c.out.indent();
1458
+ c.scope = c.scope.push();
1459
+ emitCompoundStatementBody(c, eif_body);
1460
+ c.scope = c.scope.parent;
1461
+ c.out.dedent();
1462
+ c.out.add('}');
1463
+ } else if (child.type === 'else_clause') {
1464
+ const else_body = namedChildByType(child, 'compound_statement');
1465
+ // else_body may instead be an if_statement (else-if shorthand).
1466
+ const nested_if = namedChildByType(child, 'if_statement');
1467
+ if (else_body !== null) {
1468
+ c.out.add('else {');
1469
+ c.out.indent();
1470
+ c.scope = c.scope.push();
1471
+ emitCompoundStatementBody(c, else_body);
1472
+ c.scope = c.scope.parent;
1473
+ c.out.dedent();
1474
+ c.out.add('}');
1475
+ } else if (nested_if !== null) {
1476
+ c.out.add('else');
1477
+ emitIfStatement(c, nested_if);
1478
+ }
1479
+ }
1480
+ }
1481
+ }
1482
+
1483
+ function emitForStatement(c, node) {
1484
+ const for_header = namedChildByType(node, 'for_header');
1485
+ const for_init = namedChildByType(for_header, 'for_init');
1486
+ const cond_expr = namedChildByType(for_header, 'expression');
1487
+ const for_update = namedChildByType(for_header, 'for_update');
1488
+ const body = namedChildByType(node, 'compound_statement');
1489
+
1490
+ c.scope = c.scope.push();
1491
+
1492
+ // Init / cond / update parts.
1493
+ let init_str = '';
1494
+ if (for_init !== null) {
1495
+ // Tree-sitter wraps it in a variable_or_value_statement; capture the emission as text.
1496
+ const sub = new Compiler();
1497
+ sub.scope = c.scope;
1498
+ sub.structs = c.structs;
1499
+ sub.functions = c.functions;
1500
+ const inner = for_init.namedChildren[0];
1501
+ emitForInitInline(sub, inner);
1502
+ init_str = sub.out.build().trimEnd();
1503
+ if (init_str.endsWith(';')) init_str = init_str.slice(0, -1);
1504
+ }
1505
+
1506
+ const cond_str = cond_expr !== null ? compileExpression(c, cond_expr).code : '';
1507
+
1508
+ let update_str = '';
1509
+ if (for_update !== null) {
1510
+ const inner = for_update.namedChildren[0];
1511
+ update_str = emitForUpdateInline(c, inner);
1512
+ }
1513
+
1514
+ c.out.add(`for (${init_str}; ${cond_str}; ${update_str}) {`);
1515
+ c.out.indent();
1516
+ // `continue` inside this loop targets this loop, not an outer `loop`'s continuing block
1517
+ const saved_continue_label = c.continue_label;
1518
+ c.continue_label = null;
1519
+ emitCompoundStatementBody(c, body);
1520
+ c.continue_label = saved_continue_label;
1521
+ c.out.dedent();
1522
+ c.out.add('}');
1523
+
1524
+ c.scope = c.scope.parent;
1525
+ }
1526
+
1527
+ /**
1528
+ * Emit a `variable_or_value_statement` inline (as a single line with no trailing newline structure).
1529
+ * Used by `for(init; ...)`.
1530
+ */
1531
+ function emitForInitInline(c, node) {
1532
+ if (node.type === 'variable_or_value_statement') {
1533
+ const var_decl = node.namedChildren[0] && node.namedChildren[0].type === 'variable_decl'
1534
+ ? node.namedChildren[0]
1535
+ : null;
1536
+ const opt_ident = namedChildByType(var_decl !== null ? var_decl : node, 'optionally_typed_ident');
1537
+ const expr_node = namedChildByType(node, 'expression');
1538
+ const ident = namedChildByType(opt_ident, 'ident');
1539
+ const type_spec = namedChildByType(opt_ident, 'type_specifier');
1540
+ const name = ident.text;
1541
+ const init = expr_node !== null ? compileExpression(c, expr_node) : null;
1542
+ let type = type_spec !== null ? parseTypeSpecifier(type_spec) : T_UNKNOWN;
1543
+ if (type.kind === 'unknown' && init !== null) {
1544
+ // `for (var i = 0; ...)`: a bare integer literal concretises to i32, as in a `let`
1545
+ type = init.abstract_int === true ? T_I32 : init.type;
1546
+ }
1547
+ c.scope.declare(name, type);
1548
+ const value = init !== null ? init.code : defaultValueForType(type);
1549
+ // `var i = …` (mutable, common in `for (var i = 0; ...; i = i + 1)`) → JS `let`.
1550
+ // `let i = …` / `const i = …` (immutable) → JS `const`.
1551
+ const kind = var_decl !== null ? 'let' : 'const';
1552
+ c.out.add(`${kind} ${identToJs(name)} = ${value};`);
1553
+ return;
1554
+ }
1555
+ if (node.type === 'variable_updating_statement') {
1556
+ emitVariableUpdatingStatement(c, node);
1557
+ return;
1558
+ }
1559
+ if (node.type === 'func_call_statement') {
1560
+ emitFunctionCallStatement(c, node);
1561
+ return;
1562
+ }
1563
+ }
1564
+
1565
+ /**
1566
+ * @returns {string} JS update expression (no semicolon).
1567
+ */
1568
+ function emitForUpdateInline(c, node) {
1569
+ if (node.type === 'variable_updating_statement') {
1570
+ const inner = node.namedChildren[0];
1571
+ if (inner.type === 'assignment_statement') {
1572
+ const lhs = namedChildByType(inner, 'lhs_expression');
1573
+ const expr = namedChildByType(inner, 'expression');
1574
+ const op_text = textBetween(inner, lhs, expr).trim();
1575
+ const lhs_compiled = compileLhs(c, lhs);
1576
+ const rhs_compiled = compileExpression(c, expr);
1577
+ if (op_text === '=' || op_text === '') {
1578
+ if (lhs_compiled.through_pointer === true) {
1579
+ return `${lhs_compiled.code} = wgsl.store_ptr(${lhs_compiled.code}, ${rhs_compiled.code})`;
1580
+ }
1581
+ return `${lhs_compiled.code} = ${rhs_compiled.code}`;
1582
+ }
1583
+ const arith = { '+=': 'add', '-=': 'sub', '*=': 'mul', '/=': 'div', '%=': 'rem' };
1584
+ if (arith.hasOwnProperty(op_text)) {
1585
+ const helper = compoundArithmeticHelper(arith[op_text], op_text, lhs_compiled, rhs_compiled);
1586
+
1587
+ if (lhs_compiled.through_pointer === true) {
1588
+ return `${lhs_compiled.code} = wgsl.store_ptr(${lhs_compiled.code}, wgsl.${helper}(${lhs_compiled.code}, ${rhs_compiled.code}))`;
1589
+ }
1590
+ return `${lhs_compiled.code} = wgsl.${helper}(${lhs_compiled.code}, ${rhs_compiled.code})`;
1591
+ }
1592
+ return `${lhs_compiled.code} ${op_text} ${rhs_compiled.code}`;
1593
+ }
1594
+ if (inner.type === 'increment_statement') {
1595
+ const lhs = namedChildByType(inner, 'lhs_expression');
1596
+ const lhs_compiled = compileLhs(c, lhs);
1597
+ return `${lhs_compiled.code} = wgsl.add(${lhs_compiled.code}, 1)`;
1598
+ }
1599
+ if (inner.type === 'decrement_statement') {
1600
+ const lhs = namedChildByType(inner, 'lhs_expression');
1601
+ const lhs_compiled = compileLhs(c, lhs);
1602
+ return `${lhs_compiled.code} = wgsl.sub(${lhs_compiled.code}, 1)`;
1603
+ }
1604
+ }
1605
+ return '';
1606
+ }
1607
+
1608
+ function emitWhileStatement(c, node) {
1609
+ const cond = namedChildByType(node, 'expression');
1610
+ const body = namedChildByType(node, 'compound_statement');
1611
+ const cc = compileExpression(c, cond);
1612
+ c.out.add(`while (${cc.code}) {`);
1613
+ c.out.indent();
1614
+ c.scope = c.scope.push();
1615
+ // `continue` inside this loop targets this loop, not an outer `loop`'s continuing block
1616
+ const saved_continue_label = c.continue_label;
1617
+ c.continue_label = null;
1618
+ emitCompoundStatementBody(c, body);
1619
+ c.continue_label = saved_continue_label;
1620
+ c.scope = c.scope.parent;
1621
+ c.out.dedent();
1622
+ c.out.add('}');
1623
+ }
1624
+
1625
+ function emitLoopStatement(c, node) {
1626
+ // NOTE: the grammar puts the loop's `statement` children and the optional
1627
+ // `continuing_statement` directly on the `loop_statement` node (no
1628
+ // `compound_statement` wrapper); emitCompoundStatementBody visits only the
1629
+ // `statement` children, which is exactly the loop body.
1630
+ const body = node;
1631
+ const continuing = namedChildByType(node, 'continuing_statement');
1632
+
1633
+ const saved_continue_label = c.continue_label;
1634
+
1635
+ c.out.add('while (true) {');
1636
+ c.out.indent();
1637
+ c.scope = c.scope.push();
1638
+
1639
+ if (continuing === null) {
1640
+
1641
+ // no continuing block: JS `continue` already has the right semantics
1642
+ c.continue_label = null;
1643
+ emitCompoundStatementBody(c, body);
1644
+
1645
+ } else {
1646
+
1647
+ // WGSL `continue` transfers control INTO the `continuing` block. Emit the loop
1648
+ // body inside a labeled block: `continue` becomes `break <label>`, which lands on
1649
+ // the continuing code that follows the block (still inside the `while`).
1650
+ const label = `loop_body_${c.loop_label_counter++}`;
1651
+ c.continue_label = label;
1652
+
1653
+ c.out.add(`${label}: {`);
1654
+ c.out.indent();
1655
+ emitCompoundStatementBody(c, body);
1656
+ c.out.dedent();
1657
+ c.out.add('}');
1658
+
1659
+ c.continue_label = null;
1660
+
1661
+ const cont_body = namedChildByType(continuing, 'continuing_compound_statement');
1662
+ if (cont_body !== null) {
1663
+ emitCompoundStatementBody(c, cont_body);
1664
+
1665
+ // `break if expr;` — only legal as the trailing statement of a continuing block.
1666
+ // It is a direct named child of the continuing compound (not wrapped in `statement`),
1667
+ // so emitCompoundStatementBody does not visit it.
1668
+ const break_if = namedChildByType(cont_body, 'break_if_statement');
1669
+ if (break_if !== null) {
1670
+ const break_expr = namedChildByType(break_if, 'expression');
1671
+ const bc = compileExpression(c, break_expr);
1672
+ c.out.add(`if (${bc.code}) { break; }`);
1673
+ }
1674
+ }
1675
+
1676
+ }
1677
+
1678
+ c.continue_label = saved_continue_label;
1679
+ c.scope = c.scope.parent;
1680
+ c.out.dedent();
1681
+ c.out.add('}');
1682
+ }
1683
+
1684
+ /**
1685
+ * Emit a WGSL `switch`.
1686
+ *
1687
+ * Grammar (tree-sitter-wgsl): `switch_statement { expression, switch_body { switch_clause* } }`,
1688
+ * where each `switch_clause` wraps either a `case_clause { case_selectors { case_selector+ },
1689
+ * compound_statement }` or a `default_alone_clause { compound_statement }`. A `case_selector` holds
1690
+ * either an `expression` (a case value) or the `default` keyword.
1691
+ *
1692
+ * WGSL switch has no fall-through — each selected clause runs its body and stops — so we terminate
1693
+ * every clause body with `break;`. Multiple selectors on one clause become stacked JS `case` labels
1694
+ * over a shared body.
1695
+ */
1696
+ function emitSwitchStatement(c, node) {
1697
+ const expr = namedChildByType(node, 'expression');
1698
+ const ec = compileExpression(c, expr);
1699
+ c.out.add(`switch (${ec.code}) {`);
1700
+ c.out.indent();
1701
+
1702
+ const body = namedChildByType(node, 'switch_body');
1703
+ if (body) {
1704
+ for (const clause of namedChildrenByType(body, 'switch_clause')) {
1705
+ const case_clause = namedChildByType(clause, 'case_clause');
1706
+ const default_clause = namedChildByType(clause, 'default_alone_clause');
1707
+ const inner = case_clause ?? default_clause;
1708
+ if (!inner) {
1709
+ continue;
1710
+ }
1711
+
1712
+ if (case_clause) {
1713
+ const case_selectors = namedChildByType(case_clause, 'case_selectors');
1714
+ if (case_selectors) {
1715
+ for (const sel of namedChildrenByType(case_selectors, 'case_selector')) {
1716
+ const sel_expr = namedChildByType(sel, 'expression');
1717
+ if (sel_expr) {
1718
+ c.out.add(`case ${compileExpression(c, sel_expr).code}:`);
1719
+ } else {
1720
+ // a bare `default` used within a case_selectors list
1721
+ c.out.add('default:');
1722
+ }
1723
+ }
1724
+ }
1725
+ } else {
1726
+ c.out.add('default:');
1727
+ }
1728
+
1729
+ // Wrap each clause body in its own JS block. WGSL case clauses are independent scopes,
1730
+ // but JS switch clauses share the switch's block scope — without the braces, `let`
1731
+ // temporaries declared in two clauses collide ("Identifier already declared").
1732
+ const case_body = namedChildByType(inner, 'compound_statement');
1733
+ c.out.add('{');
1734
+ c.out.indent();
1735
+ c.scope = c.scope.push();
1736
+ if (case_body) {
1737
+ emitCompoundStatementBody(c, case_body);
1738
+ }
1739
+ c.out.add('break;');
1740
+ c.scope = c.scope.parent;
1741
+ c.out.dedent();
1742
+ c.out.add('}');
1743
+ }
1744
+ }
1745
+
1746
+ c.out.dedent();
1747
+ c.out.add('}');
1748
+ }
1749
+
1750
+ function emitFunctionCallStatement(c, node) {
1751
+ const call_phrase = namedChildByType(node, 'call_phrase');
1752
+ const r = compileCallPhraseTyped(c, call_phrase);
1753
+ c.out.add(`${r.code};`);
1754
+ }
1755
+
1756
+ // =========================================================================
1757
+ // Expressions
1758
+ // =========================================================================
1759
+
1760
+ /**
1761
+ * Compile an expression node (any wrapper or specific kind).
1762
+ * @param {Compiler} c
1763
+ * @param {Node} node
1764
+ * @returns {{ code: string, type: WgslType }}
1765
+ */
1766
+ function compileExpression(c, node) {
1767
+ const u = unwrapExpression(node);
1768
+
1769
+ // Binary operations
1770
+ switch (u.type) {
1771
+ case 'expression':
1772
+ // tree-sitter-wgsl can leave `&&` / `||` directly under an `expression` node — i.e.
1773
+ // the operator wraps two operands without a more specific short_circuit_*_expression
1774
+ // wrapper around it. With 2 named children the unnamed operator sits between them.
1775
+ return compileBinaryExpression(c, u, '__shortcircuit_unused__', 'raw');
1776
+ case 'relational_expression':
1777
+ return compileBinaryExpression(c, u, 'relational_operator', 'raw');
1778
+ case 'shift_expression':
1779
+ return compileBinaryExpression(c, u, 'shift_operator', 'raw');
1780
+ case 'additive_expression':
1781
+ return compileBinaryExpression(c, u, 'additive_operator', 'arith');
1782
+ case 'multiplicative_expression':
1783
+ return compileBinaryExpression(c, u, 'multiplicative_operator', 'arith');
1784
+ case 'short_circuit_and_expression':
1785
+ case 'short_circuit_or_expression':
1786
+ return compileBinaryExpression(c, u, '__shortcircuit_unused__', 'raw');
1787
+ case 'bitwise_expression':
1788
+ // Top-level WGSL `^` / `&` / `|` operator. The operator is an unnamed token between
1789
+ // the two named operands; compileBinaryExpression's 2-named-children path picks it up.
1790
+ return compileBinaryExpression(c, u, '__bitwise_unused__', 'raw');
1791
+ case 'binary_and_expression':
1792
+ case 'binary_or_expression':
1793
+ case 'binary_xor_expression':
1794
+ // Inner chain nodes from the WGSL grammar (e.g. `a ^ b ^ c` nests as
1795
+ // `binary_xor_expression(binary_xor_expression(a, b), c)`). When 2 named children
1796
+ // appear, the unnamed operator sits between them; the 1-child case is a passthrough.
1797
+ return compileBinaryExpression(c, u, '__bitwise_unused__', 'raw');
1798
+ }
1799
+
1800
+ // Unary
1801
+ if (u.type === 'unary_expression') {
1802
+ return compileUnaryExpression(c, u);
1803
+ }
1804
+
1805
+ // Singular (primary + chained component access)
1806
+ if (u.type === 'singular_expression') {
1807
+ return compileSingularExpression(c, u);
1808
+ }
1809
+
1810
+ // Primary subkinds
1811
+ if (u.type === 'literal' || u.type === 'int_literal' || u.type === 'float_literal' || u.type === 'bool_literal') {
1812
+ // A bare integer literal is WGSL's AbstractInt. Its concrete type comes from context this
1813
+ // compiler does not track, so the type stays unknown, but operator selection still needs
1814
+ // to know it is an integer: see integerDivision().
1815
+ return { code: literalToJs(u.text), type: literalType(u.text), abstract_int: isBareIntLiteral(u.text) };
1816
+ }
1817
+ if (u.type === 'paren_expression') {
1818
+ const inner = namedChildByType(u, 'expression');
1819
+ const e = compileExpression(c, inner);
1820
+ return { code: `(${e.code})`, type: e.type, abstract_int: e.abstract_int };
1821
+ }
1822
+ if (u.type === 'call_expression') {
1823
+ const call_phrase = namedChildByType(u, 'call_phrase');
1824
+ return compileCallPhraseTyped(c, call_phrase);
1825
+ }
1826
+ if (u.type === 'template_elaborated_ident') {
1827
+ const ident = namedChildByType(u, 'ident');
1828
+ const name = ident !== null ? ident.text : u.text;
1829
+ return { code: identToJs(name), type: c.scope.lookup(name) };
1830
+ }
1831
+ if (u.type === 'ident') {
1832
+ return { code: identToJs(u.text), type: c.scope.lookup(u.text) };
1833
+ }
1834
+
1835
+ c.error(u, `unsupported expression: ${u.type}`);
1836
+ }
1837
+
1838
+ /**
1839
+ * Compile a binary expression node. Two grammar shapes are supported:
1840
+ * - 3 named children where the middle child has type `op_type` — used for additive / multiplicative
1841
+ * where the operator is an explicit named node (`additive_operator`, `multiplicative_operator`).
1842
+ * - 2 named children with an unnamed operator token between them — used for relational / shift,
1843
+ * where the operator (e.g. `<`, `>=`, `<<`) is a raw token.
1844
+ *
1845
+ * Mode:
1846
+ * - `'arith'` → use `wgsl.add/sub/mul/div/rem` (handles vectors)
1847
+ * - `'raw'` → emit raw JS operator
1848
+ */
1849
+ function compileBinaryExpression(c, node, op_type, mode) {
1850
+ const named = node.namedChildren;
1851
+ if (named.length === 1) {
1852
+ return compileExpression(c, named[0]);
1853
+ }
1854
+
1855
+ let op_text = null;
1856
+ let left_node;
1857
+ let right_node;
1858
+
1859
+ if (named.length === 3 && named[1].type === op_type) {
1860
+ op_text = named[1].text;
1861
+ left_node = named[0];
1862
+ right_node = named[2];
1863
+ } else if (named.length === 2) {
1864
+ left_node = named[0];
1865
+ right_node = named[1];
1866
+ // tree-sitter-web doesn't surface unnamed children in `node.children`. Extract the
1867
+ // operator by slicing the original text using the operands' source positions.
1868
+ op_text = textBetween(node, left_node, right_node).trim();
1869
+ } else {
1870
+ return { code: node.text, type: T_UNKNOWN };
1871
+ }
1872
+
1873
+ const left = compileExpression(c, left_node);
1874
+ const right = compileExpression(c, right_node);
1875
+
1876
+ if (mode === 'arith') {
1877
+ const helper = ARITHMETIC_OP[op_text];
1878
+ if (helper !== undefined) {
1879
+ // `*` on matrix/vector operands has WGSL-specific algebra (dot-products and
1880
+ // accumulation) that the element-wise `wgsl.mul` doesn't capture. Route to a
1881
+ // dedicated `mNxR_multiply_*` helper when at least one side is a matrix.
1882
+ if (op_text === '*') {
1883
+ const dispatched = dispatchMatrixMul(left, right);
1884
+ if (dispatched !== null) return dispatched;
1885
+ }
1886
+ // WGSL `/` on integer types is truncated integer division. Route through the
1887
+ // integer-truncating helper when WGSL would type the division as integer;
1888
+ // otherwise use float div.
1889
+ let actual_helper = helper;
1890
+ if (op_text === '/' && integerDivision(left, right)) {
1891
+ actual_helper = 'idiv';
1892
+ }
1893
+ // WGSL `+` / `-` / `*` on integer types wrap at 32 bits. JS numbers don't, and the bits
1894
+ // an overflowing f64 drops are the low ones — which silently ruins hashes and PRNGs
1895
+ // (see the wrapping helpers in WGSLLanguageCore.js). Route to the wrapping variant only
1896
+ // when the result type is *known* to be an integer, so anything untyped or float keeps
1897
+ // the plain helper.
1898
+ const arith_type = inferBinaryArithResultType(left.type, right.type);
1899
+ const wrapping = INTEGER_WRAPPING_OP[op_text];
1900
+ if (wrapping !== undefined && isIntegerType(arith_type)) {
1901
+ actual_helper = `${wrapping}_${integerScalarName(arith_type)}`;
1902
+ }
1903
+
1904
+ // Same shape for f32 scalars: only when the result type is KNOWN to be one, so an
1905
+ // AbstractFloat const-expression — which WGSL evaluates at higher precision — is left
1906
+ // alone. A vec is already rounded lane by lane through its Float32Array.
1907
+ const f32_scalar = F32_SCALAR_OP[op_text];
1908
+ if (f32_scalar !== undefined && isScalarF32(arith_type)) {
1909
+ actual_helper = f32_scalar;
1910
+ }
1911
+ return {
1912
+ code: `wgsl.${actual_helper}(${left.code}, ${right.code})`,
1913
+ type: arith_type,
1914
+ // arithmetic on two AbstractInts is still AbstractInt: `(1 + 2) / 2` is 1
1915
+ abstract_int: left.abstract_int === true && right.abstract_int === true,
1916
+ };
1917
+ }
1918
+ }
1919
+
1920
+ // Bitwise (`&` / `|` / `^`) and shift (`<<` / `>>`) operators. Routed through the element-wise
1921
+ // helpers for vec/mat operands (JS raw operators coerce typed arrays to NaN), for bool operands
1922
+ // (raw JS yields 0/1 where WGSL yields a bool), and for *any* u32-typed scalar operand.
1923
+ //
1924
+ // That last one used to be `>>` alone. Every one of these raw JS operators is ToInt32-based and
1925
+ // hands back a signed int32, so on a u32 they go negative the moment bit 31 is involved:
1926
+ // `x << 31u` at x=1 was -2147483648 against the device's 2147483648, and `x ^ y` with the high
1927
+ // bit set was negative too. The helpers normalise with `>>> 0`, which is what WGSL u32 means.
1928
+ //
1929
+ // Deliberately not extended to i32: `bit_and` and friends return an unsigned result, and a
1930
+ // signed operand is exactly the case raw JS already gets right.
1931
+ const bitwise_helper = BITWISE_HELPER[op_text];
1932
+ if (bitwise_helper !== undefined) {
1933
+ if (isContainerType(left.type) || isContainerType(right.type)
1934
+ || isScalarBool(left.type) || isScalarBool(right.type)
1935
+ || isScalarUnsigned(left.type) || isScalarUnsigned(right.type)) {
1936
+ return {
1937
+ code: `wgsl.${bitwise_helper}(${left.code}, ${right.code})`,
1938
+ type: inferRawBinaryResultType(left.type, right.type, op_text),
1939
+ };
1940
+ }
1941
+ }
1942
+
1943
+ // Comparison operators. JS's raw `==` etc. compare TypedArrays by reference; for WGSL
1944
+ // `vec<T>` operands we need element-wise comparison returning a `vec<bool>`.
1945
+ const cmp_helper = COMPARISON_HELPER[op_text];
1946
+ if (cmp_helper !== undefined && (isContainerType(left.type) || isContainerType(right.type))) {
1947
+ return {
1948
+ code: `wgsl.${cmp_helper}(${left.code}, ${right.code})`,
1949
+ type: inferRawBinaryResultType(left.type, right.type, op_text),
1950
+ };
1951
+ }
1952
+
1953
+ return {
1954
+ code: `${left.code} ${op_text} ${right.code}`,
1955
+ type: inferRawBinaryResultType(left.type, right.type, op_text),
1956
+ };
1957
+ }
1958
+
1959
+ /** Map WGSL bitwise/shift operators to language-core element-wise helper names. */
1960
+ const BITWISE_HELPER = {
1961
+ '&': 'bit_and',
1962
+ '|': 'bit_or',
1963
+ '^': 'bit_xor',
1964
+ '<<': 'shl',
1965
+ '>>': 'shr',
1966
+ };
1967
+
1968
+ /** Map WGSL comparison operators to language-core element-wise helper names. */
1969
+ const COMPARISON_HELPER = {
1970
+ '==': 'eq',
1971
+ '!=': 'ne',
1972
+ '<': 'lt',
1973
+ '>': 'gt',
1974
+ '<=': 'le',
1975
+ '>=': 'ge',
1976
+ };
1977
+
1978
+ /** True if `t` is a vector or matrix — operand types that need element-wise dispatch. */
1979
+ function isContainerType(t) {
1980
+ return t && (t.kind === 'vec' || t.kind === 'mat');
1981
+ }
1982
+
1983
+ /** True if `t` is a u32 scalar — needed to route `>>` through the unsigned-shift helper. */
1984
+ function isScalarUnsigned(t) {
1985
+ return t && t.kind === 'primitive' && t.name === 'u32';
1986
+ }
1987
+
1988
+ /** True if `t` is a bool scalar — WGSL `&` / `|` / `^` on bools are logical and stay bool. */
1989
+ function isScalarBool(t) {
1990
+ return t && t.kind === 'primitive' && t.name === 'bool';
1991
+ }
1992
+
1993
+ /** The scalar name (`u32` / `i32`) of an integer type, for picking a wrapping arithmetic helper. */
1994
+ function integerScalarName(t) {
1995
+ if (t.kind === 'primitive') return t.name;
1996
+ return t.scalar;
1997
+ }
1998
+
1999
+ /** True if `t` is an `f32` SCALAR — a vec's lanes round through their Float32Array already. */
2000
+ function isScalarF32(t) {
2001
+ return t !== undefined && t !== null && t.kind === 'primitive' && t.name === 'f32';
2002
+ }
2003
+
2004
+ /** True if `t` is an integer type (scalar or vec/mat of i32/u32). */
2005
+ function isIntegerType(t) {
2006
+ if (!t) return false;
2007
+ if (t.kind === 'primitive') return t.name === 'i32' || t.name === 'u32';
2008
+ if (t.kind === 'vec' || t.kind === 'mat') return t.scalar === 'i32' || t.scalar === 'u32';
2009
+ return false;
2010
+ }
2011
+
2012
+ /** True if the literal's spelling is a bare integer: no suffix, no fraction, no exponent. */
2013
+ function isBareIntLiteral(text) {
2014
+ return /^(0[xX][0-9a-fA-F]+|[0-9]+)$/.test(text.trim());
2015
+ }
2016
+
2017
+ /**
2018
+ * True if WGSL evaluates `left / right` as integer division. Both operands integer-typed is the
2019
+ * obvious case. A bare literal is AbstractInt and takes the other operand's integer type, so
2020
+ * `index / 3` truncates; two bare literals divide as AbstractInt, so `7 / 2` is 3 even where an
2021
+ * f32 is expected. Negation and parentheses keep a literal abstract: `index / -3` and
2022
+ * `index / (3)` truncate too.
2023
+ */
2024
+ function integerDivision(left, right) {
2025
+ const isInt = (operand) => isIntegerType(operand.type) || operand.abstract_int === true;
2026
+ return isInt(left) && isInt(right);
2027
+ }
2028
+
2029
+ /**
2030
+ * Dispatch a WGSL `*` expression to the appropriate matrix/vector helper in the language
2031
+ * core when at least one operand is a matrix. Returns `null` to indicate "fall through to the
2032
+ * element-wise multiply" — used for scalar×scalar, vec×scalar, vec×vec (Hadamard product),
2033
+ * matrix×scalar, etc., which `wgsl.mul` already handles correctly.
2034
+ *
2035
+ * Naming includes the scalar type suffix (`f` / `i` / `u` / `h`), e.g.
2036
+ * `m4x4f_multiply_v4f`, `v3f_multiply_m3x3f`, `m4x4f_multiply_m4x4f`. Unsupported
2037
+ * shapes (e.g. mat3x4 × vec3) produce a runtime `TypeError: wgsl.<name> is not a function`
2038
+ * — adding support is a single new function in WGSLLanguageCore.js.
2039
+ *
2040
+ * @param {{ code: string, type: WgslType }} left
2041
+ * @param {{ code: string, type: WgslType }} right
2042
+ * @returns {{ code: string, type: WgslType } | null}
2043
+ */
2044
+ function dispatchMatrixMul(left, right) {
2045
+ const lt = left.type;
2046
+ const rt = right.type;
2047
+ const isVec = (t) => t && t.kind === 'vec';
2048
+ const isMat = (t) => t && t.kind === 'mat';
2049
+
2050
+ // mat × mat → mat(b.cols, a.rows). Multiplication is defined only when a.cols == b.rows.
2051
+ if (isMat(lt) && isMat(rt)) {
2052
+ const lh = `m${lt.cols}x${lt.rows}${scalarTypeSuffix(lt.scalar)}`;
2053
+ const rh = `m${rt.cols}x${rt.rows}${scalarTypeSuffix(rt.scalar)}`;
2054
+ return {
2055
+ code: `wgsl.${lh}_multiply_${rh}(${left.code}, ${right.code})`,
2056
+ type: { kind: 'mat', cols: rt.cols, rows: lt.rows, scalar: lt.scalar },
2057
+ };
2058
+ }
2059
+
2060
+ // mat × vec → vec(rows). Vec must have length == cols.
2061
+ if (isMat(lt) && isVec(rt)) {
2062
+ const lh = `m${lt.cols}x${lt.rows}${scalarTypeSuffix(lt.scalar)}`;
2063
+ const rh = `v${rt.size}${scalarTypeSuffix(rt.scalar)}`;
2064
+ return {
2065
+ code: `wgsl.${lh}_multiply_${rh}(${left.code}, ${right.code})`,
2066
+ type: { kind: 'vec', size: lt.rows, scalar: lt.scalar },
2067
+ };
2068
+ }
2069
+
2070
+ // vec × mat → vec(cols). Vec acts as a row vector; vec.length must equal rows.
2071
+ if (isVec(lt) && isMat(rt)) {
2072
+ const lh = `v${lt.size}${scalarTypeSuffix(lt.scalar)}`;
2073
+ const rh = `m${rt.cols}x${rt.rows}${scalarTypeSuffix(rt.scalar)}`;
2074
+ return {
2075
+ code: `wgsl.${lh}_multiply_${rh}(${left.code}, ${right.code})`,
2076
+ type: { kind: 'vec', size: rt.cols, scalar: rt.scalar },
2077
+ };
2078
+ }
2079
+
2080
+ return null;
2081
+ }
2082
+
2083
+ /** Scalar type → suffix character used in matrix/vector helper names: f / i / u / h. */
2084
+ function scalarTypeSuffix(scalar) {
2085
+ return { f32: 'f', i32: 'i', u32: 'u', f16: 'h' }[scalar] || 'f';
2086
+ }
2087
+
2088
+ /**
2089
+ * Pick the result type of an element-wise arithmetic op given the operand types.
2090
+ * Vec wins over scalar; matrix wins over scalar; scalar otherwise.
2091
+ */
2092
+ function inferBinaryArithResultType(a, b) {
2093
+ const isVec = (t) => t && t.kind === 'vec';
2094
+ const isMat = (t) => t && t.kind === 'mat';
2095
+ const isPrim = (t) => t && t.kind === 'primitive';
2096
+
2097
+ if (isVec(a)) return a;
2098
+ if (isVec(b)) return b;
2099
+ if (isMat(a)) return a;
2100
+ if (isMat(b)) return b;
2101
+ if (isPrim(a)) return a;
2102
+ if (isPrim(b)) return b;
2103
+ return T_UNKNOWN;
2104
+ }
2105
+
2106
+ /**
2107
+ * Pick the result type of a non-arithmetic binary op (comparison / logical / bitwise / shift).
2108
+ * Comparisons return bool; bitwise and shift preserve the leftmost known integer operand type.
2109
+ */
2110
+ function inferRawBinaryResultType(a, b, op) {
2111
+ const COMPARISON = new Set(['==', '!=', '<', '>', '<=', '>=']);
2112
+ const LOGICAL = new Set(['&&', '||']);
2113
+ if (COMPARISON.has(op) || LOGICAL.has(op)) {
2114
+ return { kind: 'primitive', name: 'bool' };
2115
+ }
2116
+ // Bitwise / shift: propagate the first known integer-ish operand type. This lets `bitcast`
2117
+ // and other downstream consumers see u32/i32 even when the literal on one side is untyped.
2118
+ if (a && a.kind === 'primitive') return a;
2119
+ if (b && b.kind === 'primitive') return b;
2120
+ if (a && a.kind === 'vec') return a;
2121
+ if (b && b.kind === 'vec') return b;
2122
+ return T_UNKNOWN;
2123
+ }
2124
+
2125
+ function compileUnaryExpression(c, node) {
2126
+ const named = node.namedChildren;
2127
+ const prefix = textBeforeFirstNamed(node).trim();
2128
+
2129
+ if (prefix === '') {
2130
+ return compileExpression(c, named[0]);
2131
+ }
2132
+
2133
+ const operand = compileExpression(c, named[named.length - 1]);
2134
+
2135
+ if (prefix === '-') return { code: `wgsl.neg(${operand.code})`, type: operand.type, abstract_int: operand.abstract_int };
2136
+ if (prefix === '!') return { code: `!${operand.code}`, type: operand.type };
2137
+ if (prefix === '~') return { code: `wgsl.not(${operand.code})`, type: operand.type };
2138
+ if (prefix === '*' || prefix === '&') return { code: operand.code, type: operand.type };
2139
+
2140
+ return { code: `${prefix}${operand.code}`, type: operand.type };
2141
+ }
2142
+
2143
+ function compileSingularExpression(c, node) {
2144
+ const named = node.namedChildren;
2145
+ const head = named[0];
2146
+ const head_result = head.type === 'primary_expression'
2147
+ ? compileExpression(c, unwrapExpression(head))
2148
+ : compileExpression(c, head);
2149
+
2150
+ let code = head_result.code;
2151
+ let type = head_result.type;
2152
+
2153
+ for (let i = 1; i < named.length; i++) {
2154
+ const spec = named[i];
2155
+ if (spec.type !== 'component_or_swizzle_specifier') break;
2156
+ const next = applyAccessSpecifier(c, spec, code, type);
2157
+ code = next.code;
2158
+ type = next.type;
2159
+ }
2160
+
2161
+ // a bare literal reached through a singular expression is still AbstractInt; anything with an
2162
+ // access specifier on it is not a literal
2163
+ return { code, type, abstract_int: named.length === 1 ? head_result.abstract_int : undefined };
2164
+ }
2165
+
2166
+ /**
2167
+ * Apply a `.member`, `.swizzle`, or `[index]` access to an expression that has already been
2168
+ * compiled to `lhs_code` of type `lhs_type`.
2169
+ */
2170
+ function applyAccessSpecifier(c, node, lhs_code, lhs_type) {
2171
+ // tree-sitter-wgsl groups chained access like `[i].x` (or `.foo[i]`) as a SINGLE outer
2172
+ // `component_or_swizzle_specifier` whose first named child is the immediate access (an
2173
+ // `expression` for `[]` or a `member_ident` for `.field`) and whose second named child
2174
+ // is a NESTED `component_or_swizzle_specifier` for the rest of the chain. We apply the
2175
+ // immediate access first, then recurse into any nested specifier.
2176
+ let code = lhs_code;
2177
+ let type = lhs_type;
2178
+
2179
+ const member_ident = namedChildByType(node, 'member_ident');
2180
+ if (member_ident !== null) {
2181
+ const r = applyMemberAccess(c, member_ident.text, code, type);
2182
+ code = r.code;
2183
+ type = r.type;
2184
+ } else {
2185
+ const expr = namedChildByType(node, 'expression');
2186
+ if (expr !== null) {
2187
+ const e = compileExpression(c, expr);
2188
+ // Matrices are stored as flat column-major typed arrays, so the bare `m[i]`
2189
+ // would index a scalar — route through `wgsl.mat_col` to get the column as a vec.
2190
+ if (type && type.kind === 'mat') {
2191
+ code = `wgsl.mat_col(${code}, ${e.code}, ${type.rows})`;
2192
+ type = { kind: 'vec', size: type.rows, scalar: type.scalar };
2193
+ } else {
2194
+ code = `${code}[${e.code}]`;
2195
+ if (type && type.kind === 'array') type = type.element;
2196
+ else if (type && type.kind === 'vec') type = { kind: 'primitive', name: type.scalar };
2197
+ else type = T_UNKNOWN;
2198
+ }
2199
+ }
2200
+ }
2201
+
2202
+ const nested = namedChildByType(node, 'component_or_swizzle_specifier');
2203
+ if (nested !== null) {
2204
+ const r = applyAccessSpecifier(c, nested, code, type);
2205
+ code = r.code;
2206
+ type = r.type;
2207
+ }
2208
+
2209
+ return { code, type };
2210
+ }
2211
+
2212
+ /** Apply a `.field` / `.swizzle` access to an already-compiled expression of `lhs_type`. */
2213
+ function applyMemberAccess(c, name, lhs_code, lhs_type) {
2214
+ if (lhs_type !== null && lhs_type !== undefined && lhs_type.kind === 'vec' && isSwizzlePattern(name)) {
2215
+ if (name.length === 1) {
2216
+ return {
2217
+ code: `${lhs_code}[${SWIZZLE_INDEX[name]}]`,
2218
+ type: { kind: 'primitive', name: lhs_type.scalar },
2219
+ };
2220
+ }
2221
+ const new_size = name.length;
2222
+ const ctor = vecAliasName(new_size, lhs_type.scalar);
2223
+ const elements = Array.from(name).map(ch => `${lhs_code}[${SWIZZLE_INDEX[ch]}]`);
2224
+ return {
2225
+ code: `wgsl.${ctor}(${elements.join(', ')})`,
2226
+ type: { kind: 'vec', size: new_size, scalar: lhs_type.scalar },
2227
+ };
2228
+ }
2229
+ if (lhs_type !== null && lhs_type !== undefined && lhs_type.kind === 'struct') {
2230
+ const struct_info = c.structs.get(lhs_type.name);
2231
+ if (struct_info !== undefined) {
2232
+ const field = struct_info.fields.find(f => f.name === name);
2233
+ if (field !== undefined) {
2234
+ return { code: `${lhs_code}.${name}`, type: field.type };
2235
+ }
2236
+ }
2237
+ }
2238
+ return { code: `${lhs_code}.${name}`, type: T_UNKNOWN };
2239
+ }
2240
+
2241
+ function isSwizzlePattern(name) {
2242
+ if (name.length === 0 || name.length > 4) return false;
2243
+ for (const ch of name) {
2244
+ if (!SWIZZLE_LETTERS.has(ch)) return false;
2245
+ }
2246
+ return true;
2247
+ }
2248
+
2249
+ /**
2250
+ * Compile a `call_phrase` and return both the JS code and the inferred result type.
2251
+ *
2252
+ * Special cases:
2253
+ * - `vec3<f32>(a, b, c)` → `wgsl.vec3f(a, b, c)` (vec result)
2254
+ * - `f32(x)` → `wgsl.f32(x)` (scalar result)
2255
+ * - WGSL builtin (mix, clamp, dot, length, ...) → `wgsl.<name>(...)` (best-effort type)
2256
+ * - User function → `name(...)` (uses declared return type)
2257
+ *
2258
+ * @returns {{ code: string, type: WgslType }}
2259
+ */
2260
+ function compileCallPhraseTyped(c, node) {
2261
+ const ident_node = namedChildByType(node, 'template_elaborated_ident');
2262
+ const arg_list = namedChildByType(node, 'argument_expression_list');
2263
+
2264
+ const ident_inner = namedChildByType(ident_node, 'ident');
2265
+ const callee_name = ident_inner.text;
2266
+ const template = namedChildByType(ident_node, 'template_list');
2267
+
2268
+ /** @type {Array<{ code: string, type: WgslType }>} */
2269
+ const arg_results = [];
2270
+ if (arg_list !== null) {
2271
+ const comma_list = namedChildByType(arg_list, 'expression_comma_list');
2272
+ if (comma_list !== null) {
2273
+ for (const arg of namedChildrenByType(comma_list, 'expression')) {
2274
+ arg_results.push(compileExpression(c, arg));
2275
+ }
2276
+ }
2277
+ }
2278
+ const args = arg_results.map(a => a.code);
2279
+
2280
+ // 1) Vec aliases: vec3f, vec4i, vec2h, etc.
2281
+ if (VECTOR_ALIASES.hasOwnProperty(callee_name)) {
2282
+ const a = VECTOR_ALIASES[callee_name];
2283
+ return {
2284
+ code: `wgsl.${callee_name}(${args.join(', ')})`,
2285
+ type: { kind: 'vec', size: a.size, scalar: a.scalar },
2286
+ };
2287
+ }
2288
+ // 2) Templated vec: vec3<f32>(...).
2289
+ if (callee_name === 'vec2' || callee_name === 'vec3' || callee_name === 'vec4') {
2290
+ const size = parseInt(callee_name.slice(3));
2291
+ let scalar;
2292
+ if (template !== null) {
2293
+ const targs = extractTemplateArgs(template);
2294
+ if (targs.length > 0) scalar = targs[0];
2295
+ }
2296
+ if (scalar === undefined) {
2297
+ // No explicit template — infer the component type from the arguments, mirroring
2298
+ // WGSL's overload resolution. e.g. `vec4(some_u32)` is `vec4<u32>`, not `vec4<f32>`.
2299
+ for (const a of arg_results) {
2300
+ const t = a.type;
2301
+ if (t && t.kind === 'primitive' && t.name !== 'bool') { scalar = t.name; break; }
2302
+ if (t && (t.kind === 'vec' || t.kind === 'mat')) { scalar = t.scalar; break; }
2303
+ }
2304
+ if (scalar === undefined) scalar = 'f32';
2305
+ }
2306
+ return {
2307
+ code: `wgsl.${vecAliasName(size, scalar)}(${args.join(', ')})`,
2308
+ type: { kind: 'vec', size, scalar },
2309
+ };
2310
+ }
2311
+ // 3) Matrix constructors.
2312
+ {
2313
+ const m = callee_name.match(/^mat(\d)x(\d)([ifh]?)$/);
2314
+ if (m !== null) {
2315
+ const cols = parseInt(m[1]);
2316
+ const rows = parseInt(m[2]);
2317
+ const suffix = m[3];
2318
+ let scalar;
2319
+ if (suffix === 'f') scalar = 'f32';
2320
+ else if (suffix === 'i') scalar = 'i32';
2321
+ else if (suffix === 'h') scalar = 'f16';
2322
+ else if (template !== null) {
2323
+ const targs = extractTemplateArgs(template);
2324
+ scalar = targs[0] || 'f32';
2325
+ } else {
2326
+ scalar = 'f32';
2327
+ }
2328
+ const fn_suffix = suffix !== '' ? '' : ({ f32: 'f', i32: 'i', f16: 'h' }[scalar] || 'f');
2329
+ return {
2330
+ code: `wgsl.${callee_name}${fn_suffix}(${args.join(', ')})`,
2331
+ type: { kind: 'mat', cols, rows, scalar },
2332
+ };
2333
+ }
2334
+ }
2335
+
2336
+ // 4) Scalar casts: f32(x), i32(x), u32(x), f16(x), bool(x).
2337
+ if (PRIMITIVE_NAMES.has(callee_name)) {
2338
+ return {
2339
+ code: `wgsl.${callee_name}(${args.join(', ')})`,
2340
+ type: { kind: 'primitive', name: callee_name },
2341
+ };
2342
+ }
2343
+
2344
+ // 5) `bitcast<T>(x)` — JS can't tell a u32 from an f32 by value alone, so we emit the
2345
+ // source type alongside the target. The compiler infers source from the argument's tracked
2346
+ // type; if that's unknown the runtime falls back to a heuristic.
2347
+ if (callee_name === 'bitcast') {
2348
+ let target = 'f32';
2349
+ if (template !== null) {
2350
+ const targs = extractTemplateArgs(template);
2351
+ if (targs.length > 0) target = targs[0];
2352
+ }
2353
+ const arg_type = arg_results[0] !== undefined ? arg_results[0].type : null;
2354
+ let source = null;
2355
+ if (arg_type) {
2356
+ if (arg_type.kind === 'primitive') source = arg_type.name;
2357
+ else if (arg_type.kind === 'vec') source = arg_type.scalar;
2358
+ }
2359
+ const source_arg = source !== null ? `, ${JSON.stringify(source)}` : '';
2360
+ // Parse the target string: `vec3<u32>` etc. become a vec type so that downstream
2361
+ // swizzle/component access compiles correctly. Bare `f32` / `u32` / `i32` stay primitive.
2362
+ let resultType;
2363
+ const vec_match = target.match(/^vec(\d)<([^>]+)>$/);
2364
+ if (vec_match !== null) {
2365
+ resultType = { kind: 'vec', size: parseInt(vec_match[1]), scalar: vec_match[2] };
2366
+ } else {
2367
+ resultType = { kind: 'primitive', name: target };
2368
+ }
2369
+ return {
2370
+ code: `wgsl.bitcast(${args[0]}, ${JSON.stringify(target)}${source_arg})`,
2371
+ type: resultType,
2372
+ };
2373
+ }
2374
+
2375
+ // 6) array / array<T, N> constructor.
2376
+ if (callee_name === 'array') {
2377
+ return { code: `[${args.join(', ')}]`, type: T_UNKNOWN };
2378
+ }
2379
+
2380
+ // 7) Struct constructor.
2381
+ if (c.structs.has(callee_name)) {
2382
+ const info = c.structs.get(callee_name);
2383
+ const parts = [`(() => { const __s__ = new ${identToJs(callee_name)}();`];
2384
+ for (let i = 0; i < info.fields.length && i < args.length; i++) {
2385
+ parts.push(`__s__.${info.fields[i].name} = ${args[i]};`);
2386
+ }
2387
+ parts.push(`return __s__; })()`);
2388
+ return { code: parts.join(' '), type: { kind: 'struct', name: callee_name } };
2389
+ }
2390
+
2391
+ // 8) User-defined function.
2392
+ if (c.functions.has(callee_name)) {
2393
+ return {
2394
+ code: `${identToJs(callee_name)}(${args.join(', ')})`,
2395
+ type: c.functions.get(callee_name).returnType,
2396
+ };
2397
+ }
2398
+
2399
+ // 9) WGSL builtins — best-effort type inference for common helpers.
2400
+ //
2401
+ // A few of them mean different things on i32 and on u32, and the operand type is the only
2402
+ // thing that says which — the same selection the arithmetic operators make.
2403
+ if (INTEGER_TYPED_BUILTIN.has(callee_name)) {
2404
+ const operand_type = arg_results[0] === undefined ? undefined : arg_results[0].type;
2405
+
2406
+ if (isIntegerType(operand_type)) {
2407
+ return {
2408
+ code: `wgsl.${callee_name}_${integerScalarName(operand_type)}(${args.join(', ')})`,
2409
+ type: inferBuiltinReturnType(callee_name, arg_results),
2410
+ };
2411
+ }
2412
+ }
2413
+
2414
+ return {
2415
+ code: `wgsl.${callee_name}(${args.join(', ')})`,
2416
+ type: inferBuiltinReturnType(callee_name, arg_results),
2417
+ };
2418
+ }
2419
+
2420
+ /**
2421
+ * Builtins whose answer depends on whether the operand is i32 or u32, dispatched to a
2422
+ * `<name>_i32` / `<name>_u32` pair in the runtime core.
2423
+ *
2424
+ * `abs` wraps at the most negative i32 and is the identity on u32; `firstLeadingBit` scans for the
2425
+ * most significant bit unlike the sign bit on i32 and for the most significant set bit on u32, which
2426
+ * are different functions rather than the same one read differently. Taking the JS meaning for both
2427
+ * made the emulator answer things no device does, on the oracle the chunk specs are checked against.
2428
+ *
2429
+ * @type {Set<string>}
2430
+ */
2431
+ const INTEGER_TYPED_BUILTIN = new Set(['abs', 'firstLeadingBit', 'firstTrailingBit']);
2432
+
2433
+ /**
2434
+ * Best-effort return type for WGSL builtins commonly used in compute shaders.
2435
+ * Handles the cases needed for accurate swizzle / member-access codegen downstream.
2436
+ */
2437
+ function inferBuiltinReturnType(name, args) {
2438
+ // Element-wise vector-preserving math: result follows the first vector argument.
2439
+ const ELEMENT_WISE = new Set([
2440
+ 'abs', 'sign', 'floor', 'ceil', 'round', 'trunc', 'fract', 'sqrt', 'inverseSqrt',
2441
+ 'exp', 'exp2', 'log', 'log2', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan',
2442
+ 'pow', 'atan2', 'min', 'max', 'step', 'clamp', 'saturate', 'mix', 'smoothstep',
2443
+ 'normalize', 'reflect', 'fma',
2444
+ // not math, but the same shape: the result has the type of its one argument
2445
+ 'subgroupBroadcastFirst',
2446
+ ]);
2447
+ if (ELEMENT_WISE.has(name)) {
2448
+ for (const a of args) {
2449
+ if (a.type && (a.type.kind === 'vec' || a.type.kind === 'mat')) return a.type;
2450
+ }
2451
+ if (args[0] && args[0].type) return args[0].type;
2452
+ return T_UNKNOWN;
2453
+ }
2454
+ if (name === 'length' || name === 'distance' || name === 'dot' || name === 'determinant') {
2455
+ return { kind: 'primitive', name: 'f32' };
2456
+ }
2457
+ if (name === 'cross') {
2458
+ return args[0] && args[0].type && args[0].type.kind === 'vec'
2459
+ ? args[0].type
2460
+ : { kind: 'vec', size: 3, scalar: 'f32' };
2461
+ }
2462
+ if (name === 'all' || name === 'any') return { kind: 'primitive', name: 'bool' };
2463
+ if (name === 'select') {
2464
+ if (args[0] && args[0].type) return args[0].type;
2465
+ if (args[1] && args[1].type) return args[1].type;
2466
+ return T_UNKNOWN;
2467
+ }
2468
+ if (name === 'textureLoad' || name === 'textureSampleLevel' || name === 'textureSample' || name === 'textureSampleGrad') {
2469
+ return { kind: 'vec', size: 4, scalar: 'f32' };
2470
+ }
2471
+ // Both gathers return the four texels of a 2x2 footprint. Saying so here matters more than
2472
+ // for most builtins: the shadow chunks immediately swizzle the result (`samples.wzxy`), and
2473
+ // an unknown type degrades swizzle codegen downstream.
2474
+ if (name === 'textureGather' || name === 'textureGatherCompare') {
2475
+ return { kind: 'vec', size: 4, scalar: 'f32' };
2476
+ }
2477
+ if (name === 'textureDimensions') {
2478
+ return { kind: 'vec', size: 2, scalar: 'u32' };
2479
+ }
2480
+ if (name === 'atomicLoad') return { kind: 'primitive', name: 'i32' };
2481
+ if (name === 'unpack2x16unorm' || name === 'unpack2x16snorm' || name === 'unpack2x16float') {
2482
+ return { kind: 'vec', size: 2, scalar: 'f32' };
2483
+ }
2484
+ if (name === 'unpack4x8unorm' || name === 'unpack4x8snorm') {
2485
+ return { kind: 'vec', size: 4, scalar: 'f32' };
2486
+ }
2487
+ if (name === 'pack2x16unorm' || name === 'pack2x16snorm' || name === 'pack2x16float'
2488
+ || name === 'pack4x8unorm' || name === 'pack4x8snorm') {
2489
+ return { kind: 'primitive', name: 'u32' };
2490
+ }
2491
+ // extractBits/insertBits return the integer type (scalar or vector) of their first operand.
2492
+ if (name === 'extractBits' || name === 'insertBits') {
2493
+ return args[0] && args[0].type ? args[0].type : T_UNKNOWN;
2494
+ }
2495
+ return T_UNKNOWN;
2496
+ }
2497
+
2498
+ // =========================================================================
2499
+ // LHS expressions (for assignments)
2500
+ // =========================================================================
2501
+
2502
+ function compileLhs(c, node) {
2503
+ if (node.type !== 'lhs_expression') {
2504
+ return compileExpression(c, node);
2505
+ }
2506
+
2507
+ // Pointer deref / address-of: `*lhs` / `&lhs`. The emulator models pointers as values, so
2508
+ // both collapse to the operand's value. The grammar puts the `*` / `&` as an unnamed leading
2509
+ // token with a nested `lhs_expression` named child.
2510
+ //
2511
+ // A whole-value store through a deref (`*p = v`, with nothing selected out of it) is flagged
2512
+ // so {@link emitWriteStatement} writes through the reference rather than rebinding the local
2513
+ // — see `wgsl.store_ptr`. A store into part of the pointee (`(*p).x`, `(*p)[i]`) already
2514
+ // lands on the shared object and needs no such treatment.
2515
+ const prefix = textBeforeFirstNamed(node).trim();
2516
+ if (prefix === '*' || prefix === '&') {
2517
+ const nested_lhs = namedChildByType(node, 'lhs_expression');
2518
+ if (nested_lhs !== null) {
2519
+ const inner = compileLhs(c, nested_lhs);
2520
+
2521
+ const selects_part = node.namedChildren.some(
2522
+ child => child.type === 'component_or_swizzle_specifier'
2523
+ );
2524
+
2525
+ return {
2526
+ ...inner,
2527
+ through_pointer: prefix === '*' && !selects_part,
2528
+ };
2529
+ }
2530
+ }
2531
+
2532
+ const core = namedChildByType(node, 'core_lhs_expression');
2533
+ let code;
2534
+ let type;
2535
+ if (core !== null) {
2536
+ const ident = namedChildByType(core, 'ident');
2537
+ if (ident !== null) {
2538
+ code = identToJs(ident.text);
2539
+ type = c.scope.lookup(ident.text);
2540
+ } else {
2541
+ const nested = namedChildByType(core, 'lhs_expression');
2542
+ if (nested !== null) {
2543
+ const r = compileLhs(c, nested);
2544
+ code = `(${r.code})`;
2545
+ type = r.type;
2546
+ } else {
2547
+ code = core.text;
2548
+ type = T_UNKNOWN;
2549
+ }
2550
+ }
2551
+ } else {
2552
+ code = node.text;
2553
+ type = T_UNKNOWN;
2554
+ }
2555
+
2556
+ for (const child of node.namedChildren) {
2557
+ if (child.type === 'component_or_swizzle_specifier') {
2558
+ const next = applyAccessSpecifier(c, child, code, type);
2559
+ code = next.code;
2560
+ type = next.type;
2561
+ }
2562
+ }
2563
+ return { code, type };
2564
+ }