@woosh/meep-engine 3.30.0 → 3.32.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 (1627) 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 +42 -14
  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/ebvh_optimize_treelet.js +3 -3
  33. package/src/core/bvh8/bvh8_geometry_validate.d.ts.map +1 -1
  34. package/src/core/bvh8/bvh8_geometry_validate.js +2 -88
  35. package/src/core/bvh8/bvh8_geometry_validate_bounds.d.ts +25 -0
  36. package/src/core/bvh8/bvh8_geometry_validate_bounds.d.ts.map +1 -0
  37. package/src/core/bvh8/bvh8_geometry_validate_bounds.js +105 -0
  38. package/src/core/bvh8/bvh8_geometry_validate_indirect.d.ts.map +1 -1
  39. package/src/core/bvh8/bvh8_geometry_validate_indirect.js +2 -91
  40. package/src/core/clipboard/obtainClipBoard.d.ts +4 -0
  41. package/src/core/clipboard/obtainClipBoard.d.ts.map +1 -1
  42. package/src/core/clipboard/obtainClipBoard.js +29 -8
  43. package/src/core/clipboard/safeClipboardReadText.d.ts.map +1 -1
  44. package/src/core/clipboard/safeClipboardReadText.js +73 -38
  45. package/src/core/clipboard/safeClipboardWriteText.d.ts.map +1 -1
  46. package/src/core/clipboard/safeClipboardWriteText.js +11 -9
  47. package/src/core/collection/array/iterator/ArrayIteratorRandom.d.ts.map +1 -1
  48. package/src/core/collection/array/iterator/ArrayIteratorRandom.js +6 -0
  49. package/src/core/collection/heap/IndexedFloatMinHeap.d.ts +6 -0
  50. package/src/core/collection/heap/IndexedFloatMinHeap.d.ts.map +1 -1
  51. package/src/core/collection/heap/IndexedFloatMinHeap.js +14 -0
  52. package/src/core/collection/list/FilteredListProjection.d.ts.map +1 -1
  53. package/src/core/collection/list/FilteredListProjection.js +7 -54
  54. package/src/core/collection/list/List.d.ts +4 -0
  55. package/src/core/collection/list/List.d.ts.map +1 -1
  56. package/src/core/collection/list/List.js +10 -52
  57. package/src/core/collection/list/SortedListProjection.d.ts +7 -0
  58. package/src/core/collection/list/SortedListProjection.d.ts.map +1 -1
  59. package/src/core/collection/list/SortedListProjection.js +12 -0
  60. package/src/core/collection/list/list_apply_ordered_diff.d.ts +37 -0
  61. package/src/core/collection/list/list_apply_ordered_diff.d.ts.map +1 -0
  62. package/src/core/collection/list/list_apply_ordered_diff.js +87 -0
  63. package/src/core/collection/map/BiMap.d.ts.map +1 -1
  64. package/src/core/collection/map/BiMap.js +19 -6
  65. package/src/core/collection/map/HashMap.d.ts.map +1 -1
  66. package/src/core/collection/map/HashMap.js +38 -11
  67. package/src/core/collection/queue/Deque.d.ts +2 -2
  68. package/src/core/collection/queue/Deque.d.ts.map +1 -1
  69. package/src/core/collection/queue/Deque.js +12 -1
  70. package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
  71. package/src/core/collection/table/RowFirstTable.js +15 -2
  72. package/src/core/collection/table/serializeRowFirstTable.d.ts.map +1 -1
  73. package/src/core/collection/table/serializeRowFirstTable.js +2 -3
  74. package/src/core/color/operations/color_lerp.d.ts.map +1 -1
  75. package/src/core/color/operations/color_lerp.js +77 -55
  76. package/src/core/color/sRGB/linear_to_sRGB.d.ts.map +1 -1
  77. package/src/core/color/sRGB/linear_to_sRGB.js +3 -1
  78. package/src/core/debug/matchers/AllOf.d.ts +2 -1
  79. package/src/core/debug/matchers/AllOf.d.ts.map +1 -1
  80. package/src/core/debug/matchers/AllOf.js +1 -1
  81. package/src/core/debug/matchers/AnyOf.d.ts +2 -1
  82. package/src/core/debug/matchers/AnyOf.d.ts.map +1 -1
  83. package/src/core/debug/matchers/AnyOf.js +1 -1
  84. package/src/core/debug/matchers/CombinableMatcher.d.ts +2 -1
  85. package/src/core/debug/matchers/CombinableMatcher.d.ts.map +1 -1
  86. package/src/core/debug/matchers/CombinableMatcher.js +1 -1
  87. package/src/core/debug/matchers/DescribeAs.d.ts +2 -1
  88. package/src/core/debug/matchers/DescribeAs.d.ts.map +1 -1
  89. package/src/core/debug/matchers/DescribeAs.js +2 -1
  90. package/src/core/debug/matchers/IsAnything.d.ts +2 -1
  91. package/src/core/debug/matchers/IsAnything.d.ts.map +1 -1
  92. package/src/core/debug/matchers/IsAnything.js +2 -1
  93. package/src/core/debug/matchers/IsEqual.d.ts +2 -1
  94. package/src/core/debug/matchers/IsEqual.d.ts.map +1 -1
  95. package/src/core/debug/matchers/IsEqual.js +2 -1
  96. package/src/core/debug/matchers/IsFinite.d.ts +2 -1
  97. package/src/core/debug/matchers/IsFinite.d.ts.map +1 -1
  98. package/src/core/debug/matchers/IsFinite.js +2 -1
  99. package/src/core/debug/matchers/IsIn.d.ts +2 -1
  100. package/src/core/debug/matchers/IsIn.d.ts.map +1 -1
  101. package/src/core/debug/matchers/IsIn.js +2 -1
  102. package/src/core/debug/matchers/IsInteger.d.ts +2 -1
  103. package/src/core/debug/matchers/IsInteger.d.ts.map +1 -1
  104. package/src/core/debug/matchers/IsInteger.js +2 -1
  105. package/src/core/debug/matchers/IsIterableContaining.d.ts +2 -1
  106. package/src/core/debug/matchers/IsIterableContaining.d.ts.map +1 -1
  107. package/src/core/debug/matchers/IsIterableContaining.js +1 -1
  108. package/src/core/debug/matchers/IsNot.d.ts +2 -1
  109. package/src/core/debug/matchers/IsNot.d.ts.map +1 -1
  110. package/src/core/debug/matchers/IsNot.js +2 -1
  111. package/src/core/debug/matchers/IsNull.d.ts +2 -1
  112. package/src/core/debug/matchers/IsNull.d.ts.map +1 -1
  113. package/src/core/debug/matchers/IsNull.js +2 -1
  114. package/src/core/debug/matchers/IsUndefined.d.ts +2 -1
  115. package/src/core/debug/matchers/IsUndefined.d.ts.map +1 -1
  116. package/src/core/debug/matchers/IsUndefined.js +2 -1
  117. package/src/core/events/signal/Signal.d.ts +15 -0
  118. package/src/core/events/signal/Signal.d.ts.map +1 -1
  119. package/src/core/events/signal/Signal.js +857 -820
  120. package/src/core/fsm/simple/SimpleStateMachineDescription.d.ts.map +1 -1
  121. package/src/core/fsm/simple/SimpleStateMachineDescription.js +4 -3
  122. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_bruteforce.d.ts.map +1 -1
  123. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_bruteforce.js +6 -1
  124. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts +1 -1
  125. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts.map +1 -1
  126. package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js +6 -7
  127. package/src/core/geom/2d/hash-grid/SpatialHashGrid.d.ts.map +1 -1
  128. package/src/core/geom/2d/hash-grid/SpatialHashGrid.js +23 -6
  129. package/src/core/geom/2d/line/ray2_ray2_compute_intersection_array_2d.d.ts.map +1 -1
  130. package/src/core/geom/2d/line/ray2_ray2_compute_intersection_array_2d.js +13 -1
  131. package/src/core/geom/3d/aabb/aabb3_raycast_hit_point.d.ts.map +1 -1
  132. package/src/core/geom/3d/aabb/aabb3_raycast_hit_point.js +53 -32
  133. package/src/core/geom/3d/atlas/segment/atlas_chart_growth_cost.d.ts +40 -0
  134. package/src/core/geom/3d/atlas/segment/atlas_chart_growth_cost.d.ts.map +1 -0
  135. package/src/core/geom/3d/atlas/segment/atlas_chart_growth_cost.js +54 -0
  136. package/src/core/geom/3d/atlas/segment/atlas_segment_charts.d.ts +21 -3
  137. package/src/core/geom/3d/atlas/segment/atlas_segment_charts.d.ts.map +1 -1
  138. package/src/core/geom/3d/atlas/segment/atlas_segment_charts.js +24 -15
  139. package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.d.ts +6 -3
  140. package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.d.ts.map +1 -1
  141. package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.js +9 -15
  142. package/src/core/geom/3d/cone/cone_compute_plane_side.d.ts.map +1 -1
  143. package/src/core/geom/3d/cone/cone_compute_plane_side.js +31 -19
  144. package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.d.ts +11 -1
  145. package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.d.ts.map +1 -1
  146. package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.js +11 -1
  147. package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.d.ts +11 -1
  148. package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.d.ts.map +1 -1
  149. package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.js +11 -1
  150. package/src/core/geom/3d/frustum/frustum3_compute_closest_point.d.ts.map +1 -1
  151. package/src/core/geom/3d/frustum/frustum3_compute_closest_point.js +55 -0
  152. package/src/core/geom/3d/frustum/frustum_from_projection_matrix_array.d.ts +14 -0
  153. package/src/core/geom/3d/frustum/frustum_from_projection_matrix_array.d.ts.map +1 -1
  154. package/src/core/geom/3d/frustum/frustum_from_projection_matrix_array.js +17 -1
  155. package/src/core/geom/3d/gjk/gjk.d.ts +15 -0
  156. package/src/core/geom/3d/gjk/gjk.d.ts.map +1 -1
  157. package/src/core/geom/3d/gjk/gjk.js +15 -0
  158. package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts.map +1 -1
  159. package/src/core/geom/3d/gjk/gjk_epa_penetration.js +18 -0
  160. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts +32 -3
  161. package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts.map +1 -1
  162. package/src/core/geom/3d/hash-grid/PointHashGrid3.js +36 -3
  163. package/src/core/geom/3d/morton/v3_morton_encode_lut.d.ts.map +1 -1
  164. package/src/core/geom/3d/morton/v3_morton_encode_lut.js +11 -4
  165. package/src/core/geom/3d/morton/v3_morton_encode_normalized.d.ts +16 -4
  166. package/src/core/geom/3d/morton/v3_morton_encode_normalized.d.ts.map +1 -1
  167. package/src/core/geom/3d/morton/v3_morton_encode_normalized.js +21 -8
  168. package/src/core/geom/3d/normal/spherical/encode_unit_to_spheremap.d.ts.map +1 -1
  169. package/src/core/geom/3d/normal/spherical/encode_unit_to_spheremap.js +17 -3
  170. package/src/core/geom/3d/octahedra/octahedral_direction_to_uv.d.ts +10 -0
  171. package/src/core/geom/3d/octahedra/octahedral_direction_to_uv.d.ts.map +1 -1
  172. package/src/core/geom/3d/octahedra/octahedral_direction_to_uv.js +46 -49
  173. package/src/core/geom/3d/octahedra/octahedral_uv_to_direction.d.ts +13 -1
  174. package/src/core/geom/3d/octahedra/octahedral_uv_to_direction.d.ts.map +1 -1
  175. package/src/core/geom/3d/octahedra/octahedral_uv_to_direction.js +36 -39
  176. package/src/core/geom/3d/quadric/quadric3_to_tensor_m3_inverse.d.ts +4 -1
  177. package/src/core/geom/3d/quadric/quadric3_to_tensor_m3_inverse.d.ts.map +1 -1
  178. package/src/core/geom/3d/quadric/quadric3_to_tensor_m3_inverse.js +22 -4
  179. package/src/core/geom/3d/quaternion/quat3_canonicalize_sign_run.d.ts +38 -0
  180. package/src/core/geom/3d/quaternion/quat3_canonicalize_sign_run.d.ts.map +1 -0
  181. package/src/core/geom/3d/quaternion/quat3_canonicalize_sign_run.js +76 -0
  182. package/src/core/geom/3d/quaternion/quat3_encode_to_uint32.d.ts +11 -0
  183. package/src/core/geom/3d/quaternion/quat3_encode_to_uint32.d.ts.map +1 -1
  184. package/src/core/geom/3d/quaternion/quat3_encode_to_uint32.js +14 -34
  185. package/src/core/geom/3d/shape/PosedShape3D.d.ts +9 -0
  186. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
  187. package/src/core/geom/3d/shape/PosedShape3D.js +43 -0
  188. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  189. package/src/core/geom/3d/shape/UnionShape3D.js +20 -3
  190. package/src/core/geom/3d/shape/json/type_adapters.d.ts +11 -2
  191. package/src/core/geom/3d/shape/json/type_adapters.d.ts.map +1 -1
  192. package/src/core/geom/3d/shape/json/type_adapters.js +36 -12
  193. package/src/core/geom/3d/sphere/harmonics/sh3_sample_irradiance_by_direction.d.ts +13 -0
  194. package/src/core/geom/3d/sphere/harmonics/sh3_sample_irradiance_by_direction.d.ts.map +1 -1
  195. package/src/core/geom/3d/sphere/harmonics/sh3_sample_irradiance_by_direction.js +17 -4
  196. package/src/core/geom/3d/tetrahedra/tetrahedral_flip_layouts.d.ts +88 -0
  197. package/src/core/geom/3d/tetrahedra/tetrahedral_flip_layouts.d.ts.map +1 -0
  198. package/src/core/geom/3d/tetrahedra/tetrahedral_flip_layouts.js +108 -0
  199. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.d.ts.map +1 -1
  200. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.js +13 -31
  201. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.d.ts.map +1 -1
  202. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.js +14 -22
  203. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts.map +1 -1
  204. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js +96 -26
  205. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts.map +1 -1
  206. package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +17 -6
  207. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts +27 -0
  208. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts.map +1 -1
  209. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.js +101 -0
  210. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts +3 -0
  211. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts.map +1 -1
  212. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js +5 -57
  213. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
  214. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +2 -34
  215. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts.map +1 -1
  216. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.js +2 -43
  217. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +54 -33
  218. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
  219. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +229 -68
  220. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts.map +1 -1
  221. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js +4 -15
  222. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_mesh_split_pinched_vertices.d.ts.map +1 -1
  223. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_mesh_split_pinched_vertices.js +13 -1
  224. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.d.ts.map +1 -1
  225. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.js +3 -1
  226. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
  227. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +22 -3
  228. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_count_faces.d.ts +17 -2
  229. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_count_faces.d.ts.map +1 -1
  230. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_count_faces.js +28 -4
  231. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.d.ts.map +1 -1
  232. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.js +8 -1
  233. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_edge_adjacent_faces_weighted.d.ts.map +1 -1
  234. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_edge_adjacent_faces_weighted.js +10 -2
  235. package/src/core/geom/3d/topology/struct/binary/query/bt_face_island_flood_fill.d.ts.map +1 -1
  236. package/src/core/geom/3d/topology/struct/binary/query/bt_face_island_flood_fill.js +2 -0
  237. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.d.ts.map +1 -1
  238. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.js +25 -5
  239. package/src/core/geom/3d/triangle/tri3_compute_normal.d.ts +5 -1
  240. package/src/core/geom/3d/triangle/tri3_compute_normal.d.ts.map +1 -1
  241. package/src/core/geom/3d/triangle/tri3_compute_normal.js +8 -1
  242. package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts.map +1 -1
  243. package/src/core/geom/3d/triangle/tri3_ray_intersection.js +15 -3
  244. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric.d.ts +2 -1
  245. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric.d.ts.map +1 -1
  246. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric.js +2 -1
  247. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric_edge.d.ts +1 -1
  248. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric_edge.d.ts.map +1 -1
  249. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric_edge.js +8 -1
  250. package/src/core/geom/vec/vector_normalize.d.ts.map +1 -1
  251. package/src/core/geom/vec/vector_normalize.js +5 -1
  252. package/src/core/geom/vec3/v3_slerp.d.ts.map +1 -1
  253. package/src/core/geom/vec3/v3_slerp.js +69 -4
  254. package/src/core/geom/vec4/v4_max_axis.d.ts +28 -0
  255. package/src/core/geom/vec4/v4_max_axis.d.ts.map +1 -0
  256. package/src/core/geom/vec4/v4_max_axis.js +41 -0
  257. package/src/core/graph/coloring/colorizeGraph.js +10 -7
  258. package/src/core/graph/layout/graph_peel_topological_layer.d.ts.map +1 -1
  259. package/src/core/graph/layout/graph_peel_topological_layer.js +16 -2
  260. package/src/core/json/JsonUtils.d.ts.map +1 -1
  261. package/src/core/json/JsonUtils.js +6 -2
  262. package/src/core/json/abstractJSONSerializer.d.ts.map +1 -1
  263. package/src/core/json/abstractJSONSerializer.js +5 -1
  264. package/src/core/lang/reactive/ReactiveOperatorType.d.ts +20 -0
  265. package/src/core/lang/reactive/ReactiveOperatorType.d.ts.map +1 -1
  266. package/src/core/lang/reactive/ReactiveOperatorType.js +34 -12
  267. package/src/core/localization/LanguageMetadata.d.ts +2 -1
  268. package/src/core/localization/LanguageMetadata.d.ts.map +1 -1
  269. package/src/core/localization/LanguageMetadata.js +6 -0
  270. package/src/core/localization/Localization.d.ts.map +1 -1
  271. package/src/core/localization/Localization.js +23 -10
  272. package/src/core/localization/LocalizationEngine.d.ts.map +1 -1
  273. package/src/core/localization/LocalizationEngine.js +4 -0
  274. package/src/core/math/fract.d.ts.map +1 -1
  275. package/src/core/math/fract.js +4 -3
  276. package/src/core/math/hash/squirrel3.d.ts +10 -2
  277. package/src/core/math/hash/squirrel3.d.ts.map +1 -1
  278. package/src/core/math/hash/squirrel3.js +16 -8
  279. package/src/core/math/linalg/m2/m2_polar_decomp_noS.d.ts +7 -0
  280. package/src/core/math/linalg/m2/m2_polar_decomp_noS.d.ts.map +1 -1
  281. package/src/core/math/linalg/m2/m2_polar_decomp_noS.js +20 -1
  282. package/src/core/math/physics/pdf/pdf_normal.d.ts +11 -3
  283. package/src/core/math/physics/pdf/pdf_normal.d.ts.map +1 -1
  284. package/src/core/math/physics/pdf/pdf_normal.js +25 -11
  285. package/src/core/math/solveQuadratic.d.ts.map +1 -1
  286. package/src/core/math/solveQuadratic.js +22 -3
  287. package/src/core/math/statistics/computeStatisticalPartialMedian.d.ts +9 -2
  288. package/src/core/math/statistics/computeStatisticalPartialMedian.d.ts.map +1 -1
  289. package/src/core/math/statistics/computeStatisticalPartialMedian.js +12 -6
  290. package/src/core/math/statistics/computeStatisticalPercentile.d.ts.map +1 -1
  291. package/src/core/math/statistics/computeStatisticalPercentile.js +9 -2
  292. package/src/core/math/statistics/gaussian_amplitude.d.ts +10 -1
  293. package/src/core/math/statistics/gaussian_amplitude.d.ts.map +1 -1
  294. package/src/core/math/statistics/gaussian_amplitude.js +20 -15
  295. package/src/core/model/BooleanVector3.d.ts.map +1 -1
  296. package/src/core/model/BooleanVector3.js +18 -2
  297. package/src/core/model/BoundedValue.d.ts +9 -0
  298. package/src/core/model/BoundedValue.d.ts.map +1 -1
  299. package/src/core/model/BoundedValue.js +30 -3
  300. package/src/core/model/ObservedBoolean.d.ts.map +1 -1
  301. package/src/core/model/ObservedBoolean.js +22 -2
  302. package/src/core/model/ObservedEnum.d.ts.map +1 -1
  303. package/src/core/model/ObservedEnum.js +6 -2
  304. package/src/core/model/node-graph/NodeGraph.d.ts +6 -1
  305. package/src/core/model/node-graph/NodeGraph.d.ts.map +1 -1
  306. package/src/core/model/node-graph/NodeGraph.js +22 -4
  307. package/src/core/model/node-graph/json/deserializeNodeGraphFromJSON.d.ts.map +1 -1
  308. package/src/core/model/node-graph/json/deserializeNodeGraphFromJSON.js +3 -1
  309. package/src/core/model/node-graph/json/serializeNodeGraphToJSON.d.ts.map +1 -1
  310. package/src/core/model/node-graph/json/serializeNodeGraphToJSON.js +5 -0
  311. package/src/core/model/node-graph/type/DataType.d.ts.map +1 -1
  312. package/src/core/model/node-graph/type/DataType.js +8 -0
  313. package/src/core/model/node-graph/type/ParametricDataType.d.ts.map +1 -1
  314. package/src/core/model/node-graph/type/ParametricDataType.js +19 -0
  315. package/src/core/model/node-graph/visual/NodeGraphVisualData.d.ts.map +1 -1
  316. package/src/core/model/node-graph/visual/NodeGraphVisualData.js +5 -0
  317. package/src/core/model/reactive/js/compileReactiveToJS.d.ts +22 -0
  318. package/src/core/model/reactive/js/compileReactiveToJS.d.ts.map +1 -1
  319. package/src/core/model/reactive/js/compileReactiveToJS.js +113 -219
  320. package/src/core/model/reactive/model/ReactiveBinaryExpression.d.ts.map +1 -1
  321. package/src/core/model/reactive/model/ReactiveBinaryExpression.js +8 -2
  322. package/src/core/model/reactive/model/comparative/ReactiveEquals.d.ts.map +1 -1
  323. package/src/core/model/reactive/model/comparative/ReactiveEquals.js +3 -1
  324. package/src/core/model/reactive/model/comparative/ReactiveNotEquals.d.ts.map +1 -1
  325. package/src/core/model/reactive/model/comparative/ReactiveNotEquals.js +2 -1
  326. package/src/core/model/reactive/model/terminal/ReactiveLiteralString.d.ts.map +1 -1
  327. package/src/core/model/reactive/model/terminal/ReactiveLiteralString.js +4 -2
  328. package/src/core/model/stat/Stat.d.ts.map +1 -1
  329. package/src/core/model/stat/Stat.js +4 -0
  330. package/src/core/parser/seedVariablesIntoTemplateString.d.ts.map +1 -1
  331. package/src/core/parser/seedVariablesIntoTemplateString.js +5 -0
  332. package/src/core/parser/simple/readArrayLiteral.d.ts.map +1 -1
  333. package/src/core/parser/simple/readArrayLiteral.js +7 -0
  334. package/src/core/parser/simple/readHexToken.d.ts +3 -0
  335. package/src/core/parser/simple/readHexToken.d.ts.map +1 -1
  336. package/src/core/parser/simple/readHexToken.js +39 -106
  337. package/src/core/parser/simple/readNumberToken.d.ts.map +1 -1
  338. package/src/core/parser/simple/readNumberToken.js +13 -4
  339. package/src/core/parser/simple/readUnsignedIntegerToken.d.ts +2 -0
  340. package/src/core/parser/simple/readUnsignedIntegerToken.d.ts.map +1 -1
  341. package/src/core/parser/simple/readUnsignedIntegerToken.js +31 -71
  342. package/src/core/parser/simple/read_digits.d.ts +31 -0
  343. package/src/core/parser/simple/read_digits.d.ts.map +1 -0
  344. package/src/core/parser/simple/read_digits.js +74 -0
  345. package/src/core/primitives/numbers/number_format_by_thousands.d.ts.map +1 -1
  346. package/src/core/primitives/numbers/number_format_by_thousands.js +16 -1
  347. package/src/core/primitives/numbers/number_pretty_print.d.ts.map +1 -1
  348. package/src/core/primitives/numbers/number_pretty_print.js +6 -1
  349. package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
  350. package/src/core/process/executor/ConcurrentExecutor.js +36 -0
  351. package/src/core/process/task/Task.d.ts +8 -0
  352. package/src/core/process/task/Task.d.ts.map +1 -1
  353. package/src/core/process/task/Task.js +12 -1
  354. package/src/core/process/task/TaskGroup.d.ts +6 -0
  355. package/src/core/process/task/TaskGroup.d.ts.map +1 -1
  356. package/src/core/process/task/TaskGroup.js +7 -1
  357. package/src/core/process/undo/ActionProcessor.d.ts +12 -0
  358. package/src/core/process/undo/ActionProcessor.d.ts.map +1 -1
  359. package/src/core/process/undo/ActionProcessor.js +41 -15
  360. package/src/core/process/worker/OnDemandWorkerManager.d.ts.map +1 -1
  361. package/src/core/process/worker/OnDemandWorkerManager.js +6 -1
  362. package/src/core/process/worker/WorkerBuilder.d.ts.map +1 -1
  363. package/src/core/process/worker/WorkerBuilder.js +27 -5
  364. package/src/engine/Clock.d.ts.map +1 -1
  365. package/src/engine/Clock.js +11 -0
  366. package/src/engine/Engine.d.ts.map +1 -1
  367. package/src/engine/Engine.js +107 -6
  368. package/src/engine/achievements/AchievementManager.d.ts.map +1 -1
  369. package/src/engine/achievements/AchievementManager.js +16 -1
  370. package/src/engine/animation/clip/ecd_bind_animation_curve.d.ts.map +1 -1
  371. package/src/engine/animation/clip/ecd_bind_animation_curve.js +17 -6
  372. package/src/engine/animation/clip/hemisphere_align_quaternion_values.d.ts +19 -10
  373. package/src/engine/animation/clip/hemisphere_align_quaternion_values.d.ts.map +1 -1
  374. package/src/engine/animation/clip/hemisphere_align_quaternion_values.js +19 -23
  375. package/src/engine/animation/keyed2/AnimationTrackPlayback.d.ts +1 -1
  376. package/src/engine/animation/keyed2/AnimationTrackPlayback.d.ts.map +1 -1
  377. package/src/engine/animation/keyed2/AnimationTrackPlayback.js +21 -4
  378. package/src/engine/asset/AssetManager.d.ts.map +1 -1
  379. package/src/engine/asset/AssetManager.js +11 -3
  380. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +1 -0
  381. package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
  382. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +28 -0
  383. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
  384. package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +14 -0
  385. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +23 -2
  386. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
  387. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2122 -2078
  388. package/src/engine/ecs/Entity.d.ts.map +1 -1
  389. package/src/engine/ecs/Entity.js +43 -7
  390. package/src/engine/ecs/EntityBlueprint.d.ts.map +1 -1
  391. package/src/engine/ecs/EntityBlueprint.js +13 -4
  392. package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
  393. package/src/engine/ecs/EntityComponentDataset.js +95 -9
  394. package/src/engine/ecs/EntityManager.d.ts +16 -0
  395. package/src/engine/ecs/EntityManager.d.ts.map +1 -1
  396. package/src/engine/ecs/EntityManager.js +112 -37
  397. package/src/engine/ecs/EntityObserver.d.ts +7 -0
  398. package/src/engine/ecs/EntityObserver.d.ts.map +1 -1
  399. package/src/engine/ecs/EntityObserver.js +8 -1
  400. package/src/engine/ecs/System.d.ts +23 -0
  401. package/src/engine/ecs/System.d.ts.map +1 -1
  402. package/src/engine/ecs/System.js +25 -0
  403. package/src/engine/ecs/components/Tag.d.ts.map +1 -1
  404. package/src/engine/ecs/components/Tag.js +4 -1
  405. package/src/engine/ecs/computeComponentClassName.d.ts +13 -1
  406. package/src/engine/ecs/computeComponentClassName.d.ts.map +1 -1
  407. package/src/engine/ecs/computeComponentClassName.js +11 -1
  408. package/src/engine/ecs/dynamic_actions/DynamicActorSystem.d.ts.map +1 -1
  409. package/src/engine/ecs/dynamic_actions/DynamicActorSystem.js +11 -0
  410. package/src/engine/ecs/fow/FogOfWar.d.ts.map +1 -1
  411. package/src/engine/ecs/fow/FogOfWar.js +37 -11
  412. package/src/engine/ecs/parent/EntityNode.d.ts.map +1 -1
  413. package/src/engine/ecs/parent/EntityNode.js +8 -0
  414. package/src/engine/ecs/speaker/VoiceSystem.d.ts.map +1 -1
  415. package/src/engine/ecs/speaker/VoiceSystem.js +9 -0
  416. package/src/engine/ecs/storage/binary/BinaryClassSerializationAdapter.d.ts +15 -0
  417. package/src/engine/ecs/storage/binary/BinaryClassSerializationAdapter.d.ts.map +1 -1
  418. package/src/engine/ecs/storage/binary/BinaryClassSerializationAdapter.js +18 -0
  419. package/src/engine/ecs/system/AbstractContextSystem.d.ts.map +1 -1
  420. package/src/engine/ecs/system/AbstractContextSystem.js +14 -4
  421. package/src/engine/ecs/system/SystemEntityContext.d.ts +12 -0
  422. package/src/engine/ecs/system/SystemEntityContext.d.ts.map +1 -1
  423. package/src/engine/ecs/system/SystemEntityContext.js +23 -0
  424. package/src/engine/ecs/system_validate_class.d.ts.map +1 -1
  425. package/src/engine/ecs/system_validate_class.js +6 -2
  426. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +37 -8
  427. package/src/engine/ecs/terrain/tiles/TerrainTile.d.ts.map +1 -1
  428. package/src/engine/ecs/terrain/tiles/TerrainTile.js +45 -3
  429. package/src/engine/ecs/terrain/tiles/TerrainTileManager.d.ts.map +1 -1
  430. package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +5 -8
  431. package/src/engine/graphics/ecs/camera/pp/PerfectPanner.d.ts.map +1 -1
  432. package/src/engine/graphics/ecs/camera/pp/PerfectPanner.js +62 -7
  433. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.d.ts +9 -0
  434. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.d.ts.map +1 -1
  435. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js +13 -0
  436. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshAnimationControllerSystem.d.ts +11 -0
  437. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshAnimationControllerSystem.d.ts.map +1 -1
  438. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshAnimationControllerSystem.js +78 -13
  439. package/src/engine/graphics/ecs/path/tube/build/make_ring_vertices.d.ts.map +1 -1
  440. package/src/engine/graphics/ecs/path/tube/build/make_ring_vertices.js +22 -8
  441. package/src/engine/graphics/geometry/buffered/geometry_compute_vertex_normals_indexed.d.ts.map +1 -1
  442. package/src/engine/graphics/geometry/buffered/geometry_compute_vertex_normals_indexed.js +18 -2
  443. package/src/engine/graphics/geometry/geometry_construct_triangle_normal.d.ts +3 -1
  444. package/src/engine/graphics/geometry/geometry_construct_triangle_normal.d.ts.map +1 -1
  445. package/src/engine/graphics/geometry/geometry_construct_triangle_normal.js +3 -1
  446. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts +32 -0
  447. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts.map +1 -0
  448. package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.js +53 -0
  449. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts +22 -2
  450. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
  451. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +1201 -1160
  452. package/src/engine/graphics/particles/particular/engine/simulator/SimulationStepCurlNoiseVelocity.d.ts +0 -1
  453. package/src/engine/graphics/particles/particular/engine/simulator/SimulationStepCurlNoiseVelocity.d.ts.map +1 -1
  454. package/src/engine/graphics/particles/particular/engine/simulator/SimulationStepCurlNoiseVelocity.js +10 -5
  455. package/src/engine/graphics/particles/particular/engine/simulator/update_parameters.d.ts.map +1 -1
  456. package/src/engine/graphics/particles/particular/engine/simulator/update_parameters.js +23 -0
  457. package/src/engine/graphics/particles/particular/group/itemSizeFromAttributeType.d.ts +1 -1
  458. package/src/engine/graphics/sh3/path_tracer/texture/apply_texture_clamping_to_coordinate.d.ts.map +1 -1
  459. package/src/engine/graphics/sh3/path_tracer/texture/apply_texture_clamping_to_coordinate.js +6 -1
  460. package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.d.ts.map +1 -1
  461. package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.js +20 -0
  462. package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts +1 -0
  463. package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts.map +1 -1
  464. package/src/engine/graphics/texture/atlas/TextureAtlas.js +24 -5
  465. package/src/engine/graphics/texture/sampler/Sampler2D.d.ts.map +1 -1
  466. package/src/engine/graphics/texture/sampler/Sampler2D.js +14 -1
  467. package/src/engine/graphics/texture/sampler/sampler2d_sub_copy_same_item_size.d.ts.map +1 -1
  468. package/src/engine/graphics/texture/sampler/sampler2d_sub_copy_same_item_size.js +16 -5
  469. package/src/engine/graphics/texture/sampler/sampler2d_to_uint8_RGBA.d.ts.map +1 -1
  470. package/src/engine/graphics/texture/sampler/sampler2d_to_uint8_RGBA.js +29 -8
  471. package/src/engine/graphics/texture/sampler/serialization/TextureBinaryBufferSerializer.d.ts.map +1 -1
  472. package/src/engine/graphics/texture/sampler/serialization/TextureBinaryBufferSerializer.js +8 -3
  473. package/src/engine/graphics3/DebugDrawSystem.d.ts.map +1 -1
  474. package/src/engine/graphics3/DebugDrawSystem.js +6 -2
  475. package/src/engine/graphics3/DecalSystem.d.ts +5 -4
  476. package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
  477. package/src/engine/graphics3/DecalSystem.js +5 -4
  478. package/src/engine/graphics3/GraphicsEngine.d.ts +40 -7
  479. package/src/engine/graphics3/GraphicsEngine.d.ts.map +1 -1
  480. package/src/engine/graphics3/GraphicsEngine.js +92 -7
  481. package/src/engine/graphics3/MeshSystem.d.ts +7 -0
  482. package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
  483. package/src/engine/graphics3/MeshSystem.js +681 -661
  484. package/src/engine/graphics3/ParticleEmitterSystem.d.ts +1 -0
  485. package/src/engine/graphics3/ParticleEmitterSystem.d.ts.map +1 -1
  486. package/src/engine/graphics3/ParticleEmitterSystem.js +1 -0
  487. package/src/engine/graphics3/PathDisplaySystem.d.ts.map +1 -1
  488. package/src/engine/graphics3/PathDisplaySystem.js +311 -307
  489. package/src/engine/graphics3/TerrainSystem.d.ts +10 -40
  490. package/src/engine/graphics3/TerrainSystem.d.ts.map +1 -1
  491. package/src/engine/graphics3/TerrainSystem.js +186 -185
  492. package/src/engine/graphics3/Trail3DSystem.d.ts +28 -19
  493. package/src/engine/graphics3/Trail3DSystem.d.ts.map +1 -1
  494. package/src/engine/graphics3/Trail3DSystem.js +57 -64
  495. package/src/engine/graphics3/debug/gizmo_write_geometry.d.ts.map +1 -1
  496. package/src/engine/graphics3/debug/gizmo_write_geometry.js +7 -59
  497. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts.map +1 -1
  498. package/src/engine/graphics3/decal/GPUDecalRenderer.js +23 -7
  499. package/src/engine/graphics3/decal/shader_cluster_assign_decals.d.ts.map +1 -1
  500. package/src/engine/graphics3/decal/shader_cluster_assign_decals.js +29 -6
  501. package/src/engine/graphics3/path/tube_stream_write_geometry.d.ts.map +1 -1
  502. package/src/engine/graphics3/path/tube_stream_write_geometry.js +7 -56
  503. package/src/engine/graphics3/register_instance_animation.d.ts +3 -3
  504. package/src/engine/graphics3/register_instance_animation.js +3 -3
  505. package/src/engine/graphics3/terrain/TERRAIN_MATERIAL_TEMPLATE.d.ts +77 -0
  506. package/src/engine/graphics3/terrain/TERRAIN_MATERIAL_TEMPLATE.d.ts.map +1 -0
  507. package/src/engine/graphics3/terrain/TERRAIN_MATERIAL_TEMPLATE.js +485 -0
  508. package/src/engine/graphics3/terrain/TerrainShadeMaterial.d.ts +103 -0
  509. package/src/engine/graphics3/terrain/TerrainShadeMaterial.d.ts.map +1 -0
  510. package/src/engine/graphics3/terrain/TerrainShadeMaterial.js +130 -0
  511. package/src/engine/graphics3/terrain/chunk_terrain_material_surface.d.ts +23 -0
  512. package/src/engine/graphics3/terrain/chunk_terrain_material_surface.d.ts.map +1 -0
  513. package/src/engine/graphics3/terrain/chunk_terrain_material_surface.js +68 -0
  514. package/src/engine/graphics3/trail/trail_tube_write_geometry.d.ts.map +1 -1
  515. package/src/engine/graphics3/trail/trail_tube_write_geometry.js +8 -59
  516. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts.map +1 -1
  517. package/src/engine/grid/transform2grid/Transform2GridPositionSystem.js +10 -0
  518. package/src/engine/input/devices/PointerDevice.d.ts.map +1 -1
  519. package/src/engine/input/devices/PointerDevice.js +58 -5
  520. package/src/engine/input/ecs/ism/InputMapProgram.d.ts.map +1 -1
  521. package/src/engine/input/ecs/ism/InputMapProgram.js +13 -0
  522. package/src/engine/input/ecs/systems/InputControllerSystem.d.ts +1 -0
  523. package/src/engine/input/ecs/systems/InputControllerSystem.d.ts.map +1 -1
  524. package/src/engine/input/ecs/systems/InputControllerSystem.js +52 -2
  525. package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts.map +1 -1
  526. package/src/engine/intelligence/behavior/composite/ParallelBehavior.js +8 -0
  527. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.d.ts.map +1 -1
  528. package/src/engine/intelligence/behavior/decorator/RepeatBehavior.js +7 -0
  529. package/src/engine/intelligence/behavior/decorator/RepeatUntilSuccessBehavior.d.ts.map +1 -1
  530. package/src/engine/intelligence/behavior/decorator/RepeatUntilSuccessBehavior.js +14 -0
  531. package/src/engine/intelligence/behavior/ecs/BehaviorSystem.d.ts.map +1 -1
  532. package/src/engine/intelligence/behavior/ecs/BehaviorSystem.js +13 -0
  533. package/src/engine/interpolation/InterpolationLog.d.ts +51 -4
  534. package/src/engine/interpolation/InterpolationLog.d.ts.map +1 -1
  535. package/src/engine/interpolation/InterpolationLog.js +132 -2
  536. package/src/engine/interpolation/InterpolationSystem.d.ts +113 -35
  537. package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
  538. package/src/engine/interpolation/InterpolationSystem.js +674 -50
  539. package/src/engine/network/NetworkSession.d.ts +176 -47
  540. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  541. package/src/engine/network/NetworkSession.js +1462 -272
  542. package/src/engine/network/README.md +106 -3
  543. package/src/engine/network/SMOOTHNESS_DESIGN.md +392 -0
  544. package/src/engine/network/adapters/PoseCorrection.d.ts +50 -0
  545. package/src/engine/network/adapters/PoseCorrection.d.ts.map +1 -0
  546. package/src/engine/network/adapters/PoseCorrection.js +211 -0
  547. package/src/engine/network/adapters/TransformReplicationAdapter.d.ts +1 -0
  548. package/src/engine/network/adapters/TransformReplicationAdapter.d.ts.map +1 -1
  549. package/src/engine/network/adapters/TransformReplicationAdapter.js +17 -0
  550. package/src/engine/network/adapters/VelocityCorrection.d.ts +31 -0
  551. package/src/engine/network/adapters/VelocityCorrection.d.ts.map +1 -0
  552. package/src/engine/network/adapters/VelocityCorrection.js +71 -0
  553. package/src/engine/network/adapters/replicate_transform64.d.ts +13 -0
  554. package/src/engine/network/adapters/replicate_transform64.d.ts.map +1 -0
  555. package/src/engine/network/adapters/replicate_transform64.js +18 -0
  556. package/src/engine/network/adapters/rigid_body_of.d.ts +22 -0
  557. package/src/engine/network/adapters/rigid_body_of.d.ts.map +1 -0
  558. package/src/engine/network/adapters/rigid_body_of.js +33 -0
  559. package/src/engine/network/correction/Correction.d.ts +120 -0
  560. package/src/engine/network/correction/Correction.d.ts.map +1 -0
  561. package/src/engine/network/correction/Correction.js +143 -0
  562. package/src/engine/network/ecs/NetworkSystem.d.ts +36 -7
  563. package/src/engine/network/ecs/NetworkSystem.d.ts.map +1 -1
  564. package/src/engine/network/ecs/NetworkSystem.js +49 -7
  565. package/src/engine/network/orchestrator/NetworkPeer.d.ts +50 -1
  566. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  567. package/src/engine/network/orchestrator/NetworkPeer.js +143 -10
  568. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +38 -2
  569. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
  570. package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +58 -10
  571. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts +68 -2
  572. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
  573. package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +299 -18
  574. package/src/engine/network/replication/Replicator.d.ts +8 -1
  575. package/src/engine/network/replication/Replicator.d.ts.map +1 -1
  576. package/src/engine/network/replication/Replicator.js +50 -6
  577. package/src/engine/network/sim/ActionLog.d.ts +5 -2
  578. package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
  579. package/src/engine/network/sim/ActionLog.js +5 -2
  580. package/src/engine/network/sim/RewindEngine.d.ts.map +1 -1
  581. package/src/engine/network/sim/RewindEngine.js +6 -0
  582. package/src/engine/network/sim/SimActionExecutor.d.ts +48 -3
  583. package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
  584. package/src/engine/network/sim/SimActionExecutor.js +152 -6
  585. package/src/engine/network/sim/SmoothingState.d.ts +54 -2
  586. package/src/engine/network/sim/SmoothingState.d.ts.map +1 -1
  587. package/src/engine/network/sim/SmoothingState.js +107 -3
  588. package/src/engine/network/state/MutationLedger.d.ts.map +1 -1
  589. package/src/engine/network/state/MutationLedger.js +18 -2
  590. package/src/engine/network/state/PredictionHistory.d.ts +67 -0
  591. package/src/engine/network/state/PredictionHistory.d.ts.map +1 -0
  592. package/src/engine/network/state/PredictionHistory.js +145 -0
  593. package/src/engine/network/time/RenderPlayout.d.ts +2 -1
  594. package/src/engine/network/time/RenderPlayout.d.ts.map +1 -1
  595. package/src/engine/network/time/RenderPlayout.js +174 -163
  596. package/src/engine/network/transport/DeferredTransport.d.ts +57 -0
  597. package/src/engine/network/transport/DeferredTransport.d.ts.map +1 -0
  598. package/src/engine/network/transport/DeferredTransport.js +143 -0
  599. package/src/engine/network/transport/LoopbackTransport.d.ts +8 -0
  600. package/src/engine/network/transport/LoopbackTransport.d.ts.map +1 -1
  601. package/src/engine/network/transport/LoopbackTransport.js +12 -1
  602. package/src/engine/network/transport/ReliableCommandPipeline.d.ts.map +1 -1
  603. package/src/engine/network/transport/ReliableCommandPipeline.js +20 -0
  604. package/src/engine/network/transport/adapters/NodeUDPTransport.d.ts.map +1 -1
  605. package/src/engine/network/transport/adapters/NodeUDPTransport.js +11 -2
  606. package/src/engine/network/transport/adapters/WebTransportTransport.d.ts.map +1 -1
  607. package/src/engine/network/transport/adapters/WebTransportTransport.js +8 -1
  608. package/src/engine/network/transport/fragments/FragmentAssembler.d.ts +2 -1
  609. package/src/engine/network/transport/fragments/FragmentAssembler.d.ts.map +1 -1
  610. package/src/engine/network/transport/fragments/FragmentAssembler.js +67 -3
  611. package/src/engine/network/transport/fragments/fragment_send.d.ts +8 -0
  612. package/src/engine/network/transport/fragments/fragment_send.d.ts.map +1 -1
  613. package/src/engine/network/transport/fragments/fragment_send.js +17 -7
  614. package/src/engine/network/transport/fragments/packet_size.d.ts +6 -0
  615. package/src/engine/network/transport/fragments/packet_size.d.ts.map +1 -1
  616. package/src/engine/network/transport/fragments/packet_size.js +6 -0
  617. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  618. package/src/engine/physics/ccd/linear_sweep.js +19 -1
  619. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +7 -3
  620. package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
  621. package/src/engine/physics/cloth/ecs/ClothWorld.js +34 -4
  622. package/src/engine/physics/cloth/solver/cloth_self_find.js +17 -0
  623. package/src/engine/physics/contact/ManifoldStore.d.ts +20 -1
  624. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
  625. package/src/engine/physics/contact/ManifoldStore.js +24 -2
  626. package/src/engine/physics/ecs/PhysicsSystem.d.ts +51 -88
  627. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  628. package/src/engine/physics/ecs/PhysicsSystem.js +82 -217
  629. package/src/engine/physics/ecs/is_sensor.d.ts +24 -0
  630. package/src/engine/physics/ecs/is_sensor.d.ts.map +1 -1
  631. package/src/engine/physics/ecs/is_sensor.js +39 -0
  632. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +18 -4
  633. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -1
  634. package/src/engine/physics/fluid/ecs/FluidComponent.js +29 -8
  635. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  636. package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts +8 -0
  637. package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts.map +1 -1
  638. package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +8 -0
  639. package/src/engine/physics/fluid/solver/NOTES.md +46 -0
  640. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.js +1 -1
  641. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +1 -1
  642. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +1 -1
  643. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.js +1 -1
  644. package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.js +1 -1
  645. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.d.ts.map +1 -1
  646. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.js +8 -0
  647. package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.d.ts.map +1 -1
  648. package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.js +8 -0
  649. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -1
  650. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +8 -0
  651. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.d.ts +5 -0
  652. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.d.ts.map +1 -1
  653. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.js +5 -0
  654. package/src/engine/physics/integration/integrate_velocity.d.ts +15 -0
  655. package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
  656. package/src/engine/physics/integration/integrate_velocity.js +15 -0
  657. package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -1
  658. package/src/engine/physics/island/IslandBuilder.js +6 -7
  659. package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
  660. package/src/engine/physics/mls-mpm/MLS_MPM.js +29 -13
  661. package/src/engine/physics/mls-mpm/mls_mpm_demo_scene.d.ts +29 -0
  662. package/src/engine/physics/mls-mpm/mls_mpm_demo_scene.d.ts.map +1 -0
  663. package/src/engine/physics/mls-mpm/mls_mpm_demo_scene.js +44 -0
  664. package/src/engine/physics/mls-mpm/testMLS_MPM.js +3 -3
  665. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  666. package/src/engine/physics/narrowphase/narrowphase_step.js +74 -11
  667. package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -1
  668. package/src/engine/physics/queries/overlap_shape.js +92 -45
  669. package/src/engine/physics/queries/raycast.d.ts.map +1 -1
  670. package/src/engine/physics/queries/raycast.js +55 -43
  671. package/src/engine/physics/queries/shape_cast.d.ts.map +1 -1
  672. package/src/engine/physics/queries/shape_cast.js +185 -174
  673. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
  674. package/src/engine/physics/solver/solve_contacts.js +42 -19
  675. package/src/engine/plugin/EnginePluginManager.d.ts +10 -0
  676. package/src/engine/plugin/EnginePluginManager.d.ts.map +1 -1
  677. package/src/engine/plugin/EnginePluginManager.js +54 -1
  678. package/src/engine/plugin/PluginReferenceContext.d.ts.map +1 -1
  679. package/src/engine/plugin/PluginReferenceContext.js +7 -3
  680. package/src/engine/reference/v2/Reference.d.ts +9 -0
  681. package/src/engine/reference/v2/Reference.d.ts.map +1 -1
  682. package/src/engine/reference/v2/Reference.js +39 -2
  683. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  684. package/src/engine/simulation/Ticker.js +20 -1
  685. package/src/engine/sound/ecs/SoundListenerSystem.d.ts +27 -0
  686. package/src/engine/sound/ecs/SoundListenerSystem.d.ts.map +1 -1
  687. package/src/engine/sound/ecs/SoundListenerSystem.js +82 -21
  688. package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts.map +1 -1
  689. package/src/engine/sound/ecs/audio/LiveEmitterSet.js +394 -356
  690. package/src/engine/sound/material/concrete/SoundMaterialComposition.d.ts.map +1 -1
  691. package/src/engine/sound/material/concrete/SoundMaterialComposition.js +54 -17
  692. package/src/engine/sound/material/detector/terrain/TerrainSoundMaterialSurfaceDetector.d.ts.map +1 -1
  693. package/src/engine/sound/material/detector/terrain/TerrainSoundMaterialSurfaceDetector.js +34 -3
  694. package/src/engine/sound/simulation/core/AcousticSolution.d.ts +5 -0
  695. package/src/engine/sound/simulation/core/AcousticSolution.d.ts.map +1 -1
  696. package/src/engine/sound/simulation/core/AcousticSolution.js +5 -0
  697. package/src/engine/sound/simulation/definition/AcousticMaterial.d.ts +8 -0
  698. package/src/engine/sound/simulation/definition/AcousticMaterial.d.ts.map +1 -1
  699. package/src/engine/sound/simulation/definition/AcousticMaterial.js +8 -0
  700. package/src/engine/sound/simulation/probe/probe_visibility_augment.d.ts +6 -4
  701. package/src/engine/sound/simulation/probe/probe_visibility_augment.d.ts.map +1 -1
  702. package/src/engine/sound/simulation/probe/probe_visibility_augment.js +19 -7
  703. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts +39 -0
  704. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts.map +1 -1
  705. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +130 -1
  706. package/src/engine/sound/simulation/render/ProbeReverbRenderer.d.ts +3 -2
  707. package/src/engine/sound/simulation/render/ProbeReverbRenderer.d.ts.map +1 -1
  708. package/src/engine/sound/simulation/render/ProbeReverbRenderer.js +15 -1
  709. package/src/engine/sound/sopra/SopraEngine.d.ts +10 -0
  710. package/src/engine/sound/sopra/SopraEngine.d.ts.map +1 -1
  711. package/src/engine/sound/sopra/SopraEngine.js +486 -440
  712. package/src/engine/sound/sopra/runtime/BusGraph.d.ts +29 -0
  713. package/src/engine/sound/sopra/runtime/BusGraph.d.ts.map +1 -1
  714. package/src/engine/sound/sopra/runtime/BusGraph.js +69 -2
  715. package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
  716. package/src/engine/sound/sopra/runtime/EventInstance.js +130 -9
  717. package/src/engine/ui/GUIEngine.d.ts +14 -0
  718. package/src/engine/ui/GUIEngine.d.ts.map +1 -1
  719. package/src/engine/ui/GUIEngine.js +52 -4
  720. package/src/format/image/avif/api/apply_transformations.d.ts +2 -1
  721. package/src/format/image/avif/api/apply_transformations.d.ts.map +1 -1
  722. package/src/format/image/avif/api/apply_transformations.js +129 -120
  723. package/src/format/image/avif/api/convert_to_rgba.d.ts.map +1 -1
  724. package/src/format/image/avif/api/convert_to_rgba.js +35 -2
  725. package/src/format/image/avif/api/decode_image_item.d.ts +2 -1
  726. package/src/format/image/avif/api/decode_image_item.d.ts.map +1 -1
  727. package/src/format/image/avif/api/decode_image_item.js +322 -234
  728. package/src/format/image/avif/av1/decode/decode_av1_still.js +329 -309
  729. package/src/format/image/avif/av1/encode/encode_tile.js +2349 -2331
  730. package/src/format/image/avif/av1/entropy/symbol_cost.d.ts.map +1 -1
  731. package/src/format/image/avif/av1/entropy/symbol_cost.js +86 -76
  732. package/src/format/image/avif/heif/AvifFile.d.ts +11 -0
  733. package/src/format/image/avif/heif/AvifFile.d.ts.map +1 -1
  734. package/src/format/image/avif/heif/AvifFile.js +154 -142
  735. package/src/format/image/avif/heif/find_item_properties.d.ts +23 -0
  736. package/src/format/image/avif/heif/find_item_properties.d.ts.map +1 -0
  737. package/src/format/image/avif/heif/find_item_properties.js +36 -0
  738. package/src/format/image/avif/heif/parse_avif_file.js +6 -3
  739. package/src/format/image/avif/heif/read_item_data.d.ts.map +1 -1
  740. package/src/format/image/avif/heif/read_item_data.js +131 -97
  741. package/src/format/image/jpeg/decodeScan.d.ts.map +1 -1
  742. package/src/format/image/jpeg/decodeScan.js +17 -0
  743. package/src/format/scene/gltf/gltf_parse_container.d.ts.map +1 -1
  744. package/src/format/scene/gltf/gltf_parse_container.js +61 -41
  745. package/src/format/scene/gltf/gltf_read_accessor.d.ts +21 -0
  746. package/src/format/scene/gltf/gltf_read_accessor.d.ts.map +1 -1
  747. package/src/format/scene/gltf/gltf_read_accessor.js +37 -0
  748. package/src/format/scene/usd/usd_compose_transform.d.ts.map +1 -1
  749. package/src/format/scene/usd/usd_compose_transform.js +56 -6
  750. package/src/format/texture/basis/transcode/fit_endpoints.d.ts +6 -0
  751. package/src/format/texture/basis/transcode/fit_endpoints.d.ts.map +1 -1
  752. package/src/format/texture/basis/transcode/fit_endpoints.js +33 -39
  753. package/src/generation/filtering/numeric/CellFilterCache.d.ts +17 -0
  754. package/src/generation/filtering/numeric/CellFilterCache.d.ts.map +1 -1
  755. package/src/generation/filtering/numeric/CellFilterCache.js +36 -3
  756. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.d.ts +9 -0
  757. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.d.ts.map +1 -1
  758. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.js +37 -6
  759. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.d.ts.map +1 -1
  760. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.js +8 -21
  761. package/src/generation/grid/actions/grid_obstacle_write_grid_point.d.ts +28 -0
  762. package/src/generation/grid/actions/grid_obstacle_write_grid_point.d.ts.map +1 -0
  763. package/src/generation/grid/actions/grid_obstacle_write_grid_point.js +41 -0
  764. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.d.ts +15 -1
  765. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.d.ts.map +1 -1
  766. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.js +17 -3
  767. package/src/generation/markers/actions/MarkerNodeProcessingRuleSet.d.ts.map +1 -1
  768. package/src/generation/markers/actions/MarkerNodeProcessingRuleSet.js +16 -1
  769. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.d.ts.map +1 -1
  770. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.js +8 -1
  771. package/src/generation/theme/TerrainTheme.d.ts.map +1 -1
  772. package/src/generation/theme/TerrainTheme.js +20 -1
  773. package/src/shade/RENDERER_CONTRACT.md +63 -8
  774. package/src/shade/descriptor/texture/format/gpu_texture_formats_copy_compatible.d.ts +23 -0
  775. package/src/shade/descriptor/texture/format/gpu_texture_formats_copy_compatible.d.ts.map +1 -0
  776. package/src/shade/descriptor/texture/format/gpu_texture_formats_copy_compatible.js +28 -0
  777. package/src/shade/descriptor/texture/format/gpu_texture_formats_view_compatible.d.ts +25 -0
  778. package/src/shade/descriptor/texture/format/gpu_texture_formats_view_compatible.d.ts.map +1 -0
  779. package/src/shade/descriptor/texture/format/gpu_texture_formats_view_compatible.js +42 -0
  780. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +5 -0
  781. package/src/shade/device/ShadeGPUCommandContext.d.ts +15 -2
  782. package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
  783. package/src/shade/device/ShadeGPUCommandContext.js +1003 -857
  784. package/src/shade/device/mock/SoftwareGPUBindGroup.d.ts +38 -1
  785. package/src/shade/device/mock/SoftwareGPUBindGroup.d.ts.map +1 -1
  786. package/src/shade/device/mock/SoftwareGPUBindGroup.js +73 -1
  787. package/src/shade/device/mock/SoftwareGPUBuffer.d.ts.map +1 -1
  788. package/src/shade/device/mock/SoftwareGPUBuffer.js +5 -0
  789. package/src/shade/device/mock/SoftwareGPUCommandBuffer.d.ts +34 -0
  790. package/src/shade/device/mock/SoftwareGPUCommandBuffer.d.ts.map +1 -1
  791. package/src/shade/device/mock/SoftwareGPUCommandBuffer.js +71 -1
  792. package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts +15 -0
  793. package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts.map +1 -1
  794. package/src/shade/device/mock/SoftwareGPUCommandEncoder.js +109 -1
  795. package/src/shade/device/mock/SoftwareGPUComputePassEncoder.d.ts.map +1 -1
  796. package/src/shade/device/mock/SoftwareGPUComputePassEncoder.js +51 -0
  797. package/src/shade/device/mock/SoftwareGPUDevice.d.ts +5 -1
  798. package/src/shade/device/mock/SoftwareGPUDevice.d.ts.map +1 -1
  799. package/src/shade/device/mock/SoftwareGPUDevice.js +58 -1
  800. package/src/shade/device/mock/SoftwareGPUPipeline.d.ts +1 -0
  801. package/src/shade/device/mock/SoftwareGPUPipeline.d.ts.map +1 -1
  802. package/src/shade/device/mock/SoftwareGPUPipeline.js +17 -11
  803. package/src/shade/device/mock/SoftwareGPUQueue.d.ts.map +1 -1
  804. package/src/shade/device/mock/SoftwareGPUQueue.js +41 -0
  805. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts.map +1 -1
  806. package/src/shade/device/mock/SoftwareGPURenderPassEncoder.js +24 -0
  807. package/src/shade/device/mock/SoftwareGPUTexture.d.ts +11 -1
  808. package/src/shade/device/mock/SoftwareGPUTexture.d.ts.map +1 -1
  809. package/src/shade/device/mock/SoftwareGPUTexture.js +45 -8
  810. package/src/shade/device/mock/SoftwareGPUTextureView.d.ts +20 -1
  811. package/src/shade/device/mock/SoftwareGPUTextureView.d.ts.map +1 -1
  812. package/src/shade/device/mock/SoftwareGPUTextureView.js +28 -1
  813. package/src/shade/device/mock/recorded_binding_kind_mismatches.d.ts +20 -0
  814. package/src/shade/device/mock/recorded_binding_kind_mismatches.d.ts.map +1 -0
  815. package/src/shade/device/mock/recorded_binding_kind_mismatches.js +84 -0
  816. package/src/shade/device/mock/texture_copy.d.ts.map +1 -1
  817. package/src/shade/device/mock/texture_copy.js +41 -3
  818. package/src/shade/device/mock/texture_view_resource.d.ts +26 -0
  819. package/src/shade/device/mock/texture_view_resource.d.ts.map +1 -0
  820. package/src/shade/device/mock/texture_view_resource.js +47 -0
  821. package/src/shade/device/timing/GPUTimer.d.ts.map +1 -1
  822. package/src/shade/device/timing/GPUTimer.js +35 -21
  823. package/src/shade/playground/caldera/caldera_format.d.ts +28 -1
  824. package/src/shade/playground/caldera/caldera_format.d.ts.map +1 -1
  825. package/src/shade/playground/caldera/caldera_format.js +37 -0
  826. package/src/shade/playground/caldera/main.js +12 -2
  827. package/src/shade/playground/frame_rate_meter.d.ts +92 -0
  828. package/src/shade/playground/frame_rate_meter.d.ts.map +1 -0
  829. package/src/shade/playground/frame_rate_meter.js +147 -0
  830. package/src/shade/playground/particle_ecs/main.js +53 -7
  831. package/src/shade/playground/particle_ecs/moonlit_environment.js +2 -2
  832. package/src/shade/playground/particle_stats_readback.d.ts +58 -0
  833. package/src/shade/playground/particle_stats_readback.d.ts.map +1 -0
  834. package/src/shade/playground/particle_stats_readback.js +83 -0
  835. package/src/shade/playground/particle_system/main.js +378 -325
  836. package/src/shade/playground/skinned_blas_refit/main.d.ts.map +1 -1
  837. package/src/shade/playground/skinned_blas_refit/main.js +7 -2
  838. package/src/shade/playground/sponza_path_trace/main.d.ts.map +1 -1
  839. package/src/shade/playground/sponza_path_trace/main.js +398 -393
  840. package/src/shade/playground/volumetrics_froxel/main.d.ts.map +1 -1
  841. package/src/shade/playground/volumetrics_froxel/main.js +941 -936
  842. package/src/shade/renderer/GraphicsContext.d.ts +9 -1
  843. package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
  844. package/src/shade/renderer/GraphicsContext.js +61 -17
  845. package/src/shade/renderer/Renderer.d.ts +66 -5
  846. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  847. package/src/shade/renderer/Renderer.js +337 -29
  848. package/src/shade/renderer/animation/ANIMATION_CLIP_STATE_STRUCT.d.ts +4 -7
  849. package/src/shade/renderer/animation/ANIMATION_CLIP_STATE_STRUCT.d.ts.map +1 -1
  850. package/src/shade/renderer/animation/ANIMATION_CLIP_STATE_STRUCT.js +19 -16
  851. package/src/shade/renderer/animation/ANIMATION_CURVE_HEADER_STRUCT.js +11 -11
  852. package/src/shade/renderer/animation/ANIMATION_DATABASE_SPEC.d.ts +14 -18
  853. package/src/shade/renderer/animation/ANIMATION_DATABASE_SPEC.d.ts.map +1 -1
  854. package/src/shade/renderer/animation/ANIMATION_DATABASE_SPEC.js +95 -24
  855. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_STRUCT.d.ts +5 -4
  856. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_STRUCT.d.ts.map +1 -1
  857. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_STRUCT.js +7 -4
  858. package/src/shade/renderer/animation/ANIMATION_SKIN_STRUCT.d.ts +6 -12
  859. package/src/shade/renderer/animation/ANIMATION_SKIN_STRUCT.d.ts.map +1 -1
  860. package/src/shade/renderer/animation/ANIMATION_SKIN_STRUCT.js +9 -16
  861. package/src/shade/renderer/animation/ANIMATION_TRACK_BINDING_STRUCT.d.ts +6 -5
  862. package/src/shade/renderer/animation/ANIMATION_TRACK_BINDING_STRUCT.d.ts.map +1 -1
  863. package/src/shade/renderer/animation/ANIMATION_TRACK_BINDING_STRUCT.js +12 -5
  864. package/src/shade/renderer/animation/GPUAnimationManager.d.ts +83 -95
  865. package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
  866. package/src/shade/renderer/animation/GPUAnimationManager.js +496 -629
  867. package/src/shade/renderer/animation/chunk_animation_curve_evaluate.d.ts +10 -14
  868. package/src/shade/renderer/animation/chunk_animation_curve_evaluate.d.ts.map +1 -1
  869. package/src/shade/renderer/animation/chunk_animation_curve_evaluate.js +40 -67
  870. package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts.map +1 -1
  871. package/src/shade/renderer/animation/chunk_pose_accumulator.js +13 -4
  872. package/src/shade/renderer/animation/shader_animation_apply.d.ts +14 -8
  873. package/src/shade/renderer/animation/shader_animation_apply.d.ts.map +1 -1
  874. package/src/shade/renderer/animation/shader_animation_apply.js +129 -128
  875. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +2 -2
  876. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts +3 -2
  877. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts.map +1 -1
  878. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.js +3 -2
  879. package/src/shade/renderer/animation/skinning/shader_skin_matrix_prep.d.ts +12 -7
  880. package/src/shade/renderer/animation/skinning/shader_skin_matrix_prep.d.ts.map +1 -1
  881. package/src/shade/renderer/animation/skinning/shader_skin_matrix_prep.js +107 -104
  882. package/src/shade/renderer/binding/BindingResource.d.ts +36 -1
  883. package/src/shade/renderer/binding/BindingResource.d.ts.map +1 -1
  884. package/src/shade/renderer/binding/BindingResource.js +36 -3
  885. package/src/shade/renderer/binding/BufferBinding.d.ts +8 -0
  886. package/src/shade/renderer/binding/BufferBinding.d.ts.map +1 -1
  887. package/src/shade/renderer/binding/BufferBinding.js +21 -0
  888. package/src/shade/renderer/buffer/GPUBufferStagingAllocator.d.ts +11 -2
  889. package/src/shade/renderer/buffer/GPUBufferStagingAllocator.d.ts.map +1 -1
  890. package/src/shade/renderer/buffer/GPUBufferStagingAllocator.js +95 -13
  891. package/src/shade/renderer/buffer/GPUBufferUploadAllocator.d.ts +60 -0
  892. package/src/shade/renderer/buffer/GPUBufferUploadAllocator.d.ts.map +1 -0
  893. package/src/shade/renderer/buffer/GPUBufferUploadAllocator.js +202 -0
  894. package/src/shade/renderer/buffer/GPUUploadBlock.d.ts +68 -0
  895. package/src/shade/renderer/buffer/GPUUploadBlock.d.ts.map +1 -0
  896. package/src/shade/renderer/buffer/GPUUploadBlock.js +97 -0
  897. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts +19 -0
  898. package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
  899. package/src/shade/renderer/buffer/table/GPUDatabase.js +114 -1
  900. package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.d.ts +132 -1
  901. package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.d.ts.map +1 -1
  902. package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.js +384 -1
  903. package/src/shade/renderer/buffer/table/GPUDatabaseReadback.d.ts.map +1 -1
  904. package/src/shade/renderer/buffer/table/GPUDatabaseReadback.js +1332 -1323
  905. package/src/shade/renderer/buffer/table/GPUTableLink.d.ts +67 -0
  906. package/src/shade/renderer/buffer/table/GPUTableLink.d.ts.map +1 -0
  907. package/src/shade/renderer/buffer/table/GPUTableLink.js +76 -0
  908. package/src/shade/renderer/buffer/table/GPUTableRange.d.ts +72 -0
  909. package/src/shade/renderer/buffer/table/GPUTableRange.d.ts.map +1 -0
  910. package/src/shade/renderer/buffer/table/GPUTableRange.js +82 -0
  911. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts +106 -5
  912. package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
  913. package/src/shade/renderer/buffer/table/GPUTypedTable.js +444 -28
  914. package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.d.ts.map +1 -1
  915. package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.js +28 -5
  916. package/src/shade/renderer/buffer/table/GPU_DATABASE_NULL.d.ts +14 -0
  917. package/src/shade/renderer/buffer/table/GPU_DATABASE_NULL.d.ts.map +1 -0
  918. package/src/shade/renderer/buffer/table/GPU_DATABASE_NULL.js +13 -0
  919. package/src/shade/renderer/buffer/table/gpu_database_check_links.d.ts +80 -0
  920. package/src/shade/renderer/buffer/table/gpu_database_check_links.d.ts.map +1 -0
  921. package/src/shade/renderer/buffer/table/gpu_database_check_links.js +456 -0
  922. package/src/shade/renderer/buffer/table/gpu_table_field_word.d.ts +17 -0
  923. package/src/shade/renderer/buffer/table/gpu_table_field_word.d.ts.map +1 -0
  924. package/src/shade/renderer/buffer/table/gpu_table_field_word.js +111 -0
  925. package/src/shade/renderer/buffer/table/gpu_table_range_well_formed.d.ts +20 -0
  926. package/src/shade/renderer/buffer/table/gpu_table_range_well_formed.d.ts.map +1 -0
  927. package/src/shade/renderer/buffer/table/gpu_table_range_well_formed.js +27 -0
  928. package/src/shade/renderer/camera/CameraManager.d.ts +11 -0
  929. package/src/shade/renderer/camera/CameraManager.d.ts.map +1 -1
  930. package/src/shade/renderer/camera/CameraManager.js +18 -0
  931. package/src/shade/renderer/create_frame_loop.d.ts +16 -0
  932. package/src/shade/renderer/create_frame_loop.d.ts.map +1 -1
  933. package/src/shade/renderer/create_frame_loop.js +16 -0
  934. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct.d.ts +23 -0
  935. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct.d.ts.map +1 -1
  936. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct.js +27 -32
  937. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_heavy.d.ts +9 -7
  938. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_heavy.d.ts.map +1 -1
  939. package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_heavy.js +16 -108
  940. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts +135 -0
  941. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts.map +1 -0
  942. package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.js +296 -0
  943. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts +22 -9
  944. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts.map +1 -1
  945. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.js +30 -138
  946. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.d.ts.map +1 -1
  947. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +185 -167
  948. package/src/shade/renderer/dynamic/GPUDynamicMeshResidencyTable.d.ts +49 -0
  949. package/src/shade/renderer/dynamic/GPUDynamicMeshResidencyTable.d.ts.map +1 -0
  950. package/src/shade/renderer/dynamic/GPUDynamicMeshResidencyTable.js +185 -0
  951. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts +24 -0
  952. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts.map +1 -0
  953. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.js +49 -0
  954. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts +18 -0
  955. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts.map +1 -0
  956. package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.js +54 -0
  957. package/src/shade/renderer/dynamic/dynamic_mesh_live_bounds.d.ts +26 -0
  958. package/src/shade/renderer/dynamic/dynamic_mesh_live_bounds.d.ts.map +1 -0
  959. package/src/shade/renderer/dynamic/dynamic_mesh_live_bounds.js +96 -0
  960. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts +102 -0
  961. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts.map +1 -0
  962. package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.js +364 -0
  963. package/src/shade/renderer/dynamic/shader_dynamic_mesh.d.ts.map +1 -1
  964. package/src/shade/renderer/dynamic/shader_dynamic_mesh.js +153 -177
  965. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts +20 -0
  966. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts.map +1 -0
  967. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.js +136 -0
  968. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_occupancy.d.ts +20 -0
  969. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_occupancy.d.ts.map +1 -0
  970. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_occupancy.js +106 -0
  971. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts +32 -0
  972. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts.map +1 -0
  973. package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +163 -0
  974. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +13 -2
  975. package/src/shade/renderer/fow/GPUFogOfWarRenderer.d.ts.map +1 -1
  976. package/src/shade/renderer/fow/GPUFogOfWarRenderer.js +5 -14
  977. package/src/shade/renderer/fow/fow_obtain_mask.d.ts +17 -0
  978. package/src/shade/renderer/fow/fow_obtain_mask.d.ts.map +1 -0
  979. package/src/shade/renderer/fow/fow_obtain_mask.js +41 -0
  980. package/src/shade/renderer/frame_jitter_applies.d.ts +21 -0
  981. package/src/shade/renderer/frame_jitter_applies.d.ts.map +1 -0
  982. package/src/shade/renderer/frame_jitter_applies.js +23 -0
  983. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
  984. package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +128 -3
  985. package/src/shade/renderer/geometry/geometry_obtain_attribute.d.ts +42 -0
  986. package/src/shade/renderer/geometry/geometry_obtain_attribute.d.ts.map +1 -0
  987. package/src/shade/renderer/geometry/geometry_obtain_attribute.js +83 -0
  988. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +12 -0
  989. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
  990. package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +65 -0
  991. package/src/shade/renderer/geometry/meshlet/build/geometry_to_meshlets_greedy.d.ts.map +1 -1
  992. package/src/shade/renderer/geometry/meshlet/build/geometry_to_meshlets_greedy.js +4 -1
  993. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts +5 -0
  994. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
  995. package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +23 -1
  996. package/src/shade/renderer/geometry/normals/encode_normals_to_octahedral_u32.d.ts.map +1 -1
  997. package/src/shade/renderer/geometry/normals/encode_normals_to_octahedral_u32.js +4 -1
  998. package/src/shade/renderer/geometry/normals/geometry_build_tangents.d.ts.map +1 -1
  999. package/src/shade/renderer/geometry/normals/geometry_build_tangents.js +39 -1
  1000. package/src/shade/renderer/geometry/util/geometry_merge.d.ts.map +1 -1
  1001. package/src/shade/renderer/geometry/util/geometry_merge.js +18 -2
  1002. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +77 -39
  1003. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_collect_geometries.d.ts.map +1 -1
  1004. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_collect_geometries.js +31 -2
  1005. package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.d.ts +18 -0
  1006. package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.d.ts.map +1 -1
  1007. package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.js +19 -0
  1008. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.d.ts +8 -0
  1009. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.d.ts.map +1 -1
  1010. package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.js +9 -0
  1011. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.d.ts.map +1 -1
  1012. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +10 -1
  1013. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.d.ts.map +1 -1
  1014. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.js +4 -0
  1015. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.d.ts.map +1 -1
  1016. package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.js +12 -0
  1017. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
  1018. package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +10 -1
  1019. package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +21 -0
  1020. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
  1021. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +33 -1
  1022. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -1
  1023. package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +63 -2
  1024. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +17 -0
  1025. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -1
  1026. package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +39 -0
  1027. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
  1028. package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +7 -0
  1029. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_decode.d.ts.map +1 -1
  1030. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_decode.js +23 -2
  1031. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_decode_from_storage.d.ts.map +1 -1
  1032. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_decode_from_storage.js +22 -1
  1033. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_encode.d.ts.map +1 -1
  1034. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_encode.js +23 -2
  1035. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_encode_to_storage.d.ts.map +1 -1
  1036. package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_encode_to_storage.js +22 -1
  1037. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.d.ts +2 -1
  1038. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.d.ts.map +1 -1
  1039. package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.js +12 -53
  1040. package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lvp_atlas_to_sh.d.ts.map +1 -1
  1041. package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lvp_atlas_to_sh.js +2 -1
  1042. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_patch_texel_coord.d.ts +17 -0
  1043. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_patch_texel_coord.d.ts.map +1 -0
  1044. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_patch_texel_coord.js +38 -0
  1045. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_read_patch_texel.d.ts.map +1 -1
  1046. package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_read_patch_texel.js +16 -10
  1047. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts +1 -1
  1048. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts.map +1 -1
  1049. package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.js +25 -14
  1050. package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +94 -0
  1051. package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.d.ts +10 -7
  1052. package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.d.ts.map +1 -1
  1053. package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.js +10 -7
  1054. package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
  1055. package/src/shade/renderer/light/GPULightCollection.js +22 -1
  1056. package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.d.ts.map +1 -1
  1057. package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.js +26 -0
  1058. package/src/shade/renderer/light/cluster/chunk_cluster_keep_smallest.d.ts +21 -0
  1059. package/src/shade/renderer/light/cluster/chunk_cluster_keep_smallest.d.ts.map +1 -0
  1060. package/src/shade/renderer/light/cluster/chunk_cluster_keep_smallest.js +47 -0
  1061. package/src/shade/renderer/light/cluster/shader_cluster_assign_lights.d.ts.map +1 -1
  1062. package/src/shade/renderer/light/cluster/shader_cluster_assign_lights.js +12 -8
  1063. package/src/shade/renderer/light/environment/equirectangular_zenith_first_direction_to_uv.d.ts +36 -0
  1064. package/src/shade/renderer/light/environment/equirectangular_zenith_first_direction_to_uv.d.ts.map +1 -0
  1065. package/src/shade/renderer/light/environment/equirectangular_zenith_first_direction_to_uv.js +41 -0
  1066. package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts.map +1 -1
  1067. package/src/shade/renderer/light/environment/execute_filter_environment_map.js +17 -1
  1068. package/src/shade/renderer/light/environment/octahedral_uv_to_direction.d.ts +5 -13
  1069. package/src/shade/renderer/light/environment/octahedral_uv_to_direction.d.ts.map +1 -1
  1070. package/src/shade/renderer/light/environment/octahedral_uv_to_direction.js +10 -30
  1071. package/src/shade/renderer/light/environment/octahedral_z_pole_uv_to_direction.d.ts +31 -0
  1072. package/src/shade/renderer/light/environment/octahedral_z_pole_uv_to_direction.d.ts.map +1 -0
  1073. package/src/shade/renderer/light/environment/octahedral_z_pole_uv_to_direction.js +45 -0
  1074. package/src/shade/renderer/light/environment/resample_cube_to_octahedral.js +2 -2
  1075. package/src/shade/renderer/light/environment/resample_equirectangular_to_octahedral.d.ts.map +1 -1
  1076. package/src/shade/renderer/light/environment/resample_equirectangular_to_octahedral.js +11 -8
  1077. package/src/shade/renderer/light/model/SpotLight.d.ts +10 -1
  1078. package/src/shade/renderer/light/model/SpotLight.d.ts.map +1 -1
  1079. package/src/shade/renderer/light/model/SpotLight.js +11 -3
  1080. package/src/shade/renderer/light/model/io/light_record_directional.d.ts.map +1 -1
  1081. package/src/shade/renderer/light/model/io/light_record_directional.js +3 -1
  1082. package/src/shade/renderer/light/model/io/light_record_point.d.ts.map +1 -1
  1083. package/src/shade/renderer/light/model/io/light_record_point.js +3 -1
  1084. package/src/shade/renderer/light/model/io/light_record_spot.d.ts.map +1 -1
  1085. package/src/shade/renderer/light/model/io/light_record_spot.js +3 -1
  1086. package/src/shade/renderer/loader/gltf/gltf_base_url.d.ts +20 -0
  1087. package/src/shade/renderer/loader/gltf/gltf_base_url.d.ts.map +1 -0
  1088. package/src/shade/renderer/loader/gltf/gltf_base_url.js +27 -0
  1089. package/src/shade/renderer/loader/gltf/gltf_create_material.d.ts.map +1 -1
  1090. package/src/shade/renderer/loader/gltf/gltf_create_material.js +50 -10
  1091. package/src/shade/renderer/loader/gltf/load_gltf.d.ts +4 -0
  1092. package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
  1093. package/src/shade/renderer/loader/gltf/load_gltf.js +28 -56
  1094. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  1095. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts.map +1 -1
  1096. package/src/shade/renderer/loader/gltf/tiny-gltf.js +843 -843
  1097. package/src/shade/renderer/material/GPUMaterialContext.d.ts +63 -26
  1098. package/src/shade/renderer/material/GPUMaterialContext.d.ts.map +1 -1
  1099. package/src/shade/renderer/material/GPUMaterialContext.js +255 -390
  1100. package/src/shade/renderer/material/GPUMaterialManager.d.ts +51 -1
  1101. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  1102. package/src/shade/renderer/material/GPUMaterialManager.js +345 -91
  1103. package/src/shade/renderer/material/ShadeMaterial.d.ts +21 -0
  1104. package/src/shade/renderer/material/ShadeMaterial.d.ts.map +1 -1
  1105. package/src/shade/renderer/material/ShadeMaterial.js +31 -0
  1106. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  1107. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +25 -6
  1108. package/src/shade/renderer/material/standard/SHADING_MATERIAL_RESOURCE_GROUP.d.ts +10 -0
  1109. package/src/shade/renderer/material/standard/SHADING_MATERIAL_RESOURCE_GROUP.d.ts.map +1 -1
  1110. package/src/shade/renderer/material/standard/SHADING_MATERIAL_RESOURCE_GROUP.js +14 -2
  1111. package/src/shade/renderer/material/standard/STANDARD_MATERIAL_TEMPLATE.d.ts +12 -0
  1112. package/src/shade/renderer/material/standard/STANDARD_MATERIAL_TEMPLATE.d.ts.map +1 -0
  1113. package/src/shade/renderer/material/standard/STANDARD_MATERIAL_TEMPLATE.js +166 -0
  1114. package/src/shade/renderer/material/standard/VT_MATERIAL_TEMPLATE.d.ts +10 -0
  1115. package/src/shade/renderer/material/standard/VT_MATERIAL_TEMPLATE.d.ts.map +1 -0
  1116. package/src/shade/renderer/material/standard/VT_MATERIAL_TEMPLATE.js +141 -0
  1117. package/src/shade/renderer/material/standard/chunk_standard_material_surface.d.ts +29 -0
  1118. package/src/shade/renderer/material/standard/chunk_standard_material_surface.d.ts.map +1 -0
  1119. package/src/shade/renderer/material/standard/chunk_standard_material_surface.js +92 -0
  1120. package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts +74 -28
  1121. package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts.map +1 -1
  1122. package/src/shade/renderer/material/standard/fragment_gbuffer.js +165 -67
  1123. package/src/shade/renderer/material/standard/fragment_gbuffer_vt.d.ts +27 -18
  1124. package/src/shade/renderer/material/standard/fragment_gbuffer_vt.d.ts.map +1 -1
  1125. package/src/shade/renderer/material/standard/fragment_gbuffer_vt.js +70 -91
  1126. package/src/shade/renderer/material/standard/material_gbuffer_vertex.d.ts +9 -6
  1127. package/src/shade/renderer/material/standard/material_gbuffer_vertex.d.ts.map +1 -1
  1128. package/src/shade/renderer/material/standard/material_gbuffer_vertex.js +13 -14
  1129. package/src/shade/renderer/material/template/GPUMaterialServices.d.ts +73 -0
  1130. package/src/shade/renderer/material/template/GPUMaterialServices.d.ts.map +1 -0
  1131. package/src/shade/renderer/material/template/GPUMaterialServices.js +79 -0
  1132. package/src/shade/renderer/material/template/ShadeMaterialTemplate.d.ts +170 -0
  1133. package/src/shade/renderer/material/template/ShadeMaterialTemplate.d.ts.map +1 -0
  1134. package/src/shade/renderer/material/template/ShadeMaterialTemplate.js +234 -0
  1135. package/src/shade/renderer/material/template/chunk_material_surface.d.ts +47 -0
  1136. package/src/shade/renderer/material/template/chunk_material_surface.d.ts.map +1 -0
  1137. package/src/shade/renderer/material/template/chunk_material_surface.js +116 -0
  1138. package/src/shade/renderer/material/template/flat_material_template_spec_support.d.ts +22 -0
  1139. package/src/shade/renderer/material/template/flat_material_template_spec_support.d.ts.map +1 -0
  1140. package/src/shade/renderer/material/template/flat_material_template_spec_support.js +78 -0
  1141. package/src/shade/renderer/material/template/material_metadata_neutral.d.ts +15 -0
  1142. package/src/shade/renderer/material/template/material_metadata_neutral.d.ts.map +1 -0
  1143. package/src/shade/renderer/material/template/material_metadata_neutral.js +46 -0
  1144. package/src/shade/renderer/material/template/material_template_of.d.ts +10 -0
  1145. package/src/shade/renderer/material/template/material_template_of.d.ts.map +1 -0
  1146. package/src/shade/renderer/material/template/material_template_of.js +20 -0
  1147. package/src/shade/renderer/object_property/chunk_write_object_property.d.ts +5 -0
  1148. package/src/shade/renderer/object_property/chunk_write_object_property.d.ts.map +1 -1
  1149. package/src/shade/renderer/object_property/chunk_write_object_property.js +7 -1
  1150. package/src/shade/renderer/object_property/chunk_write_object_property_node3d.d.ts +7 -1
  1151. package/src/shade/renderer/object_property/chunk_write_object_property_node3d.d.ts.map +1 -1
  1152. package/src/shade/renderer/object_property/chunk_write_object_property_node3d.js +9 -2
  1153. package/src/shade/renderer/particles/DESIGN.md +7 -0
  1154. package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.d.ts.map +1 -1
  1155. package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.js +81 -68
  1156. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts +22 -3
  1157. package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts.map +1 -1
  1158. package/src/shade/renderer/particles/isa/ParticleVMISA.js +30 -3
  1159. package/src/shade/renderer/particles/isa/particle_assembly.js +41 -1
  1160. package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts +7 -1
  1161. package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts.map +1 -1
  1162. package/src/shade/renderer/particles/optimizer/particle_program_analysis.js +23 -17
  1163. package/src/shade/renderer/particles/optimizer/pass_allocate_registers.js +1 -1
  1164. package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +10 -9
  1165. package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts.map +1 -1
  1166. package/src/shade/renderer/particles/optimizer/pass_inline_constants.js +4 -3
  1167. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.d.ts.map +1 -1
  1168. package/src/shade/renderer/particles/optimizer/pass_narrow_widths.js +1 -1
  1169. package/src/shade/renderer/particles/optimizer/pass_pack_registers.d.ts.map +1 -1
  1170. package/src/shade/renderer/particles/optimizer/pass_pack_registers.js +12 -4
  1171. package/src/shade/renderer/particles/optimizer/pass_peephole.d.ts.map +1 -1
  1172. package/src/shade/renderer/particles/optimizer/pass_peephole.js +11 -10
  1173. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.d.ts.map +1 -1
  1174. package/src/shade/renderer/particles/optimizer/pass_propagate_copies.js +12 -10
  1175. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.d.ts.map +1 -1
  1176. package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.js +12 -4
  1177. package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
  1178. package/src/shade/renderer/particles/runtime/ParticleEmitter.js +7 -0
  1179. package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.d.ts +4 -0
  1180. package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.d.ts.map +1 -1
  1181. package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.js +47 -88
  1182. package/src/shade/renderer/particles/shaders/shader_particle_avboit_occupancy.d.ts.map +1 -1
  1183. package/src/shade/renderer/particles/shaders/shader_particle_avboit_occupancy.js +22 -68
  1184. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts.map +1 -1
  1185. package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.js +5 -3
  1186. package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
  1187. package/src/shade/renderer/particles/vm/ParticleVMReference.js +17 -1
  1188. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.d.ts.map +1 -1
  1189. package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.js +12 -2
  1190. package/src/shade/renderer/postprocess/TemporalJitterSequence.d.ts +44 -0
  1191. package/src/shade/renderer/postprocess/TemporalJitterSequence.d.ts.map +1 -0
  1192. package/src/shade/renderer/postprocess/TemporalJitterSequence.js +104 -0
  1193. package/src/shade/renderer/postprocess/chunk_find_nearest_depth.d.ts +25 -0
  1194. package/src/shade/renderer/postprocess/chunk_find_nearest_depth.d.ts.map +1 -0
  1195. package/src/shade/renderer/postprocess/chunk_find_nearest_depth.js +74 -0
  1196. package/src/shade/renderer/postprocess/denoise/shader_temporal_reprojection_luma.d.ts.map +1 -1
  1197. package/src/shade/renderer/postprocess/denoise/shader_temporal_reprojection_luma.js +19 -4
  1198. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_recombine.d.ts.map +1 -1
  1199. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_recombine.js +12 -1
  1200. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts.map +1 -1
  1201. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.js +8 -0
  1202. package/src/shade/renderer/postprocess/eye/shader_autoexposure_adapt.d.ts.map +1 -1
  1203. package/src/shade/renderer/postprocess/eye/shader_autoexposure_adapt.js +18 -3
  1204. package/src/shade/renderer/postprocess/eye/shader_autoexposure_read_histogram.d.ts.map +1 -1
  1205. package/src/shade/renderer/postprocess/eye/shader_autoexposure_read_histogram.js +17 -4
  1206. package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.d.ts +29 -0
  1207. package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.d.ts.map +1 -0
  1208. package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.js +69 -0
  1209. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts +4 -16
  1210. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
  1211. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +10 -52
  1212. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts +0 -16
  1213. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
  1214. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +23 -55
  1215. package/src/shade/renderer/postprocess/motion_blur/MotionBlur.d.ts +4 -1
  1216. package/src/shade/renderer/postprocess/motion_blur/MotionBlur.d.ts.map +1 -1
  1217. package/src/shade/renderer/postprocess/motion_blur/MotionBlur.js +4 -1
  1218. package/src/shade/renderer/postprocess/motion_blur/chunk_motion_blur_resolution.d.ts +18 -0
  1219. package/src/shade/renderer/postprocess/motion_blur/chunk_motion_blur_resolution.d.ts.map +1 -0
  1220. package/src/shade/renderer/postprocess/motion_blur/chunk_motion_blur_resolution.js +43 -0
  1221. package/src/shade/renderer/postprocess/motion_blur/graph_postprocess_motion_blur.d.ts +5 -1
  1222. package/src/shade/renderer/postprocess/motion_blur/graph_postprocess_motion_blur.d.ts.map +1 -1
  1223. package/src/shade/renderer/postprocess/motion_blur/graph_postprocess_motion_blur.js +12 -2
  1224. package/src/shade/renderer/postprocess/motion_blur/shader_motion_blur_reconstruct.d.ts.map +1 -1
  1225. package/src/shade/renderer/postprocess/motion_blur/shader_motion_blur_reconstruct.js +33 -6
  1226. package/src/shade/renderer/postprocess/nss/NSS.d.ts +16 -8
  1227. package/src/shade/renderer/postprocess/nss/NSS.d.ts.map +1 -1
  1228. package/src/shade/renderer/postprocess/nss/NSS.js +37 -35
  1229. package/src/shade/renderer/postprocess/nss/chunk_nss_find_nearest_depth.d.ts +2 -2
  1230. package/src/shade/renderer/postprocess/nss/chunk_nss_find_nearest_depth.d.ts.map +1 -1
  1231. package/src/shade/renderer/postprocess/nss/chunk_nss_find_nearest_depth.js +28 -61
  1232. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
  1233. package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +296 -291
  1234. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.d.ts.map +1 -1
  1235. package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +13 -0
  1236. package/src/shade/renderer/postprocess/ssr/SSR.d.ts.map +1 -1
  1237. package/src/shade/renderer/postprocess/ssr/SSR.js +9 -7
  1238. package/src/shade/renderer/postprocess/ssr/depth_max_shader.d.ts +14 -0
  1239. package/src/shade/renderer/postprocess/ssr/depth_max_shader.d.ts.map +1 -1
  1240. package/src/shade/renderer/postprocess/ssr/depth_max_shader.js +53 -25
  1241. package/src/shade/renderer/postprocess/ssr/graph_build_depth_max_pyramid.d.ts +11 -1
  1242. package/src/shade/renderer/postprocess/ssr/graph_build_depth_max_pyramid.d.ts.map +1 -1
  1243. package/src/shade/renderer/postprocess/ssr/graph_build_depth_max_pyramid.js +11 -1
  1244. package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +46 -0
  1245. package/src/shade/renderer/postprocess/ssr/prefilter/shader_ssr_prefilter.d.ts.map +1 -1
  1246. package/src/shade/renderer/postprocess/ssr/prefilter/shader_ssr_prefilter.js +7 -0
  1247. package/src/shade/renderer/postprocess/ssr/shader/chunk_ssr_depth_thickness.d.ts +32 -0
  1248. package/src/shade/renderer/postprocess/ssr/shader/chunk_ssr_depth_thickness.d.ts.map +1 -0
  1249. package/src/shade/renderer/postprocess/ssr/shader/chunk_ssr_depth_thickness.js +41 -0
  1250. package/src/shade/renderer/postprocess/ssr/ssr_trace_shader.d.ts.map +1 -1
  1251. package/src/shade/renderer/postprocess/ssr/ssr_trace_shader.js +11 -6
  1252. package/src/shade/renderer/postprocess/taa/TAA.d.ts +13 -4
  1253. package/src/shade/renderer/postprocess/taa/TAA.d.ts.map +1 -1
  1254. package/src/shade/renderer/postprocess/taa/TAA.js +29 -48
  1255. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts +11 -0
  1256. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts.map +1 -1
  1257. package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.js +25 -4
  1258. package/src/shade/renderer/postprocess/taa/shader_depth_occlusion_clip.d.ts +8 -0
  1259. package/src/shade/renderer/postprocess/taa/shader_depth_occlusion_clip.d.ts.map +1 -1
  1260. package/src/shade/renderer/postprocess/taa/shader_depth_occlusion_clip.js +14 -42
  1261. package/src/shade/renderer/rasterize/RasterizationJob.d.ts +4 -2
  1262. package/src/shade/renderer/rasterize/RasterizationJob.d.ts.map +1 -1
  1263. package/src/shade/renderer/rasterize/RasterizationJob.js +3 -1
  1264. package/src/shade/renderer/rasterize/TemplatePassDescriptor.d.ts +57 -0
  1265. package/src/shade/renderer/rasterize/TemplatePassDescriptor.d.ts.map +1 -0
  1266. package/src/shade/renderer/rasterize/TemplatePassDescriptor.js +133 -0
  1267. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts.map +1 -1
  1268. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.js +17 -0
  1269. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
  1270. package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +30 -4
  1271. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts +3 -1
  1272. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.d.ts.map +1 -1
  1273. package/src/shade/renderer/rasterize/bucket/rasterization_has_opaque_bucket.js +3 -1
  1274. package/src/shade/renderer/rasterize/bucket/shader_count_meshlets_by_material.d.ts.map +1 -1
  1275. package/src/shade/renderer/rasterize/bucket/shader_count_meshlets_by_material.js +74 -68
  1276. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
  1277. package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +11 -1
  1278. package/src/shade/renderer/rasterize/bucket/shader_sort_meshlets_by_material.d.ts.map +1 -1
  1279. package/src/shade/renderer/rasterize/bucket/shader_sort_meshlets_by_material.js +70 -64
  1280. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way.d.ts.map +1 -1
  1281. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way.js +3 -4
  1282. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
  1283. package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +8 -2
  1284. package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.d.ts.map +1 -1
  1285. package/src/shade/renderer/rasterize/expand/bucket/mesh/shader_instances_rasterization_bucket_sort.js +134 -88
  1286. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.d.ts.map +1 -1
  1287. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.js +3 -4
  1288. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
  1289. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +7 -5
  1290. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.d.ts.map +1 -1
  1291. package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js +59 -29
  1292. package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.d.ts.map +1 -1
  1293. package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.js +3 -4
  1294. package/src/shade/renderer/rasterize/expand/mesh/shader_prefix_sum_to_command.d.ts.map +1 -1
  1295. package/src/shade/renderer/rasterize/expand/mesh/shader_prefix_sum_to_command.js +5 -2
  1296. package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.d.ts.map +1 -1
  1297. package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.js +3 -4
  1298. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.d.ts.map +1 -1
  1299. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +28 -20
  1300. package/src/shade/renderer/rasterize/forward/SHADING_SCENE_RESOURCE_GROUP.d.ts +20 -0
  1301. package/src/shade/renderer/rasterize/forward/SHADING_SCENE_RESOURCE_GROUP.d.ts.map +1 -1
  1302. package/src/shade/renderer/rasterize/forward/SHADING_SCENE_RESOURCE_GROUP.js +25 -0
  1303. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.d.ts.map +1 -1
  1304. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.js +2 -1
  1305. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.d.ts.map +1 -1
  1306. package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.js +2 -1
  1307. package/src/shade/renderer/rasterize/forward/forward_template_pipeline.d.ts +40 -0
  1308. package/src/shade/renderer/rasterize/forward/forward_template_pipeline.d.ts.map +1 -0
  1309. package/src/shade/renderer/rasterize/forward/forward_template_pipeline.js +86 -0
  1310. package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.d.ts +11 -0
  1311. package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.d.ts.map +1 -1
  1312. package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.js +13 -2
  1313. package/src/shade/renderer/rasterize/graph_clear_raster_targets.d.ts +38 -0
  1314. package/src/shade/renderer/rasterize/graph_clear_raster_targets.d.ts.map +1 -0
  1315. package/src/shade/renderer/rasterize/graph_clear_raster_targets.js +105 -0
  1316. package/src/shade/renderer/rasterize/native/alpha_tested_pass_resources.d.ts +59 -1
  1317. package/src/shade/renderer/rasterize/native/alpha_tested_pass_resources.d.ts.map +1 -1
  1318. package/src/shade/renderer/rasterize/native/alpha_tested_pass_resources.js +109 -7
  1319. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +16 -1
  1320. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
  1321. package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +13 -1
  1322. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +247 -0
  1323. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +20 -2
  1324. package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +1 -1
  1325. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_coverage.d.ts +17 -0
  1326. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_coverage.d.ts.map +1 -0
  1327. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_coverage.js +25 -0
  1328. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_fold_pairs.d.ts +4 -5
  1329. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_fold_pairs.d.ts.map +1 -1
  1330. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_fold_pairs.js +7 -6
  1331. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_mark.d.ts +17 -0
  1332. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_mark.d.ts.map +1 -0
  1333. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_mark.js +51 -0
  1334. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_premultiplied_contribution.d.ts +23 -0
  1335. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_premultiplied_contribution.d.ts.map +1 -0
  1336. package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_premultiplied_contribution.js +77 -0
  1337. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  1338. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +16 -20
  1339. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.d.ts +8 -2
  1340. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.d.ts.map +1 -1
  1341. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.js +57 -43
  1342. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.d.ts +8 -2
  1343. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.d.ts.map +1 -1
  1344. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.js +57 -43
  1345. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_occupancy.d.ts.map +1 -1
  1346. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_occupancy.js +8 -2
  1347. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.d.ts +7 -2
  1348. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.d.ts.map +1 -1
  1349. package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +67 -58
  1350. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.d.ts +8 -2
  1351. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.d.ts.map +1 -1
  1352. package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.js +186 -156
  1353. package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.d.ts +2 -2
  1354. package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.d.ts.map +1 -1
  1355. package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.js +36 -28
  1356. package/src/shade/renderer/rasterize/native/material_draw_indirect.d.ts +14 -12
  1357. package/src/shade/renderer/rasterize/native/material_draw_indirect.d.ts.map +1 -1
  1358. package/src/shade/renderer/rasterize/native/material_draw_indirect.js +29 -23
  1359. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts.map +1 -1
  1360. package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +16 -22
  1361. package/src/shade/renderer/rasterize/native/oit/oit_resolve_fragment_body.d.ts +33 -0
  1362. package/src/shade/renderer/rasterize/native/oit/oit_resolve_fragment_body.d.ts.map +1 -0
  1363. package/src/shade/renderer/rasterize/native/oit/oit_resolve_fragment_body.js +123 -0
  1364. package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.d.ts +7 -2
  1365. package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.d.ts.map +1 -1
  1366. package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.js +227 -218
  1367. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.d.ts +8 -2
  1368. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.d.ts.map +1 -1
  1369. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.js +112 -180
  1370. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.d.ts +8 -2
  1371. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.d.ts.map +1 -1
  1372. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.js +110 -178
  1373. package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.d.ts +7 -2
  1374. package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.d.ts.map +1 -1
  1375. package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.js +242 -204
  1376. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts +1 -1
  1377. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.d.ts.map +1 -1
  1378. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +21 -1
  1379. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.d.ts.map +1 -1
  1380. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +12 -20
  1381. package/src/shade/renderer/restir/reservoir/shader.d.ts.map +1 -1
  1382. package/src/shade/renderer/restir/reservoir/shader.js +27 -1
  1383. package/src/shade/renderer/scene/GPUSceneContext.d.ts +2 -1
  1384. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  1385. package/src/shade/renderer/scene/GPUSceneContext.js +11 -9
  1386. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +22 -0
  1387. package/src/shade/renderer/scene/SceneManager.d.ts +10 -0
  1388. package/src/shade/renderer/scene/SceneManager.d.ts.map +1 -1
  1389. package/src/shade/renderer/scene/SceneManager.js +17 -0
  1390. package/src/shade/renderer/scene/rows/GPUEntityBoundsReadback.d.ts.map +1 -1
  1391. package/src/shade/renderer/scene/rows/GPUEntityBoundsReadback.js +164 -144
  1392. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts +10 -0
  1393. package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
  1394. package/src/shade/renderer/scene/rows/GPUSceneRows.js +14 -0
  1395. package/src/shade/renderer/scene/serialization/serialize_scene.d.ts.map +1 -1
  1396. package/src/shade/renderer/scene/serialization/serialize_scene.js +2 -6
  1397. package/src/shade/renderer/shader/ComputeShader.d.ts +5 -0
  1398. package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
  1399. package/src/shade/renderer/shader/ComputeShader.js +358 -353
  1400. package/src/shade/renderer/shader/chunk/atmosphere/chunk_integrate_scattering.d.ts.map +1 -1
  1401. package/src/shade/renderer/shader/chunk/atmosphere/chunk_integrate_scattering.js +15 -1
  1402. package/src/shade/renderer/shader/chunk/binary/chunk_encode_f16.d.ts +11 -2
  1403. package/src/shade/renderer/shader/chunk/binary/chunk_encode_f16.d.ts.map +1 -1
  1404. package/src/shade/renderer/shader/chunk/binary/chunk_encode_f16.js +33 -13
  1405. package/src/shade/renderer/shader/chunk/brdf/chunk_D_GGX.d.ts.map +1 -1
  1406. package/src/shade/renderer/shader/chunk/brdf/chunk_D_GGX.js +31 -3
  1407. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_decode32_morton2.d.ts +10 -1
  1408. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_decode32_morton2.d.ts.map +1 -1
  1409. package/src/shade/renderer/shader/chunk/bvh/morton/chunk_decode32_morton2.js +23 -8
  1410. package/src/shade/renderer/shader/chunk/camera/chunk_pixel_radius_to_world.d.ts +8 -1
  1411. package/src/shade/renderer/shader/chunk/camera/chunk_pixel_radius_to_world.d.ts.map +1 -1
  1412. package/src/shade/renderer/shader/chunk/camera/chunk_pixel_radius_to_world.js +12 -5
  1413. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray.d.ts +15 -1
  1414. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray.d.ts.map +1 -1
  1415. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray.js +24 -28
  1416. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray_v2.d.ts +5 -0
  1417. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray_v2.d.ts.map +1 -1
  1418. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray_v2.js +18 -13
  1419. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_intersects_ray.d.ts.map +1 -1
  1420. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_intersects_ray.js +1 -47
  1421. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast.d.ts +10 -0
  1422. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast.d.ts.map +1 -1
  1423. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast.js +23 -8
  1424. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast_positive.d.ts +7 -0
  1425. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast_positive.d.ts.map +1 -1
  1426. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast_positive.js +12 -25
  1427. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_slab_span.d.ts +32 -0
  1428. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_slab_span.d.ts.map +1 -0
  1429. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_slab_span.js +52 -0
  1430. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_view_depth_range.d.ts +20 -0
  1431. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_view_depth_range.d.ts.map +1 -0
  1432. package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_view_depth_range.js +42 -0
  1433. package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_octahedral_uv_wrap.d.ts +10 -1
  1434. package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_octahedral_uv_wrap.d.ts.map +1 -1
  1435. package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_octahedral_uv_wrap.js +18 -3
  1436. package/src/shade/renderer/shader/chunk/geometry/quaternion/chunk_quat_encode_u32.d.ts.map +1 -1
  1437. package/src/shade/renderer/shader/chunk/geometry/quaternion/chunk_quat_encode_u32.js +8 -4
  1438. package/src/shade/renderer/shader/chunk/grid/chunk_folded_workgroup_index.d.ts +24 -0
  1439. package/src/shade/renderer/shader/chunk/grid/chunk_folded_workgroup_index.d.ts.map +1 -0
  1440. package/src/shade/renderer/shader/chunk/grid/chunk_folded_workgroup_index.js +36 -0
  1441. package/src/shade/renderer/shader/chunk/grid/chunk_grid3d_to_index.d.ts +6 -0
  1442. package/src/shade/renderer/shader/chunk/grid/chunk_grid3d_to_index.d.ts.map +1 -1
  1443. package/src/shade/renderer/shader/chunk/grid/chunk_grid3d_to_index.js +6 -0
  1444. package/src/shade/renderer/shader/chunk/light/INCIDENT_LIGHT_STRUCT.d.ts.map +1 -1
  1445. package/src/shade/renderer/shader/chunk/light/INCIDENT_LIGHT_STRUCT.js +6 -1
  1446. package/src/shade/renderer/shader/chunk/light/io/chunk_get_spot_light_info.d.ts.map +1 -1
  1447. package/src/shade/renderer/shader/chunk/light/io/chunk_get_spot_light_info.js +6 -1
  1448. package/src/shade/renderer/shader/chunk/material/chunk_albedo_unpremultiply.d.ts +24 -0
  1449. package/src/shade/renderer/shader/chunk/material/chunk_albedo_unpremultiply.d.ts.map +1 -0
  1450. package/src/shade/renderer/shader/chunk/material/chunk_albedo_unpremultiply.js +31 -0
  1451. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg2d.js +2 -2
  1452. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg3d16.js +1 -1
  1453. package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg4d.js +1 -1
  1454. package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_validate_hit.d.ts.map +1 -1
  1455. package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_validate_hit.js +8 -4
  1456. package/src/shade/renderer/shader/chunk/sdf/chunk_mesh_sdf_soft_shadow.d.ts.map +1 -1
  1457. package/src/shade/renderer/shader/chunk/sdf/chunk_mesh_sdf_soft_shadow.js +17 -3
  1458. package/src/shade/renderer/shader/graph/compute/graph_compute_indirect_pass.d.ts +4 -0
  1459. package/src/shade/renderer/shader/graph/compute/graph_compute_indirect_pass.d.ts.map +1 -1
  1460. package/src/shade/renderer/shader/graph/compute/graph_compute_indirect_pass.js +4 -0
  1461. package/src/shade/renderer/shader/graph/graph_import_typed_buffer.d.ts +2 -1
  1462. package/src/shade/renderer/shader/graph/graph_import_typed_buffer.d.ts.map +1 -1
  1463. package/src/shade/renderer/shader/graph/graph_import_typed_buffer.js +15 -28
  1464. package/src/shade/renderer/shader/pass/RenderPassDescriptor.d.ts +8 -0
  1465. package/src/shade/renderer/shader/pass/RenderPassDescriptor.d.ts.map +1 -1
  1466. package/src/shade/renderer/shader/pass/RenderPassDescriptor.js +203 -192
  1467. package/src/shade/renderer/shader/resource/ShaderResourceGroupDescriptor.d.ts.map +1 -1
  1468. package/src/shade/renderer/shader/resource/ShaderResourceGroupDescriptor.js +12 -0
  1469. package/src/shade/renderer/shader/type/WebGPUArray.d.ts.map +1 -1
  1470. package/src/shade/renderer/shader/type/WebGPUArray.js +25 -1
  1471. package/src/shade/renderer/shader/type/queue_typed_buffer_update.d.ts.map +1 -1
  1472. package/src/shade/renderer/shader/type/queue_typed_buffer_update.js +15 -0
  1473. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  1474. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +10 -9
  1475. package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.d.ts +12 -2
  1476. package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.d.ts.map +1 -1
  1477. package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.js +210 -196
  1478. package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.d.ts +10 -3
  1479. package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.d.ts.map +1 -1
  1480. package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.js +219 -194
  1481. package/src/shade/renderer/shadow/map/shadowmap_budget_carry_over.d.ts +32 -0
  1482. package/src/shade/renderer/shadow/map/shadowmap_budget_carry_over.d.ts.map +1 -0
  1483. package/src/shade/renderer/shadow/map/shadowmap_budget_carry_over.js +47 -0
  1484. package/src/shade/renderer/shadow/vsm/VirtualShadowMap.d.ts.map +1 -1
  1485. package/src/shade/renderer/shadow/vsm/VirtualShadowMap.js +11 -1
  1486. package/src/shade/renderer/texture/ShadeTexture.d.ts +16 -0
  1487. package/src/shade/renderer/texture/ShadeTexture.d.ts.map +1 -1
  1488. package/src/shade/renderer/texture/ShadeTexture.js +17 -0
  1489. package/src/shade/renderer/texture/TextureManager.d.ts +22 -5
  1490. package/src/shade/renderer/texture/TextureManager.d.ts.map +1 -1
  1491. package/src/shade/renderer/texture/TextureManager.js +109 -6
  1492. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts.map +1 -1
  1493. package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.js +8 -2
  1494. package/src/shade/renderer/texture/download_texture_data.d.ts.map +1 -1
  1495. package/src/shade/renderer/texture/download_texture_data.js +12 -4
  1496. package/src/shade/renderer/texture/encode/shader_texture_encode_astc_4x4.d.ts.map +1 -1
  1497. package/src/shade/renderer/texture/encode/shader_texture_encode_astc_4x4.js +66 -63
  1498. package/src/shade/renderer/texture/encode/shader_texture_encode_bc1.d.ts.map +1 -1
  1499. package/src/shade/renderer/texture/encode/shader_texture_encode_bc1.js +63 -60
  1500. package/src/shade/renderer/texture/encode/shader_texture_encode_bc4.d.ts.map +1 -1
  1501. package/src/shade/renderer/texture/encode/shader_texture_encode_bc4.js +79 -76
  1502. package/src/shade/renderer/texture/encode/shader_texture_encode_bc4_snorm.d.ts.map +1 -1
  1503. package/src/shade/renderer/texture/encode/shader_texture_encode_bc4_snorm.js +67 -64
  1504. package/src/shade/renderer/texture/encode/shader_texture_encode_bc5.d.ts.map +1 -1
  1505. package/src/shade/renderer/texture/encode/shader_texture_encode_bc5.js +70 -67
  1506. package/src/shade/renderer/texture/encode/shader_texture_encode_bc5_snorm.d.ts.map +1 -1
  1507. package/src/shade/renderer/texture/encode/shader_texture_encode_bc5_snorm.js +66 -63
  1508. package/src/shade/renderer/texture/encode/shader_texture_encode_bc6h.d.ts.map +1 -1
  1509. package/src/shade/renderer/texture/encode/shader_texture_encode_bc6h.js +65 -62
  1510. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts.map +1 -1
  1511. package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.js +61 -58
  1512. package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts +7 -1
  1513. package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts.map +1 -1
  1514. package/src/shade/renderer/texture/format/texture_format_from_shade_image.js +100 -95
  1515. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts.map +1 -1
  1516. package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +59 -68
  1517. package/src/shade/renderer/texture/mipmaps/filters/mipmap_shader_code_wronski2021.d.ts +30 -1
  1518. package/src/shade/renderer/texture/mipmaps/filters/mipmap_shader_code_wronski2021.d.ts.map +1 -1
  1519. package/src/shade/renderer/texture/mipmaps/filters/mipmap_shader_code_wronski2021.js +37 -20
  1520. package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.js +73 -73
  1521. package/src/shade/renderer/view/ViewManager.d.ts +8 -0
  1522. package/src/shade/renderer/view/ViewManager.d.ts.map +1 -1
  1523. package/src/shade/renderer/view/ViewManager.js +15 -0
  1524. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
  1525. package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +516 -507
  1526. package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.d.ts.map +1 -1
  1527. package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.js +272 -260
  1528. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts.map +1 -1
  1529. package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +160 -134
  1530. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts +3 -0
  1531. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
  1532. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +243 -62
  1533. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  1534. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +110 -7
  1535. package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
  1536. package/src/shade/wgsl/validate_wgsl_source.js +57 -0
  1537. package/src/view/asset/AssetLoaderStatusView.d.ts.map +1 -1
  1538. package/src/view/asset/AssetLoaderStatusView.js +8 -0
  1539. package/src/view/common/LabelView.d.ts.map +1 -1
  1540. package/src/view/common/LabelView.js +4 -0
  1541. package/src/view/common/ListView.d.ts +6 -2
  1542. package/src/view/common/ListView.d.ts.map +1 -1
  1543. package/src/view/common/ListView.js +27 -7
  1544. package/src/view/common/TabbedView.d.ts.map +1 -1
  1545. package/src/view/common/TabbedView.js +8 -0
  1546. package/src/view/common/VirtualListView.d.ts.map +1 -1
  1547. package/src/view/common/VirtualListView.js +17 -1
  1548. package/src/view/common/dnd/DropTarget.d.ts.map +1 -1
  1549. package/src/view/common/dnd/DropTarget.js +18 -0
  1550. package/src/view/elements/DropDownSelectionView.d.ts.map +1 -1
  1551. package/src/view/elements/DropDownSelectionView.js +8 -0
  1552. package/src/view/elements/image/SvgImageView.d.ts.map +1 -1
  1553. package/src/view/elements/image/SvgImageView.js +8 -0
  1554. package/src/view/elements/navigation/ViewStack.d.ts.map +1 -1
  1555. package/src/view/elements/navigation/ViewStack.js +4 -0
  1556. package/src/view/elements/notify/NotificationView.d.ts.map +1 -1
  1557. package/src/view/elements/notify/NotificationView.js +4 -0
  1558. package/src/view/elements/progress/segmented/SegmentedResourceBarView.d.ts.map +1 -1
  1559. package/src/view/elements/progress/segmented/SegmentedResourceBarView.js +8 -0
  1560. package/src/view/elements/radial/RadialMenu.d.ts.map +1 -1
  1561. package/src/view/elements/radial/RadialMenu.js +4 -0
  1562. package/src/view/minimap/Minimap.d.ts.map +1 -1
  1563. package/src/view/minimap/Minimap.js +8 -0
  1564. package/src/view/minimap/MinimapCanvasView.d.ts.map +1 -1
  1565. package/src/view/minimap/MinimapCanvasView.js +21 -1
  1566. package/src/view/minimap/dom/MinimapCameraView.d.ts.map +1 -1
  1567. package/src/view/minimap/dom/MinimapCameraView.js +232 -220
  1568. package/src/view/minimap/dom/MinimapMarkerView.d.ts.map +1 -1
  1569. package/src/view/minimap/dom/MinimapMarkerView.js +8 -0
  1570. package/src/view/minimap/minimap_focus_area.d.ts +5 -0
  1571. package/src/view/minimap/minimap_focus_area.d.ts.map +1 -1
  1572. package/src/view/minimap/minimap_focus_area.js +22 -0
  1573. package/src/view/tooltip/TooltipManager.d.ts.map +1 -1
  1574. package/src/view/tooltip/TooltipManager.js +16 -4
  1575. package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts +0 -73
  1576. package/src/core/geom/3d/atlas/atlas_bench_lib.d.ts.map +0 -1
  1577. package/src/core/geom/3d/atlas/atlas_bench_lib.js +0 -315
  1578. package/src/engine/graphics/ecs/mesh/MeshEvents.d.ts +0 -6
  1579. package/src/engine/graphics/ecs/mesh/MeshEvents.d.ts.map +0 -1
  1580. package/src/engine/graphics/ecs/mesh/MeshEvents.js +0 -16
  1581. package/src/engine/graphics/ecs/mesh/commonObject3DFastMatrixUpdate.d.ts +0 -2
  1582. package/src/engine/graphics/ecs/mesh/commonObject3DFastMatrixUpdate.d.ts.map +0 -1
  1583. package/src/engine/graphics/ecs/mesh/commonObject3DFastMatrixUpdate.js +0 -37
  1584. package/src/engine/graphics/ecs/mesh/copyToVector3.d.ts +0 -8
  1585. package/src/engine/graphics/ecs/mesh/copyToVector3.d.ts.map +0 -1
  1586. package/src/engine/graphics/ecs/mesh/copyToVector3.js +0 -18
  1587. package/src/engine/graphics/ecs/mesh/object3DFastMatrixUpdate.d.ts +0 -6
  1588. package/src/engine/graphics/ecs/mesh/object3DFastMatrixUpdate.d.ts.map +0 -1
  1589. package/src/engine/graphics/ecs/mesh/object3DFastMatrixUpdate.js +0 -18
  1590. package/src/engine/graphics/ecs/mesh/rootObject3DFastMatrixUpdate.d.ts +0 -6
  1591. package/src/engine/graphics/ecs/mesh/rootObject3DFastMatrixUpdate.d.ts.map +0 -1
  1592. package/src/engine/graphics/ecs/mesh/rootObject3DFastMatrixUpdate.js +0 -14
  1593. package/src/engine/graphics/ecs/mesh/setMesh.d.ts +0 -16
  1594. package/src/engine/graphics/ecs/mesh/setMesh.d.ts.map +0 -1
  1595. package/src/engine/graphics/ecs/mesh/setMesh.js +0 -55
  1596. package/src/engine/graphics/ecs/mesh/skeleton/BoneMapping.d.ts +0 -13
  1597. package/src/engine/graphics/ecs/mesh/skeleton/BoneMapping.d.ts.map +0 -1
  1598. package/src/engine/graphics/ecs/mesh/skeleton/BoneMapping.js +0 -99
  1599. package/src/engine/graphics/ecs/mesh/skeleton/HumanoidBoneType.d.ts +0 -25
  1600. package/src/engine/graphics/ecs/mesh/skeleton/HumanoidBoneType.d.ts.map +0 -1
  1601. package/src/engine/graphics/ecs/mesh/skeleton/HumanoidBoneType.js +0 -29
  1602. package/src/engine/graphics/ecs/mesh/updateMeshTransform.d.ts +0 -6
  1603. package/src/engine/graphics/ecs/mesh/updateMeshTransform.d.ts.map +0 -1
  1604. package/src/engine/graphics/ecs/mesh/updateMeshTransform.js +0 -15
  1605. package/src/engine/graphics/ecs/mesh/updateNodeByTransformAndBBB.d.ts +0 -8
  1606. package/src/engine/graphics/ecs/mesh/updateNodeByTransformAndBBB.d.ts.map +0 -1
  1607. package/src/engine/graphics/ecs/mesh/updateNodeByTransformAndBBB.js +0 -14
  1608. package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.d.ts +0 -59
  1609. package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.d.ts.map +0 -1
  1610. package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.js +0 -481
  1611. package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts +0 -22
  1612. package/src/engine/graphics3/terrain/pack_terrain_row_table.d.ts.map +0 -1
  1613. package/src/engine/graphics3/terrain/pack_terrain_row_table.js +0 -48
  1614. package/src/engine/graphics3/terrain/shader_terrain_splat.d.ts +0 -26
  1615. package/src/engine/graphics3/terrain/shader_terrain_splat.d.ts.map +0 -1
  1616. package/src/engine/graphics3/terrain/shader_terrain_splat.js +0 -215
  1617. package/src/shade/renderer/animation/ANIMATION_BOUND_TRACK_GROUP_STRUCT.d.ts +0 -25
  1618. package/src/shade/renderer/animation/ANIMATION_BOUND_TRACK_GROUP_STRUCT.d.ts.map +0 -1
  1619. package/src/shade/renderer/animation/ANIMATION_BOUND_TRACK_GROUP_STRUCT.js +0 -57
  1620. package/src/shade/renderer/animation/ANIMATION_KEYFRAME_BLOCK_STRUCT.d.ts +0 -26
  1621. package/src/shade/renderer/animation/ANIMATION_KEYFRAME_BLOCK_STRUCT.d.ts.map +0 -1
  1622. package/src/shade/renderer/animation/ANIMATION_KEYFRAME_BLOCK_STRUCT.js +0 -50
  1623. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_BLOCK_STRUCT.d.ts +0 -29
  1624. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_BLOCK_STRUCT.d.ts.map +0 -1
  1625. package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_BLOCK_STRUCT.js +0 -62
  1626. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.d.ts +0 -46
  1627. package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.d.ts.map +0 -1
@@ -11,15 +11,21 @@ import { NetworkSystem } from "./ecs/NetworkSystem.js";
11
11
  import { NetworkIdentitySerializationAdapter, } from "./ecs/serialization/NetworkIdentitySerializationAdapter.js";
12
12
  import { NetworkPeer, ResumeRejectReason, } from "./orchestrator/NetworkPeer.js";
13
13
  import { ServerAuthoritativeClient } from "./orchestrator/ServerAuthoritativeClient.js";
14
- import { ServerAuthoritativeServer } from "./orchestrator/ServerAuthoritativeServer.js";
14
+ import { LateInput, ServerAuthoritativeServer } from "./orchestrator/ServerAuthoritativeServer.js";
15
15
  import { OwnerAwareScope } from "./replication/ScopeFilter.js";
16
16
  import { BinaryInterpolationAdapter, InterpolationKind, } from "../interpolation/BinaryInterpolationAdapter.js";
17
+ import { Interpoland } from "../interpolation/Interpoland.js";
18
+ import { Interpolated, INTERPOLATION_SOURCE_LOCAL } from "../interpolation/Interpolated.js";
17
19
  import { InterpolationLog } from "../interpolation/InterpolationLog.js";
20
+ import { InterpolationSystem } from "../interpolation/InterpolationSystem.js";
18
21
  import { SimAction } from "./sim/SimAction.js";
19
22
  import { snapshotter_emit } from "./sim/Snapshotter.js";
23
+ import { PredictionHistory } from "./state/PredictionHistory.js";
20
24
  import { AdaptiveRenderDelay } from "./time/AdaptiveRenderDelay.js";
21
25
  import { RenderPlayout } from "./time/RenderPlayout.js";
22
26
  import { TimeDilation } from "./time/TimeDilation.js";
27
+ import { DeferredTransport } from "./transport/DeferredTransport.js";
28
+ import { CorrectionTarget, HOST_VALUE_CORRECTION } from "./correction/Correction.js";
23
29
 
24
30
  /**
25
31
  * Roles a session can occupy. The orchestrator it wires up underneath is
@@ -44,10 +50,38 @@ export const NetworkSessionRole = Object.freeze({
44
50
  Host: 'host',
45
51
  });
46
52
 
47
- const DEFAULT_TICK_RATE_HZ = 60;
53
+ /**
54
+ * How a client brings the entities it predicts back in line with the host's authoritative state.
55
+ *
56
+ * @readonly @enum {string}
57
+ */
58
+ export const NetworkSessionReconcile = Object.freeze({
59
+ /**
60
+ * Compare the host's state for frame S with what this client predicted for S. Equal: nothing
61
+ * to do. Different: carry the difference observed at S into the present, component by
62
+ * component, as each component's {@link Correction} says — a pose by its offset and turn, a
63
+ * velocity by its difference, a value with no notion of difference by the host's value. No
64
+ * rewind, no replay, so it holds for state produced by physics and any other fixed-step system,
65
+ * not only by actions.
66
+ */
67
+ Correct: 'correct',
68
+ /**
69
+ * Rewind the action log to S, apply the host's state, and re-execute this client's input for
70
+ * every frame since. Exact when everything predicted is produced by deterministic actions; a
71
+ * replay re-executes actions only, never the engine's systems.
72
+ */
73
+ Replay: 'replay',
74
+ });
75
+
48
76
  const DEFAULT_SIMULATION_DELAY_TICKS = 4;
49
77
  const DEFAULT_INITIAL_RENDER_DELAY_FRAMES = 6;
50
78
 
79
+ /**
80
+ * Frames of remote state the network timeline keeps at the least: the adaptive render delay's
81
+ * ceiling (30) plus room for the playhead to blend across a burst of late arrivals.
82
+ */
83
+ const PLAYOUT_HISTORY_FRAMES = 64;
84
+
51
85
  /**
52
86
  * Default depth of the action-log ring (in frames). This single value bounds
53
87
  * THREE distinct horizons at once:
@@ -66,8 +100,6 @@ const DEFAULT_INITIAL_RENDER_DELAY_FRAMES = 6;
66
100
  * orchestrator, so it is cheap to grow).
67
101
  */
68
102
  const DEFAULT_ACTION_LOG_FRAME_CAPACITY = 32;
69
- const MAX_CLIENT_DILATED_TICKS_PER_STEP = 3;
70
- const MAX_FIXED_STEPS_PER_TICK = 8;
71
103
 
72
104
  const DEFAULT_SERVER_RESUME_GRACE_MS = 30_000;
73
105
  /**
@@ -108,6 +140,19 @@ const ReconnectState = Object.freeze({
108
140
  Lost: 'lost',
109
141
  });
110
142
 
143
+ /**
144
+ * Client-side: how the host has answered the transport binding in use. A new binding does not know
145
+ * which world the client is in until the host says: the one it has been predicting on, which the
146
+ * host resumes (RESUME_ACCEPT), or the host's own, sent as a snapshot (INITIAL_SYNC). The first
147
+ * answer is the answer; the host's handshake arriving after it is stale.
148
+ * @readonly @enum {string}
149
+ */
150
+ const BindingAnswer = Object.freeze({
151
+ Pending: 'pending',
152
+ Resumed: 'resumed',
153
+ Synced: 'synced',
154
+ });
155
+
111
156
  /**
112
157
  * Scratch buffer size used for AUTH_STATE assembly and net_mutate_component
113
158
  * event payloads. Sized for the common cases (Transform ≈ 36 B); components
@@ -115,12 +160,92 @@ const ReconnectState = Object.freeze({
115
160
  */
116
161
  const SCRATCH_BUFFER_BYTES = 1024;
117
162
 
163
+
118
164
  /**
119
- * Shared zero-length payload for empty ack packets. Hoisted to module scope so
120
- * the per-peer, per-tick ack send doesn't allocate a fresh array each time.
121
- * @type {Uint8Array}
165
+ * {@link NetworkSession#tick} warns once per process.
166
+ * @type {boolean}
122
167
  */
123
- const EMPTY_PAYLOAD = new Uint8Array(0);
168
+ let tick_deprecation_warned = false;
169
+
170
+ /**
171
+ * The deprecated {@link NetworkSession#replicate} warns once per process.
172
+ * @type {boolean}
173
+ */
174
+ let replicate_deprecation_warned = false;
175
+
176
+ /**
177
+ * @param {string} method for the message
178
+ * @param {string} name the component's, for the message
179
+ * @param {*} adapter the blend
180
+ */
181
+ function assert_linear_blend(method, name, adapter) {
182
+ if (!(adapter instanceof BinaryInterpolationAdapter)) {
183
+ throw new Error(`NetworkSession.${method}: the blend for ${name} must extend BinaryInterpolationAdapter`);
184
+ }
185
+ if (adapter.kind !== InterpolationKind.Linear) {
186
+ throw new Error(
187
+ `NetworkSession.${method}: only Linear interpolation is currently supported; got kind=${adapter.kind} for ${name}. ` +
188
+ `A component with no in-between is replicated with replicate_discrete(); Cubic is reserved.`,
189
+ );
190
+ }
191
+ }
192
+
193
+ /**
194
+ * @param {string} method for the message
195
+ * @param {string} name the component's, for the message
196
+ * @param {*} correction
197
+ */
198
+ function assert_correction(method, name, correction) {
199
+ if (correction === null || correction === undefined || correction.isCorrection !== true) {
200
+ throw new Error(
201
+ `NetworkSession.${method}: ${name} needs a Correction — how a client that predicts it corrects it when the host disagrees ` +
202
+ `(HOST_VALUE_CORRECTION takes the host's value)`,
203
+ );
204
+ }
205
+ }
206
+
207
+ /**
208
+ * While a blend is drawn over a component, its simulated value is held aside and put back before the
209
+ * next step. Held through a wire layout it would come back rounded, every step, and small increments
210
+ * would drift or stall; held with the component's own `copy`, it comes back exactly.
211
+ *
212
+ * @param {string} method for the message
213
+ * @param {string} name the component's, for the message
214
+ * @param {Function} ComponentClass
215
+ */
216
+ function assert_copies_itself(method, name, ComponentClass) {
217
+ if (typeof ComponentClass.prototype.copy !== 'function') {
218
+ throw new Error(
219
+ `NetworkSession.${method}: ${name} is blended between network ticks, and while a blend is drawn over it the engine holds ` +
220
+ `its simulated value with ${name}.prototype.copy(other), which it does not have. Give ${name} a copy(other) that copies every ` +
221
+ `field the simulation uses, or replicate it with replicate_discrete().`,
222
+ );
223
+ }
224
+ }
225
+
226
+ /**
227
+ * @param {Uint8Array} a
228
+ * @param {Uint8Array} b
229
+ * @param {number} length
230
+ * @returns {boolean}
231
+ */
232
+ function bytes_equal(a, b, length) {
233
+ for (let i = 0; i < length; i++) {
234
+ if (a[i] !== b[i]) return false;
235
+ }
236
+ return true;
237
+ }
238
+
239
+ /**
240
+ * @param {Uint8Array} a
241
+ * @param {number} a_length
242
+ * @param {Uint8Array} b
243
+ * @param {number} b_length
244
+ * @returns {boolean}
245
+ */
246
+ function bytes_equal_lengths(a, a_length, b, b_length) {
247
+ return a_length === b_length && bytes_equal(a, b, a_length);
248
+ }
124
249
 
125
250
  /**
126
251
  * High-level networking facade. Wraps the orchestrator + state machinery
@@ -133,23 +258,45 @@ const EMPTY_PAYLOAD = new Uint8Array(0);
133
258
  * Mutation is event-driven: callers fire
134
259
  * `dataset.sendEvent(entity, "net_mutate_component", payload)`.
135
260
  *
136
- * Per-tick driving is a single `session.tick(dt_seconds)`. The session
137
- * runs fixed-timestep stepping, client time dilation, server-side input
138
- * buffer, AUTH_STATE dispatch, time-dilation feedback, and interpolated
139
- * rendering for remote-owned entities.
261
+ * **The session runs on the engine's clock.** The `EntityManager`'s fixed
262
+ * step is the network tick: each step opens a network frame before any
263
+ * system's `fixedUpdate` and closes it after the last, so everything the
264
+ * step simulates — physics, controllers, game code — happens inside the
265
+ * frame. There is nothing to call per frame; `entity_manager.update(dt)`
266
+ * (the engine loop) drives it. Client time dilation is applied as the
267
+ * `EntityManager`'s `fixedStepTimeScale`.
268
+ *
269
+ * What arrives from the network is applied as a step opens, never when the
270
+ * transport happens to deliver it: a browser delivers packets whenever its
271
+ * event loop gets to them, which is usually between a frame's render blend and
272
+ * its draw. And the session's timers — the render playout, idle reaping, the
273
+ * grace window — run on the frame time the engine passes to `update`, so they
274
+ * pause with the engine and follow any engine that is driven by hand.
275
+ *
276
+ * **Networked entities are smooth by default.** The session attaches an
277
+ * {@link Interpolated} to each one and keeps it in line with ownership: on
278
+ * the host, and for entities the client owns (and predicts), the local
279
+ * fixed-step timeline; for everything else on a client, the network's
280
+ * render-delayed playout. Both are blended by the engine's
281
+ * {@link InterpolationSystem}, which the session adds if the engine has
282
+ * none.
140
283
  *
141
284
  * @author Alex Goldring
142
285
  * @copyright Company Named Limited (c) 2026
143
286
  */
144
287
  export class NetworkSession {
145
288
 
146
- // ---- Pre-start registration (set via replicate / defineAction / defineInputSampler) ----
289
+ // ---- Pre-start registration (replicate_* / defineAction / defineInputSampler) ----
147
290
 
148
291
  /**
149
- * User-registered replicated component classes, in `replicate()` call
150
- * order. Finalized at `start()` into {@link #replicated} with
151
- * `NetworkIdentity` prepended.
152
- * @private @type {Array<{klass: Function, interp: BinaryInterpolationAdapter|null}>}
292
+ * User-registered replicated component classes, in the order they were
293
+ * registered. Finalized at `start()` into {@link #replicated} with
294
+ * `NetworkIdentity` prepended. `interpoland` is how the component is blended
295
+ * between network ticks, `null` when it is not; `interpolator` is the blend
296
+ * handed to the deprecated {@link replicate}, turned into an interpoland at
297
+ * `start()`, when the component's replication layout is known; `correction`
298
+ * is how a client corrects it.
299
+ * @private @type {Array<{klass: Function, interpoland: Interpoland|null, interpolator: BinaryInterpolationAdapter|null, correction: Correction}>}
153
300
  */
154
301
  #user_replicated = [];
155
302
 
@@ -157,8 +304,8 @@ export class NetworkSession {
157
304
  * Finalized at `start()`. Insertion order = wire-format order;
158
305
  * `NetworkIdentity` is the first entry (its slot allocation must
159
306
  * fire before subsequent components attach during initial-sync apply).
160
- * Each value: `{ interp, interp_type_id }`.
161
- * @private @type {Map<Function, {interp: BinaryInterpolationAdapter|null, interp_type_id: number}>}
307
+ * `interp_type_id` is the component's replication type id.
308
+ * @private @type {Map<Function, {interp_type_id: number, interpoland: Interpoland|null, interpolator: BinaryInterpolationAdapter|null, correction: Correction|null}>}
162
309
  */
163
310
  #replicated = new Map();
164
311
 
@@ -215,19 +362,145 @@ export class NetworkSession {
215
362
  #playout;
216
363
 
217
364
  /**
218
- * Set after `#render_interpolated_entities` writes interp values into
219
- * live components; cleared by `normalize_if_dirty`. Drives the
220
- * canonical-form invariant: live is canonical when this is false,
221
- * polluted (smooth) when true.
222
- * @private @type {boolean}
365
+ * @deprecated Always false. Render blends are owned by the {@link InterpolationSystem}, which
366
+ * restores them itself; {@link normalize_if_dirty} restores unconditionally.
367
+ * @type {boolean}
223
368
  */
224
369
  render_dirty = false;
225
370
 
371
+ // ---- Interpolation wiring (set in start()) ----
372
+
373
+ /** @private @type {InterpolationSystem|null} */
374
+ #interpolation = null;
375
+
376
+ /** @private @type {number} source id of the network playout in {@link #interpolation} */
377
+ #interp_source_id = -1;
378
+
379
+ /**
380
+ * Interpolands for the replicated components that interpolate, in `#replicated` order. The
381
+ * same list serves both timelines: records on the local timeline are keyed by entity, records
382
+ * in the network log by `network_id`.
383
+ * @private @type {Interpoland[]}
384
+ */
385
+ #interpolands = [];
386
+
387
+ /**
388
+ * Networked entities whose {@link Interpolated} has to be brought in line with their role —
389
+ * newly networked, or ownership changed. Applied as the next step opens, not from inside the
390
+ * observer that noticed: on an initial sync the identity arrives before the components it
391
+ * would interpolate.
392
+ * @private @type {Set<number>}
393
+ */
394
+ #interpolation_pending = new Set();
395
+
396
+ /**
397
+ * The {@link Interpolated} components this session attached, by entity, so it can take them
398
+ * back.
399
+ * @private @type {Map<number, Interpolated>}
400
+ */
401
+ #attached_interpolated = new Map();
402
+
403
+ /** @private @type {{tick_a:number, tick_b:number, t:number}} */
404
+ #playout_window = { tick_a: 0, tick_b: 0, t: 0 };
405
+
226
406
  // ---- Per-tick driver state ----
227
407
 
228
408
  /** @private @type {number} */ #local_frame = 0;
229
- /** @private @type {number} */ #local_frame_accum = 0;
230
- /** @private @type {number} */ #sim_accum_ms = 0;
409
+
410
+ /** @private @type {boolean} a network frame is open: the fixed step that opened it has not closed */
411
+ #step_open = false;
412
+
413
+ /**
414
+ * Every connected peer's transport, holding what arrives until the next fixed step opens.
415
+ * @private @type {Map<number, DeferredTransport>}
416
+ */
417
+ #inbound = new Map();
418
+
419
+ // ---- Host: publishing what the simulation changed ----
420
+
421
+ /** @private @type {boolean} */
422
+ #publish_changes;
423
+
424
+ /** @private @type {string} */
425
+ #late_input;
426
+
427
+ /**
428
+ * What the peers hold for each networked entity, per replicated component type id, as the
429
+ * replication adapter's bytes — so "changed" means "changed on the wire". Updated by every
430
+ * record the host publishes and by every action it executes (the peers apply the action and
431
+ * arrive at the same value), and compared with the live state at the end of each step.
432
+ * @private @type {Map<number, Array<{bytes: Uint8Array, length: number}|null>>}
433
+ */
434
+ #published = new Map();
435
+
436
+ /** @private @type {BinaryBuffer} */
437
+ #scratch_publish_buf = new BinaryBuffer();
438
+
439
+ // ---- Client: reconciliation by comparison ----
440
+
441
+ /** @private @type {string} */
442
+ #reconcile;
443
+
444
+ /**
445
+ * What this client predicted for the entities it owns, per frame, as wire bytes.
446
+ * @private @type {PredictionHistory}
447
+ */
448
+ #prediction_history = new PredictionHistory(128);
449
+
450
+ /**
451
+ * Authoritative states waiting for the next step, newest per network id: the frame and each
452
+ * replicated component's bytes, in `#replicated` order (`null` where the entity lacks it).
453
+ * @private @type {Map<number, {frame: number, parts: Array<{type_id: number, bytes: Uint8Array}|null>}>}
454
+ */
455
+ #pending_auth = new Map();
456
+
457
+ /**
458
+ * The newest frame reconciled per network id. An authoritative state for that frame or an
459
+ * earlier one arriving afterwards — reordered, or retransmitted — is stale: the present was
460
+ * already moved by a newer one, and moving it again by an older difference would undo that.
461
+ * @private @type {Map<number, number>}
462
+ */
463
+ #reconciled_frame = new Map();
464
+
465
+ /**
466
+ * Scratch instances per replicated class, for decoding without touching the world: the host's
467
+ * state, the prediction, and a later prediction being corrected.
468
+ * @private @type {Map<Function, object[]>}
469
+ */
470
+ #decode_scratch = new Map();
471
+
472
+ /** @private @type {CorrectionTarget} */
473
+ #correction_target = new CorrectionTarget();
474
+
475
+ /**
476
+ * Per replicated component, in `#replicated` order: whether the one being reconciled differs.
477
+ * @private @type {boolean[]}
478
+ */
479
+ #differs = [];
480
+
481
+ /**
482
+ * Client: authoritative states that differed from the prediction and were corrected.
483
+ * @type {number}
484
+ */
485
+ correction_count = 0;
486
+
487
+ /**
488
+ * Client: authoritative states that could not be compared because the prediction for their
489
+ * frame is not held (before the first predicted frame, or older than the history).
490
+ * @type {number}
491
+ */
492
+ correction_skipped_count = 0;
493
+
494
+ /**
495
+ * Client, {@link NetworkSessionReconcile.Correct}: a component of an authoritative state
496
+ * differed from the prediction, and the present was corrected. Once per component corrected.
497
+ * Args: `(entity_id, server_frame, component_class, magnitude)` — the size of the correction as
498
+ * the component's {@link Correction} measures it (a pose: how far the position moved, in world
499
+ * units). Diagnostic: a steady stream of these on a quiet link means the client simulates
500
+ * something differently from the host.
501
+ * @type {Signal}
502
+ */
503
+ onCorrection = new Signal();
231
504
 
232
505
  /** @private @type {Set<number>} */
233
506
  #connected_peers = new Set();
@@ -235,12 +508,28 @@ export class NetworkSession {
235
508
  /**
236
509
  * Host-only: peer_id → remaining-resends. Drained in
237
510
  * `#on_host_tick_complete` once `current_sim_frame >= 0`. Sent twice
238
- * for loss tolerance; production code should re-send on receiver
239
- * RECOVERY request.
511
+ * for loss tolerance, and never queued again on the peer's say-so: each
512
+ * send serializes the whole world, and a sync the peer could ask for is one
513
+ * it could keep asking for. Filled only by {@link #queue_initial_sync}.
514
+ * (A fragment of one that goes missing is re-sent on the receiver's
515
+ * NACK_FRAGMENT. That repair is `NetworkPeer`'s: a NACK re-sends each
516
+ * chunk of the sync at most once, for at most
517
+ * `FRAGMENT_RETENTION_MAX_RETRIES` NACKs, so it adds at most that many
518
+ * copies of each sync, however the peer asks.)
240
519
  * @private @type {Map<number, number>}
241
520
  */
242
521
  #pending_initial_sync = new Map();
243
522
 
523
+ /**
524
+ * Host-only: peers whose current connection has been given its
525
+ * INITIAL_SYNC — queued, or queued and already sent. A connection is
526
+ * given the world once. Cleared when `connect()` binds the peer a new
527
+ * connection; until then it describes the last one, on which nothing can
528
+ * arrive any more.
529
+ * @private @type {Set<number>}
530
+ */
531
+ #initial_sync_given = new Set();
532
+
244
533
  /**
245
534
  * Sampled-action ledger for predict-reconcile replay. The sampler
246
535
  * reads live input, so re-calling it during reconcile would give
@@ -270,6 +559,15 @@ export class NetworkSession {
270
559
  */
271
560
  #peer_grace_state = new Map();
272
561
 
562
+ /**
563
+ * Peers whose current connection has had its RESUME_HELLO answered. A
564
+ * client sends at most one per connection, from `connect()`; the host
565
+ * answers the first and ignores the rest. Cleared when `connect()` binds
566
+ * the peer a new connection.
567
+ * @private @type {Set<number>}
568
+ */
569
+ #resume_hello_answered = new Set();
570
+
273
571
  /**
274
572
  * Per-peer transport onDisconnect listener bookkeeping so we can
275
573
  * unsubscribe when the peer is fully dropped.
@@ -312,6 +610,26 @@ export class NetworkSession {
312
610
  * @private @type {boolean}
313
611
  */
314
612
  #has_ever_connected = false;
613
+ /**
614
+ * Client-side: how the host has answered the binding the last `connect()`
615
+ * made. Once it has, what the binding carries about the handshake is news
616
+ * no longer: the host sends each sync more than once against loss, and a
617
+ * host that has finished with our old session takes the new transport for
618
+ * a fresh peer and sends its sync before reading the RESUME_HELLO the
619
+ * transport carried, so the RESUME_REJECT it answers that with arrives
620
+ * after the resync it asks for.
621
+ * @private @type {BindingAnswer|string}
622
+ */
623
+ #binding_answer = BindingAnswer.Pending;
624
+ /**
625
+ * Client-side: the first frame predicted on the world this client holds —
626
+ * where the last INITIAL_SYNC it applied set the frame counter, 0 before
627
+ * any. Input predicted before it was predicted on a world the sync
628
+ * replaced, and is never sent: not by the binding that brought the sync,
629
+ * and not by any later one that resumes the world the sync began.
630
+ * @private @type {number}
631
+ */
632
+ #world_start_frame = 0;
315
633
 
316
634
  // ---- Signals (initialized inline because they take no input) ----
317
635
 
@@ -376,7 +694,13 @@ export class NetworkSession {
376
694
  /** @private @type {(() => object) | null} */ #transport_factory;
377
695
 
378
696
  /** @private @type {number} ms of inbound silence before reaping; 0 = off */ #connection_timeout_ms;
379
- /** @private @type {number} monotonic ms clock advanced by tick(dt) */ #liveness_clock_ms = 0;
697
+ /**
698
+ * The session's clock, in milliseconds: the engine's frame time, advanced by the delta of every
699
+ * rendered frame. Paces the render playout, idle reaping and the grace window, so all of them
700
+ * follow the engine — a paused engine pauses them, a test that drives the engine drives them.
701
+ * @private @type {number}
702
+ */
703
+ #clock_ms = 0;
380
704
  /**
381
705
  * Per-peer liveness mark: the inbound-packet count last seen and the clock
382
706
  * time it was last seen advancing. Drives idle reaping.
@@ -421,7 +745,10 @@ export class NetworkSession {
421
745
  * unique across peers.
422
746
  * - `simulation_delay_ticks` is honored only under `role: 'host'`.
423
747
  * Default 4. See {@link ServerAuthoritativeServer}.
424
- * - `tick_rate_hz` defaults to 60.
748
+ * - `tick_rate_hz`: the network tick rate, which is the engine's fixed-step
749
+ * rate — given, it sets `entity_manager.fixedUpdateStepSize`; omitted, the
750
+ * session uses the step the engine already has (60 Hz by default). Every
751
+ * peer must run the same rate.
425
752
  * - `frame_capacity` sizes the action-log ring (rollback depth + back-fill
426
753
  * range + retransmit window — see {@link DEFAULT_ACTION_LOG_FRAME_CAPACITY}).
427
754
  * Default 32. Raise it for high-RTT / lossy links.
@@ -435,6 +762,18 @@ export class NetworkSession {
435
762
  * - `reconnect` (client role): policy for the reconnect ladder. See
436
763
  * {@link DEFAULT_RECONNECT_POLICY}. Set `enabled: false` to opt
437
764
  * out entirely.
765
+ * - `publish_changes` (host role, default true): at the end of every
766
+ * step, send each replicated component the simulation changed — physics,
767
+ * controllers, anything that wrote it directly. Components an action
768
+ * wrote are already on the wire and are not sent twice. Publishing never
769
+ * writes back into the host's own state. Set false to publish by hand
770
+ * (`net_mutate_component`).
771
+ * - `reconcile` (client role): see {@link NetworkSessionReconcile}. Default
772
+ * `'correct'`.
773
+ * - `late_input` (host role): what to do with client input that arrives
774
+ * for a frame already simulated — see {@link LateInput}. Default
775
+ * `'apply'`: fold it into the current frame. `'rollback'` rewinds and
776
+ * replays, which re-executes actions only, never the engine's systems.
438
777
  */
439
778
  constructor({
440
779
  entity_manager,
@@ -443,7 +782,7 @@ export class NetworkSession {
443
782
  role = NetworkSessionRole.Client,
444
783
  local_peer_id = -1,
445
784
  simulation_delay_ticks = DEFAULT_SIMULATION_DELAY_TICKS,
446
- tick_rate_hz = DEFAULT_TICK_RATE_HZ,
785
+ tick_rate_hz = undefined,
447
786
  frame_capacity = DEFAULT_ACTION_LOG_FRAME_CAPACITY,
448
787
  binary_registry = null,
449
788
  scope_filter = null,
@@ -452,14 +791,19 @@ export class NetworkSession {
452
791
  server_resume_grace_ms = DEFAULT_SERVER_RESUME_GRACE_MS,
453
792
  connection_timeout_ms = DEFAULT_CONNECTION_TIMEOUT_MS,
454
793
  reconnect = null,
794
+ publish_changes = true,
795
+ late_input = LateInput.Apply,
796
+ reconcile = NetworkSessionReconcile.Correct,
455
797
  } = {}) {
456
798
  assert.ok(entity_manager !== undefined && entity_manager !== null,
457
799
  'NetworkSession: entity_manager is required');
458
800
  if (role !== NetworkSessionRole.Client && role !== NetworkSessionRole.Host) {
459
801
  throw new Error(`NetworkSession: invalid role '${role}'`);
460
802
  }
461
- assert.isNumber(tick_rate_hz, 'tick_rate_hz');
462
- assert.ok(tick_rate_hz > 0, 'tick_rate_hz must be positive');
803
+ if (tick_rate_hz !== undefined) {
804
+ assert.isNumber(tick_rate_hz, 'tick_rate_hz');
805
+ assert.ok(tick_rate_hz > 0, 'tick_rate_hz must be positive');
806
+ }
463
807
  assert.isNonNegativeInteger(simulation_delay_ticks, 'simulation_delay_ticks');
464
808
  assert.isPositiveInteger(frame_capacity, 'frame_capacity');
465
809
 
@@ -481,11 +825,18 @@ export class NetworkSession {
481
825
  */
482
826
  this.role = role;
483
827
 
828
+ // One clock: the network tick IS the engine's fixed step. A rate given here sets the step;
829
+ // otherwise the session adopts the one the engine already has.
830
+ if (tick_rate_hz !== undefined) {
831
+ entity_manager.fixedUpdateStepSize = 1 / tick_rate_hz;
832
+ }
833
+
484
834
  /**
835
+ * The network tick period, which is the `EntityManager`'s fixed step.
485
836
  * @readonly
486
837
  * @type {number}
487
838
  */
488
- this.tick_period_ms = 1000 / tick_rate_hz;
839
+ this.tick_period_ms = entity_manager.fixedUpdateStepSize * 1000;
489
840
 
490
841
  /**
491
842
  * @readonly
@@ -553,6 +904,12 @@ export class NetworkSession {
553
904
  this.#connection_timeout_ms = connection_timeout_ms;
554
905
  this.#reconnect_policy = Object.freeze({ ...DEFAULT_RECONNECT_POLICY, ...(reconnect || {}) });
555
906
  this.#transport_factory = transport_factory;
907
+ this.#publish_changes = publish_changes;
908
+ this.#late_input = late_input;
909
+ if (reconcile !== NetworkSessionReconcile.Correct && reconcile !== NetworkSessionReconcile.Replay) {
910
+ throw new Error(`NetworkSession: reconcile must be one of ${Object.values(NetworkSessionReconcile).join(', ')}, got '${reconcile}'`);
911
+ }
912
+ this.#reconcile = reconcile;
556
913
  }
557
914
 
558
915
  // ----------------------------------------------------------------
@@ -560,52 +917,129 @@ export class NetworkSession {
560
917
  // ----------------------------------------------------------------
561
918
 
562
919
  /**
563
- * Register a component class for network replication.
920
+ * Replicate `ComponentClass`, and draw it between network ticks by blending. A network tick is
921
+ * coarser than a rendered frame, and a component shown only as each state lands moves in steps;
922
+ * `interpoland` says how it is drawn instead — the layout each tick's state is recorded in, and
923
+ * the blend of two records for a rendered frame.
924
+ *
925
+ * - `interpoland.component_class` is `ComponentClass`, and its blend is of kind
926
+ * {@link InterpolationKind.Linear}.
927
+ * - `interpoland.type_id` names its records. No two components one session replicates may share
928
+ * one; {@link start} checks.
929
+ * - `ComponentClass` has `copy(other)`: while a blend is drawn over the component, its simulated
930
+ * value is held with it, and put back exactly before the next step.
931
+ *
932
+ * `correction` is how a client that predicts the component corrects it when the host disagrees
933
+ * — see {@link Correction}.
934
+ *
935
+ * See {@link replicate_discrete} for a component with no in-between.
936
+ *
937
+ * Like every replicated component, `ComponentClass` needs a
938
+ * {@link BinaryClassSerializationAdapter} registered for its `typeName` in `binary_registry`
939
+ * before {@link start} — its wire format. Components are laid out on the wire in the order they
940
+ * are replicated, so every peer must replicate the same components in the same order.
941
+ *
942
+ * @param {Function} ComponentClass
943
+ * @param {Interpoland} interpoland
944
+ * @param {Correction} correction
945
+ */
946
+ replicate_interpolated(ComponentClass, interpoland, correction) {
947
+ const name = this.#assert_can_replicate('replicate_interpolated', ComponentClass);
948
+
949
+ if (interpoland === null || interpoland === undefined || interpoland.isInterpoland !== true) {
950
+ throw new Error(`NetworkSession.replicate_interpolated: ${name} needs an Interpoland — the layout its states are recorded in, and the blend between them`);
951
+ }
952
+ if (interpoland.component_class !== ComponentClass) {
953
+ throw new Error(`NetworkSession.replicate_interpolated: the interpoland given for ${name} interpolates ${interpoland.component_class?.typeName ?? interpoland.component_class?.name}`);
954
+ }
955
+
956
+ assert_linear_blend('replicate_interpolated', name, interpoland.interpolation_adapter);
957
+ assert_copies_itself('replicate_interpolated', name, ComponentClass);
958
+ assert_correction('replicate_interpolated', name, correction);
959
+
960
+ this.#user_replicated.push({ klass: ComponentClass, interpoland, interpolator: null, correction });
961
+ }
962
+
963
+ /**
964
+ * Replicate `ComponentClass`, and draw it as each state lands, with no blend between network
965
+ * ticks. For a value that has no in-between — a count, a name, a state machine's state.
564
966
  *
565
- * The component must have a {@link BinaryClassSerializationAdapter}
566
- * registered for its `typeName` in the session's `binary_registry`
567
- * before {@link start} is called — that adapter handles the wire
568
- * format and rewind capture.
967
+ * `correction` is how a client that predicts the component corrects it when the host disagrees
968
+ * — see {@link Correction}.
569
969
  *
570
- * `interpolator` is optional. When omitted, the component's state
571
- * snaps on each received update (no sub-tick smoothing). When
572
- * provided, it must extend {@link BinaryInterpolationAdapter} with
573
- * `kind = InterpolationKind.Linear` — Discrete and Cubic are
574
- * reserved for future support and currently throw.
970
+ * Like every replicated component, `ComponentClass` needs a
971
+ * {@link BinaryClassSerializationAdapter} registered for its `typeName` in `binary_registry`
972
+ * before {@link start} — its wire format. Components are laid out on the wire in the order they
973
+ * are replicated, so every peer must replicate the same components in the same order.
575
974
  *
576
- * The order of `replicate()` calls must match across all peers in
577
- * the session: AUTH_STATE payload layout iterates components in
578
- * insertion order.
975
+ * @param {Function} ComponentClass
976
+ * @param {Correction} correction
977
+ */
978
+ replicate_discrete(ComponentClass, correction) {
979
+ const name = this.#assert_can_replicate('replicate_discrete', ComponentClass);
980
+
981
+ assert_correction('replicate_discrete', name, correction);
982
+
983
+ this.#user_replicated.push({ klass: ComponentClass, interpoland: null, interpolator: null, correction });
984
+ }
985
+
986
+ /**
987
+ * **Deprecated.** Use {@link replicate_interpolated} or {@link replicate_discrete}, which say how
988
+ * the component is drawn. Warns once.
579
989
  *
990
+ * Keeps its meaning: `replicate(C)` replicates `C` discretely; `replicate(C, interpolator)` blends
991
+ * it with `interpolator`, recorded in its replication layout. A component blended this way needs
992
+ * `copy(other)`, as with {@link replicate_interpolated}. A client corrects what it registers by
993
+ * taking the host's value ({@link HOST_VALUE_CORRECTION}).
994
+ *
995
+ * @deprecated
580
996
  * @param {Function} ComponentClass
581
- * @param {BinaryInterpolationAdapter} [interpolator]
997
+ * @param {BinaryInterpolationAdapter|null} [interpolator]
582
998
  */
583
999
  replicate(ComponentClass, interpolator = null) {
584
- this.#assert_not_started('replicate');
1000
+ if (!replicate_deprecation_warned) {
1001
+ replicate_deprecation_warned = true;
1002
+ console.warn(
1003
+ 'NetworkSession.replicate() is deprecated: use replicate_interpolated(C, interpoland, correction) for a component ' +
1004
+ 'blended between network ticks, or replicate_discrete(C, correction) for one that is not.',
1005
+ );
1006
+ }
1007
+
1008
+ if (interpolator === null) {
1009
+ this.replicate_discrete(ComponentClass, HOST_VALUE_CORRECTION);
1010
+ return;
1011
+ }
1012
+
1013
+ const name = this.#assert_can_replicate('replicate', ComponentClass);
1014
+
1015
+ assert_linear_blend('replicate', name, interpolator);
1016
+ assert_copies_itself('replicate', name, ComponentClass);
1017
+
1018
+ this.#user_replicated.push({ klass: ComponentClass, interpoland: null, interpolator, correction: HOST_VALUE_CORRECTION });
1019
+ }
1020
+
1021
+ /**
1022
+ * @param {string} method
1023
+ * @param {Function} ComponentClass
1024
+ * @returns {string} the component's name, for messages
1025
+ */
1026
+ #assert_can_replicate(method, ComponentClass) {
1027
+ this.#assert_not_started(method);
585
1028
  assert.isFunction(ComponentClass, 'ComponentClass');
586
1029
 
1030
+ const name = ComponentClass.typeName ?? ComponentClass.name;
1031
+
587
1032
  if (ComponentClass === NetworkIdentity) {
588
- throw new Error("NetworkSession.replicate: NetworkIdentity is auto-replicated; do not call replicate() for it");
1033
+ throw new Error(`NetworkSession.${method}: NetworkIdentity is replicated by the session itself`);
589
1034
  }
590
1035
 
591
1036
  for (const entry of this.#user_replicated) {
592
1037
  if (entry.klass === ComponentClass) {
593
- throw new Error(`NetworkSession.replicate: ${ComponentClass.typeName ?? ComponentClass.name} already registered`);
1038
+ throw new Error(`NetworkSession.${method}: ${name} is already replicated`);
594
1039
  }
595
1040
  }
596
- if (interpolator !== null) {
597
- if (!(interpolator instanceof BinaryInterpolationAdapter)) {
598
- throw new Error("NetworkSession.replicate: interpolator must extend BinaryInterpolationAdapter");
599
- }
600
- if (interpolator.kind !== InterpolationKind.Linear) {
601
- throw new Error(
602
- `NetworkSession.replicate: only Linear interpolation is currently supported; ` +
603
- `got kind=${interpolator.kind} for ${ComponentClass.typeName ?? ComponentClass.name}. ` +
604
- `Omit the interpolator argument for snap (Discrete) behavior; Cubic is reserved.`,
605
- );
606
- }
607
- }
608
- this.#user_replicated.push({ klass: ComponentClass, interp: interpolator });
1041
+
1042
+ return name;
609
1043
  }
610
1044
 
611
1045
  /**
@@ -658,12 +1092,12 @@ export class NetworkSession {
658
1092
  /**
659
1093
  * Wire the session to the engine. After this, the EntityObserver
660
1094
  * is active, the right orchestrator is constructed, and a
661
- * {@link NetworkSystem} is attached. Subsequent {@link replicate}
1095
+ * {@link NetworkSystem} is attached. Subsequent `replicate_*`
662
1096
  * / {@link defineAction} / {@link defineInputSampler} calls throw.
663
1097
  *
664
- * Pre-condition: every component class passed to {@link replicate}
665
- * must already have a `BinaryClassSerializationAdapter` registered
666
- * in the session's binary_registry.
1098
+ * Pre-condition: every replicated component class must already have a
1099
+ * `BinaryClassSerializationAdapter` registered in the session's
1100
+ * binary_registry.
667
1101
  */
668
1102
  async start() {
669
1103
  if (this.#started) throw new Error("NetworkSession.start: already started");
@@ -684,13 +1118,15 @@ export class NetworkSession {
684
1118
  const network_identity_scratch = new BinaryBuffer();
685
1119
  network_identity_scratch.setCapacity(SCRATCH_BUFFER_BYTES);
686
1120
  this.#replicated.set(NetworkIdentity, {
687
- interp: null,
688
1121
  interp_type_id: next_id++,
1122
+ interpoland: null,
1123
+ interpolator: null,
1124
+ correction: null, // ownership is never predicted
689
1125
  });
690
1126
  this.#interp_type_id_to_class[0] = NetworkIdentity;
691
- for (const { klass, interp } of this.#user_replicated) {
1127
+ for (const { klass, interpoland, interpolator, correction } of this.#user_replicated) {
692
1128
  const interp_type_id = next_id++;
693
- this.#replicated.set(klass, { interp, interp_type_id });
1129
+ this.#replicated.set(klass, { interp_type_id, interpoland, interpolator, correction });
694
1130
  this.#interp_type_id_to_class[interp_type_id] = klass;
695
1131
  }
696
1132
 
@@ -705,6 +1141,8 @@ export class NetworkSession {
705
1141
  }
706
1142
  }
707
1143
 
1144
+ this.#interpolands = this.#build_interpolands();
1145
+
708
1146
  // Build the synthetic ReplaceComponentAction now so it's in the
709
1147
  // action_classes list when the orchestrator is constructed.
710
1148
  this.#ReplaceComponentAction = this.#make_replace_component_action_class();
@@ -724,6 +1162,7 @@ export class NetworkSession {
724
1162
  this.#server = new ServerAuthoritativeServer({
725
1163
  ...orchestrator_opts,
726
1164
  simulation_delay_ticks: this.simulation_delay_ticks,
1165
+ late_input: this.#late_input,
727
1166
  });
728
1167
  this.#peer = this.#server.peer;
729
1168
  this.#peer.replicator.scope_filter = this.#scope_filter || new OwnerAwareScope({
@@ -732,6 +1171,9 @@ export class NetworkSession {
732
1171
  identity_class: NetworkIdentity,
733
1172
  });
734
1173
  this.#server.onTickComplete.add((sim_frame) => this.#on_host_tick_complete(sim_frame));
1174
+ if (this.#publish_changes) {
1175
+ this.#server.onBeforeTickClose.add(() => this.#publish_simulated_changes());
1176
+ }
735
1177
  } else {
736
1178
  // Client role: covers both "playing" (input sampler registered)
737
1179
  // and "spectator" (no sampler — sampler-driven onPredict
@@ -740,7 +1182,13 @@ export class NetworkSession {
740
1182
  this.#client = new ServerAuthoritativeClient({
741
1183
  ...orchestrator_opts,
742
1184
  time_dilation: this.#time_dilation,
1185
+ auto_reconcile: this.#reconcile === NetworkSessionReconcile.Replay,
743
1186
  });
1187
+ if (this.#reconcile === NetworkSessionReconcile.Correct) {
1188
+ this.#client.peer.onAuthState.add((_peer_id, server_frame, network_id, buffer) => {
1189
+ this.#queue_auth_state(server_frame, network_id, buffer);
1190
+ });
1191
+ }
744
1192
  this.#peer = this.#client.peer;
745
1193
  if (this.#scope_filter) {
746
1194
  this.#peer.replicator.scope_filter = this.#scope_filter;
@@ -750,12 +1198,19 @@ export class NetworkSession {
750
1198
 
751
1199
  // Install the canonical-form normalize hook on the executor.
752
1200
  // Anything that calls executor.execute — predict apply, action-
753
- // stream apply, reconcile replay — first normalizes the world.
754
- // Idempotent: cheap when `render_dirty` is false (one bool
755
- // check), expensive (one adapter.deserialize per remote-owned
756
- // component) only on the first execute after a render pass.
1201
+ // stream apply, reconcile replay — first puts back any render
1202
+ // blend, so the prior state it captures is the truth. Idempotent:
1203
+ // cheap when nothing is blended, one compare + deserialize per
1204
+ // blended component on the first execute after a render pass.
757
1205
  this.#peer.executor.before_execute = this.#bound_normalize_if_dirty;
758
1206
 
1207
+ if (this.role === NetworkSessionRole.Host && this.#publish_changes) {
1208
+ // an action carries its own change to the peers: what it wrote is what they will hold
1209
+ this.#peer.executor.on_component_written = (entity_id, component_class) => {
1210
+ this.#note_published(entity_id, component_class);
1211
+ };
1212
+ }
1213
+
759
1214
  // Secure-by-default inbound authorization on the host: a remote client
760
1215
  // may only mutate entities it owns (NetworkIdentity.owner_peer_id ===
761
1216
  // sender); the authoritative server (sender === local_peer_id) may
@@ -776,14 +1231,30 @@ export class NetworkSession {
776
1231
  // startup completes (it auto-starts when added to an already-Running
777
1232
  // EM). Await it so the session's identity observer below doesn't
778
1233
  // race with the NetworkSystem's observer over slot_table allocation.
779
- await this.entity_manager.addSystem(new NetworkSystem(this.#peer));
780
-
781
- // Sub-tick interpolation log: records per-frame replicated component
782
- // state, sampled at render time for remotely-owned entities.
1234
+ //
1235
+ // It is also the session's place in the engine loop: each fixed step opens a network frame
1236
+ // and closes it, and every rendered frame runs the session's wall-paced work.
1237
+ await this.entity_manager.addSystem(new NetworkSystem(this.#peer, {
1238
+ open_step: () => this.#open_step(),
1239
+ close_step: () => this.#close_step(),
1240
+ frame: (dt) => this.#on_frame(dt),
1241
+ }));
1242
+
1243
+ // The network timeline: per-frame state of every remote entity, blended at render time on
1244
+ // the render-delayed playout by the engine's InterpolationSystem.
783
1245
  this.#interp_log = new InterpolationLog({
784
- buffer_capacity_bytes: 65536,
785
- records_capacity: 4096,
786
- });
1246
+ buffer_capacity_bytes: 1 << 18,
1247
+ records_capacity: 8192,
1248
+ }); // grows with the entity count, see #on_frame_applied
1249
+
1250
+ let interpolation = this.entity_manager.getSystem(InterpolationSystem);
1251
+ if (interpolation === null) {
1252
+ interpolation = new InterpolationSystem();
1253
+ await this.entity_manager.addSystem(interpolation);
1254
+ }
1255
+ this.#interpolation = interpolation;
1256
+ this.#interp_source_id = interpolation.allocateSourceId();
1257
+ interpolation.registerSource(this.#interp_source_id, this.#interp_log, () => this.#sample_playout());
787
1258
 
788
1259
  // Per-frame applied: snapshot all replicated components for each
789
1260
  // remote-owned entity into the interpolation log.
@@ -796,7 +1267,15 @@ export class NetworkSession {
796
1267
  // action-stream processing, and finalize any in-flight Tier-3
797
1268
  // resync state.
798
1269
  if (this.role === NetworkSessionRole.Client) {
799
- this.#peer.onInitialSync.add((_peer_id, session_token, frame_number, buf, payload_end) => {
1270
+ this.#peer.onInitialSync.add((peer_id, session_token, frame_number, buf, payload_end) => {
1271
+ if (this.#binding_answer === BindingAnswer.Synced && this.#reconnect_state !== ReconnectState.Resyncing) {
1272
+ // A copy: the host sends every sync more than once, against loss, and this
1273
+ // binding already has its world. The client has been predicting on it since;
1274
+ // applied again, it would put what the client owns back behind input already
1275
+ // sent, and seek the frame counter over frames already predicted.
1276
+ return;
1277
+ }
1278
+
800
1279
  const token = new UUID();
801
1280
  token.data = session_token;
802
1281
  this.session_token = token;
@@ -816,7 +1295,22 @@ export class NetworkSession {
816
1295
  */
817
1296
  this.seek_to_frame(frame_number + 1 + this.#time_dilation.target_buffer_depth);
818
1297
 
1298
+ // The world is about to be the host's. What this client predicted, sampled or was
1299
+ // told about the one it had is about a world, and a frame numbering, that is gone.
1300
+ this.#prediction_history.clear();
1301
+ this.#pending_auth.clear();
1302
+ this.#reconciled_frame.clear();
1303
+ this.#sampled_actions_per_frame.clear();
1304
+
819
1305
  this.#apply_initial_sync(buf, payload_end);
1306
+ this.#binding_answer = BindingAnswer.Synced;
1307
+
1308
+ // Input from here on is predicted on the host's world. What was predicted before —
1309
+ // held since this binding was made, or still in the log from before it — was
1310
+ // predicted on the world just replaced, and is never sent.
1311
+ this.#world_start_frame = this.#local_frame;
1312
+ this.#peer.release_outbound(peer_id, this.#world_start_frame);
1313
+
820
1314
  // Reconnecting counts as well as Resyncing: a host that has
821
1315
  // finished with our old session readmits us as a fresh peer,
822
1316
  // so the snapshot arrives with no RESUME_ACCEPT ahead of it.
@@ -833,7 +1327,15 @@ export class NetworkSession {
833
1327
  }
834
1328
  });
835
1329
  // Host's response to our RESUME_HELLO during reconnect.
836
- this.#peer.onResumeAccept.add(() => {
1330
+ this.#peer.onResumeAccept.add((peer_id) => {
1331
+ if (this.#binding_answer !== BindingAnswer.Pending) {
1332
+ // stale, as a reject would be: this binding has had its answer
1333
+ return;
1334
+ }
1335
+ this.#binding_answer = BindingAnswer.Resumed;
1336
+ // The host kept the world this client holds, so what the client predicted on it —
1337
+ // while cut off, and since — is owed to the host like any input, late as it is.
1338
+ this.#peer.release_outbound(peer_id, this.#world_start_frame);
837
1339
  if (this.#reconnect_state === ReconnectState.Reconnecting
838
1340
  || this.#reconnect_state === ReconnectState.Resyncing) {
839
1341
  this.#enter_connected();
@@ -841,6 +1343,15 @@ export class NetworkSession {
841
1343
  }
842
1344
  });
843
1345
  this.#peer.onResumeReject.add((_peer_id, reason_code) => {
1346
+ if (this.#binding_answer !== BindingAnswer.Pending) {
1347
+ // Stale: this binding has had its answer. A host that has finished with our
1348
+ // old session readmits the binding as a fresh peer before it reads our
1349
+ // RESUME_HELLO, and the sync it sends then is the resync this reject asks for,
1350
+ // already applied. Acted on, the reject would throw away the token that sync
1351
+ // issued and wait on a sync already here. A reject that ends the connection is
1352
+ // followed by a DISCONNECT, which still does.
1353
+ return;
1354
+ }
844
1355
  if (this.#reconnect_policy.accept_state_resync) {
845
1356
  // Tier-3: drop unconfirmed predictions and wait for
846
1357
  // the host to deliver a fresh INITIAL_SYNC.
@@ -899,15 +1410,36 @@ export class NetworkSession {
899
1410
  * a peer id is the matchmaking layer's decision, not a race between
900
1411
  * whatever connections happen to arrive.
901
1412
  *
1413
+ * A client sends its input on the new connection only once the host has
1414
+ * answered it. A RESUME_ACCEPT sends everything predicted meanwhile; an
1415
+ * INITIAL_SYNC drops everything predicted before it, on the world it
1416
+ * replaces. See the network README, "Connecting, and coming back".
1417
+ *
902
1418
  * @param {number} remote_peer_id
903
1419
  * @param {object} transport
904
1420
  */
905
1421
  connect(remote_peer_id, transport) {
906
1422
  if (!this.#started) throw new Error("NetworkSession.connect: call start() first");
907
1423
 
1424
+ // What the peer's previous transport delivered — and its end, if it has ended — is taken
1425
+ // before the new transport is bound, in the order it arrived: a connection that dropped
1426
+ // moments ago has not been noticed until its news is read, and a peer id is only free
1427
+ // once it has been. That holds when this is called from inside that transport's own
1428
+ // delivery — by an application handing on the id of a peer whose DISCONNECT is being
1429
+ // read, say: the flush goes on from the packet after the one being read.
1430
+ const previous = this.#inbound.get(remote_peer_id);
1431
+ if (previous !== undefined) {
1432
+ previous.flush();
1433
+ }
1434
+
908
1435
  if (this.role === NetworkSessionRole.Host) {
909
1436
  const in_grace = this.#peer_grace_state.has(remote_peer_id);
910
- this.#server.connect_peer(remote_peer_id, transport);
1437
+ const deferred = this.#bind_deferred(remote_peer_id, transport,
1438
+ (t) => this.#server.connect_peer(remote_peer_id, t));
1439
+ // A new connection: nothing it says has been answered yet, and it
1440
+ // has not been given the world.
1441
+ this.#resume_hello_answered.delete(remote_peer_id);
1442
+ this.#initial_sync_given.delete(remote_peer_id);
911
1443
  if (in_grace) {
912
1444
  // Resume candidate. Wait for RESUME_HELLO; restore
913
1445
  // baseline + add to connected_peers on validation.
@@ -915,10 +1447,10 @@ export class NetworkSession {
915
1447
  // RESUME_REJECT.
916
1448
  } else {
917
1449
  // Fresh peer. Queue initial-sync for the next host tick.
918
- this.#pending_initial_sync.set(remote_peer_id, 2);
1450
+ this.#queue_initial_sync(remote_peer_id);
919
1451
  this.#connected_peers.add(remote_peer_id);
920
1452
  }
921
- this.#wire_peer_transport_disconnect(remote_peer_id, transport);
1453
+ this.#wire_peer_transport_disconnect(remote_peer_id, deferred);
922
1454
  } else {
923
1455
  // Client. Release whatever binding this peer id already has: the
924
1456
  // reconnect ladder fires on a back-off timer, not on the previous
@@ -934,11 +1466,19 @@ export class NetworkSession {
934
1466
  this.#peer.disconnect_peer(remote_peer_id);
935
1467
  this.#connected_peers.delete(remote_peer_id);
936
1468
  this.#peer_inbound_mark.delete(remote_peer_id);
937
- this.#client.connect_to_server(remote_peer_id, transport);
1469
+ const deferred = this.#bind_deferred(remote_peer_id, transport,
1470
+ (t) => this.#client.connect_to_server(remote_peer_id, t));
938
1471
  this.#remote_peer_id = remote_peer_id;
939
- this.#current_transport = transport;
940
- this.#wire_client_transport_disconnect(transport);
1472
+ this.#wire_client_transport_disconnect(deferred);
1473
+ this.#current_transport = deferred;
941
1474
  this.#connected_peers.add(remote_peer_id);
1475
+ // A new binding, and until the host answers it the client does not know which world it
1476
+ // is in: the one it has been predicting on, if the host resumes it (RESUME_ACCEPT), or
1477
+ // the host's, if it sends a snapshot (INITIAL_SYNC) — and input predicted on a world the
1478
+ // snapshot replaces must never reach the host. So what the client predicts meanwhile is
1479
+ // held: sent on an accept, dropped on a sync.
1480
+ this.#binding_answer = BindingAnswer.Pending;
1481
+ this.#peer.hold_outbound(remote_peer_id);
942
1482
 
943
1483
  // Announce ourselves whenever this connect could be a claim on an
944
1484
  // id the host still holds a record for: we have a token to prove
@@ -1057,116 +1597,322 @@ export class NetworkSession {
1057
1597
  }
1058
1598
 
1059
1599
  /**
1060
- * Tear down. Idempotent — safe to call from cleanup paths.
1600
+ * Tear down. Idempotent — safe to call from cleanup paths.
1601
+ */
1602
+ stop() {
1603
+ if (!this.#started) return;
1604
+
1605
+ this.entity_manager.fixedStepTimeScale = 1;
1606
+
1607
+ if (this.#step_open) {
1608
+ // stopped from inside a fixed step: close the frame the step opened
1609
+ this.#step_open = false;
1610
+ if (this.#server !== null) this.#server.end_tick(); else this.#client.end_tick();
1611
+ }
1612
+
1613
+ if (this.#interpolation !== null) {
1614
+ this.#interpolation.restore();
1615
+ this.#interpolation.unregisterSource(this.#interp_source_id);
1616
+ }
1617
+ for (const [entity_id, interpolated] of this.#attached_interpolated) {
1618
+ if (this.world.getComponent(entity_id, Interpolated) === interpolated) {
1619
+ this.world.removeComponentFromEntity(entity_id, Interpolated);
1620
+ }
1621
+ }
1622
+ this.#attached_interpolated.clear();
1623
+ this.#interpolation_pending.clear();
1624
+ this.#pending_auth.clear();
1625
+ this.#reconciled_frame.clear();
1626
+ this.#prediction_history.clear();
1627
+
1628
+ if (this.#identity_observer !== null) {
1629
+ this.#identity_observer.disconnect();
1630
+ this.#identity_observer = null;
1631
+ }
1632
+ for (const [entity_id, listener] of this.#event_listeners) {
1633
+ this.world.removeEntityEventListener(entity_id, "net_mutate_component", listener);
1634
+ }
1635
+ this.#event_listeners.clear();
1636
+ this.#remote_entities.clear();
1637
+ this.#sampled_actions_per_frame.clear();
1638
+ this.#peer_inbound_mark.clear();
1639
+ for (const transport of this.#inbound.values()) {
1640
+ transport.release();
1641
+ }
1642
+ this.#inbound.clear();
1643
+ this.#started = false;
1644
+ }
1645
+
1646
+ // ----------------------------------------------------------------
1647
+ // Per-tick driver
1648
+ // ----------------------------------------------------------------
1649
+
1650
+ /**
1651
+ * **Deprecated; does nothing.** The session used to run its own fixed-step clock here, next to
1652
+ * the engine's: two clocks, so network frame N and the engine's step N were unrelated, and
1653
+ * nothing interpolated against one could be blended on the other. The session now runs on the
1654
+ * `EntityManager`'s fixed step — `entity_manager.update(dt)`, which the engine loop already
1655
+ * calls, drives it — and calling this as well would advance it twice.
1656
+ *
1657
+ * Warns once. Remove the call.
1658
+ *
1659
+ * @deprecated
1660
+ * @param {number} [dt_seconds]
1661
+ */
1662
+ tick(dt_seconds) {
1663
+ if (!tick_deprecation_warned) {
1664
+ tick_deprecation_warned = true;
1665
+ console.warn('NetworkSession.tick() is deprecated and does nothing: the session runs on the EntityManager fixed step, driven by entity_manager.update(dt). Remove the call.');
1666
+ }
1667
+ }
1668
+
1669
+ /**
1670
+ * The fixed step about to run opens a network frame. Before it does: the live components are
1671
+ * given back the simulation's truth (a render blend is not state), and everything that arrived
1672
+ * from the network since the last step is applied to it — here, where simulation writes happen,
1673
+ * and not whenever the browser delivers a packet, which is usually between a frame's blend and
1674
+ * its draw.
1675
+ */
1676
+ #open_step() {
1677
+ if (!this.#started) return;
1678
+
1679
+ this.#interpolation.settle();
1680
+
1681
+ this.#flush_inbound();
1682
+
1683
+ this.#apply_pending_interpolation();
1684
+
1685
+ if (this.#client !== null && this.#pending_auth.size > 0) {
1686
+ this.#apply_pending_corrections();
1687
+ }
1688
+
1689
+ try {
1690
+ if (this.#server !== null) {
1691
+ this.#server.begin_tick(this.#local_frame);
1692
+ } else {
1693
+ this.#client.begin_tick(this.#local_frame);
1694
+ }
1695
+ } catch (e) {
1696
+ // the frame is spent: the next step moves on to the next one rather than repeat it
1697
+ // over what this one already applied
1698
+ this.#local_frame++;
1699
+ throw e;
1700
+ }
1701
+
1702
+ this.#step_open = true;
1703
+ }
1704
+
1705
+ /**
1706
+ * The fixed step has run: close its network frame.
1707
+ */
1708
+ #close_step() {
1709
+ if (!this.#step_open) return;
1710
+
1711
+ try {
1712
+ if (this.#server !== null) {
1713
+ // runs the frame's local sim, then publishes (onBeforeTickClose), then closes it
1714
+ this.#server.end_tick();
1715
+ } else {
1716
+ this.#client.end_tick();
1717
+ this.#send_frame_marker(this.#local_frame);
1718
+ if (this.#reconcile === NetworkSessionReconcile.Correct) {
1719
+ this.#record_prediction(this.#local_frame);
1720
+ }
1721
+ }
1722
+ } finally {
1723
+ this.#step_open = false;
1724
+ this.#local_frame++;
1725
+ }
1726
+ }
1727
+
1728
+ /**
1729
+ * Deliver what every peer's transport has held since the last step, and let go of the
1730
+ * transports of peers no longer connected.
1731
+ */
1732
+ #flush_inbound() {
1733
+ for (const [peer_id, transport] of this.#inbound) {
1734
+ if (!this.#peer.is_connected(peer_id)) {
1735
+ transport.release();
1736
+ this.#inbound.delete(peer_id);
1737
+ continue;
1738
+ }
1739
+ transport.flush();
1740
+ }
1741
+ }
1742
+
1743
+ /**
1744
+ * Bind `peer_id` to `transport` through `bind`, with the transport's traffic held for
1745
+ * {@link #open_step}. Whatever held the peer's traffic before is let go once the new binding
1746
+ * stands; if binding throws, nothing changes.
1747
+ *
1748
+ * @param {number} peer_id
1749
+ * @param {object} transport
1750
+ * @param {(deferred: DeferredTransport) => void} bind
1751
+ * @returns {DeferredTransport}
1752
+ */
1753
+ #bind_deferred(peer_id, transport, bind) {
1754
+ const deferred = new DeferredTransport(transport);
1755
+
1756
+ try {
1757
+ bind(deferred);
1758
+ } catch (e) {
1759
+ deferred.release();
1760
+ throw e;
1761
+ }
1762
+
1763
+ const previous = this.#inbound.get(peer_id);
1764
+ if (previous !== undefined) {
1765
+ previous.release();
1766
+ }
1767
+ this.#inbound.set(peer_id, deferred);
1768
+
1769
+ return deferred;
1770
+ }
1771
+
1772
+ /**
1773
+ * Host, end of step: record every replicated component whose wire image differs from what the
1774
+ * peers hold, into the still-open frame, for the action stream to carry. Recorded, not
1775
+ * executed — see {@link SimActionExecutor#record}. A component an action wrote this step and
1776
+ * nothing changed since is not sent again: the peers apply the action.
1777
+ */
1778
+ #publish_simulated_changes() {
1779
+ const world = this.world;
1780
+ const executor = this.#peer.executor;
1781
+ const scratch = this.#scratch_publish_buf;
1782
+ const changed_entities = executor.changed_entities;
1783
+
1784
+ for (const entity_id of this.#event_listeners.keys()) {
1785
+ const identity = world.getComponent(entity_id, NetworkIdentity);
1786
+ if (identity === undefined || identity.network_id < 0) continue;
1787
+
1788
+ for (const [ComponentClass, desc] of this.#replicated) {
1789
+ if (ComponentClass === NetworkIdentity) continue;
1790
+
1791
+ const live = world.getComponent(entity_id, ComponentClass);
1792
+ if (live === undefined) continue;
1793
+
1794
+ const type_id = desc.interp_type_id;
1795
+
1796
+ scratch.position = 0;
1797
+ this.binary_registry.getAdapter(ComponentClass.typeName).serialize(scratch, live);
1798
+ const length = scratch.position;
1799
+
1800
+ if (!this.#remember_published(entity_id, type_id, scratch.raw_bytes, length)) continue;
1801
+
1802
+ const action = this.#peer.action_registry.acquire(this.#ReplaceComponentAction);
1803
+ try {
1804
+ action.network_id = identity.network_id;
1805
+ action.component_type_id = type_id;
1806
+ action.payload_buf.position = 0;
1807
+ action.payload_buf.writeBytes(scratch.raw_bytes, 0, length);
1808
+ action.payload_length = length;
1809
+ executor.record(action);
1810
+ } finally {
1811
+ this.#peer.action_registry.release(action);
1812
+ }
1813
+
1814
+ if (changed_entities !== null) changed_entities.add(identity.network_id);
1815
+ }
1816
+ }
1817
+ }
1818
+
1819
+ /**
1820
+ * Host: an action wrote `ComponentClass` of `entity_id`; the peers will hold what it wrote.
1821
+ * @param {number} entity_id
1822
+ * @param {Function} ComponentClass
1823
+ */
1824
+ #note_published(entity_id, ComponentClass) {
1825
+ const desc = this.#replicated.get(ComponentClass);
1826
+ if (desc === undefined || ComponentClass === NetworkIdentity) return;
1827
+
1828
+ const live = this.world.getComponent(entity_id, ComponentClass);
1829
+ if (live === undefined) return;
1830
+
1831
+ const scratch = this.#scratch_publish_buf;
1832
+ scratch.position = 0;
1833
+ this.binary_registry.getAdapter(ComponentClass.typeName).serialize(scratch, live);
1834
+ this.#remember_published(entity_id, desc.interp_type_id, scratch.raw_bytes, scratch.position);
1835
+ }
1836
+
1837
+ /**
1838
+ * Set what the peers hold for `(entity_id, type_id)`.
1839
+ * @param {number} entity_id
1840
+ * @param {number} type_id
1841
+ * @param {Uint8Array} bytes
1842
+ * @param {number} length
1843
+ * @returns {boolean} whether it differs from what was held before
1061
1844
  */
1062
- stop() {
1063
- if (!this.#started) return;
1064
- if (this.#identity_observer !== null) {
1065
- this.#identity_observer.disconnect();
1066
- this.#identity_observer = null;
1845
+ #remember_published(entity_id, type_id, bytes, length) {
1846
+ let published = this.#published.get(entity_id);
1847
+ if (published === undefined) {
1848
+ published = [];
1849
+ this.#published.set(entity_id, published);
1067
1850
  }
1068
- for (const [entity_id, listener] of this.#event_listeners) {
1069
- this.world.removeEntityEventListener(entity_id, "net_mutate_component", listener);
1851
+ while (published.length <= type_id) published.push(null);
1852
+
1853
+ let held = published[type_id];
1854
+ if (held !== null && held.length === length && bytes_equal(bytes, held.bytes, length)) {
1855
+ return false;
1070
1856
  }
1071
- this.#event_listeners.clear();
1072
- this.#remote_entities.clear();
1073
- this.#sampled_actions_per_frame.clear();
1074
- this.#peer_inbound_mark.clear();
1075
- this.#started = false;
1076
- }
1077
1857
 
1078
- // ----------------------------------------------------------------
1079
- // Per-tick driver
1080
- // ----------------------------------------------------------------
1858
+ if (held === null || held.bytes.length < length) {
1859
+ held = { bytes: new Uint8Array(Math.max(length, 32)), length: 0 };
1860
+ published[type_id] = held;
1861
+ }
1862
+ held.bytes.set(bytes.subarray(0, length), 0);
1863
+ held.length = length;
1864
+
1865
+ return true;
1866
+ }
1081
1867
 
1082
1868
  /**
1083
- * Fixed-timestep accumulator-driven step. Catch-up bounded by
1084
- * `MAX_FIXED_STEPS_PER_TICK`. Under `role: 'client'` the local frame
1085
- * advances at `1 / dilation_factor` per fixed step.
1086
- *
1087
- * @param {number} dt_seconds elapsed wall seconds since the previous call
1869
+ * Once per rendered frame: the work paced by wall time rather than by the simulation.
1870
+ * @param {number} dt_seconds
1088
1871
  */
1089
- tick(dt_seconds) {
1872
+ #on_frame(dt_seconds) {
1090
1873
  if (!this.#started) return;
1091
1874
 
1092
- // Restore canonical form before sim work. The executor's
1093
- // `before_execute` hook also covers per-action paths (e.g.
1094
- // packets delivered between session.tick calls).
1095
- this.normalize_if_dirty();
1096
-
1097
1875
  const dt_ms = dt_seconds * 1000;
1098
1876
 
1099
- // Host: expire grace-window peers whose deadline has passed.
1877
+ this.#clock_ms += dt_ms;
1878
+
1879
+ // the playhead moves with the clock whether or not anything is drawn from it this frame
1880
+ this.#playout.window(this.#clock_ms);
1881
+
1100
1882
  if (this.role === NetworkSessionRole.Host) {
1101
- this.#expire_grace_peers(performance.now());
1883
+ // Host: expire grace-window peers whose deadline has passed.
1884
+ this.#expire_grace_peers(this.#clock_ms);
1102
1885
  } else {
1103
1886
  // Client: drive the reconnect timer.
1104
1887
  this.#tick_reconnect(dt_ms);
1888
+
1889
+ // Time dilation: run the whole local simulation a few percent fast or slow, as the
1890
+ // host asks, by stretching the wall time each step consumes. The step itself — and so
1891
+ // every system's dt — is unchanged, and the render alpha stays a true fraction of it.
1892
+ this.entity_manager.fixedStepTimeScale = 1 / this.#client.dilation_factor;
1105
1893
  }
1106
1894
 
1107
1895
  // Idle reaping: a connected peer that has gone silent past the timeout
1108
- // is reaped (host → grace, client → reconnect ladder). The clock is the
1109
- // deterministic tick-dt accumulator (not wall-clock), so it's testable.
1896
+ // is reaped (host → grace, client → reconnect ladder).
1110
1897
  if (this.#connection_timeout_ms > 0) {
1111
- this.#liveness_clock_ms += dt_ms;
1112
1898
  this.#reap_silent_peers();
1113
1899
  }
1114
-
1115
- this.#sim_accum_ms += dt_ms;
1116
- let steps = 0;
1117
- while (this.#sim_accum_ms >= this.tick_period_ms && steps < MAX_FIXED_STEPS_PER_TICK) {
1118
- this.#sim_accum_ms -= this.tick_period_ms;
1119
- this.#simulate_one_step();
1120
- steps++;
1121
- }
1122
- if (steps === MAX_FIXED_STEPS_PER_TICK) this.#sim_accum_ms = 0;
1123
-
1124
- // Per-render-frame: smooth interpolated rendering of remote
1125
- // entities. Marks the live ECD as polluted so the next sim-tick
1126
- // or reconcile starts with a normalize.
1127
- this.#render_interpolated_entities();
1128
1900
  }
1129
1901
 
1130
1902
  /**
1131
- * Undo render-time interpolation on remote-owned components by
1132
- * restoring each from its latest InterpolationLog entry. Idempotent
1133
- * via the `render_dirty` flag — cheap when false.
1903
+ * Put the truth back wherever a render blend is in the live components — the
1904
+ * {@link InterpolationSystem}'s restore. Anything written over a blend since goes with it; what
1905
+ * is written after this call stays. Idempotent and cheap when nothing is blended.
1134
1906
  *
1135
- * Called from `tick()` (top), `executor.before_execute` (per-action
1136
- * applies, including transport-delivered action stream), and
1137
- * `client.onBeforeReconcile` (before the rewind walk).
1138
- *
1139
- * @private
1907
+ * Runs before every action the executor applies (an action captures the prior value of what it
1908
+ * overwrites, and that must not be a blend), before a reconciliation, and at the start of every
1909
+ * fixed step. Game code that writes a networked entity's state between steps calls it first.
1910
+ * The name is kept from when the session owned its own blend.
1140
1911
  */
1141
1912
  normalize_if_dirty() {
1142
- if (!this.render_dirty) return;
1143
1913
  this.render_dirty = false;
1144
-
1145
- if (!this.#playout.has_frames) return;
1146
- if (this.#remote_entities.size === 0) return;
1147
-
1148
- const scratch = this.#scratch_interp_buf;
1149
- const tick = this.#playout.latest_frame;
1150
-
1151
- for (const entity_id of this.#remote_entities) {
1152
- const identity = this.world.getComponent(entity_id, NetworkIdentity);
1153
- if (identity === undefined || identity.network_id < 0) continue;
1154
- for (const [ComponentClass, desc] of this.#replicated) {
1155
- if (desc.interp === null) continue;
1156
- const live = this.world.getComponent(entity_id, ComponentClass);
1157
- if (live === undefined) continue;
1158
- scratch.position = 0;
1159
- // tick_a === tick_b, t = 0 — degenerate "snap to single
1160
- // snapshot" lerp. Output equals the stored snapshot.
1161
- const ok = this.#interp_log.interpolate(
1162
- scratch, identity.network_id, desc.interp_type_id,
1163
- tick, tick, 0, desc.interp,
1164
- );
1165
- if (!ok) continue;
1166
- scratch.position = 0;
1167
- const adapter = this.binary_registry.getAdapter(ComponentClass.typeName);
1168
- adapter.deserialize(scratch, live);
1169
- }
1914
+ if (this.#interpolation !== null) {
1915
+ this.#interpolation.restore();
1170
1916
  }
1171
1917
  }
1172
1918
 
@@ -1324,13 +2070,23 @@ export class NetworkSession {
1324
2070
  * A client now seeks automatically on INITIAL_SYNC. This is the manual door, for a caller that
1325
2071
  * computes its own lead.
1326
2072
  *
2073
+ * A client sends the host nothing it predicted before its last sync, and knows it by frame: its
2074
+ * input starts at the frame the sync sought to. A caller whose own lead is shorter moves that
2075
+ * start back with it, so what it predicts on the synced world is sent however it counts it.
2076
+ *
1327
2077
  * @param {number} frame
1328
2078
  */
1329
2079
  seek_to_frame(frame) {
1330
2080
  assert.isNonNegativeInteger(frame, 'frame');
1331
2081
 
1332
2082
  this.#local_frame = frame;
1333
- this.#local_frame_accum = 0;
2083
+
2084
+ if (frame < this.#world_start_frame) {
2085
+ this.#world_start_frame = frame;
2086
+ if (this.#binding_answer !== BindingAnswer.Pending && this.#peer.is_connected(this.#remote_peer_id)) {
2087
+ this.#peer.release_outbound(this.#remote_peer_id, frame);
2088
+ }
2089
+ }
1334
2090
  }
1335
2091
 
1336
2092
  // ----------------------------------------------------------------
@@ -1353,6 +2109,7 @@ export class NetworkSession {
1353
2109
  if (identity.owner_peer_id !== this.local_peer_id) {
1354
2110
  this.#remote_entities.add(entity_id);
1355
2111
  }
2112
+ this.#interpolation_pending.add(entity_id);
1356
2113
  // Per-entity event listener for net_mutate_component.
1357
2114
  const listener = (payload) => this.#on_net_mutate_component(entity_id, payload);
1358
2115
  this.world.addEntityEventListener(entity_id, "net_mutate_component", listener);
@@ -1366,6 +2123,10 @@ export class NetworkSession {
1366
2123
  this.#event_listeners.delete(entity_id);
1367
2124
  }
1368
2125
  this.#remote_entities.delete(entity_id);
2126
+ this.#published.delete(entity_id);
2127
+ this.#prediction_history.forget(entity_id);
2128
+ // take back our Interpolated at the next step or frame, if the entity outlives its identity
2129
+ this.#interpolation_pending.add(entity_id);
1369
2130
  }
1370
2131
 
1371
2132
  /**
@@ -1387,7 +2148,7 @@ export class NetworkSession {
1387
2148
  }
1388
2149
  const desc = this.#replicated.get(component_type);
1389
2150
  if (desc === undefined) {
1390
- throw new Error(`net_mutate_component: ${component_type.typeName ?? component_type.name} is not replicated; call session.replicate() for it before mutating`);
2151
+ throw new Error(`net_mutate_component: ${component_type.typeName ?? component_type.name} is not replicated; replicate it (replicate_interpolated or replicate_discrete) before mutating`);
1391
2152
  }
1392
2153
 
1393
2154
  const network_id = this.#peer.slot_table.network_for(entity_id);
@@ -1497,32 +2258,16 @@ export class NetworkSession {
1497
2258
  // Internal: per-step simulation
1498
2259
  // ----------------------------------------------------------------
1499
2260
 
1500
- #simulate_one_step() {
1501
- if (this.role === NetworkSessionRole.Host) {
1502
- this.#server.tick(this.#local_frame);
1503
- this.#local_frame++;
1504
- return;
1505
- }
1506
- // Client. Dilated tick rate: each fixed step advances by
1507
- // `1 / dilation_factor` (capped at MAX_CLIENT_DILATED_TICKS_PER_STEP).
1508
- this.#local_frame_accum += 1.0 / this.#client.dilation_factor;
1509
- let inner = 0;
1510
- while (this.#local_frame_accum >= 1.0 && inner < MAX_CLIENT_DILATED_TICKS_PER_STEP) {
1511
- this.#local_frame_accum -= 1.0;
1512
- this.#client.tick(this.#local_frame);
1513
- this.#send_empty_ack_packet();
1514
- this.#local_frame++;
1515
- inner++;
1516
- }
1517
- }
1518
-
1519
2261
  /**
1520
- * Empty action-stream packet to advance the channel's seq/ack
1521
- * baseline on ticks with no outbound actions of our own.
2262
+ * The tick's keep-alive to the host: a frame marker, which advances the channel's seq/ack
2263
+ * baseline like any packet and tells the host how far this client's clock has run — the depth
2264
+ * its time dilation steers by — on ticks that carry no input as well as on ones that do.
2265
+ *
2266
+ * @param {number} frame the frame just simulated
1522
2267
  */
1523
- #send_empty_ack_packet() {
2268
+ #send_frame_marker(frame) {
1524
2269
  for (const peer_id of this.#connected_peers) {
1525
- this.#peer.channel_for(peer_id).send(EMPTY_PAYLOAD, 0);
2270
+ this.#peer.send_frame_marker(peer_id, frame);
1526
2271
  }
1527
2272
  }
1528
2273
 
@@ -1577,6 +2322,21 @@ export class NetworkSession {
1577
2322
  }
1578
2323
 
1579
2324
 
2325
+ /**
2326
+ * Queue `peer_id`'s INITIAL_SYNC, unless its connection has been given
2327
+ * one already — queued, or queued and sent. These are the host's only
2328
+ * full-world sends, so how many a connection gets is the host's decision:
2329
+ * one, when it takes the connection for a fresh peer — as `connect()`
2330
+ * binds it, or after refusing its claim to resume. Nothing the peer sends
2331
+ * afterwards earns it another.
2332
+ * @param {number} peer_id
2333
+ */
2334
+ #queue_initial_sync(peer_id) {
2335
+ if (this.#initial_sync_given.has(peer_id)) return;
2336
+ this.#initial_sync_given.add(peer_id);
2337
+ this.#pending_initial_sync.set(peer_id, 2);
2338
+ }
2339
+
1580
2340
  /**
1581
2341
  * Emit a Snapshotter-format payload to a freshly-connected peer.
1582
2342
  * Generates and stashes a UUID v1 session token on first send,
@@ -1619,6 +2379,9 @@ export class NetworkSession {
1619
2379
  *
1620
2380
  */
1621
2381
  #apply_initial_sync(buffer, payload_end) {
2382
+ // written over the truth, not over a render blend that a restore would then put back
2383
+ this.normalize_if_dirty();
2384
+
1622
2385
  const entity_count = buffer.readUintVar();
1623
2386
  for (let i = 0; i < entity_count; i++) {
1624
2387
  const network_id = buffer.readUintVar();
@@ -1644,6 +2407,8 @@ export class NetworkSession {
1644
2407
  this.world.addComponentToEntity(local_entity_id, component);
1645
2408
  } else {
1646
2409
  adapter.deserialize(buffer, existing);
2410
+ adapter.announce(this.world, local_entity_id);
2411
+ this.#note_moved(local_entity_id);
1647
2412
 
1648
2413
  /*
1649
2414
  Re-decide what this entity is to us.
@@ -1706,6 +2471,7 @@ export class NetworkSession {
1706
2471
  } else {
1707
2472
  this.#remote_entities.add(entity_id);
1708
2473
  }
2474
+ this.#interpolation_pending.add(entity_id);
1709
2475
  }
1710
2476
 
1711
2477
  /**
@@ -1800,7 +2566,7 @@ export class NetworkSession {
1800
2566
  this.#pending_initial_sync.delete(peer_id);
1801
2567
  this.#unwire_peer_transport_disconnect(peer_id);
1802
2568
  this.#peer_grace_state.set(peer_id, {
1803
- deadline_ms: performance.now() + this.#server_resume_grace_ms,
2569
+ deadline_ms: this.#clock_ms + this.#server_resume_grace_ms,
1804
2570
  last_acked,
1805
2571
  });
1806
2572
  this.onPeerLost.send2(peer_id, reason);
@@ -1808,11 +2574,24 @@ export class NetworkSession {
1808
2574
 
1809
2575
  /**
1810
2576
  * Validate a RESUME_HELLO and either welcome the peer back (restore
1811
- * baseline + send RESUME_ACCEPT) or reject with a reason code.
1812
- * Rejection schedules a fresh INITIAL_SYNC so the client falls
1813
- * through to Tier-3.
2577
+ * baseline + send RESUME_ACCEPT) or reject with a reason code. A claim
2578
+ * the host cannot honour is readmitted as a fresh peer, whose
2579
+ * INITIAL_SYNC is the Tier-3 resync; one it must not honour is kicked.
2580
+ *
2581
+ * Answered once per connection; see the first branch.
1814
2582
  */
1815
2583
  #on_resume_hello(transport_peer_id, claimed_peer_id, last_acked_frame, has_token, claimed_token_bytes) {
2584
+ // A client says RESUME_HELLO at most once per connection, from
2585
+ // `connect()`, so a second one on the same connection is a duplicated
2586
+ // datagram — the channel passes those on — or a peer asking the host to
2587
+ // do its work again. Every answer below costs the host something: a
2588
+ // packet at least, a serialization of its whole world at most. What a
2589
+ // connection gets is settled the first time it asks, and the rest are
2590
+ // ignored: unanswered rather than kicked, since a kick would also land
2591
+ // on a client whose one hello the network happened to deliver twice.
2592
+ if (this.#resume_hello_answered.has(transport_peer_id)) return;
2593
+ this.#resume_hello_answered.add(transport_peer_id);
2594
+
1816
2595
  // Engine convention: the matchmaking layer routes the reconnecting
1817
2596
  // transport to the same `peer_id` it had before. If `claimed_peer_id`
1818
2597
  // disagrees with `transport_peer_id`, the matchmaker mis-routed —
@@ -1866,12 +2645,17 @@ export class NetworkSession {
1866
2645
  }
1867
2646
  const grace = this.#peer_grace_state.get(claimed_peer_id);
1868
2647
  if (grace === undefined) {
1869
- // Either the peer is fully unknown OR they're already
1870
- // connected (their previous transport never dropped).
1871
- // Either way, no resume record to validate against.
2648
+ // No resume record to validate against. There was none when
2649
+ // `connect()` bound this connection either — a record outlives
2650
+ // neither grace expiry nor `drop_peer`, and both release the
2651
+ // channel of an attempt waiting on it — so the connection was
2652
+ // taken for a fresh peer: it is in the live set, and its
2653
+ // INITIAL_SYNC is queued or already sent. Refuse the claim, and
2654
+ // treat the peer as the fresh one it is; the sync it has is the
2655
+ // resync, and `#queue_initial_sync` does not give a connection
2656
+ // the world twice.
1872
2657
  this.#peer.send_resume_reject(transport_peer_id, ResumeRejectReason.UnknownPeer);
1873
- // Treat as a fresh peer; schedule INITIAL_SYNC.
1874
- this.#pending_initial_sync.set(transport_peer_id, 2);
2658
+ this.#queue_initial_sync(transport_peer_id);
1875
2659
  this.#connected_peers.add(transport_peer_id);
1876
2660
  return;
1877
2661
  }
@@ -1879,7 +2663,7 @@ export class NetworkSession {
1879
2663
  if (expected_token === undefined) {
1880
2664
  this.#peer.send_resume_reject(transport_peer_id, ResumeRejectReason.UnknownPeer);
1881
2665
  this.#peer_grace_state.delete(claimed_peer_id);
1882
- this.#pending_initial_sync.set(transport_peer_id, 2);
2666
+ this.#queue_initial_sync(transport_peer_id);
1883
2667
  this.#connected_peers.add(transport_peer_id);
1884
2668
  return;
1885
2669
  }
@@ -1919,7 +2703,7 @@ export class NetworkSession {
1919
2703
  if (last_acked_frame + 1 < ring_floor) {
1920
2704
  this.#peer.send_resume_reject(transport_peer_id, ResumeRejectReason.StaleFrame);
1921
2705
  this.#peer_grace_state.delete(claimed_peer_id);
1922
- this.#pending_initial_sync.set(transport_peer_id, 2);
2706
+ this.#queue_initial_sync(transport_peer_id);
1923
2707
  this.#connected_peers.add(transport_peer_id);
1924
2708
  return;
1925
2709
  }
@@ -1996,18 +2780,20 @@ export class NetworkSession {
1996
2780
  * @private
1997
2781
  */
1998
2782
  #peer_is_silent(peer_id) {
1999
- const count = this.#peer.inbound_count(peer_id);
2783
+ // what the peer has sent, whether or not the next step has applied it yet
2784
+ const inbound = this.#inbound.get(peer_id);
2785
+ const count = inbound !== undefined ? inbound.received_count : this.#peer.inbound_count(peer_id);
2000
2786
  const mark = this.#peer_inbound_mark.get(peer_id);
2001
2787
  if (mark === undefined) {
2002
- this.#peer_inbound_mark.set(peer_id, { count, since_ms: this.#liveness_clock_ms });
2788
+ this.#peer_inbound_mark.set(peer_id, { count, since_ms: this.#clock_ms });
2003
2789
  return false;
2004
2790
  }
2005
2791
  if (count !== mark.count) {
2006
2792
  mark.count = count;
2007
- mark.since_ms = this.#liveness_clock_ms;
2793
+ mark.since_ms = this.#clock_ms;
2008
2794
  return false;
2009
2795
  }
2010
- return this.#liveness_clock_ms - mark.since_ms >= this.#connection_timeout_ms;
2796
+ return this.#clock_ms - mark.since_ms >= this.#connection_timeout_ms;
2011
2797
  }
2012
2798
 
2013
2799
  // ----------------------------------------------------------------
@@ -2041,7 +2827,7 @@ export class NetworkSession {
2041
2827
  // Stop treating this peer as a live send target. The channel is
2042
2828
  // gone, but `#remote_peer_id` is deliberately kept so the reconnect
2043
2829
  // ladder can re-`connect()` to the same id. Without this delete,
2044
- // `#send_empty_ack_packet` (driven every tick) dereferences the
2830
+ // `#send_frame_marker` (driven every tick) dereferences the
2045
2831
  // now-undefined channel and throws — which would crash the very
2046
2832
  // tick loop that drives the reconnect ladder.
2047
2833
  this.#connected_peers.delete(this.#remote_peer_id);
@@ -2151,13 +2937,232 @@ export class NetworkSession {
2151
2937
  // Internal: client predict-reconcile wiring
2152
2938
  // ----------------------------------------------------------------
2153
2939
 
2940
+ /**
2941
+ * A scratch instance of `ComponentClass`, for decoding wire bytes without touching the world.
2942
+ * @param {Function} ComponentClass
2943
+ * @param {number} slot 0: the host's state, 1: the prediction, 2: a later prediction
2944
+ * @returns {object}
2945
+ */
2946
+ #scratch_of(ComponentClass, slot) {
2947
+ let instances = this.#decode_scratch.get(ComponentClass);
2948
+ if (instances === undefined) {
2949
+ instances = [new ComponentClass(), new ComponentClass(), new ComponentClass()];
2950
+ this.#decode_scratch.set(ComponentClass, instances);
2951
+ }
2952
+ return instances[slot];
2953
+ }
2954
+
2955
+ /**
2956
+ * Decode `length` bytes of `bytes` into `target` with `ComponentClass`'s replication adapter.
2957
+ */
2958
+ #decode_into(ComponentClass, bytes, length, target) {
2959
+ const buffer = this.#scratch_interp_buf;
2960
+ buffer.position = 0;
2961
+ buffer.writeBytes(bytes, 0, length);
2962
+ buffer.position = 0;
2963
+ this.binary_registry.getAdapter(ComponentClass.typeName).deserialize(buffer, target);
2964
+ }
2965
+
2966
+ /**
2967
+ * AUTH_STATE, {@link NetworkSessionReconcile.Correct}: split the payload into its components'
2968
+ * wire bytes now — the receive buffer is the peer's and is reused — and keep the newest per
2969
+ * entity for the next step. Parsing mirrors the host's writer: every replicated component the
2970
+ * entity carries, in `#replicated` order.
2971
+ */
2972
+ #queue_auth_state(server_frame, network_id, buffer) {
2973
+ const pending = this.#pending_auth.get(network_id);
2974
+ if (pending !== undefined && pending.frame >= server_frame) return;
2975
+
2976
+ const reconciled = this.#reconciled_frame.get(network_id);
2977
+ if (reconciled !== undefined && reconciled >= server_frame) return;
2978
+
2979
+ const entity_id = this.#peer.slot_table.entity_for(network_id);
2980
+ if (entity_id < 0) return;
2981
+
2982
+ const parts = [];
2983
+ for (const [ComponentClass, desc] of this.#replicated) {
2984
+ if (this.world.getComponent(entity_id, ComponentClass) === undefined) {
2985
+ parts.push(null);
2986
+ continue;
2987
+ }
2988
+ const start = buffer.position;
2989
+ this.binary_registry.getAdapter(ComponentClass.typeName).deserialize(buffer, this.#scratch_of(ComponentClass, 0));
2990
+ parts.push({ type_id: desc.interp_type_id, bytes: buffer.raw_bytes.slice(start, buffer.position) });
2991
+ }
2992
+
2993
+ this.#pending_auth.set(network_id, { frame: server_frame, parts });
2994
+ }
2995
+
2996
+ /**
2997
+ * Client, end of step: remember what was predicted for every entity this client owns.
2998
+ * @param {number} frame
2999
+ */
3000
+ #record_prediction(frame) {
3001
+ const scratch = this.#scratch_send_buf;
3002
+ const world = this.world;
3003
+
3004
+ for (const entity_id of this.#event_listeners.keys()) {
3005
+ if (this.#remote_entities.has(entity_id)) continue;
3006
+
3007
+ const identity = world.getComponent(entity_id, NetworkIdentity);
3008
+ if (identity === undefined || identity.network_id < 0) continue;
3009
+
3010
+ for (const [ComponentClass, desc] of this.#replicated) {
3011
+ if (ComponentClass === NetworkIdentity) continue;
3012
+ const live = world.getComponent(entity_id, ComponentClass);
3013
+ if (live === undefined) continue;
3014
+
3015
+ scratch.position = 0;
3016
+ this.binary_registry.getAdapter(ComponentClass.typeName).serialize(scratch, live);
3017
+ this.#prediction_history.record(entity_id, frame, desc.interp_type_id, scratch.raw_bytes, scratch.position);
3018
+ }
3019
+ }
3020
+ }
3021
+
3022
+ /**
3023
+ * Client, start of step: reconcile every queued authoritative state.
3024
+ */
3025
+ #apply_pending_corrections() {
3026
+ const pending_auth = this.#pending_auth;
3027
+
3028
+ for (const [network_id, pending] of pending_auth) {
3029
+ const entity_id = this.#peer.slot_table.entity_for(network_id);
3030
+ if (entity_id < 0 || this.#remote_entities.has(entity_id)) continue;
3031
+ this.#reconciled_frame.set(network_id, pending.frame);
3032
+ try {
3033
+ this.#reconcile_entity(entity_id, pending.frame, pending.parts);
3034
+ } catch (e) {
3035
+ // one entity's failure is its own: the others are corrected, and the step opens
3036
+ console.error(`NetworkSession: reconciling entity ${entity_id} to frame ${pending.frame} failed:`, e);
3037
+ }
3038
+ }
3039
+
3040
+ pending_auth.clear();
3041
+ }
3042
+
3043
+ /**
3044
+ * Compare the host's state of `entity_id` at `frame` with the prediction for `frame`, and where
3045
+ * a component differs, carry the difference into the present through its {@link Correction}.
3046
+ * See {@link NetworkSessionReconcile.Correct}.
3047
+ *
3048
+ * @param {number} entity_id
3049
+ * @param {number} frame
3050
+ * @param {Array<{type_id: number, bytes: Uint8Array}|null>} parts
3051
+ */
3052
+ #reconcile_entity(entity_id, frame, parts) {
3053
+ const history = this.#prediction_history;
3054
+ const differs = this.#differs;
3055
+
3056
+ // Compare first: every part must have a prediction to compare against.
3057
+ let any = false;
3058
+ let index = 0;
3059
+ for (const [ComponentClass, desc] of this.#replicated) {
3060
+ const i = index++;
3061
+ differs[i] = false;
3062
+
3063
+ const part = parts[i];
3064
+ if (part === null || desc.correction === null) continue;
3065
+
3066
+ const type_id = desc.interp_type_id;
3067
+ const predicted_length = history.length(entity_id, frame, type_id);
3068
+ if (predicted_length < 0) {
3069
+ this.correction_skipped_count++;
3070
+ return;
3071
+ }
3072
+
3073
+ const predicted_bytes = history.bytes(entity_id, frame, type_id);
3074
+ if (bytes_equal_lengths(part.bytes, part.bytes.length, predicted_bytes, predicted_length)) continue;
3075
+
3076
+ const server = this.#scratch_of(ComponentClass, 0);
3077
+ const predicted = this.#scratch_of(ComponentClass, 1);
3078
+ this.#decode_into(ComponentClass, part.bytes, part.bytes.length, server);
3079
+ this.#decode_into(ComponentClass, predicted_bytes, predicted_length, predicted);
3080
+
3081
+ if (!desc.correction.same(server, predicted)) {
3082
+ differs[i] = true;
3083
+ any = true;
3084
+ }
3085
+ }
3086
+
3087
+ if (!any) return;
3088
+
3089
+ index = 0;
3090
+ for (const [ComponentClass, desc] of this.#replicated) {
3091
+ const i = index++;
3092
+ if (!differs[i]) continue;
3093
+
3094
+ const live = this.world.getComponent(entity_id, ComponentClass);
3095
+ if (live === undefined) continue;
3096
+
3097
+ const magnitude = this.#correct_component(entity_id, live, ComponentClass, desc, frame, parts[i].bytes);
3098
+ this.onCorrection.send4(entity_id, frame, ComponentClass, magnitude);
3099
+ }
3100
+
3101
+ this.correction_count++;
3102
+ }
3103
+
3104
+ /**
3105
+ * Carry the difference between the host's state and the prediction at `frame` into the live
3106
+ * component and into every prediction since, through the component's correction.
3107
+ *
3108
+ * @returns {number} the correction's size, as the strategy measures it
3109
+ */
3110
+ #correct_component(entity_id, live, ComponentClass, desc, frame, server_bytes) {
3111
+ const history = this.#prediction_history;
3112
+ const type_id = desc.interp_type_id;
3113
+ const correction = desc.correction;
3114
+ const adapter = this.binary_registry.getAdapter(ComponentClass.typeName);
3115
+
3116
+ const server = this.#scratch_of(ComponentClass, 0);
3117
+ const predicted = this.#scratch_of(ComponentClass, 1);
3118
+ this.#decode_into(ComponentClass, server_bytes, server_bytes.length, server);
3119
+ this.#decode_into(ComponentClass, history.bytes(entity_id, frame, type_id), history.length(entity_id, frame, type_id), predicted);
3120
+
3121
+ // the present
3122
+ const target = this.#correction_target;
3123
+ target.entity_manager = this.entity_manager;
3124
+ target.entity = entity_id;
3125
+ target.component = live;
3126
+ target.interpolation = this.#interpolation;
3127
+ target.adapter = adapter;
3128
+
3129
+ let magnitude;
3130
+ try {
3131
+ magnitude = correction.apply(target, server, predicted);
3132
+ } finally {
3133
+ target.component = null;
3134
+ target.adapter = null;
3135
+ }
3136
+ adapter.announce(this.world, entity_id);
3137
+
3138
+ // the predictions: the host's at `frame`, and the difference carried into each since
3139
+ history.record(entity_id, frame, type_id, server_bytes, server_bytes.length);
3140
+
3141
+ const state = this.#scratch_of(ComponentClass, 2);
3142
+ const buffer = this.#scratch_send_buf;
3143
+ const latest = this.#local_frame - 1;
3144
+ for (let f = frame + 1; f <= latest; f++) {
3145
+ const held_length = history.length(entity_id, f, type_id);
3146
+ if (held_length < 0) continue;
3147
+ this.#decode_into(ComponentClass, history.bytes(entity_id, f, type_id), held_length, state);
3148
+ correction.carry(state, server, predicted);
3149
+ buffer.position = 0;
3150
+ adapter.serialize(buffer, state);
3151
+ history.record(entity_id, f, type_id, buffer.raw_bytes, buffer.position);
3152
+ }
3153
+
3154
+ return magnitude;
3155
+ }
3156
+
2154
3157
  #wire_client_predict_reconcile() {
2155
3158
  // Rewind doesn't go through executor.execute, so the
2156
3159
  // before_execute normalize hook misses it. Catch it here.
2157
3160
  this.#client.onBeforeReconcile.add(() => this.normalize_if_dirty());
2158
3161
 
2159
- // Predict: run the sampler, execute each action, record its
2160
- // bytes so the replay path can re-execute without re-sampling.
3162
+ // Predict: run the sampler, record each action's bytes so the replay path can re-execute
3163
+ // without re-sampling, and execute the action as those bytes say — as the host will apply
3164
+ // it, rounding included. Executed as sampled, a field the wire rounds (a Float32 speed)
3165
+ // would predict a little differently from the host every frame.
2161
3166
  this.#client.onPredict.add((frame, _input_writer) => {
2162
3167
  if (this.#input_sampler === null) return;
2163
3168
  const actions = this.#input_sampler(frame);
@@ -2171,7 +3176,10 @@ export class NetworkSession {
2171
3176
  action.serialize(scratch);
2172
3177
  const bytes = scratch.raw_bytes.slice(0, scratch.position);
2173
3178
  recorded.push({ type_id, bytes });
2174
- this.#client.executor.execute(action, this.local_peer_id);
3179
+ if (!this.#execute_recorded(type_id, bytes)) {
3180
+ // not a registered action: executed as it is, for the executor to say so
3181
+ this.#client.executor.execute(action, this.local_peer_id);
3182
+ }
2175
3183
  }
2176
3184
  this.#sampled_actions_per_frame.set(frame, recorded);
2177
3185
  this.#trim_sampled_action_ledger();
@@ -2183,19 +3191,7 @@ export class NetworkSession {
2183
3191
  const recorded = this.#sampled_actions_per_frame.get(frame);
2184
3192
  if (!recorded) return;
2185
3193
  for (const { type_id, bytes } of recorded) {
2186
- const klass = this.#peer.action_registry.klass_for(type_id);
2187
- if (klass === undefined) continue;
2188
- const action = this.#peer.action_registry.acquire(klass);
2189
- const scratch = this.#scratch_interp_buf;
2190
- scratch.position = 0;
2191
- scratch.writeBytes(bytes, 0, bytes.length);
2192
- scratch.position = 0;
2193
- action.deserialize(scratch);
2194
- try {
2195
- this.#client.executor.execute(action, this.local_peer_id);
2196
- } finally {
2197
- this.#peer.action_registry.release(action);
2198
- }
3194
+ this.#execute_recorded(type_id, bytes);
2199
3195
  }
2200
3196
  });
2201
3197
 
@@ -2209,10 +3205,36 @@ export class NetworkSession {
2209
3205
  if (live === undefined) continue;
2210
3206
  const adapter = this.binary_registry.getAdapter(ComponentClass.typeName);
2211
3207
  adapter.deserialize(buffer, live);
3208
+ adapter.announce(this.world, local);
2212
3209
  }
2213
3210
  });
2214
3211
  }
2215
3212
 
3213
+ /**
3214
+ * Execute the action `bytes` encode, as this client's own.
3215
+ * @param {number} type_id
3216
+ * @param {Uint8Array} bytes
3217
+ * @returns {boolean} false when no action is registered under `type_id`
3218
+ */
3219
+ #execute_recorded(type_id, bytes) {
3220
+ const klass = this.#peer.action_registry.klass_for(type_id);
3221
+ if (klass === undefined) return false;
3222
+
3223
+ const action = this.#peer.action_registry.acquire(klass);
3224
+ try {
3225
+ const scratch = this.#scratch_interp_buf;
3226
+ scratch.position = 0;
3227
+ scratch.writeBytes(bytes, 0, bytes.length);
3228
+ scratch.position = 0;
3229
+ action.deserialize(scratch);
3230
+ this.#client.executor.execute(action, this.local_peer_id);
3231
+ } finally {
3232
+ this.#peer.action_registry.release(action);
3233
+ }
3234
+
3235
+ return true;
3236
+ }
3237
+
2216
3238
  #trim_sampled_action_ledger() {
2217
3239
  const action_log = this.#peer.action_log;
2218
3240
  if (action_log === undefined) return;
@@ -2223,73 +3245,241 @@ export class NetworkSession {
2223
3245
  }
2224
3246
 
2225
3247
  // ----------------------------------------------------------------
2226
- // Internal: interpolation log + render-time sampling
3248
+ // Internal: interpolation — the network timeline, and each entity's role on it
2227
3249
  // ----------------------------------------------------------------
2228
3250
 
3251
+ /**
3252
+ * The interpolands of the replicated components that are blended, in `#replicated` order. One
3253
+ * given to the deprecated {@link replicate} as a bare blend is built here, recorded in the
3254
+ * component's replication layout under its replication type id.
3255
+ *
3256
+ * @returns {Interpoland[]}
3257
+ */
3258
+ #build_interpolands() {
3259
+ const out = [];
3260
+ const taken = new Map();
3261
+
3262
+ for (const [ComponentClass, desc] of this.#replicated) {
3263
+ if (desc.interpoland === null && desc.interpolator !== null) {
3264
+ desc.interpoland = new Interpoland(
3265
+ desc.interp_type_id,
3266
+ ComponentClass,
3267
+ this.binary_registry.getAdapter(ComponentClass.typeName),
3268
+ desc.interpolator,
3269
+ );
3270
+ }
3271
+
3272
+ const interpoland = desc.interpoland;
3273
+ if (interpoland === null) continue;
3274
+
3275
+ const other = taken.get(interpoland.type_id);
3276
+ if (other !== undefined) {
3277
+ throw new Error(
3278
+ `NetworkSession.start: ${ComponentClass.typeName ?? ComponentClass.name} and ${other.typeName ?? other.name} are interpolated ` +
3279
+ `under the same interpoland type_id ${interpoland.type_id}; their records would be read for each other. Give each its own.`,
3280
+ );
3281
+ }
3282
+ taken.set(interpoland.type_id, ComponentClass);
3283
+
3284
+ out.push(interpoland);
3285
+ }
3286
+
3287
+ return out;
3288
+ }
3289
+
3290
+ /**
3291
+ * The network moved `entity_id` somewhere its own simulation did not take it — a resync. On
3292
+ * the local timeline, show it there at once rather than blend across the gap. (An entity on
3293
+ * the network playout is drawn from the playout's own history, which the move does not touch.)
3294
+ * @param {number} entity_id
3295
+ */
3296
+ #note_moved(entity_id) {
3297
+ const interpolated = this.world.getComponent(entity_id, Interpolated);
3298
+ if (interpolated !== undefined && interpolated.sourceId === INTERPOLATION_SOURCE_LOCAL) {
3299
+ interpolated.snap = true;
3300
+ }
3301
+ }
3302
+
3303
+ /**
3304
+ * Bring every queued entity's {@link Interpolated} in line with what the entity is to this
3305
+ * session. Entities that cannot be decided yet (no network id, or not yet carrying what they
3306
+ * interpolate) stay queued.
3307
+ */
3308
+ #apply_pending_interpolation() {
3309
+ const pending = this.#interpolation_pending;
3310
+
3311
+ if (pending.size === 0 || this.#interpolation === null) {
3312
+ return;
3313
+ }
3314
+
3315
+ for (const entity_id of pending) {
3316
+ if (this.#assign_interpolation(entity_id)) {
3317
+ pending.delete(entity_id);
3318
+ }
3319
+ }
3320
+ }
3321
+
3322
+ /**
3323
+ * The role decides the timeline. The host simulates every entity, and a client simulates the
3324
+ * ones it owns (it predicts them): those are blended on the local fixed-step timeline, keyed by
3325
+ * entity. Everything else on a client is written by the network and blended on the network
3326
+ * playout, keyed by `network_id`.
3327
+ *
3328
+ * An `Interpolated` the game attached itself is adapted rather than replaced: it keeps any
3329
+ * interpoland of its own for a component the session does not interpolate, and hands the ones
3330
+ * the session does over to the session's (two interpolands on one component would each take
3331
+ * the other's blend for the truth).
3332
+ *
3333
+ * @param {number} entity_id
3334
+ * @returns {boolean} true when the entity is settled and can leave the queue
3335
+ */
3336
+ #assign_interpolation(entity_id) {
3337
+ const world = this.world;
3338
+
3339
+ if (!world.entityExists(entity_id)) {
3340
+ this.#attached_interpolated.delete(entity_id);
3341
+ return true;
3342
+ }
3343
+
3344
+ const identity = world.getComponent(entity_id, NetworkIdentity);
3345
+
3346
+ if (identity === undefined || identity === null) {
3347
+ // no longer networked: take back what we attached
3348
+ const ours = this.#attached_interpolated.get(entity_id);
3349
+ if (ours !== undefined) {
3350
+ this.#attached_interpolated.delete(entity_id);
3351
+ if (world.getComponent(entity_id, Interpolated) === ours) {
3352
+ world.removeComponentFromEntity(entity_id, Interpolated);
3353
+ }
3354
+ }
3355
+ return true;
3356
+ }
3357
+
3358
+ if (identity.network_id < 0) {
3359
+ return false; // not allocated yet
3360
+ }
3361
+
3362
+ // `#remote_entities` means "not owned here" on either role, but only a client plays anything
3363
+ // out from the network: the host simulates every entity, the ones its clients own included.
3364
+ const remote = this.role === NetworkSessionRole.Client && this.#remote_entities.has(entity_id);
3365
+
3366
+ const session_interpolands = this.#interpolands;
3367
+
3368
+ if (session_interpolands.length === 0) {
3369
+ return true;
3370
+ }
3371
+
3372
+ let carries_any = false;
3373
+ for (let i = 0; i < session_interpolands.length; i++) {
3374
+ if (world.getComponent(entity_id, session_interpolands[i].component_class) !== undefined) {
3375
+ carries_any = true;
3376
+ break;
3377
+ }
3378
+ }
3379
+ if (!carries_any) {
3380
+ return false; // e.g. an initial sync that has attached the identity but not the transform yet
3381
+ }
3382
+
3383
+ const source_id = remote ? this.#interp_source_id : INTERPOLATION_SOURCE_LOCAL;
3384
+
3385
+ const key = remote ? identity.network_id : entity_id;
3386
+
3387
+ let interpolated = world.getComponent(entity_id, Interpolated);
3388
+
3389
+ if (interpolated === undefined) {
3390
+ interpolated = new Interpolated();
3391
+ interpolated.interpolands = session_interpolands.slice();
3392
+ interpolated.sourceId = source_id;
3393
+ interpolated.key = key;
3394
+ world.addComponentToEntity(entity_id, interpolated);
3395
+ this.#attached_interpolated.set(entity_id, interpolated);
3396
+ return true;
3397
+ }
3398
+
3399
+ if (interpolated.sourceId === source_id && interpolated.key === key
3400
+ && session_interpolands.every(ip => interpolated.interpolands.includes(ip))) {
3401
+ return true; // already in line
3402
+ }
3403
+
3404
+ // Only ever called as a step opens, when no render blend is in the live components, so the
3405
+ // interpolands can be swapped without one being left behind as the truth.
3406
+ const kept = interpolated.interpolands.filter(
3407
+ ip => !session_interpolands.some(own => own.component_class === ip.component_class)
3408
+ );
3409
+ interpolated.interpolands = kept.concat(session_interpolands);
3410
+ interpolated.sourceId = source_id;
3411
+ interpolated.key = key;
3412
+
3413
+ return true;
3414
+ }
3415
+
2229
3416
  /**
2230
3417
  * Record post-apply state for every remote-owned entity into the
2231
- * interpolation log. Locally-owned entities are predicted, not
2232
- * interpolated, so they're skipped.
3418
+ * network timeline. Locally-owned entities are predicted, not
3419
+ * interpolated from the network, so they're skipped.
2233
3420
  *
2234
3421
  * Doesn't fire on the host — the replicator's deferral path doesn't
2235
3422
  * emit `onFrameApplied`, so the host gets no recording naturally.
2236
3423
  */
2237
3424
  #on_frame_applied(_peer_id, frame_number) {
2238
- this.#interp_log.begin_tick(frame_number);
3425
+ const log = this.#interp_log;
3426
+ const interpolands = this.#interpolands;
3427
+
3428
+ log.begin_tick(frame_number);
2239
3429
  for (const entity_id of this.#remote_entities) {
2240
3430
  const identity = this.world.getComponent(entity_id, NetworkIdentity);
2241
3431
  if (identity === undefined || identity.network_id < 0) continue;
2242
- for (const [ComponentClass, desc] of this.#replicated) {
2243
- if (desc.interp === null) continue;
2244
- const live = this.world.getComponent(entity_id, ComponentClass);
3432
+ for (let i = 0; i < interpolands.length; i++) {
3433
+ const interpoland = interpolands[i];
3434
+ const live = this.world.getComponent(entity_id, interpoland.component_class);
2245
3435
  if (live === undefined) continue;
2246
- const adapter = this.binary_registry.getAdapter(ComponentClass.typeName);
2247
- const rec_buf = this.#interp_log.begin_record(identity.network_id, desc.interp_type_id);
2248
- adapter.serialize(rec_buf, live);
2249
- this.#interp_log.end_record();
3436
+ const buffer = log.begin_record(identity.network_id, interpoland.type_id);
3437
+ interpoland.serialization_adapter.serialize(buffer, live);
3438
+ log.end_record();
2250
3439
  }
2251
3440
  }
2252
- this.#interp_log.end_tick();
3441
+ log.end_tick();
3442
+
3443
+ // hold the whole render delay's worth of frames, however many entities a frame carries
3444
+ log.ensure_ticks(PLAYOUT_HISTORY_FRAMES);
2253
3445
 
2254
- this.#playout.record_arrival(performance.now(), frame_number);
3446
+ this.#playout.record_arrival(this.#clock_ms, frame_number);
2255
3447
  }
2256
3448
 
2257
3449
  /**
2258
- * Advance the smooth_render_frame state machine and write
2259
- * interpolated bytes into each remote-owned entity's live
2260
- * components. Sets `render_dirty` if anything was written.
3450
+ * The network timeline's window for this render frame.
2261
3451
  *
2262
- * Host early-returns naturally (no `#latest_received_frame`
2263
- * recorded — deferred-apply path doesn't fire `onFrameApplied`).
3452
+ * A frame reaches the log only if it carried actions for this peer, and a frame that carried
3453
+ * none is one in which nothing replicated changed. So the value at a frame the log does not
3454
+ * hold is the value at the last one before it that it does: blend from that frame, and to the
3455
+ * next frame if it is held, otherwise hold still. Blending only between adjacent frames instead
3456
+ * would treat an unchanged frame as unknown and show the newest state early, then hold.
3457
+ *
3458
+ * @returns {{tick_a:number, tick_b:number, t:number}}
2264
3459
  */
2265
- #render_interpolated_entities() {
2266
- if (!this.#playout.has_frames) return;
2267
- if (this.#remote_entities.size === 0) return;
3460
+ #sample_playout() {
3461
+ const w = this.#playout.window(this.#clock_ms);
3462
+ const out = this.#playout_window;
3463
+ const log = this.#interp_log;
2268
3464
 
2269
- const { tick_a, tick_b, t } = this.#playout.window(performance.now());
3465
+ const a = log.latest_tick_at_or_before(w.tick_a);
2270
3466
 
2271
- const scratch = this.#scratch_interp_buf;
2272
- let wrote_anything = false;
2273
- for (const entity_id of this.#remote_entities) {
2274
- const identity = this.world.getComponent(entity_id, NetworkIdentity);
2275
- if (identity === undefined || identity.network_id < 0) continue;
2276
- for (const [ComponentClass, desc] of this.#replicated) {
2277
- if (desc.interp === null) continue; // snap mode
2278
- const live = this.world.getComponent(entity_id, ComponentClass);
2279
- if (live === undefined) continue;
2280
- scratch.position = 0;
2281
- const ok = this.#interp_log.interpolate(
2282
- scratch, identity.network_id, desc.interp_type_id,
2283
- tick_a, tick_b, t, desc.interp,
2284
- );
2285
- if (!ok) continue;
2286
- scratch.position = 0;
2287
- const adapter = this.binary_registry.getAdapter(ComponentClass.typeName);
2288
- adapter.deserialize(scratch, live);
2289
- wrote_anything = true;
2290
- }
3467
+ if (a < 0) {
3468
+ // The playhead is before anything the log holds — the playout has not started, or it
3469
+ // starts before the first frame this client received (a late join). Hold on the
3470
+ // earliest frame held: it is what the playhead reaches first, so nothing jumps back.
3471
+ const oldest = log.oldest_tick();
3472
+ out.tick_a = oldest;
3473
+ out.tick_b = oldest;
3474
+ out.t = 0;
3475
+ return out;
2291
3476
  }
2292
- if (wrote_anything) this.render_dirty = true;
3477
+
3478
+ out.tick_a = a;
3479
+ out.tick_b = log.has_tick(w.tick_b) ? w.tick_b : a;
3480
+ out.t = w.t;
3481
+
3482
+ return out;
2293
3483
  }
2294
3484
 
2295
3485
  // ----------------------------------------------------------------