@woosh/meep-engine 3.1.0 → 3.3.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 (1869) hide show
  1. package/LICENSE +188 -188
  2. package/README.md +152 -152
  3. package/editor/Editor.js +598 -598
  4. package/editor/EditorCameraNavigation.js +205 -205
  5. package/editor/EditorKeyMap.js +182 -182
  6. package/editor/SelectionVisualizer.js +127 -127
  7. package/editor/actions/concrete/ActionInvalidateSampler.js +27 -27
  8. package/editor/actions/concrete/PatchTerrainHeightAction.js +85 -85
  9. package/editor/camera/camera_framing.js +104 -104
  10. package/editor/clipboard.js +184 -184
  11. package/editor/ecs/component/editors/ObservedIntegerEditor.js +22 -22
  12. package/editor/ecs/component/editors/ObservedStringEditor.js +34 -34
  13. package/editor/ecs/component/editors/common/two_way_sync.js +50 -50
  14. package/editor/ecs/component/editors/ecs/GridObstacleEditor.js +19 -19
  15. package/editor/ecs/component/editors/ecs/ParameterLookupTableEditor.js +35 -35
  16. package/editor/ecs/component/editors/ecs/ParameterTrackEditor.js +17 -17
  17. package/editor/ecs/component/editors/ecs/SGMeshEditor.js +24 -24
  18. package/editor/ecs/component/editors/ecs/ShadedGeometryEditor.js +33 -33
  19. package/editor/ecs/component/editors/ecs/Trail3DEditor.js +45 -45
  20. package/editor/ecs/component/editors/ecs/buildGridObstaclePreview.js +19 -19
  21. package/editor/ecs/component/editors/ecs/terrain/TerrainEditor.js +72 -72
  22. package/editor/ecs/component/editors/shade/MeshletGeometryEditor.js +30 -30
  23. package/editor/ecs/component/editors/shade/ShadeImageEditor.js +70 -70
  24. package/editor/ecs/component/editors/shade/ShadeMaterialEditor.js +34 -34
  25. package/editor/ecs/component/editors/shade/ShadeTextureEditor.js +46 -46
  26. package/editor/ecs/component/editors/shade/StandardShadeMaterialEditor.js +24 -24
  27. package/editor/ecs/component/prototypeObjectEditor.js +265 -265
  28. package/editor/ecs/component/registerBasicTypeEditors.js +100 -100
  29. package/editor/ecs/component/registerEngineComponentEditors.js +95 -95
  30. package/editor/entity_world_bounds.js +27 -27
  31. package/editor/particles/lut_ops.js +148 -148
  32. package/editor/particles/particleEditEvents.js +12 -12
  33. package/editor/particles/rebuildParticleEmitter.js +31 -31
  34. package/editor/persistence/EditorLayoutStore.js +71 -71
  35. package/editor/persistence/SceneMetadata.js +52 -52
  36. package/editor/persistence/SceneSlotManager.js +144 -144
  37. package/editor/persistence/buildNewSceneDataset.js +67 -67
  38. package/editor/persistence/files.js +68 -68
  39. package/editor/persistence/scene_import.js +143 -143
  40. package/editor/persistence/scene_serialization.js +79 -79
  41. package/editor/persistence/string_buffer_codec.js +41 -41
  42. package/editor/process/GridDisplayProcess.js +125 -125
  43. package/editor/process/SymbolicDisplayProcess.js +106 -108
  44. package/editor/process/symbolic/CameraSymbolicDisplay.js +146 -146
  45. package/editor/process/symbolic/LightSymbolicDisplay.js +172 -172
  46. package/editor/process/symbolic/PathSymbolicDisplay.js +118 -118
  47. package/editor/process/symbolic/PositionedMarkerSymbolicDisplay.js +79 -79
  48. package/editor/process/symbolic/SoundEmitterSymbolicDisplay.js +57 -57
  49. package/editor/process/symbolic/SymbolicDisplay.js +62 -62
  50. package/editor/process/symbolic/gizmo_draw_wire_box_oriented.js +85 -85
  51. package/editor/process/symbolic/gizmo_draw_wire_circle.js +53 -53
  52. package/editor/prototypeEditorShell.js +156 -156
  53. package/editor/selection/editor_pick.js +130 -130
  54. package/editor/selection/screen_rect_frustum.js +119 -119
  55. package/editor/style/controls.scss +168 -168
  56. package/editor/style/inspector.scss +223 -223
  57. package/editor/templates/entity_templates.js +167 -167
  58. package/editor/tools/GridPaintTool.js +273 -273
  59. package/editor/tools/SelectionTool.js +307 -307
  60. package/editor/tools/TransformToolV2.js +378 -378
  61. package/editor/tools/engine/ToolEngine.js +188 -188
  62. package/editor/tools/paint/TerrainTexturePaintTool.js +250 -250
  63. package/editor/tools/v2/BlenderCameraOrientationGizmo.js +501 -501
  64. package/editor/tools/v2/TransformControls.js +971 -971
  65. package/editor/tools/v2/handle/gizmo_drag_plane.js +141 -141
  66. package/editor/tools/v2/handle/gizmo_draw.js +399 -399
  67. package/editor/tools/v2/handle/gizmo_handles.js +364 -364
  68. package/editor/tools/v2/handle/gizmo_ray_shapes.js +239 -239
  69. package/editor/view/ecs/HierarchicalEntityListView.js +339 -339
  70. package/editor/view/ecs/components/DatGuiController.js +2 -2
  71. package/editor/view/ecs/components/common/AutoCanvasView.js +100 -100
  72. package/editor/view/ecs/components/common/TextController.js +59 -59
  73. package/editor/view/library/MeshLibraryView.js +175 -175
  74. package/editor/view/library/mesh_library_drag.js +63 -63
  75. package/editor/view/library/model_thumbnail_source.js +86 -86
  76. package/editor/view/makeEntityDecorators.js +125 -125
  77. package/editor/view/node-graph/NodeGraphSelection.js +89 -89
  78. package/editor/view/node-graph/NodeView.js +211 -211
  79. package/editor/view/node-graph/actions/ConnectionDeleteAction.js +36 -36
  80. package/editor/view/node-graph/actions/NodesMoveAction.js +41 -41
  81. package/editor/view/node-graph/connection_wire_geometry.js +107 -107
  82. package/editor/view/particles/ColorLutGradientView.js +291 -291
  83. package/editor/view/particles/ScalarLutCurveView.js +279 -279
  84. package/editor/view/prepareMeshLibrary.js +188 -188
  85. package/editor/view/shell/SceneTreePanelView.js +119 -119
  86. package/editor/view/v2/SplitView.js +2 -2
  87. package/package.json +94 -94
  88. package/samples/generation/generators/interactive/mir_generator_place_buff_objects.js +362 -362
  89. package/src/DUPLICATION_AUDIT_2026_08_07/00_core_reuse_surface.md +738 -738
  90. package/src/DUPLICATION_AUDIT_2026_08_07/A_core_math_geom.md +79 -79
  91. package/src/DUPLICATION_AUDIT_2026_08_07/B_core_data.md +93 -93
  92. package/src/DUPLICATION_AUDIT_2026_08_07/C_gfx_render.md +80 -80
  93. package/src/DUPLICATION_AUDIT_2026_08_07/D_gfx_features.md +164 -164
  94. package/src/DUPLICATION_AUDIT_2026_08_07/E_physics.md +69 -69
  95. package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +102 -102
  96. package/src/DUPLICATION_AUDIT_2026_08_07/G_net_save.md +129 -129
  97. package/src/DUPLICATION_AUDIT_2026_08_07/H_engine_misc.md +72 -72
  98. package/src/DUPLICATION_AUDIT_2026_08_07/I_generation_view.md +74 -74
  99. package/src/DUPLICATION_AUDIT_2026_08_07/K_crosscutting.md +169 -169
  100. package/src/DUPLICATION_AUDIT_2026_08_07.md +254 -254
  101. package/src/DUPLICATION_AUDIT_REMEDIATION.md +250 -250
  102. package/src/REVIEW_2026_08_06/adv-core.md +511 -511
  103. package/src/REVIEW_2026_08_06/adv-gfx.md +480 -480
  104. package/src/REVIEW_2026_08_06/adv-view.md +446 -446
  105. package/src/REVIEW_2026_08_06/api-core.md +296 -296
  106. package/src/REVIEW_2026_08_06/api-engine.md +195 -195
  107. package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +507 -507
  108. package/src/REVIEW_2026_08_06/core-binary.md +348 -348
  109. package/src/REVIEW_2026_08_06/core-collection.md +376 -376
  110. package/src/REVIEW_2026_08_06/core-math.md +221 -221
  111. package/src/REVIEW_2026_08_06/core-process.md +266 -266
  112. package/src/REVIEW_2026_08_06/core-science.md +223 -223
  113. package/src/REVIEW_2026_08_06/engine-ai-nav.md +279 -279
  114. package/src/REVIEW_2026_08_06/engine-animation.md +167 -167
  115. package/src/REVIEW_2026_08_06/engine-asset.md +166 -166
  116. package/src/REVIEW_2026_08_06/engine-ecs.md +920 -920
  117. package/src/REVIEW_2026_08_06/engine-input.md +197 -197
  118. package/src/REVIEW_2026_08_06/engine-misc.md +248 -248
  119. package/src/REVIEW_2026_08_06/engine-terrain.md +52 -52
  120. package/src/REVIEW_2026_08_06/generation.md +176 -176
  121. package/src/REVIEW_2026_08_06/geom-2d.md +434 -434
  122. package/src/REVIEW_2026_08_06/geom-3d.md +117 -117
  123. package/src/REVIEW_2026_08_06/gfx-gi.md +143 -143
  124. package/src/REVIEW_2026_08_06/gfx-render.md +740 -740
  125. package/src/REVIEW_2026_08_06/gfx-texture.md +690 -690
  126. package/src/REVIEW_2026_08_06/prior-criticals.md +49 -49
  127. package/src/REVIEW_2026_08_06/prior-highs.md +138 -138
  128. package/src/REVIEW_2026_08_06/test-gaps.md +364 -364
  129. package/src/REVIEW_2026_08_06/view.md +667 -667
  130. package/src/REVIEW_2026_08_06.md +610 -610
  131. package/src/avif/codec/dec/avif_dec.cpp +233 -233
  132. package/src/avif/codec/dec/avif_dec.js +16 -16
  133. package/src/avif/encoder_worker.js +5 -18
  134. package/src/core/binary/BitImage2.js +246 -246
  135. package/src/core/binary/align_32.js +21 -21
  136. package/src/core/binary/data_view/DataType2DataViewReaders.js +23 -23
  137. package/src/core/binary/data_view/DataType2DataViewWriters.js +25 -25
  138. package/src/core/binary/hash/XXH128Hash.js +55 -55
  139. package/src/core/binary/hash/XXH3_SECRET.js +25 -25
  140. package/src/core/binary/hash/xxh3_128.js +341 -341
  141. package/src/core/binary/hash/xxh3_64.js +241 -241
  142. package/src/core/binary/hash/xxh3_common.js +476 -476
  143. package/src/core/binary/lz4/LZ4_MAX_INPUT_SIZE.js +9 -9
  144. package/src/core/binary/lz4/lz4_compress_block.js +385 -385
  145. package/src/core/binary/lz4/lz4_compress_bound.js +25 -25
  146. package/src/core/binary/lz4/lz4_decompress_block.js +139 -139
  147. package/src/core/binary/lz4/lz4_decompress_bound.js +30 -30
  148. package/src/core/binary/meshopt/MESHOPT_GROUP_SIZE.js +18 -18
  149. package/src/core/binary/meshopt/MeshoptCompressionFilter.js +30 -30
  150. package/src/core/binary/meshopt/MeshoptCompressionMode.js +21 -21
  151. package/src/core/binary/meshopt/__meshopt_test_streams.js +237 -237
  152. package/src/core/binary/meshopt/meshopt_decode.js +73 -73
  153. package/src/core/binary/meshopt/meshopt_decode_byte_group.js +67 -67
  154. package/src/core/binary/meshopt/meshopt_decode_data_block.js +59 -59
  155. package/src/core/binary/meshopt/meshopt_decode_filter_color.js +69 -69
  156. package/src/core/binary/meshopt/meshopt_decode_filter_exponential.js +43 -43
  157. package/src/core/binary/meshopt/meshopt_decode_filter_octahedral.js +60 -60
  158. package/src/core/binary/meshopt/meshopt_decode_filter_quaternion.js +71 -71
  159. package/src/core/binary/meshopt/meshopt_decode_index_buffer.js +294 -294
  160. package/src/core/binary/meshopt/meshopt_decode_index_sequence.js +115 -115
  161. package/src/core/binary/meshopt/meshopt_decode_vertex_buffer.js +381 -381
  162. package/src/core/binary/meshopt/meshopt_read_uint_var.js +59 -59
  163. package/src/core/binary/reinterpret_float32_as_uint32.js +13 -13
  164. package/src/core/binary/reinterpret_uint32_as_float32.js +14 -14
  165. package/src/core/binary/type/DataType2TypedArrayConstructorMapping.js +35 -35
  166. package/src/core/bvh2/bvh3/ebvh_geometry_query_any_triangle_ray.js +149 -149
  167. package/src/core/bvh2/bvh3/ebvh_sort_for_traversal_depth_first.js +96 -96
  168. package/src/core/bvh2/bvh3/query/bvh_query_depth_range_in_frustum.js +101 -101
  169. package/src/core/bvh2/bvh3/query/bvh_query_leaves_generic.js +77 -77
  170. package/src/core/bvh2/bvh3/query/bvh_query_leaves_ray.js +90 -90
  171. package/src/core/bvh2/bvh3/query/bvh_query_leaves_ray_segment.js +94 -94
  172. package/src/core/bvh2/bvh3/query/bvh_query_user_data_generic.js +86 -86
  173. package/src/core/bvh2/bvh3/query/bvh_query_user_data_intersects_capsule.js +101 -101
  174. package/src/core/bvh2/bvh3/query/bvh_query_user_data_intersects_sphere.js +92 -92
  175. package/src/core/bvh2/bvh3/query/bvh_query_user_data_ray.js +96 -96
  176. package/src/core/bvh2/bvh3/query/bvh_query_user_data_ray_segment.js +100 -100
  177. package/src/core/bvh2/visual/BVHGeometry.js +131 -131
  178. package/src/core/bvh8/BVH8.js +436 -436
  179. package/src/core/bvh8/aabb3_round_to_float32.js +22 -22
  180. package/src/core/bvh8/build/BVH8Converter.js +588 -588
  181. package/src/core/bvh8/build/TriangleCluster.js +122 -122
  182. package/src/core/bvh8/build/aabb3_compute_merge_cost.js +28 -28
  183. package/src/core/bvh8/build/aabb3_from_triangle_by_index.js +17 -17
  184. package/src/core/bvh8/build/bvh8_build_for_geometry.js +303 -303
  185. package/src/core/bvh8/build/bvh8_from_proxy.js +256 -256
  186. package/src/core/bvh8/build/byte.js +9 -9
  187. package/src/core/bvh8/build/encode_bounds_e.js +11 -11
  188. package/src/core/bvh8/bvh8_convert_to_dot.js +132 -132
  189. package/src/core/bvh8/bvh8_count_primitives.js +98 -98
  190. package/src/core/bvh8/bvh8_geometry_validate.js +138 -138
  191. package/src/core/bvh8/bvh8_geometry_validate_indirect.js +166 -166
  192. package/src/core/bvh8/bvh8_get_node_bounds.js +34 -34
  193. package/src/core/bvh8/bvh8_get_node_child_bounds.js +52 -52
  194. package/src/core/bvh8/bvh8_node_child_surface_area.js +18 -18
  195. package/src/core/bvh8/bvh8_node_count_triangles.js +27 -27
  196. package/src/core/bvh8/bvh8_quality.js +72 -72
  197. package/src/core/bvh8/bvh8_validate_structure.js +87 -87
  198. package/src/core/clipboard/obtainClipBoard.js +29 -29
  199. package/src/core/clipboard/safeClipboardReadText.js +55 -55
  200. package/src/core/clipboard/safeClipboardWriteText.js +23 -23
  201. package/src/core/collection/array/typed/typed_array_value_denormalize.js +52 -52
  202. package/src/core/collection/array/typed/typed_array_value_normalize.js +51 -51
  203. package/src/core/collection/union-find/union_find.js +79 -79
  204. package/src/core/color/PQ/PQ_constants.d.ts +43 -0
  205. package/src/core/color/PQ/PQ_constants.d.ts.map +1 -0
  206. package/src/core/color/PQ/PQ_constants.js +50 -0
  207. package/src/core/color/PQ/PQ_to_linear.d.ts +24 -0
  208. package/src/core/color/PQ/PQ_to_linear.d.ts.map +1 -0
  209. package/src/core/color/PQ/PQ_to_linear.js +35 -0
  210. package/src/core/color/PQ/linear_to_PQ.d.ts +27 -0
  211. package/src/core/color/PQ/linear_to_PQ.d.ts.map +1 -0
  212. package/src/core/color/PQ/linear_to_PQ.js +32 -0
  213. package/src/core/color/YCoCg/rgb_to_ycocg.js +20 -20
  214. package/src/core/color/YCoCg/ycocg_to_rgb.js +17 -17
  215. package/src/core/color/colormap/MAGMA_LUT.js +26 -26
  216. package/src/core/color/illuminant/D65_TRISTIMULUS_XYZ.js +19 -19
  217. package/src/core/color/lab/lab_apply_hunt_adjustment.js +27 -27
  218. package/src/core/color/lab/lab_distance_hyab.js +23 -23
  219. package/src/core/color/lab/xyz_to_lab.js +62 -62
  220. package/src/core/color/operations/color_darken.js +24 -24
  221. package/src/core/color/operations/color_desaturate.js +24 -24
  222. package/src/core/color/operations/color_lighten.js +24 -24
  223. package/src/core/color/operations/color_saturate.js +24 -24
  224. package/src/core/color/operations/color_scale_okhsv_channel.js +45 -45
  225. package/src/core/color/tonemap/tonemap_aces.js +41 -41
  226. package/src/core/color/ycxcz/xyz_to_ycxcz.js +28 -28
  227. package/src/core/color/ycxcz/ycxcz_to_xyz.js +19 -19
  228. package/src/core/dom/isImageBitmap.js +12 -12
  229. package/src/core/function/frameThrottle.js +23 -23
  230. package/src/core/geom/2d/aabb/aabb2_array_combine.js +7 -7
  231. package/src/core/geom/2d/aabb/aabb2_compute_area.js +7 -7
  232. package/src/core/geom/2d/aabb/aabb2_compute_center_from_multiple.js +7 -7
  233. package/src/core/geom/2d/aabb/aabb2_compute_overlap.js +7 -7
  234. package/src/core/geom/2d/aabb/aabb2_from_v2_array.js +7 -7
  235. package/src/core/geom/2d/aabb/aabb2_intersects_point.js +7 -7
  236. package/src/core/geom/2d/aabb/aabb2_overlap_exists.js +7 -7
  237. package/src/core/geom/2d/circle/circle_compute_circle_intersection.js +7 -7
  238. package/src/core/geom/2d/circle/circle_compute_circle_penetration.js +7 -7
  239. package/src/core/geom/2d/circle/circle_intersects_point.js +7 -7
  240. package/src/core/geom/2d/compute_polygon_area_2d.js +7 -7
  241. package/src/core/geom/2d/convex-hull/fixed_convex_hull_humus.js +7 -7
  242. package/src/core/geom/2d/convex-hull/fixed_convex_hull_relaxation.js +7 -7
  243. package/src/core/geom/2d/convex-hull/orientation3_array.js +7 -7
  244. package/src/core/geom/2d/intersect_ray_2d.js +7 -7
  245. package/src/core/geom/2d/line/line2_distance_to_point_sqr.js +7 -7
  246. package/src/core/geom/2d/line/line2_segment_intersection_fraction_2d.js +44 -44
  247. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_2d.js +7 -7
  248. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_array_2d.js +7 -7
  249. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_2d.js +7 -7
  250. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_array_2d.js +7 -7
  251. package/src/core/geom/2d/line/line_segment_intersection_fraction_2d.js +7 -7
  252. package/src/core/geom/2d/line/line_segment_line_segment_intersection_exists_2d.js +7 -7
  253. package/src/core/geom/2d/line/segment2_intersects_segment2_2d.js +25 -25
  254. package/src/core/geom/2d/line/segment2_segment_compute_intersection_array_2d.js +46 -46
  255. package/src/core/geom/2d/line/segment2_segment_intersection_fractions.js +52 -52
  256. package/src/core/geom/2d/oriented-box/min_area_rect_2d.js +69 -69
  257. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +433 -433
  258. package/src/core/geom/2d/polygon/polygon2_clip_axis_halfplane.js +51 -51
  259. package/src/core/geom/2d/polygon/polygon2_clip_halfplane.js +50 -50
  260. package/src/core/geom/2d/polygon/polygon2_is_counter_clockwise.js +84 -84
  261. package/src/core/geom/2d/polygon/polygon2_signed_area.js +52 -52
  262. package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.js +86 -86
  263. package/src/core/geom/2d/polygon/polygon2_triangulate.js +1280 -1280
  264. package/src/core/geom/2d/polygon/polygon2_triangulation_deviation.js +77 -77
  265. package/src/core/geom/2d/quad-tree/qt_collect_by_circle.js +39 -39
  266. package/src/core/geom/2d/quad-tree/qt_match_data_by_circle.js +101 -101
  267. package/src/core/geom/2d/quad-tree/qt_query_data_nearest_to_point.js +7 -7
  268. package/src/core/geom/2d/rectangle_to_aabb.js +7 -7
  269. package/src/core/geom/2d/spline_bezier2_2d.js +7 -7
  270. package/src/core/geom/2d/triangle/tri2_rasterize_conservative.js +99 -99
  271. package/src/core/geom/2d/triangle/tri2_signed_area.js +35 -35
  272. package/src/core/geom/2d/triangle2d_compute_area.js +7 -7
  273. package/src/core/geom/2d/triangle2d_contains_point.js +7 -7
  274. package/src/core/geom/2d/triangle2d_get_barycentric.js +7 -7
  275. package/src/core/geom/2d/v2_morton_encode.js +23 -23
  276. package/src/core/geom/3d/aabb/aabb3_array_intersects_frustum_degree.js +7 -7
  277. package/src/core/geom/3d/aabb/aabb3_box_surface_area_2.js +7 -7
  278. package/src/core/geom/3d/aabb/aabb3_build_frustum.js +5 -5
  279. package/src/core/geom/3d/aabb/aabb3_closest_point_on_surface.js +57 -57
  280. package/src/core/geom/3d/aabb/aabb3_combined_surface_area.js +7 -7
  281. package/src/core/geom/3d/aabb/aabb3_compute_half_surface_area.js +7 -7
  282. package/src/core/geom/3d/aabb/aabb3_compute_projected_area.js +7 -7
  283. package/src/core/geom/3d/aabb/aabb3_compute_surface_area.js +7 -7
  284. package/src/core/geom/3d/aabb/aabb3_detailed_volume_intersection.js +7 -7
  285. package/src/core/geom/3d/aabb/aabb3_estimate_projected_area2.js +7 -7
  286. package/src/core/geom/3d/aabb/aabb3_from_threejs_geometry.js +7 -7
  287. package/src/core/geom/3d/aabb/aabb3_from_triangle_group.js +46 -46
  288. package/src/core/geom/3d/aabb/aabb3_intersects_frustum_degree.js +7 -7
  289. package/src/core/geom/3d/aabb/aabb3_intersects_line_segment.js +7 -7
  290. package/src/core/geom/3d/aabb/aabb3_near_distance_to_intersection_ray_segment.js +7 -7
  291. package/src/core/geom/3d/aabb/aabb3_nearest_point_on_surface.js +7 -7
  292. package/src/core/geom/3d/aabb/aabb3_ray_segment_entry_distance.js +95 -95
  293. package/src/core/geom/3d/aabb/aabb3_raycast.js +7 -7
  294. package/src/core/geom/3d/aabb/aabb3_transform_oriented.js +93 -93
  295. package/src/core/geom/3d/aabb/aabb3_transform_oriented_inverse.js +82 -82
  296. package/src/core/geom/3d/aabb/compute_aabb_from_points.js +7 -7
  297. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.js +7 -7
  298. package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +486 -486
  299. package/src/core/geom/3d/atlas/BFF_PLAN.md +174 -174
  300. package/src/core/geom/3d/atlas/Chart.js +77 -77
  301. package/src/core/geom/3d/atlas/REVIEW_02.md +392 -392
  302. package/src/core/geom/3d/atlas/atlas_bench_lib.js +315 -315
  303. package/src/core/geom/3d/atlas/atlas_chart_type.js +16 -16
  304. package/src/core/geom/3d/atlas/atlas_compute_charts.js +188 -188
  305. package/src/core/geom/3d/atlas/atlas_extract_chart.js +107 -107
  306. package/src/core/geom/3d/atlas/atlas_generate.js +50 -50
  307. package/src/core/geom/3d/atlas/atlas_test_fixtures.js +266 -266
  308. package/src/core/geom/3d/atlas/atlas_write_chart_uvs.js +36 -36
  309. package/src/core/geom/3d/atlas/data/atlas_build_edge_dihedrals.js +62 -62
  310. package/src/core/geom/3d/atlas/data/atlas_build_edge_lengths.js +33 -33
  311. package/src/core/geom/3d/atlas/data/atlas_build_face_areas.js +50 -50
  312. package/src/core/geom/3d/atlas/io/atlas_mesh_weld_colocals.js +39 -39
  313. package/src/core/geom/3d/atlas/io/bt_loop_uv.js +35 -35
  314. package/src/core/geom/3d/atlas/pack/ChartPlacement.js +46 -46
  315. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.js +269 -269
  316. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.js +209 -209
  317. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_ortho.js +38 -38
  318. package/src/core/geom/3d/atlas/param/atlas_chart_stretch_metric.js +86 -86
  319. package/src/core/geom/3d/atlas/param/atlas_piecewise_resegment.js +183 -183
  320. package/src/core/geom/3d/atlas/param/fit_plane_basis.js +66 -66
  321. package/src/core/geom/3d/atlas/segment/RegionGraph.js +40 -40
  322. package/src/core/geom/3d/atlas/segment/atlas_build_region_graph.js +136 -136
  323. package/src/core/geom/3d/atlas/segment/atlas_chart_roundness_delta.js +30 -30
  324. package/src/core/geom/3d/atlas/segment/atlas_compute_planar_regions.js +77 -77
  325. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.js +116 -116
  326. package/src/core/geom/3d/atlas/segment/atlas_segment_charts.js +271 -271
  327. package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.js +191 -191
  328. package/src/core/geom/3d/box/box3_projected_half_extent.js +35 -35
  329. package/src/core/geom/3d/capsule/capsule_intersects_aabb3_closed.js +67 -67
  330. package/src/core/geom/3d/capsule/capsule_intersects_aabb3_iterative.js +137 -137
  331. package/src/core/geom/3d/compute_circle_bounding_box.js +7 -7
  332. package/src/core/geom/3d/cone/computeConeBoundingBox.js +7 -7
  333. package/src/core/geom/3d/cone/computeConePlaneSide.js +7 -7
  334. package/src/core/geom/3d/cone/compute_bounding_cone_of_2_cones.js +7 -7
  335. package/src/core/geom/3d/cylinder/cylinder3_raycast.d.ts +38 -0
  336. package/src/core/geom/3d/cylinder/cylinder3_raycast.d.ts.map +1 -0
  337. package/src/core/geom/3d/cylinder/cylinder3_raycast.js +105 -0
  338. package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.js +18 -18
  339. package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.js +24 -24
  340. package/src/core/geom/3d/frustum/clipping_volume_matrix4_project.js +7 -7
  341. package/src/core/geom/3d/frustum/frustum3_computeNearestPointToPoint.js +7 -7
  342. package/src/core/geom/3d/frustum/frustum3_compute_closest_point.js +117 -117
  343. package/src/core/geom/3d/frustum/frustum_matrix4_project.js +7 -7
  344. package/src/core/geom/3d/frustum/hexahedron_from_aabb.js +7 -7
  345. package/src/core/geom/3d/frustum/read_frustum_corner.js +17 -17
  346. package/src/core/geom/3d/frustum/read_three_planes_to_array.js +7 -7
  347. package/src/core/geom/3d/frustum/slice_frustum_linear_to_points.js +7 -7
  348. package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +146 -146
  349. package/src/core/geom/3d/gjk/gjk.js +430 -430
  350. package/src/core/geom/3d/gjk/gjk_epa_penetration.js +520 -520
  351. package/src/core/geom/3d/gjk/minkowski_support.js +71 -71
  352. package/src/core/geom/3d/gjk/mpr.js +368 -368
  353. package/src/core/geom/3d/line/line3_closest_points_segment_segment.js +7 -7
  354. package/src/core/geom/3d/line/line3_compute_nearest_point_to_point.js +7 -7
  355. package/src/core/geom/3d/line/line3_compute_point_segment_point_distance_unfolded.js +64 -64
  356. package/src/core/geom/3d/line/line3_compute_segment_closest_point_to_aabb3_t.js +153 -153
  357. package/src/core/geom/3d/line/line3_compute_segment_nearest_point_to_aabb3_t.js +7 -7
  358. package/src/core/geom/3d/line/line3_compute_segment_nearest_point_to_point_t.js +7 -7
  359. package/src/core/geom/3d/line/line3_compute_segment_segment_closest_points.js +88 -88
  360. package/src/core/geom/3d/line/line3_segment_segment_closest_point_pair.js +71 -71
  361. package/src/core/geom/3d/line/segment3_point_distance_to_segments.js +25 -25
  362. package/src/core/geom/3d/mat4/allocate_m4.js +7 -7
  363. package/src/core/geom/3d/mat4/apply_mat4_transform_to_direction_v3_array.js +7 -7
  364. package/src/core/geom/3d/mat4/apply_mat4_transform_to_v3_array.js +7 -7
  365. package/src/core/geom/3d/mat4/compose_matrix4_array.js +7 -7
  366. package/src/core/geom/3d/mat4/decompose_matrix_4_array.js +7 -7
  367. package/src/core/geom/3d/mat4/eulerAnglesFromMatrix.js +7 -7
  368. package/src/core/geom/3d/mat4/m4_compose.js +22 -22
  369. package/src/core/geom/3d/mat4/m4_compute_normal_matrix3.js +7 -7
  370. package/src/core/geom/3d/mat4/m4_decompose.js +64 -64
  371. package/src/core/geom/3d/mat4/m4_decompose_array.js +157 -157
  372. package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.js +32 -32
  373. package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale_scalar.js +67 -67
  374. package/src/core/geom/3d/mat4/m4_linear_matrix3.js +29 -29
  375. package/src/core/geom/3d/mat4/m4_look_at.js +96 -96
  376. package/src/core/geom/3d/mat4/m4_make_rotation_x.js +47 -47
  377. package/src/core/geom/3d/mat4/m4_make_rotation_y.js +47 -47
  378. package/src/core/geom/3d/mat4/m4_make_rotation_z.js +47 -47
  379. package/src/core/geom/3d/mat4/m4_normal_matrix3.js +39 -39
  380. package/src/core/geom/3d/mat4/m4_perspective.js +66 -66
  381. package/src/core/geom/3d/mat4/m4_transpose.js +48 -48
  382. package/src/core/geom/3d/morton/mortonEncode_LUT.js +7 -7
  383. package/src/core/geom/3d/morton/mortonEncode_magicbits.js +7 -7
  384. package/src/core/geom/3d/normal/hemioct/encode_unit3_hemioct.js +5 -5
  385. package/src/core/geom/3d/normal/hemioct/encode_unit_to_hemioct.js +28 -28
  386. package/src/core/geom/3d/normal/lambert_azimuth/decode_azimuth_to_unit.js +30 -30
  387. package/src/core/geom/3d/normal/lambert_azimuth/encode_unit_to_azimuth.js +19 -19
  388. package/src/core/geom/3d/normal/spherical/decode_spheremap_to_unit.js +38 -38
  389. package/src/core/geom/3d/normal/spherical/encode_unit_to_spheremap.js +30 -30
  390. package/src/core/geom/3d/plane/is_point_within_planes.js +7 -7
  391. package/src/core/geom/3d/plane/orient3d_fast_point.js +47 -47
  392. package/src/core/geom/3d/plane/plane3_compute_convex_3_plane_intersection.js +7 -7
  393. package/src/core/geom/3d/plane/plane3_compute_plane_intersection.js +7 -7
  394. package/src/core/geom/3d/plane/plane3_intersect_plane.js +7 -7
  395. package/src/core/geom/3d/plane/plane3_three_compute_convex_3_plane_intersection.js +7 -7
  396. package/src/core/geom/3d/point/point3_raycast.d.ts +33 -0
  397. package/src/core/geom/3d/point/point3_raycast.d.ts.map +1 -0
  398. package/src/core/geom/3d/point/point3_raycast.js +47 -0
  399. package/src/core/geom/3d/polygon/polygon3_compute_normal.js +60 -60
  400. package/src/core/geom/3d/polygon/polygon3_triangulate.js +94 -94
  401. package/src/core/geom/3d/polyhedron/convex_polyhedron3_raycast.d.ts +40 -0
  402. package/src/core/geom/3d/polyhedron/convex_polyhedron3_raycast.d.ts.map +1 -0
  403. package/src/core/geom/3d/polyhedron/convex_polyhedron3_raycast.js +94 -0
  404. package/src/core/geom/3d/quadric/QUADRIC3_SIZE.js +14 -14
  405. package/src/core/geom/3d/quadric/Quadric3.js +282 -282
  406. package/src/core/geom/3d/quadric/quadric3_add.js +33 -33
  407. package/src/core/geom/3d/quadric/quadric3_clear.js +25 -25
  408. package/src/core/geom/3d/quadric/quadric3_copy.js +27 -27
  409. package/src/core/geom/3d/quadric/quadric3_distance.js +36 -36
  410. package/src/core/geom/3d/quadric/quadric3_evaluate.js +25 -25
  411. package/src/core/geom/3d/quadric/quadric3_optimize.js +45 -45
  412. package/src/core/geom/3d/quadric/quadric3_scale.js +32 -32
  413. package/src/core/geom/3d/quadric/quadric3_set_from_plane_through_point.js +30 -30
  414. package/src/core/geom/3d/quadric/quadric3_set_from_vector4.js +35 -35
  415. package/src/core/geom/3d/quadric/quadric3_sub.js +36 -36
  416. package/src/core/geom/3d/quadric/quadric3_to_tensor_m3.js +28 -28
  417. package/src/core/geom/3d/quadric/quadric3_to_tensor_m3_inverse.js +56 -56
  418. package/src/core/geom/3d/quadric/quadric3_to_vector3.js +19 -19
  419. package/src/core/geom/3d/quaternion/quat3_createFromAxisAngle.js +7 -7
  420. package/src/core/geom/3d/quaternion/quat3_integrate.js +62 -62
  421. package/src/core/geom/3d/quaternion/quat3_multiply.js +31 -31
  422. package/src/core/geom/3d/quaternion/quat3_nlerp.js +72 -72
  423. package/src/core/geom/3d/quaternion/quat3_to_matrix3.js +69 -69
  424. package/src/core/geom/3d/quaternion/quat_decode_from_uint32.js +7 -7
  425. package/src/core/geom/3d/quaternion/quat_encode_to_uint32.js +7 -7
  426. package/src/core/geom/3d/ray/ray3_array_compose.js +7 -7
  427. package/src/core/geom/3d/ray/ray3_compute_nearest_point_to_point.js +7 -7
  428. package/src/core/geom/3d/ray/ray3_distance_to_point.js +7 -7
  429. package/src/core/geom/3d/ray/ray3_shift_origin_along_direction.js +7 -7
  430. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts +17 -0
  431. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
  432. package/src/core/geom/3d/shape/ConvexHullShape3D.js +43 -0
  433. package/src/core/geom/3d/shape/CylinderShape3D.d.ts +1 -0
  434. package/src/core/geom/3d/shape/CylinderShape3D.d.ts.map +1 -1
  435. package/src/core/geom/3d/shape/CylinderShape3D.js +21 -0
  436. package/src/core/geom/3d/shape/PointShape3D.d.ts +7 -0
  437. package/src/core/geom/3d/shape/PointShape3D.d.ts.map +1 -1
  438. package/src/core/geom/3d/shape/PointShape3D.js +88 -63
  439. package/src/core/geom/3d/shape/PosedShape3D.d.ts +6 -0
  440. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
  441. package/src/core/geom/3d/shape/PosedShape3D.js +27 -0
  442. package/src/core/geom/3d/shape/TransformedShape3D.d.ts +10 -0
  443. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  444. package/src/core/geom/3d/shape/TransformedShape3D.js +13 -0
  445. package/src/core/geom/3d/shape/Triangle3D.d.ts +1 -0
  446. package/src/core/geom/3d/shape/Triangle3D.d.ts.map +1 -1
  447. package/src/core/geom/3d/shape/Triangle3D.js +26 -0
  448. package/src/core/geom/3d/shape/UnionShape3D.d.ts +6 -0
  449. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  450. package/src/core/geom/3d/shape/UnionShape3D.js +7 -0
  451. package/src/core/geom/3d/shape/UnitCubeShape3D.js +45 -45
  452. package/src/core/geom/3d/shape/UnitSphereShape3D.js +44 -44
  453. package/src/core/geom/3d/shape/shape3_mesh_from_geometry.js +64 -64
  454. package/src/core/geom/3d/shape/shape_mesh_from_geometry.js +7 -7
  455. package/src/core/geom/3d/shape/util/compute_signed_distance_gradient_by_sampling.js +51 -51
  456. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.js +7 -7
  457. package/src/core/geom/3d/sphere/compute_bounding_sphere_of_2_spheres.js +7 -7
  458. package/src/core/geom/3d/sphere/harmonics/sh3_convolve_with_zh.js +53 -53
  459. package/src/core/geom/3d/sphere/harmonics/sh3_ggx_zh.js +30 -30
  460. package/src/core/geom/3d/sphere/harmonics/sh3_rotate_bl.js +7 -7
  461. package/src/core/geom/3d/sphere/harmonics/sh_compute_K.js +7 -7
  462. package/src/core/geom/3d/sphere/sphere_array_intersects_point.js +7 -7
  463. package/src/core/geom/3d/sphere/sphere_array_intersects_ray.js +7 -7
  464. package/src/core/geom/3d/sphere/sphere_intersects_point.js +7 -7
  465. package/src/core/geom/3d/sphere/sphere_matrix4_transform.js +5 -5
  466. package/src/core/geom/3d/sphere/sphere_projected_sphere_radius_sqr.js +7 -7
  467. package/src/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.js +7 -7
  468. package/src/core/geom/3d/sphere/spherical_from_cartesian.js +7 -7
  469. package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.js +174 -174
  470. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.js +7 -7
  471. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_volume.js +7 -7
  472. package/src/core/geom/3d/tetrahedra/delaunay/fill_in_a_cavity.js +7 -7
  473. package/src/core/geom/3d/tetrahedra/graphics/build_tetrahedral_mesh_geometry.js +39 -39
  474. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.js +48 -48
  475. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js +173 -173
  476. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_compute_tet_quality.js +22 -22
  477. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.js +146 -146
  478. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.js +232 -232
  479. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.js +255 -255
  480. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js +387 -387
  481. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.js +140 -140
  482. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_tet_get_neighbours.js +7 -7
  483. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.js +97 -97
  484. package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.js +66 -66
  485. package/src/core/geom/3d/tetrahedra/triangle/triangle_decode_depth.js +59 -59
  486. package/src/core/geom/3d/tetrahedra/triangle/triangle_rasterized_depth_sample_index.js +54 -54
  487. package/src/core/geom/3d/tetrahedra/validate_neighbour.js +70 -70
  488. package/src/core/geom/3d/topology/struct/binary/BinaryDataBlock.js +314 -314
  489. package/src/core/geom/3d/topology/struct/binary/BinaryDataLayer.js +364 -364
  490. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.js +567 -567
  491. package/src/core/geom/3d/topology/struct/binary/BinaryTopology.js +1085 -1085
  492. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.js +73 -73
  493. package/src/core/geom/3d/topology/struct/binary/io/bt_loop_kill.js +35 -35
  494. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_append.js +119 -119
  495. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js +84 -84
  496. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.js +172 -172
  497. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js +56 -56
  498. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.js +7 -7
  499. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +227 -227
  500. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple.js +161 -161
  501. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_island_erode.js +490 -490
  502. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.js +120 -120
  503. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_from_indexed_geometry.js +120 -120
  504. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.js +52 -52
  505. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.js +115 -115
  506. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_flip.js +142 -142
  507. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_get_or_create.js +21 -21
  508. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js +92 -92
  509. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_split.js +179 -179
  510. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_swap_vertex_slots.js +28 -28
  511. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_kill_only_edge.js +8 -8
  512. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.js +83 -83
  513. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.js +89 -89
  514. package/src/core/geom/3d/topology/struct/binary/io/face/bt_face_kill.js +25 -25
  515. package/src/core/geom/3d/topology/struct/binary/io/face/bt_face_poke.js +127 -127
  516. package/src/core/geom/3d/topology/struct/binary/io/face/bt_face_triangulate.js +268 -268
  517. package/src/core/geom/3d/topology/struct/binary/io/face/bt_kill_only_face.js +8 -8
  518. package/src/core/geom/3d/topology/struct/binary/io/face/bt_mesh_kill_degenerate_faces.js +72 -72
  519. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_kill_only_vert.js +7 -7
  520. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_merge_verts_by_distance.js +7 -7
  521. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_mesh_relative_merge_distance.js +48 -48
  522. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_mesh_split_pinched_vertices.js +256 -256
  523. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_mesh_vertex_merge_distance.js +77 -77
  524. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.js +7 -7
  525. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_kill.js +7 -7
  526. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.js +148 -148
  527. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_kill_only.js +7 -7
  528. package/src/core/geom/3d/topology/struct/binary/query/bt_collect_boundary_segments.js +29 -29
  529. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_breaks_link_condition.js +107 -107
  530. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_flip_is_legal.js +41 -41
  531. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_flip_would_fold.js +120 -120
  532. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.js +42 -42
  533. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_is_boundary.js +20 -20
  534. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_other_face.d.ts +32 -0
  535. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_other_face.d.ts.map +1 -0
  536. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_other_face.js +59 -0
  537. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_read_diamond.js +96 -96
  538. package/src/core/geom/3d/topology/struct/binary/query/bt_face_compute_newell_normal.js +72 -72
  539. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_attached_faces.js +7 -7
  540. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_edge_adjacent_faces.js +39 -39
  541. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_edge_adjacent_faces_weighted.js +93 -93
  542. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_neighbour_faces.js +7 -7
  543. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_shared_loop.js +48 -48
  544. package/src/core/geom/3d/topology/struct/binary/query/bt_face_island_flood_fill.js +45 -45
  545. package/src/core/geom/3d/topology/struct/binary/query/bt_face_read_triangle.js +66 -66
  546. package/src/core/geom/3d/topology/struct/binary/query/bt_face_third_vertex.d.ts +26 -0
  547. package/src/core/geom/3d/topology/struct/binary/query/bt_face_third_vertex.d.ts.map +1 -0
  548. package/src/core/geom/3d/topology/struct/binary/query/bt_face_third_vertex.js +55 -0
  549. package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.js +7 -7
  550. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_assert_valid.js +44 -44
  551. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_euclidean_distance_field.js +32 -32
  552. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_compute_face_islands.js +53 -53
  553. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.js +703 -703
  554. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.js +181 -181
  555. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.js +133 -133
  556. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.js +82 -82
  557. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_validate.js +599 -599
  558. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.js +108 -108
  559. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.js +7 -7
  560. package/src/core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.js +7 -7
  561. package/src/core/geom/3d/triangle/computeTriangleRayIntersection.js +7 -7
  562. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentric.js +7 -7
  563. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentricEdge.js +7 -7
  564. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentricGeometry.js +7 -7
  565. package/src/core/geom/3d/triangle/compute_triangle_area_3d.js +7 -7
  566. package/src/core/geom/3d/triangle/compute_triangle_normal.js +7 -7
  567. package/src/core/geom/3d/triangle/rayTriangleIntersection.js +7 -7
  568. package/src/core/geom/3d/triangle/tri3_closest_point.js +65 -65
  569. package/src/core/geom/3d/triangle/tri3_closest_point_barycentric.js +171 -171
  570. package/src/core/geom/3d/triangle/tri3_flatten_isometric.js +79 -79
  571. package/src/core/geom/3d/triangle/tri3_ray_intersection.js +160 -160
  572. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric.js +96 -96
  573. package/src/core/geom/3d/triangle/tri3_raycast.d.ts +42 -0
  574. package/src/core/geom/3d/triangle/tri3_raycast.d.ts.map +1 -0
  575. package/src/core/geom/3d/triangle/tri3_raycast.js +94 -0
  576. package/src/core/geom/3d/triangle/triangle3_incenter.js +7 -7
  577. package/src/core/geom/3d/triangle/triangle_compute_plane_side.js +7 -7
  578. package/src/core/geom/3d/triangle/triangle_compute_signed_volume.js +7 -7
  579. package/src/core/geom/3d/triangle/triangle_intersects_clipping_volume.js +7 -7
  580. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.js +7 -7
  581. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.js +7 -7
  582. package/src/core/geom/3d/util/make_justified_point_grid.js +7 -7
  583. package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +381 -381
  584. package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +684 -684
  585. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +554 -554
  586. package/src/core/geom/mat3/m3_cm_from_translation.js +7 -7
  587. package/src/core/geom/mat3/m3_cm_invert.js +7 -7
  588. package/src/core/geom/mat3/m3_make_rotation.js +5 -5
  589. package/src/core/geom/mat3/m3_make_rotation_TBN.js +31 -31
  590. package/src/core/geom/mat3/m3_multiply_vec3.js +7 -7
  591. package/src/core/geom/packing/computeBoundingSphereOfSpheres.js +7 -7
  592. package/src/core/geom/packing/max-rect/cost/costByBestShortSide.js +7 -7
  593. package/src/core/geom/packing/max-rect/cost/costByRemainingArea.js +7 -7
  594. package/src/core/geom/packing/max-rect/cutArea.js +7 -7
  595. package/src/core/geom/packing/max-rect/findBestContainer.js +7 -7
  596. package/src/core/geom/packing/max-rect/packMaxRectangles.js +7 -7
  597. package/src/core/geom/packing/max-rect/packOneBox.js +7 -7
  598. package/src/core/geom/packing/max-rect/removeRedundantBoxes.js +7 -7
  599. package/src/core/geom/packing/max-rect/removeRedundantBoxesArray.js +7 -7
  600. package/src/core/geom/random/randomPointInBox.js +7 -7
  601. package/src/core/geom/random/randomPointInCircle.js +7 -7
  602. package/src/core/geom/random/randomPointInPoint.js +7 -7
  603. package/src/core/geom/random/randomPointInSphere.js +7 -7
  604. package/src/core/geom/random/randomPointOnBox.js +7 -7
  605. package/src/core/geom/random/randomPointOnSphere.js +7 -7
  606. package/src/core/geom/random/random_orthonormal_basis.js +31 -31
  607. package/src/core/geom/vec/vector_axpy.js +15 -15
  608. package/src/core/geom/vec/vector_axpy_offset.js +20 -20
  609. package/src/core/geom/vec/vector_copy.js +7 -7
  610. package/src/core/geom/vec/vector_dot_offset.js +25 -25
  611. package/src/core/geom/vec/vector_scale_array.js +7 -7
  612. package/src/core/geom/vec2/v2_rotate.js +21 -21
  613. package/src/core/geom/vec2/v2_rotate_cos_sin.js +21 -21
  614. package/src/core/geom/vec3/v3_angle_atan2_between.js +7 -7
  615. package/src/core/geom/vec3/v3_angle_between.js +7 -7
  616. package/src/core/geom/vec3/v3_angle_cos_between.js +7 -7
  617. package/src/core/geom/vec3/v3_array_add_in_place.js +7 -7
  618. package/src/core/geom/vec3/v3_array_centroid.js +7 -7
  619. package/src/core/geom/vec3/v3_array_copy.js +7 -7
  620. package/src/core/geom/vec3/v3_array_displace_in_direction.js +7 -7
  621. package/src/core/geom/vec3/v3_array_equals.js +7 -7
  622. package/src/core/geom/vec3/v3_array_immediate_add.js +7 -7
  623. package/src/core/geom/vec3/v3_array_matrix4_rotate.js +7 -7
  624. package/src/core/geom/vec3/v3_array_normalize.js +7 -7
  625. package/src/core/geom/vec3/v3_array_scale.js +7 -7
  626. package/src/core/geom/vec3/v3_compute_interior_angle.js +7 -7
  627. package/src/core/geom/vec3/v3_cotangent.js +33 -33
  628. package/src/core/geom/vec3/v3_dot_array_array.js +7 -7
  629. package/src/core/geom/vec3/v3_matrix3_multiply.js +30 -30
  630. package/src/core/geom/vec3/v3_matrix3_rotate.js +49 -49
  631. package/src/core/geom/vec3/v3_matrix4_rotate.js +7 -7
  632. package/src/core/geom/vec3/v3_multiply.js +23 -23
  633. package/src/core/geom/vec3/v3_multiply_scalar.js +7 -7
  634. package/src/core/geom/vec3/v3_orthonormal_matrix_from_normal.js +49 -49
  635. package/src/core/geom/vec3/v3_quat3_apply.js +7 -7
  636. package/src/core/geom/vec3/v3_quat3_apply_inverse.js +7 -7
  637. package/src/core/geom/vec3/v3_quaternion_apply.js +39 -39
  638. package/src/core/geom/vec3/v3_quaternion_apply_inverse.js +41 -41
  639. package/src/core/geom/vec3/v3_reflect.js +24 -24
  640. package/src/core/geom/vec3/v3_scale_array.js +18 -18
  641. package/src/core/geom/vec3/v3_triple_cross.js +45 -45
  642. package/src/core/geom/vec3/v3_triple_cross_product.js +7 -7
  643. package/src/core/geom/vec3/v3_uniform_sample_cone.js +21 -21
  644. package/src/core/geom/vec4/v4_multiply_mat4.js +7 -7
  645. package/src/core/graph/csr/csr_graph_build_distance_field.js +112 -112
  646. package/src/core/graph/csr/csr_graph_find_edge.js +25 -25
  647. package/src/core/graph/csr/csr_graph_find_shortest_path.js +105 -105
  648. package/src/core/graph/csr/csr_graph_from_undirected_edge_list.js +94 -94
  649. package/src/core/graph/graph_k_means_cluster.js +250 -250
  650. package/src/core/graph/layout/CircleLayout.js +1 -1
  651. package/src/core/graph/layout/box/BoxLayouter.js +1 -1
  652. package/src/core/graph/layout/graph_peel_topological_layer.js +45 -45
  653. package/src/core/graph/metis/BinaryTopologyFaceGraph.js +49 -49
  654. package/src/core/graph/metis/bt_mesh_build_face_graph.js +111 -111
  655. package/src/core/graph/metis/cluster_mesh_metis.js +137 -137
  656. package/src/core/graph/metis/native/bisection/bisect_graph.js +100 -100
  657. package/src/core/graph/metis/native/bisection/compute_2way_params.js +86 -86
  658. package/src/core/graph/metis/native/bisection/fm_2way.js +297 -297
  659. package/src/core/graph/metis/native/bisection/grow_bisection.js +137 -137
  660. package/src/core/graph/metis/native/bisection/split_graph_two_way.js +119 -119
  661. package/src/core/graph/metis/native/coarsen/coarsen_graph.js +94 -94
  662. package/src/core/graph/metis/native/coarsen/create_coarse_graph.js +158 -158
  663. package/src/core/graph/metis/native/coarsen/match_shem.js +175 -175
  664. package/src/core/graph/metis/native/initial/initial_kway_bfs.js +122 -122
  665. package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.js +170 -170
  666. package/src/core/graph/metis/native/metis_partition_kway.js +126 -126
  667. package/src/core/graph/metis/native/refine/RefinementScratch.js +53 -53
  668. package/src/core/graph/metis/native/refine/fm_kway.js +487 -487
  669. package/src/core/graph/metis/native/refine/project_kway.js +43 -43
  670. package/src/core/graph/metis/native/refine/refine_kway.js +43 -43
  671. package/src/core/lang/reactive/pegjs/parser.js +3458 -3458
  672. package/src/core/math/complex/complex_horner_eval.js +31 -31
  673. package/src/core/math/computeWholeDivisorLow.js +33 -33
  674. package/src/core/math/f32_next_down.js +24 -24
  675. package/src/core/math/f32_next_up.js +27 -27
  676. package/src/core/math/hash/hash_mix2.js +22 -22
  677. package/src/core/math/hash/hash_mix3.js +19 -19
  678. package/src/core/math/linalg/cg/cg_solve.js +106 -106
  679. package/src/core/math/linalg/cg/cg_solve_normal_equations.js +59 -59
  680. package/src/core/math/linalg/cubic_residual_times_derivative_accumulate.js +43 -43
  681. package/src/core/math/linalg/eigen/matrix_householder_in_place.js +122 -122
  682. package/src/core/math/linalg/eigen/matrix_qr_in_place.js +190 -190
  683. package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.js +117 -117
  684. package/src/core/math/linalg/givens/givens_apply_rows.js +28 -28
  685. package/src/core/math/linalg/givens/givens_apply_rows_offset.js +30 -30
  686. package/src/core/math/linalg/givens/givens_rotation_coefficients.js +39 -39
  687. package/src/core/math/linalg/lu_factor_linear_system.js +108 -108
  688. package/src/core/math/linalg/lu_solve_linear_system.js +53 -53
  689. package/src/core/math/linalg/polynomial_add_into.js +29 -29
  690. package/src/core/math/linalg/polynomial_complex_roots_aberth_ehrlich.js +159 -159
  691. package/src/core/math/linalg/polynomial_cubic_derivative_eval.js +16 -16
  692. package/src/core/math/linalg/polynomial_cubic_horner_eval.js +19 -19
  693. package/src/core/math/linalg/polynomial_cubic_second_derivative_eval.js +14 -14
  694. package/src/core/math/linalg/polynomial_multiply.js +41 -41
  695. package/src/core/math/linalg/polynomial_real_roots_in_interval.js +211 -211
  696. package/src/core/math/linalg/polynomial_root_bound_cauchy.js +30 -30
  697. package/src/core/math/linalg/polynomial_scale_into.js +17 -17
  698. package/src/core/math/linalg/polynomial_sub_into.js +29 -29
  699. package/src/core/math/linalg/solve_linear_system_GEPP_2x2.js +96 -96
  700. package/src/core/math/linalg/sor_optimal_omega.js +42 -42
  701. package/src/core/math/linalg/sparse/SparseMatrixCSR.js +88 -88
  702. package/src/core/math/linalg/sparse/spm_matvec.js +22 -22
  703. package/src/core/math/linalg/sparse/spm_matvec_transpose.js +29 -29
  704. package/src/core/math/lookup/LUT_HEATMAP.js +30 -30
  705. package/src/core/math/lookup/ParameterLookupTable.js +495 -495
  706. package/src/core/math/lookup/ParameterLookupTableFlags.js +6 -6
  707. package/src/core/math/noise/curl_noise_3d.js +18 -18
  708. package/src/core/math/physics/brdf/cone_cosine_from_roughness.js +28 -28
  709. package/src/core/math/physics/brdf/reflection_sample_weight.js +48 -48
  710. package/src/core/math/physics/kinematics/computeInterceptPoint.js +79 -79
  711. package/src/core/math/random/randomSeed.js +16 -16
  712. package/src/core/math/random/random_pick_weighted_index.js +26 -26
  713. package/src/core/math/round_half_away_from_zero.js +13 -13
  714. package/src/core/math/spline/spline3_hermite_apply_transform.js +107 -107
  715. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_1d.js +125 -125
  716. package/src/core/math/spline/spline3_hermite_intersects_spline3_hermite.js +50 -50
  717. package/src/core/math/spline/spline3_hermite_reverse.js +49 -49
  718. package/src/core/math/spline/spline3_hermite_to_monomial.js +37 -37
  719. package/src/core/math/statistics/hammersley_sequence.js +53 -53
  720. package/src/core/model/reactive/model/util/createRandomReactiveExpression.js +185 -185
  721. package/src/core/path/convertPathToURL.js +107 -107
  722. package/src/core/process/delay.js +16 -16
  723. package/src/core/science/units/MEASUREMENT_UNITS_SCIENTIFIC.js +87 -87
  724. package/src/core/science/units/MEASUREMENT_UNITS_SI.js +17 -17
  725. package/src/core/science/units/NamedUnit.js +48 -48
  726. package/src/core/science/units/UNIT_DIMENSION_MAPPING.js +29 -29
  727. package/src/core/science/units/UnitDimension.js +28 -28
  728. package/src/core/science/units/format_quantity.js +74 -74
  729. package/src/core/science/units/magnitude_prefix.js +127 -127
  730. package/src/core/science/units/si/AMPERE.js +13 -13
  731. package/src/core/science/units/si/CANDELA.js +13 -13
  732. package/src/core/science/units/si/DIMENSIONLESS.js +14 -14
  733. package/src/core/science/units/si/KELVIN.js +13 -13
  734. package/src/core/science/units/si/KILOGRAM.js +13 -13
  735. package/src/core/science/units/si/METER.js +13 -13
  736. package/src/core/science/units/si/MOLE.js +13 -13
  737. package/src/core/science/units/si/SECOND.js +13 -13
  738. package/src/core/science/units/si/derived/BECQUEREL.js +16 -16
  739. package/src/core/science/units/si/derived/COULOMB.js +13 -13
  740. package/src/core/science/units/si/derived/FARAD.js +13 -13
  741. package/src/core/science/units/si/derived/GRAY.js +16 -16
  742. package/src/core/science/units/si/derived/HENRY.js +13 -13
  743. package/src/core/science/units/si/derived/HERTZ.js +16 -16
  744. package/src/core/science/units/si/derived/JOULE.js +13 -13
  745. package/src/core/science/units/si/derived/KATAL.js +13 -13
  746. package/src/core/science/units/si/derived/LUMEN.js +14 -14
  747. package/src/core/science/units/si/derived/LUX.js +13 -13
  748. package/src/core/science/units/si/derived/NEWTON.js +13 -13
  749. package/src/core/science/units/si/derived/OHM.js +13 -13
  750. package/src/core/science/units/si/derived/PASCAL.js +13 -13
  751. package/src/core/science/units/si/derived/SIEMENS.js +13 -13
  752. package/src/core/science/units/si/derived/SIEVERT.js +16 -16
  753. package/src/core/science/units/si/derived/TESLA.js +13 -13
  754. package/src/core/science/units/si/derived/VOLT.js +13 -13
  755. package/src/core/science/units/si/derived/WATT.js +13 -13
  756. package/src/core/science/units/si/derived/WEBER.js +13 -13
  757. package/src/core/science/units/unit_matrix_to_string.js +403 -403
  758. package/src/engine/Engine.js +726 -726
  759. package/src/engine/EngineHarness.js +590 -590
  760. package/src/engine/REVIEW_2026_07_03.md +211 -211
  761. package/src/engine/animation/AnimatedActions.js +81 -81
  762. package/src/engine/animation/AnimationUtils.js +252 -252
  763. package/src/engine/animation/async/TimeSeries.js +300 -300
  764. package/src/engine/animation/curve/animation_curve_binary_codec.js +60 -60
  765. package/src/engine/animation/curve/draw/canvas_point_to_curve.js +22 -22
  766. package/src/engine/animation/curve/draw/curve_point_to_canvas.js +38 -38
  767. package/src/engine/animation/curve/draw/position_canvas_to_curve.js +22 -22
  768. package/src/engine/animation/curve/draw/position_curve_to_canvas.js +22 -22
  769. package/src/engine/asset/GameAssetType.d.ts +0 -1
  770. package/src/engine/asset/GameAssetType.js +0 -1
  771. package/src/engine/asset/load_model_scene_bundle.js +27 -27
  772. package/src/engine/asset/loaders/font/FontAsset.js +21 -21
  773. package/src/engine/asset/loaders/font/FontAssetLoader.js +20 -20
  774. package/src/engine/asset/loaders/gltf_test_fixtures.js +358 -358
  775. package/src/engine/asset/loaders/image/ImageBitmapAssetLoader.js +52 -52
  776. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +94 -94
  777. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterAverage.js +59 -59
  778. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterNone.js +55 -55
  779. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterPaeth.js +74 -74
  780. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterSub.js +34 -34
  781. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterUp.js +46 -46
  782. package/src/engine/control/first-person/DESIGN.md +640 -640
  783. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +563 -563
  784. package/src/engine/control/first-person/FirstPersonMotionPhase.js +134 -134
  785. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2045 -2045
  786. package/src/engine/control/first-person/mastery/DecisionPoint.js +30 -30
  787. package/src/engine/control/first-person/math/Spring.js +71 -71
  788. package/src/engine/control/first-person/math/computeJumpFromApex.js +23 -23
  789. package/src/engine/control/first-person/math/computeLRCBreathRate.js +41 -41
  790. package/src/engine/control/first-person/math/computeMassRatios.js +44 -44
  791. package/src/engine/control/first-person/math/criticallyDampedSpring.js +34 -34
  792. package/src/engine/control/first-person/math/dampedSpringStep.js +72 -72
  793. package/src/engine/control/first-person/math/jumpDynamics.js +108 -108
  794. package/src/engine/control/first-person/math/stepTowards.js +20 -20
  795. package/src/engine/control/first-person/pose/FirstPersonPose.js +137 -137
  796. package/src/engine/control/first-person/pose/FirstPersonPosture.js +27 -27
  797. package/src/engine/control/first-person/test/buildTestPlayer.js +36 -36
  798. package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +531 -531
  799. package/src/engine/ecs/EntityManager.d.ts +7 -3
  800. package/src/engine/ecs/EntityManager.d.ts.map +1 -1
  801. package/src/engine/ecs/EntityManager.js +10 -5
  802. package/src/engine/ecs/HIERARCHY_REVIEW.md +717 -717
  803. package/src/engine/ecs/async/SystemWorkerHost.js +329 -329
  804. package/src/engine/ecs/async/SystemWorkerLoopback.js +143 -143
  805. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +246 -246
  806. package/src/engine/ecs/async/WorkerSystem.js +702 -702
  807. package/src/engine/ecs/async/WorkerSystemProtocol.js +150 -150
  808. package/src/engine/ecs/fow/FogOfWar.js +707 -707
  809. package/src/engine/ecs/fow/FogOfWarEdgeMode.js +40 -40
  810. package/src/engine/ecs/fow/fog_of_war_mask_world_bounds.js +24 -24
  811. package/src/engine/ecs/fow/fog_of_war_uv_transform.js +30 -30
  812. package/src/engine/ecs/gui/hud/testHudEdgeStick.js +132 -134
  813. package/src/engine/ecs/hierarchy/EntityChildIndex.js +140 -140
  814. package/src/engine/ecs/ik/IKProblem.js +42 -42
  815. package/src/engine/ecs/ik/InverseKinematicsSystem.js +193 -193
  816. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +134 -134
  817. package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.js +97 -97
  818. package/src/engine/ecs/ik/ik_bone_chain.js +85 -85
  819. package/src/engine/ecs/ik/ik_probe_terrain_contact.js +119 -119
  820. package/src/engine/ecs/parent/EntityNode.d.ts +1 -1
  821. package/src/engine/ecs/parent/EntityNode.js +2 -2
  822. package/src/engine/ecs/parent/ParentEntitySystem.js +255 -255
  823. package/src/engine/ecs/speaker/VoiceSystem.d.ts +2 -2
  824. package/src/engine/ecs/speaker/VoiceSystem.d.ts.map +1 -1
  825. package/src/engine/ecs/speaker/VoiceSystem.js +13 -7
  826. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +269 -269
  827. package/src/engine/ecs/storage/binary/object-v2/BinaryObjectDeSerializer.js +315 -315
  828. package/src/engine/ecs/storage/binary/object-v2/BinaryObjectSerializer.js +331 -331
  829. package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +199 -199
  830. package/src/engine/ecs/storage/binary/object-v2/ObjectBinaryFormat.js +57 -57
  831. package/src/engine/ecs/storage/binary/object-v2/ObjectSerializationAdapter.js +56 -56
  832. package/src/engine/ecs/storage/binary/object-v2/README.md +110 -110
  833. package/src/engine/ecs/storage/binary/object-v2/objectStringCodec.js +48 -48
  834. package/src/engine/ecs/storage/binary/object-v2/serializerTestHarness.js +44 -44
  835. package/src/engine/ecs/storage/populateEngineSerializationRegistry.d.ts.map +1 -1
  836. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +5 -1
  837. package/src/engine/ecs/terrain/TerrainClouds.js +97 -97
  838. package/src/engine/ecs/terrain/ecs/StubTerrainBuildWorker.js +65 -65
  839. package/src/engine/ecs/terrain/ecs/Terrain.d.ts +4 -0
  840. package/src/engine/ecs/terrain/ecs/Terrain.d.ts.map +1 -1
  841. package/src/engine/ecs/terrain/ecs/Terrain.js +790 -790
  842. package/src/engine/ecs/terrain/ecs/TerrainSystem.js +209 -209
  843. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +316 -316
  844. package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.js +416 -416
  845. package/src/engine/ecs/terrain/ecs/splat/SplatMapping.js +525 -525
  846. package/src/engine/ecs/terrain/overlay/TerrainOverlay.js +302 -302
  847. package/src/engine/ecs/terrain/tiles/TerrainTile.js +561 -561
  848. package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +896 -896
  849. package/src/engine/ecs/terrain/tiles/tile_geometry_to_meshlets.js +36 -36
  850. package/src/engine/ecs/terrain/util/loadVisibleTerrainTiles.js +129 -129
  851. package/src/engine/ecs/transform/Transform64.js +814 -814
  852. package/src/engine/ecs/transform/t64_copy_from_transform.js +35 -35
  853. package/src/engine/ecs/transform/t64_equals_transform.js +55 -55
  854. package/src/engine/ecs/transform/t64_look_rotation.js +36 -36
  855. package/src/engine/ecs/transform/t64_transform_direction.js +25 -25
  856. package/src/engine/ecs/transform/transform_copy_from_t64.js +28 -28
  857. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +345 -345
  858. package/src/engine/ecs/transform-attachment/transform_attachment_find_descendant_by_name.js +65 -65
  859. package/src/engine/ecs/transform-attachment/transform_attachment_parent_of.js +24 -24
  860. package/src/engine/ecs/util/hideEntityGracefully.js +208 -208
  861. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +446 -446
  862. package/src/engine/graphics/FULL_SCREEN_QUAD_VERTEX_SHADER.js +14 -14
  863. package/src/engine/graphics/FrameThrottle.js +2 -2
  864. package/src/engine/graphics/ecs/animation/animator/graph/AnimationState.js +207 -207
  865. package/src/engine/graphics/ecs/animation/animator/graph/AnimationTransition.js +151 -151
  866. package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.js +22 -22
  867. package/src/engine/graphics/ecs/camera/Camera.js +165 -165
  868. package/src/engine/graphics/ecs/camera/camera_active_frustum.js +25 -25
  869. package/src/engine/graphics/ecs/camera/camera_find_active.js +28 -28
  870. package/src/engine/graphics/ecs/camera/camera_traverse_active.js +18 -18
  871. package/src/engine/graphics/ecs/camera/pp/PerfectPanner.js +170 -170
  872. package/src/engine/graphics/ecs/camera/serialization/CameraSerializationAdapter.js +68 -68
  873. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +296 -296
  874. package/src/engine/graphics/ecs/decal/v2/Decal.js +220 -220
  875. package/src/engine/graphics/ecs/decal/v2/DecalSerializationAdapter.js +56 -56
  876. package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_0_1.js +38 -38
  877. package/src/engine/graphics/ecs/light/shadow/compute_view_frustum_aabb_in_space.js +62 -62
  878. package/src/engine/graphics/ecs/light/shadow/extend_shadow_camera_near_for_casters.js +77 -77
  879. package/src/engine/graphics/ecs/make_bvh_depth_range_computer.js +33 -33
  880. package/src/engine/graphics/ecs/mesh-v2/DeferredBoundsQueue.js +88 -88
  881. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +428 -428
  882. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js +303 -303
  883. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.d.ts +1 -1
  884. package/src/engine/graphics/ecs/mesh-v2/aggregate/serialization/SGMeshSerializationAdapter.js +39 -39
  885. package/src/engine/graphics/ecs/mesh-v2/sg_hierarchy_compute_bounding_box_via_parent_entity.js +36 -36
  886. package/src/engine/graphics/ecs/path/tube/build/GeometryStream.js +94 -94
  887. package/src/engine/graphics/ecs/path/tube/build/build_stream_catmullrom.js +310 -310
  888. package/src/engine/graphics/ecs/path/tube/build/build_stream_linear.js +73 -73
  889. package/src/engine/graphics/ecs/path/tube/build/computeFrenetFrames.js +199 -199
  890. package/src/engine/graphics/ecs/path/tube/build/makeTubeStream.js +217 -217
  891. package/src/engine/graphics/ecs/path/tube/build/make_cap.js +340 -340
  892. package/src/engine/graphics/ecs/path/tube/build/make_ring_faces.js +40 -40
  893. package/src/engine/graphics/ecs/path/tube/build/make_ring_vertices.js +153 -153
  894. package/src/engine/graphics/ecs/render_layers_compute_depth_range.js +64 -64
  895. package/src/engine/graphics/ecs/trail3d/Trail3D.js +483 -483
  896. package/src/engine/graphics/ecs/trail3d/Trail3DFlags.js +26 -26
  897. package/src/engine/graphics/ecs/trail3d/advance_trail.js +42 -42
  898. package/src/engine/graphics/ecs/trail3d/make_gradient_stroke.js +58 -58
  899. package/src/engine/graphics/ecs/trail3d/seed_trail_stroke.js +90 -90
  900. package/src/engine/graphics/ecs/trail3d/seed_trail_tube.js +75 -75
  901. package/src/engine/graphics/ecs/trail3d/trail_head_position.js +19 -19
  902. package/src/engine/graphics/ecs/water/Water.js +104 -104
  903. package/src/engine/graphics/geometry/AttributeData.js +84 -84
  904. package/src/engine/graphics/geometry/buffered/geometry_compute_vertex_normals_indexed.js +49 -49
  905. package/src/engine/graphics/geometry/buffered/query/GeometrySpatialQueryAccelerator.js +288 -288
  906. package/src/engine/graphics/geometry/buffered/query/nearest_point_on_triangle_record.js +87 -87
  907. package/src/engine/graphics/geometry/buffered/read_triangle_vertices.js +102 -102
  908. package/src/engine/graphics/geometry/bvh/buffered/bvh32_from_buffered_geometry.js +52 -52
  909. package/src/engine/graphics/geometry/bvh/buffered/bvh32_from_indexed_geometry.js +20 -20
  910. package/src/engine/graphics/geometry/bvh/buffered/bvh32_from_unindexed_geometry.js +19 -19
  911. package/src/engine/graphics/geometry/optimization/geometry_optimize_uv_tension.js +135 -135
  912. package/src/engine/graphics/impostors/voxel/README.md +149 -149
  913. package/src/engine/graphics/impostors/voxel/VoxelImpostorDescription.js +141 -141
  914. package/src/engine/graphics/particles/node-based/codegen/glsl/getTypeByteSize.js +20 -20
  915. package/src/engine/graphics/particles/node-based/nodes/FloatConstant.d.ts +2 -0
  916. package/src/engine/graphics/particles/node-based/nodes/FloatConstant.d.ts.map +1 -1
  917. package/src/engine/graphics/particles/node-based/nodes/ReadFloatUniform.d.ts +2 -0
  918. package/src/engine/graphics/particles/node-based/nodes/ReadFloatUniform.d.ts.map +1 -1
  919. package/src/engine/graphics/particles/node-based/nodes/ReadVelocity.d.ts +2 -0
  920. package/src/engine/graphics/particles/node-based/nodes/ReadVelocity.d.ts.map +1 -1
  921. package/src/engine/graphics/particles/node-based/nodes/ShaderNode.d.ts +1 -2
  922. package/src/engine/graphics/particles/node-based/nodes/ShaderNode.d.ts.map +1 -1
  923. package/src/engine/graphics/particles/node-based/nodes/Vector3Constant.d.ts +2 -0
  924. package/src/engine/graphics/particles/node-based/nodes/Vector3Constant.d.ts.map +1 -1
  925. package/src/engine/graphics/particles/node-based/nodes/Vector3Merge.d.ts +2 -0
  926. package/src/engine/graphics/particles/node-based/nodes/Vector3Merge.d.ts.map +1 -1
  927. package/src/engine/graphics/particles/node-based/nodes/Vector3Split.d.ts +2 -0
  928. package/src/engine/graphics/particles/node-based/nodes/Vector3Split.d.ts.map +1 -1
  929. package/src/engine/graphics/particles/node-based/nodes/WriteVelocity.d.ts +2 -0
  930. package/src/engine/graphics/particles/node-based/nodes/WriteVelocity.d.ts.map +1 -1
  931. package/src/engine/graphics/particles/node-based/nodes/attribute/ReadVector3Attribute.d.ts +2 -0
  932. package/src/engine/graphics/particles/node-based/nodes/attribute/ReadVector3Attribute.d.ts.map +1 -1
  933. package/src/engine/graphics/particles/node-based/nodes/attribute/WriteVector3Attribute.d.ts +2 -0
  934. package/src/engine/graphics/particles/node-based/nodes/attribute/WriteVector3Attribute.d.ts.map +1 -1
  935. package/src/engine/graphics/particles/node-based/nodes/math/AddFloatNode.d.ts +2 -0
  936. package/src/engine/graphics/particles/node-based/nodes/math/AddFloatNode.d.ts.map +1 -1
  937. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Add.d.ts +2 -0
  938. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Add.d.ts.map +1 -1
  939. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Divide.d.ts +2 -0
  940. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Divide.d.ts.map +1 -1
  941. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Multiply.d.ts +2 -0
  942. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Multiply.d.ts.map +1 -1
  943. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Subtract.d.ts +2 -0
  944. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Subtract.d.ts.map +1 -1
  945. package/src/engine/graphics/particles/node-based/nodes/noise/CurlNoiseNode.d.ts +2 -0
  946. package/src/engine/graphics/particles/node-based/nodes/noise/CurlNoiseNode.d.ts.map +1 -1
  947. package/src/engine/graphics/particles/node-based/nodes/particle_data_type_component_count.js +45 -45
  948. package/src/engine/graphics/particles/particular/engine/ParticularEngine.js +229 -229
  949. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts +2 -10
  950. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
  951. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +1149 -1149
  952. package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +472 -472
  953. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +2 -2
  954. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.js +2 -2
  955. package/src/engine/graphics/particles/particular/engine/parameter/ParameterSet.d.ts.map +1 -1
  956. package/src/engine/graphics/particles/particular/engine/parameter/ParameterSet.js +3 -5
  957. package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.js +135 -135
  958. package/src/engine/graphics/particles/particular/engine/utils/distribute_points_on_indexed_triangles.js +168 -168
  959. package/src/engine/graphics/render/forward_plus/plugin/forwardPlusMaterialMarker.js +18 -18
  960. package/src/engine/graphics/render/forward_plus/read_frustum_corner.js +2 -2
  961. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +219 -219
  962. package/src/engine/graphics/render/frame_graph/FrameGraph.js +900 -900
  963. package/src/engine/graphics/render/frame_graph/FrameGraphScope.js +72 -72
  964. package/src/engine/graphics/render/frame_graph/FrameGraphState.js +39 -39
  965. package/src/engine/graphics/render/frame_graph/ResourceEntry.js +96 -96
  966. package/src/engine/graphics/render/gizmo/GizmoShapeBuffer.js +105 -105
  967. package/src/engine/graphics/render/gizmo/GizmoShapeRenderingInterface.js +162 -162
  968. package/src/engine/graphics/render/layers/RenderLayer.js +95 -95
  969. package/src/engine/graphics/sh3/build_injected_shader.js +56 -56
  970. package/src/engine/graphics/sh3/grid_dilate_average.js +175 -175
  971. package/src/engine/graphics/sh3/path_tracer/BufferedGeometryBVH.js +506 -506
  972. package/src/engine/graphics/sh3/path_tracer/PathTracedMesh.js +161 -161
  973. package/src/engine/graphics/sh3/path_tracer/PathTracedRenderer.js +205 -205
  974. package/src/engine/graphics/sh3/path_tracer/PathTracedScene.js +698 -698
  975. package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +490 -490
  976. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.js +2 -2
  977. package/src/engine/graphics/sh3/path_tracer/make_sky_hosek.js +45 -45
  978. package/src/engine/graphics/sh3/path_tracer/populate_path_traced_scene_from_ecd.js +73 -73
  979. package/src/engine/graphics/sh3/path_tracer/ray_hit_apply_transform.js +32 -32
  980. package/src/engine/graphics/sh3/path_tracer/texture/apply_texture_clamping_to_coordinate.js +28 -28
  981. package/src/engine/graphics/sh3/path_tracer/texture/sample_material.js +142 -142
  982. package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.js +70 -70
  983. package/src/engine/graphics/sh3/sky/hosek/sky_hosek_compute_irradiance_by_direction.js +388 -388
  984. package/src/engine/graphics/shaders/chunks/glsl_octahedral_impostor.js +277 -277
  985. package/src/engine/graphics/shaders/chunks/glsl_voxel_impostor_splat.js +57 -57
  986. package/src/engine/graphics/shadows/vsm.glsl.js +43 -43
  987. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.js +81 -81
  988. package/src/engine/graphics/texture/EnvironmentTextureProjection.js +15 -15
  989. package/src/engine/graphics/texture/channel_count_to_format_prefix.js +26 -26
  990. package/src/engine/graphics/texture/isImageBitmap.js +2 -2
  991. package/src/engine/graphics/texture/reflection/convolve_equirectangular_reflection.js +189 -189
  992. package/src/engine/graphics/texture/reflection/equirectangular_reflection_roughness.js +51 -51
  993. package/src/engine/graphics/texture/sampler/HarmonicDiffusionGrid.js +145 -145
  994. package/src/engine/graphics/texture/sampler/Sampler2DArray.js +172 -172
  995. package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +466 -466
  996. package/src/engine/graphics/texture/sampler/compare/flip/FlipParameters.js +18 -18
  997. package/src/engine/graphics/texture/sampler/compare/flip/FlipPooling.js +33 -33
  998. package/src/engine/graphics/texture/sampler/compare/flip/flip_build_feature_kernel.js +147 -147
  999. package/src/engine/graphics/texture/sampler/compare/flip/flip_build_spatial_kernel.js +177 -177
  1000. package/src/engine/graphics/texture/sampler/compare/flip/flip_compute_color_difference.js +104 -104
  1001. package/src/engine/graphics/texture/sampler/compare/flip/flip_compute_feature_difference.js +76 -76
  1002. package/src/engine/graphics/texture/sampler/compare/flip/flip_compute_pixels_per_degree.js +34 -34
  1003. package/src/engine/graphics/texture/sampler/compare/flip/flip_constants.js +77 -77
  1004. package/src/engine/graphics/texture/sampler/compare/flip/flip_filter_feature.js +48 -48
  1005. package/src/engine/graphics/texture/sampler/compare/flip/flip_filter_spatial.js +86 -86
  1006. package/src/engine/graphics/texture/sampler/compare/flip/flip_pool.js +71 -71
  1007. package/src/engine/graphics/texture/sampler/compare/flip/flip_srgb_to_ycxcz.js +55 -55
  1008. package/src/engine/graphics/texture/sampler/compare/flip/sampler2d_flip_ldr.js +80 -80
  1009. package/src/engine/graphics/texture/sampler/filter/SeparableKernel.js +82 -82
  1010. package/src/engine/graphics/texture/sampler/filter/sampler2d_convolve_separable.js +122 -122
  1011. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_lanczos.js +148 -148
  1012. package/src/engine/graphics/texture/sampler/sampler2d_channel_apply_lut.js +82 -82
  1013. package/src/engine/graphics/texture/sampler/sampler2d_combine.js +67 -67
  1014. package/src/engine/graphics/texture/sampler/sampler2d_linear_f16_to_srgb_u8.js +54 -54
  1015. package/src/engine/graphics/texture/sampler/sampler2d_sample_equirectangular_direction.js +63 -63
  1016. package/src/engine/graphics/texture/sampler/sampler2d_srgb_to_linear.js +33 -33
  1017. package/src/engine/graphics/texture/sampler/sampler2d_srgb_u8_to_linear_f16.js +68 -68
  1018. package/src/engine/graphics/texture/shade_image_preview.js +103 -103
  1019. package/src/engine/graphics/trail/TrailSpawnMode.js +20 -20
  1020. package/src/engine/graphics/trail/tube/TubeX.js +573 -573
  1021. package/src/engine/graphics/trail/tube/TubeXMaterialSpec.js +58 -58
  1022. package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.js +34 -34
  1023. package/src/engine/graphics/trail/tube/tube_attributes_spec.js +69 -69
  1024. package/src/engine/graphics/trail/tube/tube_frame.js +83 -83
  1025. package/src/engine/graphics3/AnimationGraphSystem3.js +329 -329
  1026. package/src/engine/graphics3/AnimationSystem3.js +352 -352
  1027. package/src/engine/graphics3/CameraSystem3.js +170 -170
  1028. package/src/engine/graphics3/DecalSystem3.js +441 -441
  1029. package/src/engine/graphics3/FogOfWarSystem3.js +265 -265
  1030. package/src/engine/graphics3/GraphicsEngine3.js +776 -776
  1031. package/src/engine/graphics3/HighlightSystem3.js +241 -241
  1032. package/src/engine/graphics3/LightSystem3.js +211 -211
  1033. package/src/engine/graphics3/MeshSystem3.js +646 -646
  1034. package/src/engine/graphics3/ParticleEmitterSystem3.js +289 -289
  1035. package/src/engine/graphics3/PathDisplaySystem3.js +309 -309
  1036. package/src/engine/graphics3/PickingQuery.js +48 -48
  1037. package/src/engine/graphics3/PickingResult.js +47 -47
  1038. package/src/engine/graphics3/PickingSystem3.js +273 -273
  1039. package/src/engine/graphics3/ShadeCameraAdapter.js +55 -55
  1040. package/src/engine/graphics3/ShadedGeometrySystem3.js +169 -169
  1041. package/src/engine/graphics3/TerrainSystem3.js +566 -566
  1042. package/src/engine/graphics3/TooltipComponentSystem3.js +328 -328
  1043. package/src/engine/graphics3/Trail3DSystem3.js +221 -221
  1044. package/src/engine/graphics3/VolumetricLightMap.d.ts +90 -0
  1045. package/src/engine/graphics3/VolumetricLightMap.d.ts.map +1 -0
  1046. package/src/engine/graphics3/VolumetricLightMap.js +160 -0
  1047. package/src/engine/graphics3/VolumetricLightMapSerializationAdapter.d.ts +32 -0
  1048. package/src/engine/graphics3/VolumetricLightMapSerializationAdapter.d.ts.map +1 -0
  1049. package/src/engine/graphics3/VolumetricLightMapSerializationAdapter.js +67 -0
  1050. package/src/engine/graphics3/VolumetricLightMapSystem3.d.ts +98 -0
  1051. package/src/engine/graphics3/VolumetricLightMapSystem3.d.ts.map +1 -0
  1052. package/src/engine/graphics3/VolumetricLightMapSystem3.js +261 -0
  1053. package/src/engine/graphics3/WaterSystem3.js +293 -293
  1054. package/src/engine/graphics3/animation/ClipPlayback.js +84 -84
  1055. package/src/engine/graphics3/animation/wrap_clip_time.js +23 -23
  1056. package/src/engine/graphics3/animation/write_graph_playback.js +48 -48
  1057. package/src/engine/graphics3/camera_sync_from_transform.js +29 -29
  1058. package/src/engine/graphics3/debug/gizmo_view_from_camera.js +48 -48
  1059. package/src/engine/graphics3/decal/DECAL_CLUSTER.js +61 -61
  1060. package/src/engine/graphics3/decal/DECAL_GPU_RECORD.js +117 -117
  1061. package/src/engine/graphics3/decal/DecalAtlas.js +194 -194
  1062. package/src/engine/graphics3/decal/DecalAtlasFill.js +32 -32
  1063. package/src/engine/graphics3/decal/GPUDecalRenderer.js +360 -360
  1064. package/src/engine/graphics3/decal/chunk_decal_intersects_frustum.js +59 -59
  1065. package/src/engine/graphics3/decal/chunk_decal_sampling_info.js +57 -57
  1066. package/src/engine/graphics3/decal/chunk_decal_surface_frame.js +54 -54
  1067. package/src/engine/graphics3/decal/decal_atlas_border.js +69 -69
  1068. package/src/engine/graphics3/decal/decal_gpu_records.js +120 -120
  1069. package/src/engine/graphics3/decal/decal_material_samplers.js +109 -109
  1070. package/src/engine/graphics3/decal/graph_build_decal_clusters.js +212 -212
  1071. package/src/engine/graphics3/decal/shader_cluster_assign_decals.js +207 -207
  1072. package/src/engine/graphics3/decal/shader_cull_decals_frustum.js +108 -108
  1073. package/src/engine/graphics3/highlight/GPUHighlightRenderer.js +151 -151
  1074. package/src/engine/graphics3/highlight/HIGHLIGHT_OUTLINE.js +23 -23
  1075. package/src/engine/graphics3/highlight/chunk_highlight_lookup.js +53 -53
  1076. package/src/engine/graphics3/highlight/pack_highlight_color.js +44 -44
  1077. package/src/engine/graphics3/highlight/pack_highlight_table.js +74 -74
  1078. package/src/engine/graphics3/highlight/shader_highlight_outline.js +150 -150
  1079. package/src/engine/graphics3/load_cube_environment.js +68 -68
  1080. package/src/engine/graphics3/make_default_environment.js +107 -107
  1081. package/src/engine/graphics3/particles/particle_gpu_records.js +221 -221
  1082. package/src/engine/graphics3/path/build_tube_path_streams.js +98 -98
  1083. package/src/engine/graphics3/path/tube_stream_write_geometry.js +90 -90
  1084. package/src/engine/graphics3/preview/ModelPreviewFraming.js +35 -35
  1085. package/src/engine/graphics3/preview/make_model_preview_scene.js +154 -154
  1086. package/src/engine/graphics3/preview/make_model_thumbnail.js +48 -48
  1087. package/src/engine/graphics3/preview/model_preview_framing.js +70 -70
  1088. package/src/engine/graphics3/shade_bundle_bounds.js +55 -55
  1089. package/src/engine/graphics3/shade_camera_projection_ray.js +77 -77
  1090. package/src/engine/graphics3/shade_node_to_entity_composition.js +84 -84
  1091. package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.js +481 -481
  1092. package/src/engine/graphics3/terrain/chunk_terrain_grid_overlay.js +61 -61
  1093. package/src/engine/graphics3/terrain/chunk_terrain_splat_mix.js +66 -66
  1094. package/src/engine/graphics3/terrain/pack_terrain_row_table.js +53 -53
  1095. package/src/engine/graphics3/terrain/shader_terrain_splat.js +215 -215
  1096. package/src/engine/graphics3/trail/trail_tube_write_geometry.js +158 -158
  1097. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +717 -717
  1098. package/src/engine/input/analog/apply_radial_dead_zone.js +38 -38
  1099. package/src/engine/input/devices/GamepadDevice.js +466 -466
  1100. package/src/engine/input/devices/ManualInputDevice.js +152 -152
  1101. package/src/engine/input/devices/PointerCoordinates.js +26 -26
  1102. package/src/engine/input/devices/events/GamepadEvents.js +10 -10
  1103. package/src/engine/input/devices/gamepad/GamepadAxes.js +19 -19
  1104. package/src/engine/input/devices/gamepad/GamepadButtons.js +29 -29
  1105. package/src/engine/input/devices/gamepad/GamepadCoordinates.js +17 -17
  1106. package/src/engine/input/devices/gamepad/GamepadDeviceLayout.js +323 -323
  1107. package/src/engine/input/devices/gamepad/GamepadHandle.js +286 -286
  1108. package/src/engine/input/devices/gamepad/GamepadLayout.js +160 -160
  1109. package/src/engine/input/devices/gamepad/GamepadStandardMapping.js +31 -31
  1110. package/src/engine/input/devices/gamepad/GamepadStick.js +169 -169
  1111. package/src/engine/input/devices/gamepad/GamepadStickCalibration.js +119 -119
  1112. package/src/engine/input/devices/gamepad/GamepadStickCalibrator.js +250 -250
  1113. package/src/engine/input/devices/gamepad/gamepad_layout_database.js +144 -144
  1114. package/src/engine/input/devices/gamepad/gamepad_read_hat_axis.js +61 -61
  1115. package/src/engine/input/devices/gamepad/gamepad_write_dpad_vector.js +30 -30
  1116. package/src/engine/input/devices/gamepad/prototypeGamepadTester.js +2124 -2124
  1117. package/src/engine/input/devices/mouse/MouseButtons.js +22 -22
  1118. package/src/engine/input/ecs/components/Input.js +118 -118
  1119. package/src/engine/input/ecs/components/InputController.js +78 -78
  1120. package/src/engine/input/ecs/ism/ISM_DESIGN.md +1523 -1523
  1121. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +627 -627
  1122. package/src/engine/input/ecs/ism/InputActionEvent.js +40 -40
  1123. package/src/engine/input/ecs/ism/InputBinding.js +71 -71
  1124. package/src/engine/input/ecs/ism/InputCoordinateKind.js +25 -25
  1125. package/src/engine/input/ecs/ism/InputCoordinateSource.js +86 -86
  1126. package/src/engine/input/ecs/ism/InputDirection.js +33 -33
  1127. package/src/engine/input/ecs/ism/InputMapProgram.js +236 -236
  1128. package/src/engine/input/ecs/ism/InputMapSystem.js +976 -976
  1129. package/src/engine/input/ecs/ism/InputOcclusion.js +31 -31
  1130. package/src/engine/input/ecs/ism/InputSource.js +67 -67
  1131. package/src/engine/input/ecs/ism/InputSourceTable.js +107 -107
  1132. package/src/engine/input/ecs/ism/coordinate/InputCoordinateChannel.js +93 -93
  1133. package/src/engine/input/ecs/ism/coordinate/InputCoordinateChannelType.js +11 -11
  1134. package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.js +153 -153
  1135. package/src/engine/input/ecs/ism/coordinate/InputCoordinateSwitches.js +160 -160
  1136. package/src/engine/input/ecs/ism/device/GAMEPAD_INPUT_DEVICE_ID.js +9 -9
  1137. package/src/engine/input/ecs/ism/device/GamepadInputDeviceAdapter.js +88 -88
  1138. package/src/engine/input/ecs/ism/device/InputDeviceAdapter.js +72 -72
  1139. package/src/engine/input/ecs/ism/device/KEYBOARD_INPUT_DEVICE_ID.js +9 -9
  1140. package/src/engine/input/ecs/ism/device/KeyboardInputDeviceAdapter.js +63 -63
  1141. package/src/engine/input/ecs/ism/device/ManualInputDeviceAdapter.js +55 -55
  1142. package/src/engine/input/ecs/ism/device/POINTER_INPUT_DEVICE_ID.js +9 -9
  1143. package/src/engine/input/ecs/ism/device/PointerInputDeviceAdapter.js +160 -160
  1144. package/src/engine/input/ecs/ism/map/InputBinding.js +88 -88
  1145. package/src/engine/input/ecs/ism/map/InputCoordinateBinding.js +102 -102
  1146. package/src/engine/input/ecs/ism/map/InputLayer.js +220 -220
  1147. package/src/engine/input/ecs/ism/map/InputMap.js +331 -331
  1148. package/src/engine/input/ecs/ism/prototypeInputMap.js +309 -309
  1149. package/src/engine/input/ecs/ism/trigger/InputTrigger.js +148 -148
  1150. package/src/engine/input/ecs/ism/trigger/InputTriggerChord.js +173 -173
  1151. package/src/engine/input/ecs/ism/trigger/InputTriggerGamepadButton.js +37 -37
  1152. package/src/engine/input/ecs/ism/trigger/InputTriggerHold.js +176 -176
  1153. package/src/engine/input/ecs/ism/trigger/InputTriggerKey.js +39 -39
  1154. package/src/engine/input/ecs/ism/trigger/InputTriggerMouseButton.js +38 -38
  1155. package/src/engine/input/ecs/ism/trigger/InputTriggerRelease.js +120 -120
  1156. package/src/engine/input/ecs/ism/trigger/InputTriggerSequence.js +315 -315
  1157. package/src/engine/input/ecs/ism/trigger/InputTriggerSwitch.js +105 -105
  1158. package/src/engine/input/ecs/ism/trigger/InputTriggerType.js +17 -17
  1159. package/src/engine/input/ecs/systems/InputControllerSystem.js +253 -253
  1160. package/src/engine/input/ecs/systems/InputSystem.js +162 -162
  1161. package/src/engine/intelligence/behavior/primitive/FailingBehaviorSerializationAdapter.js +25 -25
  1162. package/src/engine/intelligence/behavior/primitive/SucceedingBehaviorSerializationAdapter.js +26 -26
  1163. package/src/engine/intelligence/behavior/util/AsynchronousDelayAction.js +55 -55
  1164. package/src/engine/interpolation/BinaryInterpolationAdapter.js +56 -56
  1165. package/src/engine/interpolation/Interpoland.js +49 -49
  1166. package/src/engine/interpolation/Interpolated.js +149 -149
  1167. package/src/engine/interpolation/PoseInterpolationAdapter.js +61 -61
  1168. package/src/engine/interpolation/TransformPoseSerializationAdapter.js +57 -57
  1169. package/src/engine/interpolation/pose_interpoland.js +27 -27
  1170. package/src/engine/navigation/ecs/path_following/PathFollower.js +222 -222
  1171. package/src/engine/navigation/mesh/NavigationMesh.js +145 -145
  1172. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +661 -0
  1173. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +229 -229
  1174. package/src/engine/navigation/mesh/build/clip_soup_against_overhangs.d.ts.map +1 -1
  1175. package/src/engine/navigation/mesh/build/clip_soup_against_overhangs.js +628 -520
  1176. package/src/engine/network/CONGESTION_CONTROL.md +87 -87
  1177. package/src/engine/network/README.md +52 -52
  1178. package/src/engine/network/adapters/QuaternionInterpolationAdapter.js +43 -43
  1179. package/src/engine/network/adapters/TransformInterpolationAdapter.js +84 -84
  1180. package/src/engine/network/adapters/TransformReplicationAdapter.js +87 -87
  1181. package/src/engine/network/adapters/Vector3InterpolationAdapter.js +46 -46
  1182. package/src/engine/network/convertPathToURL.js +2 -2
  1183. package/src/engine/network/core/MalformedPacketError.js +26 -26
  1184. package/src/engine/network/core/quantize/quantize_float.js +73 -73
  1185. package/src/engine/network/core/quantize/quantize_position.js +65 -65
  1186. package/src/engine/network/core/sequence/ack_bitfield.js +77 -77
  1187. package/src/engine/network/core/sequence/seq16.js +69 -69
  1188. package/src/engine/network/core/sequence/seq32.js +73 -73
  1189. package/src/engine/network/ecs/NetworkSystem.js +84 -84
  1190. package/src/engine/network/ecs/components/NetworkIdentity.js +73 -73
  1191. package/src/engine/network/ecs/owner_authorization.js +55 -55
  1192. package/src/engine/network/ecs/serialization/NetworkIdentitySerializationAdapter.js +64 -64
  1193. package/src/engine/network/replication/ScopeFilter.js +71 -71
  1194. package/src/engine/network/sim/ActionLog.js +152 -152
  1195. package/src/engine/network/sim/SimAction.js +273 -273
  1196. package/src/engine/network/sim/Snapshotter.js +222 -222
  1197. package/src/engine/network/state/FrameBufferRing.js +168 -168
  1198. package/src/engine/network/state/InputRing.js +134 -134
  1199. package/src/engine/network/state/PriorityAccumulator.js +180 -180
  1200. package/src/engine/network/time/TimeDilation.js +62 -62
  1201. package/src/engine/network/transport/Channel.js +336 -336
  1202. package/src/engine/network/transport/Transport.js +203 -203
  1203. package/src/engine/network/transport/adapters/NodeUDPTransport.js +186 -186
  1204. package/src/engine/network/transport/adapters/WebRTCDataChannelTransport.js +105 -105
  1205. package/src/engine/network/transport/fragments/fragment_send.js +147 -147
  1206. package/src/engine/network/transport/fragments/packet_size.js +101 -101
  1207. package/src/engine/network/xhr.js +23 -23
  1208. package/src/engine/physics/BULLET_REVIEW.md +945 -945
  1209. package/src/engine/physics/CANNON_REVIEW.md +1300 -1300
  1210. package/src/engine/physics/CONSTRAINT_SOLVER_BENCH_LOG.md +208 -208
  1211. package/src/engine/physics/CONSTRAINT_SOLVER_IMPROVEMENTS_PLAN.md +364 -364
  1212. package/src/engine/physics/INTEPOLATION_SYSTEM_PLAN.md +287 -287
  1213. package/src/engine/physics/JOLT_REVIEW.md +913 -913
  1214. package/src/engine/physics/PLAN.md +1120 -1094
  1215. package/src/engine/physics/RAPIER_REVIEW.md +934 -934
  1216. package/src/engine/physics/REVIEW_001_ACTION_PLAN.md +642 -642
  1217. package/src/engine/physics/REVIEW_002.md +151 -151
  1218. package/src/engine/physics/REVIEW_003.md +166 -166
  1219. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +97 -97
  1220. package/src/engine/physics/constraint/DofMode.js +35 -35
  1221. package/src/engine/physics/constraint/solve_constraints.js +1 -1
  1222. package/src/engine/physics/contact/combine_material.js +35 -35
  1223. package/src/engine/physics/ecs/BodyKind.js +29 -29
  1224. package/src/engine/physics/ecs/Collider.js +177 -177
  1225. package/src/engine/physics/ecs/ColliderFlags.js +15 -15
  1226. package/src/engine/physics/ecs/ColliderSerializationAdapter.js +37 -37
  1227. package/src/engine/physics/ecs/Joint.js +475 -475
  1228. package/src/engine/physics/ecs/JointSerializationAdapter.js +72 -72
  1229. package/src/engine/physics/ecs/PhysicsSystem.d.ts +3 -0
  1230. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  1231. package/src/engine/physics/ecs/PhysicsSystem.js +7 -2
  1232. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.js +37 -37
  1233. package/src/engine/physics/ecs/SleepState.js +12 -12
  1234. package/src/engine/physics/ecs/find_non_finite_physics_state.js +76 -76
  1235. package/src/engine/physics/fluid/FluidField.js +867 -867
  1236. package/src/engine/physics/fluid/FluidSimulator.js +832 -832
  1237. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +243 -243
  1238. package/src/engine/physics/fluid/SliceVisualiser.js +190 -190
  1239. package/src/engine/physics/fluid/ecs/FluidComponent.js +239 -239
  1240. package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.js +89 -89
  1241. package/src/engine/physics/fluid/ecs/FluidObstacle.js +97 -97
  1242. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  1243. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.js +348 -348
  1244. package/src/engine/physics/fluid/ecs/FluidSystem.js +142 -142
  1245. package/src/engine/physics/fluid/ecs/FluidWorkerCore.js +123 -123
  1246. package/src/engine/physics/fluid/ecs/WorkerFluidSystem.js +395 -395
  1247. package/src/engine/physics/fluid/ecs/fluid.worker.js +12 -12
  1248. package/src/engine/physics/fluid/ecs/fluid_build_world_to_grid.js +32 -32
  1249. package/src/engine/physics/fluid/ecs/fluid_gather_visible_effectors.js +47 -47
  1250. package/src/engine/physics/fluid/ecs/fluid_reanchor_field.js +85 -85
  1251. package/src/engine/physics/fluid/ecs/fluid_sync_effectors_from_transform.js +16 -16
  1252. package/src/engine/physics/fluid/ecs/fluid_worker_protocol.js +111 -111
  1253. package/src/engine/physics/fluid/ecs/makeFluidWorker.js +18 -18
  1254. package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +81 -81
  1255. package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +202 -202
  1256. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +257 -257
  1257. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +405 -405
  1258. package/src/engine/physics/fluid/prototype.js +126 -126
  1259. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.js +143 -143
  1260. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +162 -162
  1261. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +107 -107
  1262. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.js +131 -131
  1263. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +90 -90
  1264. package/src/engine/physics/fluid/solver/v3_grid_limit8_at_indices.js +38 -38
  1265. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.js +77 -77
  1266. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.js +113 -113
  1267. package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.js +92 -92
  1268. package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.js +107 -107
  1269. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +135 -135
  1270. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +511 -511
  1271. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +108 -108
  1272. package/src/engine/physics/fluid/solver/v3_mac_advect_maccormack_velocity.js +317 -317
  1273. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.js +236 -236
  1274. package/src/engine/physics/fluid/solver/v3_mac_advect_sl_velocity.js +217 -217
  1275. package/src/engine/physics/fluid/solver/v3_mac_apply_vorticity_confinement.js +174 -174
  1276. package/src/engine/physics/fluid/solver/v3_mac_clip_trace.js +95 -95
  1277. package/src/engine/physics/fluid/solver/v3_mac_compute_divergence.js +77 -77
  1278. package/src/engine/physics/fluid/solver/v3_mac_compute_face_solid.js +131 -131
  1279. package/src/engine/physics/fluid/solver/v3_mac_subtract_pressure_gradient.js +104 -104
  1280. package/src/engine/physics/inertia/world_inverse_inertia.js +160 -160
  1281. package/src/engine/physics/integration/integrate_position.js +97 -97
  1282. package/src/engine/physics/narrowphase/box_box_manifold.js +681 -681
  1283. package/src/engine/physics/narrowphase/box_triangle_contact.js +906 -906
  1284. package/src/engine/physics/narrowphase/capsule_triangle_contact.js +395 -395
  1285. package/src/engine/physics/narrowphase/compute_penetration.js +369 -369
  1286. package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.js +55 -55
  1287. package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.js +37 -37
  1288. package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.js +117 -117
  1289. package/src/engine/physics/narrowphase/narrowphase_step.js +1738 -1738
  1290. package/src/engine/physics/narrowphase/reduce_manifold_contacts.js +74 -74
  1291. package/src/engine/physics/narrowphase/refine_ray_hit.d.ts +12 -11
  1292. package/src/engine/physics/narrowphase/refine_ray_hit.d.ts.map +1 -1
  1293. package/src/engine/physics/narrowphase/refine_ray_hit.js +228 -36
  1294. package/src/engine/physics/narrowphase/sphere_sphere_contact.js +52 -52
  1295. package/src/engine/physics/narrowphase/sphere_triangle_contact.js +138 -138
  1296. package/src/engine/physics/persistence/solver_caches.js +309 -309
  1297. package/src/engine/physics/queries/overlap_shape.js +187 -187
  1298. package/src/engine/physics/queries/raycast.d.ts +7 -4
  1299. package/src/engine/physics/queries/raycast.d.ts.map +1 -1
  1300. package/src/engine/physics/queries/raycast.js +11 -5
  1301. package/src/engine/physics/queries/shape_cast.js +417 -417
  1302. package/src/engine/physics/solver/apply_impulse_to_body.js +86 -86
  1303. package/src/engine/physics/solver/friction_cone.js +37 -37
  1304. package/src/engine/physics/solver/solve_contacts.js +1 -1
  1305. package/src/engine/platform/WebEnginePlatform.d.ts.map +1 -1
  1306. package/src/engine/platform/WebEnginePlatform.js +1 -2
  1307. package/src/engine/scene/SerializedScene.d.ts +2 -2
  1308. package/src/engine/scene/SerializedScene.d.ts.map +1 -1
  1309. package/src/engine/scene/transitionToScene.js +121 -121
  1310. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  1311. package/src/engine/simulation/Ticker.js +33 -0
  1312. package/src/engine/sound/ecs/audio/LiveEmitterSet.js +345 -345
  1313. package/src/engine/sound/ecs/audio/SpatialAudioIndex.js +140 -140
  1314. package/src/engine/sound/simulation/AcousticSimulator.js +646 -646
  1315. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +432 -432
  1316. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +250 -250
  1317. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +322 -322
  1318. package/src/engine/sound/simulation/README.md +277 -277
  1319. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +261 -261
  1320. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +121 -121
  1321. package/src/engine/sound/simulation/configureAcousticSimulation.js +48 -48
  1322. package/src/engine/sound/simulation/core/AcousticMedium.js +113 -113
  1323. package/src/engine/sound/simulation/core/AcousticMediumSerializationAdapter.js +27 -27
  1324. package/src/engine/sound/simulation/core/AcousticOccluderIndex.js +312 -312
  1325. package/src/engine/sound/simulation/core/AcousticRegionIndex.js +159 -159
  1326. package/src/engine/sound/simulation/core/AcousticSolution.js +90 -90
  1327. package/src/engine/sound/simulation/core/AcousticSourceState.js +109 -109
  1328. package/src/engine/sound/simulation/core/AcousticVolumeRegion.js +73 -73
  1329. package/src/engine/sound/simulation/core/OcclusionSolver.js +112 -112
  1330. package/src/engine/sound/simulation/core/RayHit.js +50 -50
  1331. package/src/engine/sound/simulation/core/VolumeField.js +149 -149
  1332. package/src/engine/sound/simulation/definition/AcousticDirectivity.js +114 -114
  1333. package/src/engine/sound/simulation/definition/AcousticDirectivitySerializationAdapter.js +30 -30
  1334. package/src/engine/sound/simulation/definition/AcousticMaterial.js +122 -122
  1335. package/src/engine/sound/simulation/definition/AcousticMaterialSerializationAdapter.js +32 -32
  1336. package/src/engine/sound/simulation/ecs/AcousticBody.js +48 -48
  1337. package/src/engine/sound/simulation/ecs/AcousticBodySerializationAdapter.js +34 -34
  1338. package/src/engine/sound/simulation/ecs/AcousticProbeFieldSystem.js +64 -64
  1339. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.js +75 -75
  1340. package/src/engine/sound/simulation/ecs/AcousticVolume.js +74 -74
  1341. package/src/engine/sound/simulation/ecs/AcousticVolumeSerializationAdapter.js +37 -37
  1342. package/src/engine/sound/simulation/ecs/AcousticVolumeSystem.js +66 -66
  1343. package/src/engine/sound/simulation/probe/AcousticProbeField.js +578 -578
  1344. package/src/engine/sound/simulation/probe/AcousticProbeFieldSerializationAdapter.js +60 -60
  1345. package/src/engine/sound/simulation/probe/ProbeFieldPathingSolution.js +64 -64
  1346. package/src/engine/sound/simulation/probe/ProbeVisibilityRecheck.js +132 -132
  1347. package/src/engine/sound/simulation/probe/acoustic_probe_transfer.js +103 -103
  1348. package/src/engine/sound/simulation/probe/acoustic_trace_energy.js +136 -136
  1349. package/src/engine/sound/simulation/probe/bakeProbeField.js +169 -169
  1350. package/src/engine/sound/simulation/probe/bakeProbeReflectors.js +110 -110
  1351. package/src/engine/sound/simulation/probe/bakeReverbBands.js +110 -110
  1352. package/src/engine/sound/simulation/probe/bakeVisibility.js +148 -148
  1353. package/src/engine/sound/simulation/probe/echogram_band_rt60.js +83 -83
  1354. package/src/engine/sound/simulation/probe/probe_delaunay_edges.js +215 -215
  1355. package/src/engine/sound/simulation/probe/probe_densify_portals.js +140 -140
  1356. package/src/engine/sound/simulation/probe/probe_detect_portals.js +196 -196
  1357. package/src/engine/sound/simulation/probe/probe_edge_key.js +38 -38
  1358. package/src/engine/sound/simulation/probe/probe_edge_visible.js +41 -41
  1359. package/src/engine/sound/simulation/probe/probe_place_sdf_cover.js +82 -82
  1360. package/src/engine/sound/simulation/probe/probe_refine_connectivity.js +181 -181
  1361. package/src/engine/sound/simulation/probe/probe_sdf_grid.js +171 -171
  1362. package/src/engine/sound/simulation/probe/probe_visibility_augment.js +146 -146
  1363. package/src/engine/sound/simulation/probe/probe_visibility_bridge_components.js +167 -167
  1364. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +354 -354
  1365. package/src/engine/sound/simulation/render/ProbeReverbRenderer.js +231 -231
  1366. package/src/engine/sound/simulation/render/foaReverbImpulseResponse.js +105 -105
  1367. package/src/engine/sound/simulation/render/reverbImpulseResponse.js +66 -66
  1368. package/src/engine/sound/simulation/render/reverb_band_tails.js +93 -93
  1369. package/src/engine/sound/simulation/serialization/populateAcousticSerializationRegistry.js +25 -25
  1370. package/src/engine/sound/sopra/README.md +643 -643
  1371. package/src/engine/sound/sopra/SopraEngine.js +432 -432
  1372. package/src/engine/sound/sopra/asset/AssetManagerBufferProvider.js +71 -71
  1373. package/src/engine/sound/sopra/asset/BufferProvider.js +29 -29
  1374. package/src/engine/sound/sopra/asset/StubBufferProvider.js +58 -58
  1375. package/src/engine/sound/sopra/definition/BusDefinition.js +142 -142
  1376. package/src/engine/sound/sopra/definition/BusDefinitionSerializationAdapter.js +54 -54
  1377. package/src/engine/sound/sopra/definition/DuckingRule.js +106 -106
  1378. package/src/engine/sound/sopra/definition/DuckingRuleSerializationAdapter.js +31 -31
  1379. package/src/engine/sound/sopra/definition/EventDescription.js +262 -262
  1380. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.js +55 -55
  1381. package/src/engine/sound/sopra/definition/MixerSnapshot.js +83 -83
  1382. package/src/engine/sound/sopra/definition/MixerSnapshotSerializationAdapter.js +39 -39
  1383. package/src/engine/sound/sopra/definition/ParameterDefinition.js +117 -117
  1384. package/src/engine/sound/sopra/definition/ParameterDefinitionSerializationAdapter.js +31 -31
  1385. package/src/engine/sound/sopra/definition/VoiceStealMode.js +18 -18
  1386. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +109 -109
  1387. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.js +185 -185
  1388. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClipSerializationAdapter.js +59 -59
  1389. package/src/engine/sound/sopra/definition/clip/ContainerAudioClip.js +128 -128
  1390. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.js +226 -226
  1391. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClipSerializationAdapter.js +54 -54
  1392. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +191 -191
  1393. package/src/engine/sound/sopra/definition/clip/SampleAudioClipSerializationAdapter.js +39 -39
  1394. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.js +79 -79
  1395. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClipSerializationAdapter.js +42 -42
  1396. package/src/engine/sound/sopra/definition/clip/SilenceAudioClip.js +77 -77
  1397. package/src/engine/sound/sopra/definition/clip/SilenceAudioClipSerializationAdapter.js +27 -27
  1398. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +5 -0
  1399. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
  1400. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.js +125 -125
  1401. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClipSerializationAdapter.js +41 -41
  1402. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.js +24 -24
  1403. package/src/engine/sound/sopra/definition/effect/CompressorEffect.js +120 -120
  1404. package/src/engine/sound/sopra/definition/effect/CompressorEffectSerializationAdapter.js +31 -31
  1405. package/src/engine/sound/sopra/definition/effect/EqEffect.js +128 -128
  1406. package/src/engine/sound/sopra/definition/effect/EqEffectSerializationAdapter.js +29 -29
  1407. package/src/engine/sound/sopra/definition/effect/ReverbEffect.js +113 -113
  1408. package/src/engine/sound/sopra/definition/effect/ReverbEffectSerializationAdapter.js +25 -25
  1409. package/src/engine/sound/sopra/runtime/BusGraph.js +231 -231
  1410. package/src/engine/sound/sopra/runtime/ParameterStore.js +98 -98
  1411. package/src/engine/sound/sopra/runtime/SopraPlaybackContext.js +68 -68
  1412. package/src/engine/sound/sopra/runtime/Voice.js +145 -145
  1413. package/src/engine/sound/sopra/runtime/VoiceManager.js +136 -136
  1414. package/src/engine/sound/sopra/runtime/VoicePool.js +17 -17
  1415. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.js +42 -42
  1416. package/src/engine/sound/sopra/serialization/sopraJSON.js +99 -99
  1417. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.js +49 -49
  1418. package/src/engine/sound/sopra/util/MockAudioContext.js +224 -224
  1419. package/src/engine/sound/sopra/util/fadeOutAndStop.js +60 -60
  1420. package/src/engine/ui/DraggableAspect.js +115 -115
  1421. package/src/engine/ui/apply_pointer_tilt_3d.js +50 -50
  1422. package/src/generation/COORDINATES.md +54 -54
  1423. package/src/generation/GridGenerationResource.js +24 -24
  1424. package/src/generation/GridTaskGroup.js +214 -214
  1425. package/src/generation/REVIEW_01_ACTION_PLAN.md +628 -628
  1426. package/src/generation/automata/CaveGeneratorCellularAutomata.js +79 -79
  1427. package/src/generation/automata/CellularAutomata.js +22 -22
  1428. package/src/generation/compute_writes_union.js +25 -25
  1429. package/src/generation/filtering/CellFilter.js +117 -117
  1430. package/src/generation/filtering/core/CellFilterBinaryOperation.js +37 -37
  1431. package/src/generation/filtering/core/CellFilterOperationTertiary.js +43 -43
  1432. package/src/generation/filtering/core/CellFilterUnaryOperation.js +29 -29
  1433. package/src/generation/filtering/numeric/process/computeCellFilterSobel.js +36 -36
  1434. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.js +42 -42
  1435. package/src/generation/filtering/numeric/util/populateSampler2DFromCellFilter.js +18 -18
  1436. package/src/generation/filtering/numeric/util/write_cell_filter_to_sampler2d.js +47 -47
  1437. package/src/generation/filtering/util/cell_filter_weights_pick.js +54 -54
  1438. package/src/generation/grid/GridData.js +233 -233
  1439. package/src/generation/grid/coords/grid_to_texel.js +10 -10
  1440. package/src/generation/grid/coords/texel_to_grid.js +10 -10
  1441. package/src/generation/grid/generation/GridTaskApplyActionToCells.js +90 -90
  1442. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.js +388 -388
  1443. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.js +127 -127
  1444. package/src/generation/grid/generation/GridTaskSequence.js +58 -58
  1445. package/src/generation/grid/generation/NoopGridTaskGenerator.js +12 -12
  1446. package/src/generation/grid/generation/discrete/GridTaskActionRuleSet.js +48 -48
  1447. package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.js +146 -146
  1448. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.js +540 -540
  1449. package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +222 -222
  1450. package/src/generation/grid/generation/grid/GridTaskAddNodesFixed.js +44 -44
  1451. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +614 -614
  1452. package/src/generation/markers/GridCellActionPlaceMarker.js +244 -244
  1453. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +86 -86
  1454. package/src/generation/markers/actions/terrain/MarkerNodeActionPaintTerrain.js +266 -266
  1455. package/src/generation/markers/emitter/MarkerNodeEmitterGridCellAction.js +49 -49
  1456. package/src/generation/placement/GridCellActionTransformNearbyMarkers.js +120 -120
  1457. package/src/generation/placement/action/GridCellAction.js +45 -45
  1458. package/src/generation/placement/action/GridCellActionPlaceTags.js +140 -140
  1459. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.js +89 -89
  1460. package/src/generation/placement/action/random/CellActionSelectRandom.js +69 -69
  1461. package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.js +91 -91
  1462. package/src/generation/placement/action/util/GridCellActionSequence.js +61 -61
  1463. package/src/generation/placement/action/util/GridCellDisplacedAction.js +61 -61
  1464. package/src/generation/rules/cell/CellMatcherRemovalPreservesConnectivity.js +183 -183
  1465. package/src/generation/theme/ThemeEngine.js +666 -666
  1466. package/src/shade/RENDERER_CONTRACT.md +568 -568
  1467. package/src/shade/descriptor/texture/format/gpu_texture_format_info.js +267 -267
  1468. package/src/shade/device/ShadeDeviceFailure.js +104 -104
  1469. package/src/shade/device/ShadeDeviceFailureReason.js +41 -41
  1470. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +255 -255
  1471. package/src/shade/device/mock/REVIEW_2026_08_22.md +527 -527
  1472. package/src/shade/device/mock/SoftwareGPUBindGroup.js +23 -23
  1473. package/src/shade/device/mock/SoftwareGPUBindGroupLayout.js +22 -22
  1474. package/src/shade/device/mock/SoftwareGPUError.js +63 -63
  1475. package/src/shade/device/mock/SoftwareGPUPipeline.js +75 -75
  1476. package/src/shade/device/mock/SoftwareGPUQuerySet.js +113 -113
  1477. package/src/shade/device/mock/SoftwareGPUSampler.js +30 -30
  1478. package/src/shade/device/mock/SoftwareGPUShaderModule.js +32 -32
  1479. package/src/shade/device/mock/SoftwareGPUTextureView.js +22 -22
  1480. package/src/shade/device/mock/SoftwareGPUUncapturedErrorEvent.js +23 -23
  1481. package/src/shade/device/mock/normalize_dynamic_offsets.js +26 -26
  1482. package/src/shade/device/mock/texture_copy.js +287 -287
  1483. package/src/shade/device/timing/GPUTimer.js +285 -285
  1484. package/src/shade/device/timing/GPUTimerArray.js +205 -205
  1485. package/src/shade/playground/add_random_lights.js +49 -49
  1486. package/src/shade/playground/add_random_meshes.js +83 -83
  1487. package/src/shade/playground/animation_prototype.js +508 -508
  1488. package/src/shade/playground/animation_prototype_skinning.js +647 -647
  1489. package/src/shade/playground/animation_prototype_stress.js +765 -765
  1490. package/src/shade/playground/enable_picker.js +59 -59
  1491. package/src/shade/playground/gltf_skinned_prototype.js +560 -560
  1492. package/src/shade/playground/gltf_skinned_stress_prototype.js +387 -387
  1493. package/src/shade/playground/gltf_viewer.js +282 -282
  1494. package/src/shade/playground/load_default_environment.js +19 -19
  1495. package/src/shade/playground/main.js +2727 -2727
  1496. package/src/shade/playground/make_animated_instances.js +117 -117
  1497. package/src/shade/playground/prototype_virtual_texture.js +274 -274
  1498. package/src/shade/playground/prototype_volumetrics_01.js +206 -206
  1499. package/src/shade/playground/sample.js +234 -234
  1500. package/src/shade/playground/sample_load_gltf.js +102 -102
  1501. package/src/shade/playground/spread_node3d_grid.js +19 -19
  1502. package/src/shade/renderer/Renderer.js +2436 -2436
  1503. package/src/shade/renderer/ShadeIndirectLightingMode.js +14 -14
  1504. package/src/shade/renderer/animation/ShadeAnimationChannel.js +414 -414
  1505. package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.js +531 -531
  1506. package/src/shade/renderer/animation/pose/PosePlayback.js +55 -55
  1507. package/src/shade/renderer/animation/pose/pose_evaluate_local.js +179 -179
  1508. package/src/shade/renderer/animation/pose/pose_evaluate_world.js +76 -76
  1509. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +1024 -1024
  1510. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.js +79 -79
  1511. package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.js +56 -56
  1512. package/src/shade/renderer/binding/BindGroupManager.js +282 -282
  1513. package/src/shade/renderer/binding/adapt_cache_capacity.js +25 -25
  1514. package/src/shade/renderer/buffer/GPUBufferAllocator.js +116 -116
  1515. package/src/shade/renderer/buffer/buffer_pool_ops.js +123 -123
  1516. package/src/shade/renderer/buffer/table/GPU_DATABASE_PAGE_SIZE.js +9 -9
  1517. package/src/shade/renderer/buffer/table/GPU_DATABASE_UPLOAD_BUFFER_LIMIT.js +8 -8
  1518. package/src/shade/renderer/buffer/table/PageBufferPool.js +71 -71
  1519. package/src/shade/renderer/buffer/table/PageSlotAllocator.js +95 -95
  1520. package/src/shade/renderer/camera/Camera.js +281 -281
  1521. package/src/shade/renderer/camera/GPUCameraContext.js +233 -233
  1522. package/src/shade/renderer/camera/orbital/README.md +84 -84
  1523. package/src/shade/renderer/deferred/shader_composite_volumetrics.js +75 -75
  1524. package/src/shade/renderer/dynamic/DYNAMIC_MESH_VERTEX.js +25 -25
  1525. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.js +342 -342
  1526. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +167 -167
  1527. package/src/shade/renderer/dynamic/shader_dynamic_mesh.js +170 -170
  1528. package/src/shade/renderer/extension/FrameContext.js +263 -263
  1529. package/src/shade/renderer/extension/FramePhase.js +104 -104
  1530. package/src/shade/renderer/extension/FrameRecord.js +126 -126
  1531. package/src/shade/renderer/extension/GBufferTextures.js +83 -83
  1532. package/src/shade/renderer/extension/PresentTarget.js +34 -34
  1533. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +918 -918
  1534. package/src/shade/renderer/extension/RenderExtension.js +69 -69
  1535. package/src/shade/renderer/extension/RenderExtensionRegistry.js +319 -319
  1536. package/src/shade/renderer/extension/SceneColor.js +40 -40
  1537. package/src/shade/renderer/extension/ViewTextures.js +78 -78
  1538. package/src/shade/renderer/fow/GPUFogOfWarRenderer.js +182 -182
  1539. package/src/shade/renderer/geometry/Geometry.js +608 -608
  1540. package/src/shade/renderer/geometry/geometry_build_from_meshlet_geometry.js +342 -342
  1541. package/src/shade/renderer/geometry/meshlet_geometry_transfer.js +41 -41
  1542. package/src/shade/renderer/geometry/primitives/make_box_geometry.js +153 -153
  1543. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.js +240 -240
  1544. package/src/shade/renderer/geometry/primitives/make_plane_geometry.js +145 -145
  1545. package/src/shade/renderer/geometry/primitives/make_polyhedron_geometry.js +327 -327
  1546. package/src/shade/renderer/geometry/primitives/make_torus_geometry.js +107 -107
  1547. package/src/shade/renderer/geometry/primitives/make_torus_knot_geometry.js +165 -165
  1548. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +607 -607
  1549. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +66 -66
  1550. package/src/shade/renderer/geometry/virtual/build/VGeoBuildResult.js +32 -32
  1551. package/src/shade/renderer/geometry/virtual/build/VGeoFaceGraph.js +103 -103
  1552. package/src/shade/renderer/geometry/virtual/build/VGeoGatheredFaces.js +25 -25
  1553. package/src/shade/renderer/geometry/virtual/build/VGeoLevel.js +33 -33
  1554. package/src/shade/renderer/geometry/virtual/build/VGeoLevelOptions.js +62 -62
  1555. package/src/shade/renderer/geometry/virtual/build/VGeoLevelSummary.js +49 -49
  1556. package/src/shade/renderer/geometry/virtual/build/VGeoSubmesh.js +20 -20
  1557. package/src/shade/renderer/geometry/virtual/build/VirtualGeometryMesh.js +214 -214
  1558. package/src/shade/renderer/geometry/virtual/build/gltf/GltfByteSource.js +122 -122
  1559. package/src/shade/renderer/geometry/virtual/build/gltf/GltfCollectReport.js +29 -29
  1560. package/src/shade/renderer/geometry/virtual/build/gltf/GltfDocument.js +210 -210
  1561. package/src/shade/renderer/geometry/virtual/build/gltf/GltfGeometry.js +48 -48
  1562. package/src/shade/renderer/geometry/virtual/build/gltf/GltfGeometryInstance.js +25 -25
  1563. package/src/shade/renderer/geometry/virtual/build/gltf/GltfGeometrySelection.js +28 -28
  1564. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_collect_geometries.js +296 -296
  1565. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_open_document.js +166 -166
  1566. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_read_geometry.js +199 -199
  1567. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +173 -173
  1568. package/src/shade/renderer/geometry/virtual/build/vgeo_bounding_sphere.js +28 -28
  1569. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +200 -200
  1570. package/src/shade/renderer/geometry/virtual/build/vgeo_build_levels.js +1786 -1786
  1571. package/src/shade/renderer/geometry/virtual/build/vgeo_build_page_nodes.js +157 -157
  1572. package/src/shade/renderer/geometry/virtual/build/vgeo_build_root_group.js +26 -26
  1573. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_normals.js +75 -75
  1574. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_tangents.js +143 -143
  1575. package/src/shade/renderer/geometry/virtual/build/vgeo_containing_sphere.js +44 -44
  1576. package/src/shade/renderer/geometry/virtual/build/vgeo_extract_submesh.js +41 -41
  1577. package/src/shade/renderer/geometry/virtual/build/vgeo_gather_faces.js +71 -71
  1578. package/src/shade/renderer/geometry/virtual/build/vgeo_graph_components.js +123 -123
  1579. package/src/shade/renderer/geometry/virtual/build/vgeo_narrow_indices.js +26 -26
  1580. package/src/shade/renderer/geometry/virtual/build/vgeo_normalize_source.js +112 -112
  1581. package/src/shade/renderer/geometry/virtual/build/vgeo_partition_graph.js +56 -56
  1582. package/src/shade/renderer/geometry/virtual/build/vgeo_sphere_inflate_to_contain.js +70 -70
  1583. package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set.js +187 -187
  1584. package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set_packed.js +207 -207
  1585. package/src/shade/renderer/geometry/virtual/format/VGEO_DEFECT.js +18 -18
  1586. package/src/shade/renderer/geometry/virtual/format/VGeoDefect.js +38 -38
  1587. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +64 -64
  1588. package/src/shade/renderer/geometry/virtual/format/attribute/VGEO_ATTRIBUTE.js +13 -13
  1589. package/src/shade/renderer/geometry/virtual/format/attribute/VGEO_ATTRIBUTES.js +50 -50
  1590. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attribute_allocate.js +28 -28
  1591. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attribute_mask.js +23 -23
  1592. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attributes_read.js +31 -31
  1593. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_vertex.js +32 -32
  1594. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_declare.js +46 -46
  1595. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_like.js +19 -19
  1596. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_test_fixtures.js +27 -27
  1597. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_asset_id_preimage.js +62 -62
  1598. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_asset_id.js +13 -13
  1599. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_directory_block_checksum.js +41 -41
  1600. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_frame_checksum.js +41 -41
  1601. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_header_checksum.js +25 -25
  1602. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET.js +20 -20
  1603. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_RECORD_SIZE.js +5 -5
  1604. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_MAX_CHILD_REF.js +5 -5
  1605. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_MAX_CLUSTER_TRIANGLE_COUNT.js +5 -5
  1606. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_MAX_CLUSTER_VERTEX_COUNT.js +5 -5
  1607. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_NO_CHILD.js +5 -5
  1608. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_NO_GROUP.js +5 -5
  1609. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_SAME_PAGE.js +6 -6
  1610. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +81 -81
  1611. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryGroup.js +37 -37
  1612. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryPageNode.js +55 -55
  1613. package/src/shade/renderer/geometry/virtual/format/directory/VGEO_DIRECTORY_BLOCK_RECORDS.js +5 -5
  1614. package/src/shade/renderer/geometry/virtual/format/directory/VGEO_DIRECTORY_FLAG_ROOT_PAGE.js +5 -5
  1615. package/src/shade/renderer/geometry/virtual/format/directory/VGEO_DIRECTORY_RECORD_SIZE.js +5 -5
  1616. package/src/shade/renderer/geometry/virtual/format/directory/vgeo_directory_block_count.js +12 -12
  1617. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CHILD_OFFSET.js +11 -11
  1618. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CHILD_TABLE_ENTRY_SIZE.js +5 -5
  1619. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_LZ4.js +11 -11
  1620. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_RAW.js +5 -5
  1621. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_FRAME_ALIGNMENT.js +5 -5
  1622. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_FRAME_HEADER_SIZE.js +5 -5
  1623. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_FRAME_OFFSET.js +13 -13
  1624. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_PAGE_MAGIC.js +5 -5
  1625. package/src/shade/renderer/geometry/virtual/format/frame/VGeoFrameBlob.js +21 -21
  1626. package/src/shade/renderer/geometry/virtual/format/frame/VGeoFrameExtent.js +59 -59
  1627. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_codec_name.js +27 -27
  1628. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_decode_frame_blob.js +84 -84
  1629. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +56 -56
  1630. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_frame_decode_bound.js +35 -35
  1631. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_scan_frames.js +74 -74
  1632. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +6 -6
  1633. package/src/shade/renderer/geometry/virtual/format/header/VGEO_HASH_ALGO_XXH3.js +5 -5
  1634. package/src/shade/renderer/geometry/virtual/format/header/VGEO_HEADER_OFFSET.js +31 -31
  1635. package/src/shade/renderer/geometry/virtual/format/header/VGEO_HEADER_SIZE.js +5 -5
  1636. package/src/shade/renderer/geometry/virtual/format/header/VGEO_LEVEL_OFFSET.js +20 -20
  1637. package/src/shade/renderer/geometry/virtual/format/header/VGEO_LEVEL_RECORD_SIZE.js +9 -9
  1638. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MAGIC.js +5 -5
  1639. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MIN_READER_VERSION.js +5 -5
  1640. package/src/shade/renderer/geometry/virtual/format/header/VGEO_PAYLOAD_ENCODING_SHADE_MESHLET_V1.js +5 -5
  1641. package/src/shade/renderer/geometry/virtual/format/header/VGeoLevelRecord.js +41 -41
  1642. package/src/shade/renderer/geometry/virtual/format/page/VGEO_GROUP_RECORD_SIZE.js +5 -5
  1643. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_GROUP_CLUSTER_COUNT.js +6 -6
  1644. package/src/shade/renderer/geometry/virtual/format/page/VGEO_METRIC_OFFSET.js +21 -21
  1645. package/src/shade/renderer/geometry/virtual/format/page/VGEO_METRIC_SIZE.js +5 -5
  1646. package/src/shade/renderer/geometry/virtual/format/page/VGEO_NODE_FANOUT.js +9 -9
  1647. package/src/shade/renderer/geometry/virtual/format/page/VGEO_NODE_FLAG_LEAF.js +5 -5
  1648. package/src/shade/renderer/geometry/virtual/format/page/VGEO_NODE_OFFSET.js +10 -10
  1649. package/src/shade/renderer/geometry/virtual/format/page/VGEO_NODE_RECORD_SIZE.js +5 -5
  1650. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_HEADER_SIZE.js +5 -5
  1651. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +16 -16
  1652. package/src/shade/renderer/geometry/virtual/format/payload/VGEO_ENCODING_FLAGS_MASK.js +6 -6
  1653. package/src/shade/renderer/geometry/virtual/format/payload/VGeoEncodedPayload.js +18 -18
  1654. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.js +200 -200
  1655. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_payload_attribute_offset.js +39 -39
  1656. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_payload_size.js +20 -20
  1657. package/src/shade/renderer/geometry/virtual/format/prototypeVGEOFormatViewer.js +2063 -2063
  1658. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +1622 -1622
  1659. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +485 -485
  1660. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_empty_gpu_structure.d.ts +23 -0
  1661. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_empty_gpu_structure.d.ts.map +1 -0
  1662. package/src/shade/renderer/global_illumination/brick4/cpu/brick4_empty_gpu_structure.js +34 -0
  1663. package/src/shade/renderer/gpu_primitive/sort/ffx/graph_radix_sort.js +115 -115
  1664. package/src/shade/renderer/gpu_primitive/sort/one_sweep/verify_radix_sort_one_sweep.js +110 -110
  1665. package/src/shade/renderer/light/environment/octahedral_resample_kernel.js +50 -50
  1666. package/src/shade/renderer/light/environment/octahedral_uv_to_direction.js +30 -30
  1667. package/src/shade/renderer/light/environment/resample_cube_to_octahedral.js +157 -157
  1668. package/src/shade/renderer/light/make_sunlight.js +35 -35
  1669. package/src/shade/renderer/light/model/io/light_record_point.js +39 -39
  1670. package/src/shade/renderer/loader/gltf/GLTF_PRIMITIVE_MODE.js +23 -23
  1671. package/src/shade/renderer/loader/gltf/MESHOPT_COMPRESSION_PLAN.md +793 -793
  1672. package/src/shade/renderer/loader/gltf/ext/GltfBufferViewExtension.js +54 -54
  1673. package/src/shade/renderer/loader/gltf/ext/GltfBufferViewExtensionSet.js +109 -109
  1674. package/src/shade/renderer/loader/gltf/ext/gltf_apply_buffer_view_extensions.js +69 -69
  1675. package/src/shade/renderer/loader/gltf/ext/gltf_buffer_view_extensions.js +22 -22
  1676. package/src/shade/renderer/loader/gltf/ext/gltf_geometry_extensions.js +39 -39
  1677. package/src/shade/renderer/loader/gltf/ext/meshopt/MeshoptBufferViewExtension.js +301 -301
  1678. package/src/shade/renderer/loader/gltf/gltf_component_type.js +223 -223
  1679. package/src/shade/renderer/loader/gltf/gltf_node_world_matrices.js +137 -137
  1680. package/src/shade/renderer/loader/gltf/gltf_parse_container.js +241 -241
  1681. package/src/shade/renderer/loader/gltf/gltf_read_accessor.js +294 -294
  1682. package/src/shade/renderer/loader/gltf/gltf_used_image_indices.js +49 -49
  1683. package/src/shade/renderer/loader/gltf/load_gltf.js +1253 -1253
  1684. package/src/shade/renderer/loader/gltf/tiny-gltf.js +646 -646
  1685. package/src/shade/renderer/loader/usd/UsdError.js +33 -33
  1686. package/src/shade/renderer/loader/usd/UsdExtensionRegistry.js +69 -69
  1687. package/src/shade/renderer/loader/usd/load_usd.js +226 -226
  1688. package/src/shade/renderer/loader/usd/parse_usda.js +931 -931
  1689. package/src/shade/renderer/loader/usd/unpack_usdz.js +106 -106
  1690. package/src/shade/renderer/loader/usd/usd_build_scene.js +658 -658
  1691. package/src/shade/renderer/loader/usd/usd_compose_transform.js +258 -258
  1692. package/src/shade/renderer/loader/usd/usd_decode_image.js +384 -384
  1693. package/src/shade/renderer/loader/usd/usd_lz4.js +182 -182
  1694. package/src/shade/renderer/loader/usd/usd_triangulate.js +159 -159
  1695. package/src/shade/renderer/material/ShadeMaterial.d.ts +2 -2
  1696. package/src/shade/renderer/material/ShadeMaterial.js +2 -2
  1697. package/src/shade/renderer/material/standard/fragment_gbuffer.js +334 -334
  1698. package/src/shade/renderer/material/standard/fragment_gbuffer_vt.js +169 -169
  1699. package/src/shade/renderer/material/standard/material_gbuffer_vertex.js +45 -45
  1700. package/src/shade/renderer/material/standard_material_to_struct.js +23 -23
  1701. package/src/shade/renderer/particles/prototypeParticleSystem.js +450 -450
  1702. package/src/shade/renderer/particles/runtime/spawn_request_encoding.js +52 -52
  1703. package/src/shade/renderer/pool/TransientResourcePool.js +392 -392
  1704. package/src/shade/renderer/postprocess/bloom/bloom_chain_resolution.js +29 -29
  1705. package/src/shade/renderer/postprocess/bloom/graph_bloom_downsample.js +109 -109
  1706. package/src/shade/renderer/postprocess/bloom/graph_postprocess_bloom.js +155 -155
  1707. package/src/shade/renderer/postprocess/cas/shader_ffx_rcas.js +114 -114
  1708. package/src/shade/renderer/postprocess/dof/DOF_AUTOFOCUS_PARAMS_STRUCT.js +25 -25
  1709. package/src/shade/renderer/postprocess/dof/DOF_FOCUS_STATE_STRUCT.js +23 -23
  1710. package/src/shade/renderer/postprocess/dof/DOF_PRESETS.js +27 -27
  1711. package/src/shade/renderer/postprocess/dof/chunk_dof_coc_band_diameter.js +41 -41
  1712. package/src/shade/renderer/postprocess/dof/chunk_dof_coc_band_radius.js +32 -32
  1713. package/src/shade/renderer/postprocess/dof/chunk_dof_coc_coefficient.js +26 -26
  1714. package/src/shade/renderer/postprocess/dof/compute_dof_autofocus_params.js +64 -64
  1715. package/src/shade/renderer/postprocess/dof/compute_dof_uniform.js +54 -54
  1716. package/src/shade/renderer/postprocess/dof/gather/DOF2_CONFIG.js +91 -91
  1717. package/src/shade/renderer/postprocess/dof/gather/DOF2_PRESETS.js +9 -9
  1718. package/src/shade/renderer/postprocess/dof/gather/DOF2_SETTINGS_STRUCT.js +66 -66
  1719. package/src/shade/renderer/postprocess/dof/gather/DOF2_TEXTURE_FORMAT.js +22 -22
  1720. package/src/shade/renderer/postprocess/dof/gather/DepthOfFieldU.js +292 -292
  1721. package/src/shade/renderer/postprocess/dof/gather/chunk_dof2_coc_to_near_far.js +25 -25
  1722. package/src/shade/renderer/postprocess/dof/gather/chunk_dof2_gather_weight.js +30 -30
  1723. package/src/shade/renderer/postprocess/dof/gather/compute_dof2_uniform.js +54 -54
  1724. package/src/shade/renderer/postprocess/dof/gather/graph_postprocess_dof2.js +194 -194
  1725. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_fill.js +68 -68
  1726. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_gather_far.js +140 -140
  1727. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_gather_near.js +142 -142
  1728. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_recombine.js +99 -99
  1729. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_setup.js +102 -102
  1730. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_tile_dilate.js +75 -75
  1731. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_tile_max.js +73 -73
  1732. package/src/shade/renderer/postprocess/dof/raymarch/DOF_SETTINGS_STRUCT.js +49 -49
  1733. package/src/shade/renderer/postprocess/dof/raymarch/DepthOfField.js +298 -298
  1734. package/src/shade/renderer/postprocess/dof/raymarch/graph_postprocess_dof.js +244 -244
  1735. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_composite.js +91 -91
  1736. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_firefly_cleanup.js +61 -61
  1737. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_prefilter.js +90 -90
  1738. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_raymarch_compute.js +267 -267
  1739. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_slice_compute.js +271 -271
  1740. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_tile_dilate.js +70 -70
  1741. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_tile_max.js +72 -72
  1742. package/src/shade/renderer/postprocess/dof/shader_dof_autofocus.js +99 -99
  1743. package/src/shade/renderer/postprocess/gtao/generate_magic_square_noise.js +51 -51
  1744. package/src/shade/renderer/postprocess/motion_blur/MotionBlur.js +56 -56
  1745. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +78 -78
  1746. package/src/shade/renderer/postprocess/upscale-dither/UpscaleDither.js +95 -95
  1747. package/src/shade/renderer/postprocess/upscale-dither/fragment_shader_upscale_dither.js +204 -204
  1748. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.js +58 -58
  1749. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +230 -230
  1750. package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.js +278 -278
  1751. package/src/shade/renderer/rasterize/native/oit/chunk_material_side_should_draw.js +26 -26
  1752. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.js +178 -178
  1753. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +235 -235
  1754. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +208 -208
  1755. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +206 -206
  1756. package/src/shade/renderer/scene/DynamicMesh.js +70 -70
  1757. package/src/shade/renderer/scene/DynamicMeshBatch.js +90 -90
  1758. package/src/shade/renderer/scene/GPUSceneContext.js +901 -901
  1759. package/src/shade/renderer/scene/SceneNodeBinding.js +56 -56
  1760. package/src/shade/renderer/scene/SkinnedMesh.js +55 -55
  1761. package/src/shade/renderer/scene/TransformAuthority.js +33 -33
  1762. package/src/shade/renderer/scene/optimization/deduplicate_geometries.js +38 -38
  1763. package/src/shade/renderer/scene/optimization/deduplicate_images.js +93 -93
  1764. package/src/shade/renderer/scene/optimization/geometry/internal/anchor_grow_topological.d.ts.map +1 -1
  1765. package/src/shade/renderer/scene/optimization/geometry/internal/anchor_grow_topological.js +12 -3
  1766. package/src/shade/renderer/scene/optimization/geometry/internal/match_refit_validate.js +127 -127
  1767. package/src/shade/renderer/scene/optimization/geometry/internal/match_solve_transform.js +492 -492
  1768. package/src/shade/renderer/scene/optimization/geometry/internal/match_validate_topology.js +3 -3
  1769. package/src/shade/renderer/scene/optimization/geometry/internal/seed_correspondence_from_window.js +3 -3
  1770. package/src/shade/renderer/scene/optimization/optimize_texture_set.js +81 -81
  1771. package/src/shade/renderer/scene/optimization/source_to_sampler2d.js +21 -21
  1772. package/src/shade/renderer/scene/serialization/STANDARD_MATERIAL_SERIALIZED_BYTE_SIZE.js +12 -12
  1773. package/src/shade/renderer/scene/serialization/deserialize_scene.d.ts.map +1 -1
  1774. package/src/shade/renderer/scene/serialization/deserialize_scene.js +0 -2
  1775. package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_transform_point.js +26 -26
  1776. package/src/shade/renderer/shader/chunk/noise/chunk_interleaved_gradient_noise.js +20 -20
  1777. package/src/shade/renderer/shader/chunk/spherical_harmonics/dering/chunk_sh2_dering_optimize_positive.js +61 -61
  1778. package/src/shade/renderer/shader/chunk/texture/chunk_texture_filter_fxaa_lite.js +225 -225
  1779. package/src/shade/renderer/shader/chunk/texture/dither/chunk_dither_color_8bit_gradient_noise.js +25 -25
  1780. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +384 -384
  1781. package/src/shade/renderer/shadow/map/PointLightShadowmap.js +105 -105
  1782. package/src/shade/renderer/shadow/map/SpotLightShadowmap.js +63 -63
  1783. package/src/shade/renderer/shadow/map/TetrahedronPointLightShadowmap.js +89 -89
  1784. package/src/shade/renderer/shadow/map/shadowmap_update_score.js +232 -232
  1785. package/src/shade/renderer/texture/GPUTextureAllocator.js +85 -85
  1786. package/src/shade/renderer/texture/texture_pool_ops.js +171 -171
  1787. package/src/shade/renderer/texture/virtual/PageTableQuadAllocator.js +253 -253
  1788. package/src/shade/renderer/texture/virtual/README.md +276 -276
  1789. package/src/shade/renderer/texture/virtual/VTPageTable.js +330 -330
  1790. package/src/shade/renderer/texture/virtual/VTPhysicalCache.js +349 -349
  1791. package/src/shade/renderer/texture/virtual/VT_CONSTANTS.js +154 -154
  1792. package/src/shade/renderer/texture/virtual/VT_STACK_INFO_STRUCT.js +20 -20
  1793. package/src/shade/renderer/texture/virtual/VirtualTextureManager.js +1276 -1276
  1794. package/src/shade/renderer/texture/virtual/VirtualTextureStack.js +106 -106
  1795. package/src/shade/renderer/texture/virtual/build_chunk_vt_lookup.js +150 -150
  1796. package/src/shade/renderer/texture/virtual/build_shader_vt_feedback.js +232 -232
  1797. package/src/shade/renderer/texture/virtual/chunk_vt_request_key.js +28 -28
  1798. package/src/shade/renderer/texture/virtual/source/VTSourceImage.js +207 -207
  1799. package/src/shade/renderer/texture/virtual/source/VTSourceProcedural.js +135 -135
  1800. package/src/shade/renderer/texture/virtual/source/VTSourceTiled.js +132 -132
  1801. package/src/shade/renderer/water/GPUWaterRenderer.js +167 -167
  1802. package/src/shade/renderer/water/shader_water.js +246 -246
  1803. package/src/shade/renderer/water/water_height_texture_from_sampler.js +56 -56
  1804. package/src/shade/vitest.setup.mjs +89 -89
  1805. package/src/shade/wgsl/validate_wgsl_source.js +316 -316
  1806. package/src/view/controller/controls/NumericIntervalControl.js +90 -90
  1807. package/src/view/controller/controls/Vector2Control.js +83 -83
  1808. package/src/view/controller/controls/Vector3Control.js +90 -90
  1809. package/src/view/elements/Group.js +56 -56
  1810. package/src/view/elements/drawCheckers.js +33 -33
  1811. package/src/view/elements/windrose/WindRoseDiagram.js +369 -369
  1812. package/src/view/graphics/WebGLContextFailureView.js +76 -76
  1813. package/src/view/layout/DockPanel.js +51 -51
  1814. package/src/view/layout/SplitView.js +365 -365
  1815. package/src/view/layout/show_popup_menu.js +81 -81
  1816. package/src/view/minimap/MinimapCanvasView.js +411 -411
  1817. package/src/view/minimap/MinimapImageCache.js +88 -88
  1818. package/src/view/minimap/MinimapMarkerCollection.d.ts +0 -1
  1819. package/src/view/minimap/MinimapMarkerCollection.d.ts.map +1 -1
  1820. package/src/view/minimap/MinimapMarkerCollection.js +180 -180
  1821. package/src/view/minimap/dom/MinimapCameraView.js +206 -206
  1822. package/src/view/minimap/minimap_focus_area.js +97 -97
  1823. package/editor/process/symbolic/SocketsSymbolicDisplay.js +0 -192
  1824. package/src/core/geom/3d/topology/struct/binary/io/moved_tests.txt +0 -37
  1825. package/src/engine/ecs/attachment/Attachment.d.ts +0 -40
  1826. package/src/engine/ecs/attachment/Attachment.d.ts.map +0 -1
  1827. package/src/engine/ecs/attachment/Attachment.js +0 -57
  1828. package/src/engine/ecs/attachment/AttachmentBinding.d.ts +0 -28
  1829. package/src/engine/ecs/attachment/AttachmentBinding.d.ts.map +0 -1
  1830. package/src/engine/ecs/attachment/AttachmentBinding.js +0 -41
  1831. package/src/engine/ecs/attachment/AttachmentSystem.d.ts +0 -61
  1832. package/src/engine/ecs/attachment/AttachmentSystem.d.ts.map +0 -1
  1833. package/src/engine/ecs/attachment/AttachmentSystem.js +0 -307
  1834. package/src/engine/ecs/attachment/BoneAttachmentBinding.d.ts +0 -27
  1835. package/src/engine/ecs/attachment/BoneAttachmentBinding.d.ts.map +0 -1
  1836. package/src/engine/ecs/attachment/BoneAttachmentBinding.js +0 -69
  1837. package/src/engine/ecs/attachment/TransformAttachmentBinding.d.ts +0 -4
  1838. package/src/engine/ecs/attachment/TransformAttachmentBinding.d.ts.map +0 -1
  1839. package/src/engine/ecs/attachment/TransformAttachmentBinding.js +0 -51
  1840. package/src/engine/ecs/sockets/AttachmentSocket.d.ts +0 -32
  1841. package/src/engine/ecs/sockets/AttachmentSocket.d.ts.map +0 -1
  1842. package/src/engine/ecs/sockets/AttachmentSocket.js +0 -60
  1843. package/src/engine/ecs/sockets/AttachmentSocketType.d.ts +0 -6
  1844. package/src/engine/ecs/sockets/AttachmentSocketType.d.ts.map +0 -1
  1845. package/src/engine/ecs/sockets/AttachmentSocketType.js +0 -8
  1846. package/src/engine/ecs/sockets/AttachmentSockets.d.ts +0 -57
  1847. package/src/engine/ecs/sockets/AttachmentSockets.d.ts.map +0 -1
  1848. package/src/engine/ecs/sockets/AttachmentSockets.js +0 -130
  1849. package/src/engine/ecs/sockets/BoneAttachmentSocket.d.ts +0 -29
  1850. package/src/engine/ecs/sockets/BoneAttachmentSocket.d.ts.map +0 -1
  1851. package/src/engine/ecs/sockets/BoneAttachmentSocket.js +0 -56
  1852. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts +0 -6
  1853. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts.map +0 -1
  1854. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.js +0 -19
  1855. package/src/shade/renderer/animation/_dump_resolve.d.mts +0 -2
  1856. package/src/shade/renderer/animation/_dump_resolve.d.mts.map +0 -1
  1857. package/src/shade/renderer/animation/_dump_resolve.mjs +0 -5
  1858. package/src/shade/renderer/scene/optimization/geometry/internal/bt_face_loop_helpers.d.ts +0 -32
  1859. package/src/shade/renderer/scene/optimization/geometry/internal/bt_face_loop_helpers.d.ts.map +0 -1
  1860. package/src/shade/renderer/scene/optimization/geometry/internal/bt_face_loop_helpers.js +0 -77
  1861. package/src/shade/renderer/scene/optimization/geometry/internal/bt_find_edge_between.d.ts +0 -12
  1862. package/src/shade/renderer/scene/optimization/geometry/internal/bt_find_edge_between.d.ts.map +0 -1
  1863. package/src/shade/renderer/scene/optimization/geometry/internal/bt_find_edge_between.js +0 -35
  1864. package/src/shade/renderer/scene/serialization/linear_to_pq.d.ts +0 -2
  1865. package/src/shade/renderer/scene/serialization/linear_to_pq.d.ts.map +0 -1
  1866. package/src/shade/renderer/scene/serialization/linear_to_pq.js +0 -14
  1867. package/src/shade/renderer/scene/serialization/pq_to_linear.d.ts +0 -9
  1868. package/src/shade/renderer/scene/serialization/pq_to_linear.d.ts.map +0 -1
  1869. package/src/shade/renderer/scene/serialization/pq_to_linear.js +0 -30
@@ -1,717 +1,717 @@
1
- # Gamepad API — proposal
2
-
3
- Response to the external review *"how convenient is the meep gamepad API? (UX)"*.
4
-
5
- > **Revision 2.** P1, P4, P5, P6 accepted as written. **P2 replaced** with a persistent `main` handle (better than
6
- > slot pre-population — see §4.2). **P3 replaced** with learned per-stick calibration and a `GamepadStick`
7
- > abstraction, grounded in the survey in Appendix A. Revision 1's fixed `axisNoiseFloor` is withdrawn.
8
- >
9
- > **Revision 3 — implemented.** All of P1–P6 have landed. §4 describes the design **as shipped**: names,
10
- > constants and signatures there match the code. §6 records what changed between the proposal and the
11
- > implementation, and why. §1, §2 and §5 are unchanged — they are the argument, not the design.
12
-
13
- ## 0. Summary
14
-
15
- The review grades a hardware abstraction layer by how little game code the consumer had to write. That is the
16
- wrong axis, and it leads to the wrong headline recommendation.
17
-
18
- Checked against the source:
19
-
20
- * one papercut (**sparse `buttons`**) does not reproduce through any supported access path — the guard the
21
- reviewer wrote is dead code;
22
- * one technical claim (**"full-diagonal magnitude ~0.99"**) is not producible by this code at all — there is no
23
- rescaling path in `GamepadHandle#update`;
24
- * one papercut (**"the `.d.ts` doesn't carry the frame"**) is about a file that does not exist — `engine/input`
25
- contains zero `.d.ts` files, and the frame *is* documented, on the enum that defines it;
26
- * the headline recommendation (**`pad.getMovement({radialDeadzone})`**) moves gameplay policy, a coordinate
27
- convention, an options bag, and a per-frame allocation into the driver.
28
-
29
- The review did, however, bump into a **real structural gap and misdiagnose it**: the gamepad is effectively
30
- invisible to the engine's input binding layer (`InputSystem` / `InputControllerSystem`). That is *why* the
31
- reviewer ended up hand-fusing raw device state — not because the device lacks convenience methods. Closing that
32
- gap removes the "boilerplate every consumer will duplicate" without adding a single convenience method to
33
- `GamepadHandle`.
34
-
35
- Two of the underlying observations are worth acting on, in a different shape than proposed.
36
-
37
- ### Dispositions
38
-
39
- | # | Review item | Disposition |
40
- |---|---|---|
41
- | 1 | `buttons` sparse → add `pad.isDown(i)` | **Reject the mechanism, accept the goal.** Claim doesn't reproduce; fix uniformity at the source (P1), don't add a third accessor. |
42
- | 2 | `pad.getMovement({radialDeadzone})` | **Reject.** Policy in the driver. Decomposed into two device-agnostic primitives instead (P4, P5). |
43
- | 3 | Per-axis dead-zone leaks diagonals; shortens full diagonal to ~0.99 | **Half accept.** The `~0.99` claim is fabricated. The genuine defect is different and worse: the gate is destructive, misnamed, and *guesses* a number that varies 6× across hardware. Replaced by learned calibration (P3). |
44
- | 4 | Frame undocumented "at the type level" | **Reject as stated, accept a sliver.** No `.d.ts` exists; frame is documented in `GamepadAxes.js`. Add a cross-reference on `axes`/`stickLeft`/`stickRight` (P6). |
45
- | 5 | No digital view of stick / analog view of D-pad; fusion is on the caller | **Accept the observation, keep fusion on the caller.** Ship the two primitives, not the fused result (P5). |
46
- | 6 | Analog-vs-digital speed is game policy | **Agree, no action.** |
47
- | — | *(missed)* Gamepad is unbindable through the ISM path layer | **New work.** The actual defect (P1 + P2). |
48
-
49
- ---
50
-
51
- ## 1. The layering premise the review is missing
52
-
53
- meep input devices are **state mirrors of hardware**. They report what the hardware reports, plus the minimum
54
- hygiene needed to make polled hardware observable (edge detection, stuck-input release on disconnect/stop). They
55
- contain no game policy. This is not an accident of the gamepad implementation — it is the shape of the whole
56
- package:
57
-
58
- * `KeyboardDevice` exposes `keys.w.is_down`. It does not expose `keyboard.getMovement()` from WASD.
59
- * Nobody asks it to, because the layer that owns that question already exists:
60
- [`KeyboardCameraController.js`](ecs/controllers/KeyboardCameraController.js) — a *controller* that reads device
61
- switches and produces a camera-frame pan vector.
62
-
63
- `pad.getMovement()` is a request to put `KeyboardCameraController`'s job inside `KeyboardDevice`. Five concrete
64
- reasons it does not belong there:
65
-
66
- 1. **The game frame is not a property of the stick.** The reviewer wants `+y = up`. Up in *what*? meep's world is
67
- 3D; "stick up" maps to a world direction that depends on the camera yaw, the projection, and whether the game
68
- is top-down or third-person. `KeyboardCameraController` resolves exactly this and it needs a
69
- `TopDownCameraController` to do it. A `Vector2` on a driver cannot know the answer, so any answer it bakes in
70
- is wrong for some consumer — who then must un-negate it. That is strictly worse than never negating.
71
-
72
- 2. **Dead-zoning is not one policy.** Radial-with-rescale is right for locomotion; per-axis is right for menu
73
- navigation; inner+outer with a response curve is right for aiming; square-gate normalization is right for
74
- pads that report a square gate. `{radialDeadzone}` picks one and demotes the rest to "off the golden path".
75
-
76
- 3. **`{radialDeadzone}` is an options bag.** The codebase's position is typed and verbose over magic-looking
77
- configuration. An options object on a per-frame hot call is the opposite of that, and it grows monotonically
78
- — the next request is `{radialDeadzone, outerDeadzone, curve, squareGate}`.
79
-
80
- 4. **It allocates.** `getMovement()` returning a fresh `Vector2` allocates once per consumer per frame. The
81
- engine's convention for vector-producing calls is `f(result, ...)` writing into a caller-owned target.
82
-
83
- 5. **It creates a dual-mode API.** With `getMovement()` present, `stickLeft` becomes "the raw one" and
84
- `getMovement()` "the good one" — two ways to ask the same question with a silent policy difference between
85
- them. Uniform control flow means picking the common case as the *only* case at each layer, and letting
86
- callers who want something else drop to the lower-level primitive.
87
-
88
- What the reviewer actually wants is real. It just belongs one layer up, and it should be *composable functions*,
89
- not a method on the driver.
90
-
91
- ---
92
-
93
- ## 2. Item-by-item
94
-
95
- *Line references in this section point at the code **as reviewed**, before any of P1–P6 landed. They are part of
96
- the argument about what the reviewer was looking at, not navigation aids for the current tree.*
97
-
98
- ### 2.1 "`buttons` is lazily populated and sparse, so I wrote a guard"
99
-
100
- **This does not reproduce.** Trace the code:
101
-
102
- * [`GamepadHandle.js:140`](devices/gamepad/GamepadHandle.js:140) — `update()` iterates **every** button in the
103
- native snapshot and calls `getButton(i)` on each. After one update, `buttons[0 … n-1]` are all populated.
104
- * [`GamepadDevice.js:130`](devices/GamepadDevice.js:130) — `#connect()` calls `pad.update(...)` **before**
105
- setting `pad.connected = true`.
106
- * [`GamepadDevice.js:86`](devices/GamepadDevice.js:86) — `main` only returns pads with `connected === true`.
107
-
108
- So every handle reachable through `gamepad.main` has already had its full button set materialised.
109
- `pad.buttons[GamepadButtons.a].is_down` is safe, and the `button !== undefined &&` half of the reviewer's guard
110
- never evaluates false in a connected-pad path. The `?.` in the existing `@example` is belt-and-braces, and reads
111
- as a warning it isn't.
112
-
113
- The one residual hole is real but different: a **non-standard mapping** pad reporting fewer than 17 buttons.
114
- `buttons[GamepadButtons.dpad_up]` is genuinely `undefined` there, because the button does not exist.
115
- `pad.isDown(15)` would return `false` for it — converting "this hardware has no D-pad" into "the D-pad is not
116
- pressed", silently, forever. That is a worse API than the honest `undefined`, and it is the reason to reject the
117
- proposed mechanism specifically.
118
-
119
- **The goal is still right.** Keyboard/gamepad symmetry should not have an asterisk, and `pads`/`buttons`
120
- sparseness has a second, much more serious consequence (§3). Fix it at the source: pre-populate (P1/P2), so
121
- there is nothing to guard and no third accessor.
122
-
123
- ### 2.2 `getMovement()` — rejected
124
-
125
- See §1. Replaced by P4 + P5.
126
-
127
- ### 2.3 "Per-axis dead-zoning leaks diagonal drift and shortens the full diagonal to ~0.99"
128
-
129
- **First half: correct.** A per-axis gate at 0.1 admits up to `sqrt(0.1² + 0.1²) ≈ 0.141` of resting magnitude,
130
- and its boundary is anisotropic — a stick pushed to `(0.09, 0.09)` reads dead, `(0.11, 0.0)` reads live.
131
-
132
- **Second half: not producible by this code.** The gate is
133
- [`GamepadHandle.js:169`](devices/gamepad/GamepadHandle.js:169):
134
-
135
- ```js
136
- if (Math.abs(value) < deadZone) {
137
- value = 0;
138
- }
139
- ```
140
-
141
- There is no rescale, no normalization, no magnitude clamp anywhere in `update()`. A full-deflection axis passes
142
- through byte-identical to what the hardware reported. If the reviewer measured 0.99 at full diagonal, that was
143
- their pad's gate, not ours. This matters because it is the tell that the section was reasoned about rather than
144
- read — and the actual defect sitting three lines away was missed.
145
-
146
- **The actual defect** is threefold and worse than "leaks diagonals":
147
-
148
- 1. **It is destructive.** The gated value is what gets *stored* in `axes`, so a consumer who wants radial
149
- dead-zoning cannot recover the raw signal — the information is gone before they see it. Policy applied in a
150
- mirror layer is not just misplaced, it is lossy.
151
- 2. **It is discontinuous.** `0.0999 → 0`, `0.1001 → 0.1001`. Input magnitude jumps by the full dead-zone width
152
- the instant the threshold is crossed. Any consumer mapping magnitude to speed gets a visible speed pop.
153
- 3. **It is named for a policy it should not be implementing.** `deadZone` at `0.1` reads as "the engine has
154
- decided your gameplay dead-zone", which is precisely how the reviewer read it.
155
-
156
- There is a fourth problem the review could not have seen without measuring hardware, and it is the one that
157
- kills the whole "pick a good constant" approach: **the right number varies by more than 6× across pads.** XInput
158
- ships 0.24 (left stick) and 0.265 (right); SDL treats ±0.098 as at-rest; hall-effect and TMR pads need 0.02–0.03
159
- and stay there for life; a worn potentiometer pad needs 0.2+ and gets worse over time. Any single constant is
160
- sized for the worst pad in the population, and every good pad pays for it with lost range.
161
-
162
- Fixed in P3 + P4: the device *measures* its own stick instead of guessing (learned center + noise radius), and
163
- gameplay dead-zoning becomes a continuous, rescaling, radial primitive applied by the consumer.
164
-
165
- ### 2.4 "Frame is undocumented at the type level — the `.d.ts` doesn't carry it"
166
-
167
- Two problems.
168
-
169
- * **The frame is documented**, in the file that owns the concept —
170
- [`GamepadAxes.js:5`](devices/gamepad/GamepadAxes.js:5): *"Negative values are left/up, positive values are
171
- right/down"*. The review cites having read it, then calls it undocumented.
172
- * **There is no `.d.ts`.** `find src/engine/input -name "*.d.ts"` returns nothing. Hand-written `.d.ts` are not
173
- maintained in this project; whatever the reviewer was reading was IDE inference or a stale tree. If a `.d.ts`
174
- for this package appears, deleting it is the fix.
175
-
176
- **Accepted sliver:** the frame note lives on the *enum*, and a consumer touching `stickLeft` may never open
177
- `GamepadAxes.js`. One-line cross-references on `axes`, `stickLeft`, `stickRight` (P6).
178
-
179
- ### 2.5 "No digital view of the stick, no analog view of the D-pad; fusion is on the caller"
180
-
181
- Correct, and **fusion stays on the caller** — which of stick and D-pad wins, whether they sum or the last-touched
182
- device latches, and whether a held D-pad suppresses stick drift are all game decisions with no defensible
183
- default. What *is* mechanical and duplicated is the conversion on each side, so ship both directions as
184
- primitives (P5) and leave the `max`/`or`/`latch` to the consumer.
185
-
186
- ### 2.6 "Analog-vs-digital speed is a caller concern"
187
-
188
- Agreed, explicitly. No action.
189
-
190
- ---
191
-
192
- ## 3. What the review missed: the gamepad is unbindable through the ISM
193
-
194
- The engine's action-mapping layer resolves bindings by *path* against the device tree —
195
- [`InputSystem.js:18`](ecs/systems/InputSystem.js:18) and
196
- [`InputControllerSystem.js:159`](ecs/systems/InputControllerSystem.js:159), both via
197
- [`resolvePath`](../../core/json/resolvePath.js), which **throws when a path cannot be resolved**.
198
-
199
- Keyboard works because `KeyboardDevice` pre-populates every key from `KeyCodes` in its constructor, so
200
- `keyboard/keys/w/down` resolves at load time, before anyone touches the hardware.
201
-
202
- The gamepad cannot do this:
203
-
204
- * `pads` is sparse and keyed on the hardware slot, so `gamepad/pads/0/...` throws until a pad connects;
205
- * `buttons` is sparse until first poll, so `gamepad/pads/0/buttons/0/down` throws until the pad has been read.
206
-
207
- Consequences: an `InputController` carrying a gamepad binding **cannot be linked until the player has already
208
- plugged in and pressed something**; whether a given binding works depends on which physical slot the pad landed
209
- in; and a serialized `InputBinding` referencing a gamepad path is a load-order landmine. (Unlink is safe once
210
- link succeeded — handles are retained across disconnect — but that is the only part of the lifecycle that is.)
211
-
212
- This — not the absence of `getMovement()` — is why the integration was "entirely on the caller". The blessed
213
- mapping mechanism was unavailable, so the reviewer polled raw state and fused by hand, then reported the
214
- symptoms of doing so as API friction. P1 and P2 close it as a side effect of fixing uniformity.
215
-
216
- *(Separately: axis bindings have no per-axis granularity — only the aggregate `on.axis`, forcing listeners to
217
- filter by index. Noted, not proposed. The string-path ISM is already the odd one out against the codebase's
218
- typed-over-magic position; make it work, don't grow it. Direct typed state access — `pad.buttons[GamepadButtons.a].is_down`
219
- — remains the blessed path.)*
220
-
221
- ---
222
-
223
- ## 4. Proposed work
224
-
225
- ### P1 — `GamepadHandle` pre-populates the standard mapping
226
-
227
- ```js
228
- // gamepad/GamepadStandardMapping.js
229
- export const GAMEPAD_STANDARD_BUTTON_COUNT = 17;
230
- export const GAMEPAD_STANDARD_AXIS_COUNT = 4;
231
- ```
232
-
233
- `GamepadHandle` materialises those in its constructor: 17 `InputDeviceSwitch`, 17 zeroed `buttonValues`, 4 zeroed
234
- `axes`. `getButton` stays as-is and keeps growing the array for hardware exposing more than 17 buttons.
235
-
236
- Effect: `pad.buttons[GamepadButtons.dpad_up].is_down` is total. No guard, no `?.`, no `isDown()`. Exactly the
237
- keyboard's contract.
238
-
239
- **Tradeoff, stated explicitly:** on a non-standard pad with 6 buttons, `buttons[12]` now reads "up" rather than
240
- "absent". Absence is signalled by `pad.mapping !== "standard"`, which is where the Gamepad API puts it, not by
241
- holes in an array. Uniform beats expressive here — a hole is not a usable absence signal anyway, since the
242
- consumer sees a hole for "no such button" and (previously) also for "not polled yet".
243
-
244
- Cost: 17 small objects per handle, allocated once.
245
-
246
- ### P2 — `main` becomes a persistent handle bound to the active pad
247
-
248
- *(Replaces revision 1's slot pre-population. This is the better design: it gives the binding layer a stable path
249
- without pretending four pads exist, and it matches what a single-player consumer actually means by "the
250
- gamepad".)*
251
-
252
- `GamepadDevice.main` becomes a `GamepadHandle` constructed with the device, living **outside** `pads[]`, starting
253
- disconnected:
254
-
255
- * it binds to the first pad that connects;
256
- * when its bound pad disconnects, it rebinds to the **oldest still-connected** pad (connection order);
257
- * when nothing is connected, it stays present and `connected === false`, with all switches released.
258
-
259
- Mechanically `main` is a real handle fed the *same* native snapshot as its bound pad during `poll()` — not a
260
- proxy or a getter chain. That matters: `gamepad/main/buttons/0/down` is a stable `Signal` **object** that
261
- resolves at engine construction and never changes identity, which is exactly what `resolvePath` needs (§3).
262
-
263
- ```js
264
- // GamepadDevice
265
- #connection_sequence = 0;
266
-
267
- /**
268
- * The active gamepad. Always present; check {@link GamepadHandle#connected}.
269
- * Mirrors the first connected pad, falling back to the oldest remaining one when that pad is lost.
270
- * Not a member of {@link pads}.
271
- */
272
- main = new GamepadHandle();
273
- ```
274
-
275
- Notes on the implementation:
276
-
277
- * **Do not** forward `main.on.*` into the device-level `on.*` signals. The pad it mirrors already forwards, so
278
- wiring both would double-fire every press for every listener.
279
- * On unbind, `main.reset()` — releases everything, so a yank-the-cable never leaves input stuck. The next
280
- `update()` from the new source re-presses whatever is genuinely held. Free correctness from the existing edge
281
- detection.
282
- * `main.index` / `.id` / `.mapping` follow the mirrored pad, because `update()` already copies them. Useful:
283
- a settings screen can name the active pad without touching `pads`.
284
- * Connection order needs one counter — stamp `pad.connectionIndex = this.#connectionSequence++` inside
285
- `#connect`, pick the smallest among connected on rebind.
286
- * Binding, rebinding and refreshing all happen in one place at the end of `poll()`. Splitting them across
287
- `#connect`/`#disconnect` leaves `main` a frame stale on a swap — see §6.3.
288
-
289
- Cost: one extra handle update per poll (17 buttons + 4 axes) — noise.
290
-
291
- **Breaking, and an improvement:** `main` was `GamepadHandle | undefined`. It is now always a handle. Existing
292
- `if (pad !== undefined)` guards still compile and simply never trigger; the check becomes `main.connected`. This
293
- removes the only sentinel in the gamepad API, which is the direction the codebase wants anyway.
294
-
295
- **Deliberately unresolved:** per-slot paths (`gamepad/pads/1/...`) still don't resolve, because `pads` keeps its
296
- honest sparse hardware-slot semantics. Local multiplayer binds through the device-level `on.down`, which already
297
- dispatches `(buttonIndex, pad)`, or holds handles from the `connected` signal. If per-player path binding is ever
298
- wanted, the shape is an ordered player-assignment list of which `main` is element 0 — this design doesn't
299
- preclude it, and I'd rather add it when there's a consumer than guess the assignment policy now.
300
-
301
- ### P3 — Learned per-stick calibration, and a `GamepadStick` abstraction
302
-
303
- *(Replaces revision 1's fixed `axisNoiseFloor`. Appendix A is the supporting survey.)*
304
-
305
- Three findings drive this:
306
-
307
- 1. **In a browser there is no factory calibration, so learning is the only calibration available.** Native stacks
308
- can read hardware calibration — a Switch pad stores per-axis min/center/max in SPI flash, XInput and SDL apply
309
- vendor-tuned constants. The Gamepad API exposes none of it: normalized floats and nothing else. Every native
310
- stack calibrates; we're the only ones who'd be guessing.
311
- 2. **The dominant error is a center offset, not symmetric noise.** This is what "stick drift" *is*, and it is why
312
- every consumer calibration tool works by sampling the resting position and subtracting it. A fixed dead zone
313
- responds to an offset center by widening the dead area — asymmetrically, so you lose range on one side and
314
- still drift on the other. Learning the center fixes the actual defect; a dead zone only hides it.
315
- 3. **The right radius varies 6×+ across the installed base** (§2.3). Measuring is the only way to give a TMR pad
316
- its 0.02 and a worn pad its 0.15 from one code path.
317
-
318
- **Layering — why this doesn't contradict §1.** Calibration is *hardware characterization*: learning that this
319
- stick rests at `(0.03, -0.01)` with `0.018` of dispersion makes the mirror **more accurate**, which is squarely
320
- the device layer's job. Gameplay dead zone, response curve, and frame conversion remain policy and stay with the
321
- consumer via `apply_radial_dead_zone`. The line is: *the device removes what the hardware got wrong; the game
322
- decides what to do with what's left.* Getting this backwards is a known failure mode — SDL applying its own dead
323
- zone under a game that applies another is a long-standing complaint, and the result is exactly the doubled dead
324
- zone with all precision gone.
325
-
326
- #### The abstraction
327
-
328
- ```js
329
- export class GamepadStick {
330
- /** Indices into {@link GamepadHandle#axes} that this stick reads. */
331
- axisX = 0;
332
- axisY = 1;
333
-
334
- /** Hardware value, exactly as reported. */
335
- raw = new Vector2();
336
-
337
- /** Calibrated value: center-corrected and noise-gated. This is what gameplay should read. */
338
- value = new Vector2();
339
-
340
- /** @type {GamepadStickCalibration} */
341
- calibration = new GamepadStickCalibration();
342
-
343
- on = {
344
- /** Fires when {@link value} changes. A calibrated stick at rest is silent. */
345
- changed: new Signal()
346
- };
347
-
348
- /** Refresh from raw axis values, feeding the calibrator on the way through. */
349
- update(axes) {}
350
-
351
- /** Return to neutral, keeping the calibration — the hardware has not changed. */
352
- reset() {}
353
-
354
- /** Discard what was learned. For when the handle starts representing *different* hardware. */
355
- forgetCalibration() {}
356
- }
357
-
358
- export class GamepadStickCalibration {
359
- /** Learned rest position. */
360
- center = new Vector2();
361
-
362
- /** Learned dispersion around {@link center}; magnitudes inside this read as 0. */
363
- noiseRadius = 0;
364
-
365
- /** When true, learning is suspended and the current values are used as-is. */
366
- locked = false;
367
- }
368
- ```
369
-
370
- `stickLeft` / `stickRight` become `GamepadStick` rather than `Vector2`. **Breaking:** `pad.stickLeft.x` →
371
- `pad.stickLeft.value.x`. Changelog line; this is public surface.
372
-
373
- **Opt-out without a mode flag.** You asked for an opt-out, and the obvious form of it — a boolean that switches
374
- between two code paths — is the dual-mode shape we rejected for `getMovement()`. It isn't needed here: the
375
- transform is *always* applied, and an identity calibration (`center = (0,0)`, `noiseRadius = 0`, `locked =
376
- true`) is a bit-exact passthrough. One code path, and "no filtering" is just a particular calibration. The same
377
- mechanism covers a settings-screen manual dead zone and a saved per-controller profile — `GamepadStickCalibration`
378
- gets `to/fromBinaryBuffer`, keyed on `pad.id`.
379
-
380
- **Calibration belongs to hardware, not to a handle.** A handle outlives the pad it represents: slots get
381
- re-occupied, and `main` moves between pads. Carrying an estimate across that would apply one pad's correction to
382
- another — and because the calibrator only ever moves its estimate *closer* to the origin (below), a new pad
383
- resting further out could never adopt its own rest position at all. So `forgetCalibration()` is called on a fresh
384
- connection and when `main` binds a new source. It is a no-op on a locked calibration: a supplied profile is not
385
- ours to discard.
386
-
387
- #### The learning algorithm
388
-
389
- **Phase A — rest estimation.** Runs continuously and unattended; there is no separate "on connect" mode.
390
-
391
- * Collect `REST_SAMPLE_COUNT = 60` raw samples (≈1 s at rAF) as a fixed, non-overlapping window.
392
- * **Reject the whole window** if any sample magnitude exceeds `REST_CANDIDATE_MAX = 0.08`, or if per-axis spread
393
- (max − min) exceeds `REST_SPREAD_MAX = 0.015`. Resting and holding cannot be told apart inside one window —
394
- both are steady — so the bounds are biased hard toward rejection, on the asymmetry that failing to calibrate
395
- leaves an exact passthrough while calibrating wrongly injects phantom deflection. The spread bound is the
396
- primary defence, and it exploits a physical difference: a held stick carries hand tremor, a settled one
397
- carries only sensor noise, and the two differ by roughly an order of magnitude. (§6.1 and §6.4 record how
398
- these numbers were arrived at — the first version of this section got the reasoning wrong.)
399
- * **Center = per-axis median** of the window. Median, not mean: one spike shifts a 60-sample mean by 1.7% of its
400
- amplitude, and shifts the median by nothing.
401
- * **`noiseRadius` = median(d) + `NOISE_RADIUS_DEVIATIONS`·MAD(d)** where `d` are the sample distances from the
402
- learned center and MAD is the median absolute deviation. MAD is the standard robust dispersion estimator — a
403
- high quantile computed from 60 samples is dominated by its own tail, which is precisely the outliers we're
404
- trying not to fit. No clamp: the spread bound already constrains the result structurally, to
405
- `NOISE_RADIUS_MAX = REST_SPREAD_MAX · √2 · (1 + NOISE_RADIUS_DEVIATIONS)` ≈ 0.106.
406
- * **Adopt only if closer in.** A window is written to the calibration only when its center is nearer the origin
407
- than the accepted one. This is what makes a wrong estimate self-correcting: a stick that was being held when
408
- sampling started is superseded the moment it is released, with no separate recovery path. The trade is that
409
- drift *growing* within a session is not followed — a wear process measured in weeks, and calibration restarts
410
- whenever the pad reconnects.
411
- * **Recovery takes up to two windows.** Windows are fixed and non-overlapping, so the one straddling a release
412
- or a rebind still holds pre-transition samples and is rejected on spread; only the window after it is clean.
413
- This affects how quickly a correct estimate is found, never whether it is correct.
414
-
415
- **Phase B — range estimation.** Proposed as **optional and off by default.** Pads differ in gate shape (square
416
- gates reach ~1.41 at full diagonal, circular ones ~1.0), so a learned per-direction max would let us normalize to
417
- a unit circle. But a running max is a self-poisoning estimator — one spike raises the ceiling permanently and
418
- silently compresses everything afterwards. If we do it: require K consecutive samples above the current maximum
419
- before raising it, clamp to `[0.8, 1.5]`, and decay slowly. I'd rather ship Phase A, which is high-value and
420
- low-risk, and leave this behind a flag until a real pad demands it.
421
-
422
- **Not proposed, but worth knowing about:** dead-zoning only addresses error *near center*. Jitter while the stick
423
- is **deflected** is a separate problem, and the state of the art for it is the 1€ filter (Casiez et al., CHI
424
- 2012) — a speed-adaptive low-pass with two parameters: low cutoff at low speed kills jitter, rising cutoff at
425
- speed kills lag. It's ~30 lines and would slot in as an optional stage on `GamepadStick` between `raw` and
426
- `value`. I'd hold it until someone reports jitter that calibration doesn't fix, but the abstraction should leave
427
- room for it — which it does, since the stage lives inside the stick and consumers only see `value`.
428
-
429
- #### Consequences for `axes` and `deadZone`
430
-
431
- * **`pad.axes` becomes raw** — a true mirror, no destructive gating (fixes §2.3's real defect). Non-stick axes on
432
- exotic mappings are unaffected by stick calibration, as they should be.
433
- * **`GamepadDevice.deadZone` is removed**, replaced by a `@deprecated` accessor whose setter writes
434
- `noiseRadius` into every stick — existing and subsequently connected — and locks them. That is a faithful
435
- migration: the old behaviour *was* a manually-specified fixed gate, and a locked calibration is exactly that.
436
- Locking also means such a value survives reconnection, unlike a learned one.
437
- * **`on.axis` now fires at hardware sample rate on a drifting pad**, where the gate used to silence it. Decided
438
- in favour of leaving it: the raw layer is honest, and the recommended path (`stick.on.changed`) is silent at
439
- rest because the calibrated value genuinely doesn't change. The rejected alternative was gating `on.axis` at
440
- an epsilon, which is the destructive gate creeping back in under a smaller number. This is a behaviour change
441
- for anything bound to `on.axis`.
442
-
443
- ### P4 — `apply_radial_dead_zone(result, x, y, inner, outer)`
444
-
445
- `engine/input/analog/apply_radial_dead_zone.js` — device-agnostic, no allocation, no options bag, continuous:
446
-
447
- ```js
448
- export function apply_radial_dead_zone(result, x, y, inner, outer) {
449
- const m = Math.sqrt(x * x + y * y);
450
-
451
- if (m <= inner) {
452
- result.set(0, 0);
453
- return;
454
- }
455
-
456
- const scale = Math.min((m - inner) / (outer - inner), 1) / m;
457
-
458
- result.set(x * scale, y * scale);
459
- }
460
- ```
461
-
462
- Isotropic boundary (no diagonal leak), continuous at `inner` (no speed pop), saturates to unit magnitude at
463
- `outer` (no `>1` from square-gate pads). Applies equally to a stick, a touch nub, or a mouse delta.
464
-
465
- ### P5 — `gamepad_write_dpad_vector(result, pad)`
466
-
467
- `engine/input/devices/gamepad/gamepad_write_dpad_vector.js` — the D-pad as an analog vector, **in hardware
468
- frame** (`+y` down), so it composes with `stickLeft` without the consumer tracking which of the two is flipped:
469
-
470
- ```js
471
- export function gamepad_write_dpad_vector(result, pad) {
472
- const buttons = pad.buttons;
473
-
474
- const up = buttons[GamepadButtons.dpad_up].is_down;
475
- const down = buttons[GamepadButtons.dpad_down].is_down;
476
- const left = buttons[GamepadButtons.dpad_left].is_down;
477
- const right = buttons[GamepadButtons.dpad_right].is_down;
478
-
479
- result.set(
480
- (right ? 1 : 0) - (left ? 1 : 0),
481
- (down ? 1 : 0) - (up ? 1 : 0)
482
- );
483
- }
484
- ```
485
-
486
- (Total only because of P1.) The digital view of the stick is the caller's threshold on
487
- `apply_radial_dead_zone`'s output, which is a comparison, not an API.
488
-
489
- ### P6 — Documentation
490
-
491
- * Cross-reference the frame on `axes`, `stickLeft`, `stickRight`: *"Hardware frame: `+x` right, `+y` down. See
492
- {@link GamepadAxes}. Game-frame conversion belongs in the controller — see `KeyboardCameraController`."*
493
- * Drop the misleading `?.` from the `buttons` `@example` once P1 lands.
494
- * Worked gamepad-locomotion example in the `GamepadDevice` class doc (below), so the next consumer copies the
495
- intended composition instead of inventing one.
496
-
497
- ### Tests
498
-
499
- `GamepadDevice.spec.js` currently has 7 tests and does not cover any of this. Add:
500
-
501
- * P1: all standard buttons defined on a fresh handle, before any poll; `getButton(20)` still grows.
502
- * P2: `main` exists and is disconnected on a fresh device; binds to the first pad that connects; mirrors its
503
- buttons and axes; on disconnect of the bound pad falls back to the oldest remaining connected pad; goes
504
- disconnected with everything released when the last pad is lost; a button held at disconnect is released
505
- exactly once; a press on the bound pad fires device-level `on.down` exactly once (double-forwarding guard).
506
- * §3 regression: `resolvePath(devices, "gamepad/main/buttons/0/down")` resolves to a Signal on a fresh engine
507
- with no hardware, is the *same object* after connect→disconnect→reconnect, and dispatches across a pad swap.
508
- * P3 calibration: a window centered at `(0.03, -0.01)` with small noise yields a center within tolerance and a
509
- non-zero, structurally bounded `noiseRadius`; a window containing a held stick is **rejected**; a window with
510
- one 0.9 spike is rejected; a swept window is rejected; a window with one mild outlier still yields a
511
- median-based center unmoved beyond tolerance; identity + `locked` is a bit-exact passthrough of `raw` to
512
- `value`; calibrated `value` is exactly `(0,0)` for samples inside the learned radius; `axes` are byte-identical
513
- to source at all deflections (mirror contract); the deprecated `deadZone` setter reaches pads connected later.
514
- * P3 adversarial (§6.4): connecting while the stick is fully deflected, diagonally deflected, or resting at an
515
- axis extreme never calibrates; connecting while it is *slightly* deflected stays bounded below a usable
516
- gameplay dead zone and recovers; `main` and a reused slot handle each forget a previous pad's calibration, and
517
- can then learn a rest position further out than it; a locked calibration survives reconnection.
518
- * P4: rest → `(0,0)`; just inside `inner` → `(0,0)`; just outside `inner` → magnitude ≈ 0 (continuity, no jump);
519
- at `outer` → magnitude 1; beyond `outer` → magnitude 1; full diagonal on a square-gate pad → magnitude 1, not
520
- 1.41; isotropy — `(0.14, 0.14)` and `(0.198, 0)` land within epsilon of the same magnitude.
521
- * P5: each direction; opposing pair cancels to 0; diagonal → `(1, 1)` pre-normalization.
522
-
523
- All black-box, against real `GamepadHandle` / `InputDeviceSwitch` / a plain object standing in for the native
524
- `Gamepad` snapshot (a platform type we cannot construct in node — the only fake here).
525
-
526
- ### After this proposal, the reviewer's integration reads:
527
-
528
- ```js
529
- const pad = engine.devices.gamepad.main; // always present
530
-
531
- if (pad.connected) {
532
- const left = pad.stickLeft.value; // already center-corrected for this specific stick
533
-
534
- gamepad_write_dpad_vector(dpad, pad);
535
- apply_radial_dead_zone(stick, left.x, left.y, 0.15, 0.95);
536
-
537
- // fusion + frame: game policy, and this is the whole of it
538
- const x = stick.x !== 0 || stick.y !== 0 ? stick.x : dpad.x;
539
- const y = stick.x !== 0 || stick.y !== 0 ? stick.y : dpad.y;
540
-
541
- move.set(x, -y); // this game is y-up; the negation is stated once, here, on purpose
542
- }
543
- ```
544
-
545
- Shorter than what the review reported writing, with zero allocation per frame, no `undefined` guard, every policy
546
- decision visible at the call site instead of hidden behind an options bag — and a gameplay dead zone the game
547
- picks for feel rather than to paper over hardware, because the hardware error is already gone by this line.
548
-
549
- Hot-swapping pads mid-session requires no code here at all: `main` rebinds and the loop doesn't notice.
550
-
551
- ---
552
-
553
- ## 5. Explicitly not doing
554
-
555
- * **`pad.isDown(i)`** — a third way to ask a question `buttons[i].is_down` and `getButton(i).is_down` already
556
- answer, which silently converts absent hardware into an unpressed button. P1 removes the need.
557
- * **`pad.getMovement()`** — §1.
558
- * **Frame negation anywhere in the device layer** — the device reports hardware frame, full stop. One negation,
559
- in the controller, where the camera is known.
560
- * **Growing the ISM string-path layer with gamepad-specific concepts** — make the existing paths resolve (P1/P2);
561
- do not build more magic strings.
562
- * **Per-axis signals on `GamepadHandle`** — noted as a real granularity gap in §3. Partly answered by
563
- `GamepadStick.on.changed`; the remaining gap is non-stick axes on exotic mappings. Revisit if a consumer needs
564
- it.
565
- * **A calibration wizard** ("rotate the stick in circles") — the standard consumer-tool flow, and the only way to
566
- learn true per-direction range. Out of scope: Phase A needs no UI, and Phase B is deferred. If a settings
567
- screen wants one later, `GamepadStickCalibration` is already the serializable thing it would write to.
568
- * **1€ filter** — right tool for deflected-stick jitter, wrong time. Left room for it inside `GamepadStick`; see
569
- P3.
570
-
571
- ---
572
-
573
- ## 6. What changed during implementation
574
-
575
- Two corrections, both found by tests that failed against the design as written above.
576
-
577
- ### 6.1 The rest-window guard did not do what §4 claimed
578
-
579
- *(§4 now describes the shipped bounds; what it said before this correction is quoted here.)*
580
-
581
- Revision 2's P3 asserted that `REST_CANDIDATE_MAX = 0.30` plus a spread check together catch "the player was holding the
582
- stick", *"because a stick held steady at 0.25 passes the first test alone"*. That reasoning is wrong: a stick
583
- held **steady** at 0.25 also has near-zero spread, so it passes the second test too. The first implementation
584
- duly learned a held position as the rest position, producing a phantom −0.23 deflection once the player let go.
585
- The test asserting it wouldn't is what caught it.
586
-
587
- There is no way to tell resting from holding inside a single window — both are steady. So the bounds are now
588
- biased hard toward rejection, on the reasoning that **failing to calibrate is harmless** (identity is an exact
589
- passthrough) **while calibrating wrongly is actively harmful**:
590
-
591
- * `REST_CANDIDATE_MAX` 0.30 → **0.15**. Drift worse than this is a pad heading for replacement, and past some
592
- deflection a steady reading is likelier to be a hand than a stick. *(Tightened again to 0.08 in §6.4, on a
593
- better argument than this one.)*
594
- * `REST_SPREAD_MAX` 0.05 → **0.015**. This is now the primary defence, and it exploits a physical difference the
595
- original design ignored: a held stick carries the hand's tremor, a settled one carries only sensor noise, and
596
- the two differ by roughly an order of magnitude. The cost is that an unusually noisy stick never calibrates,
597
- which is the safe failure.
598
-
599
- The residual hole is documented rather than papered over: a player parked at a small steady deflection for a
600
- full second can still poison the estimate until they release, bounded by `REST_CANDIDATE_MAX`, and the
601
- minimum-magnitude rule then supersedes it. Both the poisoning and the recovery are tested.
602
-
603
- ### 6.2 `NOISE_RADIUS_MAX` became unreachable, so the clamp went
604
-
605
- With the spread bound at 0.015, a window that passes it cannot produce a radius anywhere near 0.20 — the result
606
- is structurally bounded at `REST_SPREAD_MAX · √2 · (1 + NOISE_RADIUS_DEVIATIONS)` ≈ 0.106. The clamp was a guard
607
- for a condition that can no longer occur, so it was removed and the constant kept as a derived, documented
608
- bound. The test asserts the structural property instead of the removed clamp.
609
-
610
- ### 6.3 Two smaller notes
611
-
612
- * **`main` rebinding was one frame stale.** Binding logic initially lived in `#connect`/`#disconnect`, so a
613
- successor picked up mid-poll wasn't fed hardware until the *next* poll — `main.connected` read true while
614
- `main.id` still named the unplugged pad. Binding, rebinding and refreshing now all happen in one place at the
615
- end of `poll()`, which resolves a swap within a single poll and, incidentally, removed a pre-existing
616
- duplicate `pad.update()` per poll.
617
- * **The deprecated `deadZone` setter is plumbed properly**, not just applied to pads that happen to exist when
618
- it is written — new handles pick the override up in `#obtainHandle`. A half-working compatibility shim would
619
- have been worse than none.
620
-
621
- ### 6.4 Adversarial pass: connecting with a deflected stick
622
-
623
- Two scenarios were put to the implementation afterwards. One was safe, one was not, and chasing them turned up a
624
- third defect neither scenario named.
625
-
626
- **Connecting with a *fully* deflected stick — safe by construction.** Every sample is far outside
627
- `REST_CANDIDATE_MAX`, so every window is rejected for as long as the stick is held, and release leaves an exact
628
- passthrough rather than a phantom pull the other way. Same for a diagonal hold, and for the non-standard
629
- mappings that report a released trigger as an axis resting at −1: those never calibrate, which is the correct
630
- outcome, not a silent wrong one.
631
-
632
- **Connecting with a *partially* deflected stick — this was the real gap.** A steady hold inside the plausibility
633
- bound is genuinely indistinguishable from drift in a single window, so it was adopted as the rest position and
634
- produced a phantom deflection of the same size on release. It self-corrected, but "bounded at 0.15 and recovers
635
- in about two seconds" is a weaker answer than it needs to be, because the bound was set too generously:
636
-
637
- * `REST_CANDIDATE_MAX` 0.15 → **0.08**. The reasoning that fixes it is an asymmetry the earlier revisions
638
- missed. Auto-calibration earns its keep on *small* drift — the kind that sits under a gameplay dead zone and
639
- still causes slow creep. Drift larger than that is already absorbed by any sane gameplay dead zone (XInput
640
- ships 0.24), so declining to calibrate it costs almost nothing. Poisoning, on the other hand, costs a phantom
641
- deflection. Tightening trades away the case that needs us least, and in exchange the worst wrong estimate now
642
- lands **below any usable gameplay dead zone** — it never reaches the game at all before being superseded.
643
- That is asserted directly rather than implied.
644
-
645
- **The defect neither scenario named: a handle outliving the hardware it learned.** `main` rebinding to a
646
- different pad, and a slot handle being reused when a different pad is plugged into that slot, both carried the
647
- previous pad's calibration onto new hardware. Worse than a stale offset: because the calibrator only ever moves
648
- its estimate *closer* to the origin, a new pad whose rest position sat further out than the old one's could
649
- **never** have its own rest position adopted — the wrong calibration would have been permanent. Both paths now
650
- call `forgetCalibration()`, which is a no-op on a locked calibration, since a supplied profile is not ours to
651
- discard. Regression tests cover both, including a new pad resting further out and the other way.
652
-
653
- **Recovery takes up to two windows, not one.** Windows are fixed and non-overlapping, so the one straddling a
654
- release or a rebind still contains pre-transition samples and is rejected on spread; only the window after it is
655
- clean. This affects how fast a correct estimate is found, never whether it is correct. Stated here because the
656
- first tests written assumed one window and were wrong about the contract, not about the code.
657
-
658
- **Tests: 101 passing across 13 suites in `engine/input`.** New: `GamepadHandle.spec.js`,
659
- `GamepadStick.spec.js`, `GamepadStickCalibration.spec.js`, `gamepad_write_dpad_vector.spec.js`,
660
- `apply_radial_dead_zone.spec.js`, plus P2/P3 coverage and the `resolvePath` regression in
661
- `GamepadDevice.spec.js`.
662
-
663
- ---
664
-
665
- ## Appendix A — What the state of the art actually does
666
-
667
- Surveyed while designing P3. Three things are worth having on the record.
668
-
669
- **Nobody good uses a single hard-coded constant, and everybody who ships one ships a different number.**
670
-
671
- | Stack | At-rest threshold | Notes |
672
- |---|---|---|
673
- | XInput (Microsoft) | 7849/32767 ≈ **0.240** left, 8689/32767 ≈ **0.265** right | Vendor-recommended constants, per-stick — even Microsoft doesn't use one number for both sticks on the same pad |
674
- | SDL | ±3200/32767 ≈ **0.098** | Documented as "consider at rest"; SDL notes advanced UI should let users set or **autodetect** it |
675
- | Hall-effect / TMR pads (current gen) | **0.02–0.03** | Manufacturer guidance; stable for the life of the pad rather than degrading |
676
- | Worn potentiometer pads | **0.2+**, rising | The population XInput's 0.24 is sized for |
677
- | meep today | 0.1, per-axis | Between the two, correct for neither |
678
-
679
- That spread is the argument: a constant is a bet on the worst pad you expect to see, and the modern population is
680
- bimodal — drift-free magnetic sticks alongside worn potentiometer ones. Measuring costs 60 samples once.
681
-
682
- **Native stacks calibrate against hardware data we cannot get.** A Switch pad carries factory calibration in SPI
683
- flash (per-axis min/center/max, at `0x8010`); desktop stacks apply vendor tables. The Gamepad API gives us
684
- normalized floats and `id`, and nothing else. So the choice isn't "learn vs. read the real values" — it's "learn
685
- vs. guess".
686
-
687
- **Consumer calibration tools all do the same two things**, which is a decent signal about what actually works:
688
- sample the resting position over a short window (≈60 frames is the common figure) and subtract it; then optionally
689
- sweep for range. Firmware-level fixes write the corrected center point to controller NVS. This is Phase A and
690
- Phase B, and it's why P3 puts center estimation first — offset is the defect people call "drift", and a dead zone
691
- never fixes an offset, it only hides half of one.
692
-
693
- **Dead-zone geometry.** Josh Sutphin's taxonomy (axial / radial / scaled radial / sloped-scaled-axial / hybrid)
694
- is still the reference, with a good annotated implementation set at
695
- [Minimuino/thumbstick-deadzones](https://github.com/Minimuino/thumbstick-deadzones). Scaled radial with inner and
696
- outer bounds is P4, and it's the right default: isotropic boundary, full `[0,1]` output range preserved,
697
- continuous at the inner edge. Axial has legitimate uses (menus, anything wanting pure horizontal/vertical), which
698
- is another reason it belongs in a consumer-side function rather than baked into the device.
699
-
700
- **Jitter vs. drift are different problems.** Dead zones address error near center. Error while deflected is
701
- jitter, and the state of the art is the 1€ filter (Casiez, Roussel & Vogel, CHI 2012) — a first-order low-pass
702
- whose cutoff rises with signal speed, so it stabilizes at rest and doesn't lag under motion. Two parameters,
703
- trivial to implement, measurably less lag than fixed low-pass at equal jitter reduction. Deferred, not dismissed.
704
-
705
- Sources:
706
- [XInput deadzone constants](https://learn.microsoft.com/en-us/previous-versions/windows/xna/bb197229(v=xnagamestudio.42)) ·
707
- [SDL3 gamepad axis](https://wiki.libsdl.org/SDL3/SDL_GamepadAxis) ·
708
- [SDL: stacked deadzones issue](https://github.com/libsdl-org/SDL/issues/3781) ·
709
- [Doing Thumbstick Dead Zones Right — Josh Sutphin](https://joshsutphin.com/blog/doing-thumbstick-dead-zones-right.html) ·
710
- [Understanding thumbstick deadzones](https://minimuino.github.io/thumbstick-deadzones/) ·
711
- [Switch SPI calibration layout](https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/spi_flash_notes.md) ·
712
- [Analog stick calibration data — Hand Held Legend](https://wiki.handheldlegend.com/analog-stick-calibration-data) ·
713
- [Hall-effect vs traditional thumbsticks](https://www.turtlebeach.com/blog/hall-effect-thumbsticks-vs-traditional-joysticks) ·
714
- [TMR vs hall-effect](https://www.easysmx.com/blogs/easysmx-controllers/tmr-vs-hall-effect-joysticks) ·
715
- [Controller calibration & drift — SCUF](https://www.scufgaming.com/us/en/gaming/products/scuf-products/controller-calibration-dead-zones-and-stick-drift-explained/) ·
716
- [1€ filter (CHI 2012, PDF)](https://direction.bordeaux.inria.fr/~roussel/publications/2012-CHI-one-euro-filter.pdf) ·
717
- [1€ filter reference implementations](https://github.com/casiez/OneEuroFilter)
1
+ # Gamepad API — proposal
2
+
3
+ Response to the external review *"how convenient is the meep gamepad API? (UX)"*.
4
+
5
+ > **Revision 2.** P1, P4, P5, P6 accepted as written. **P2 replaced** with a persistent `main` handle (better than
6
+ > slot pre-population — see §4.2). **P3 replaced** with learned per-stick calibration and a `GamepadStick`
7
+ > abstraction, grounded in the survey in Appendix A. Revision 1's fixed `axisNoiseFloor` is withdrawn.
8
+ >
9
+ > **Revision 3 — implemented.** All of P1–P6 have landed. §4 describes the design **as shipped**: names,
10
+ > constants and signatures there match the code. §6 records what changed between the proposal and the
11
+ > implementation, and why. §1, §2 and §5 are unchanged — they are the argument, not the design.
12
+
13
+ ## 0. Summary
14
+
15
+ The review grades a hardware abstraction layer by how little game code the consumer had to write. That is the
16
+ wrong axis, and it leads to the wrong headline recommendation.
17
+
18
+ Checked against the source:
19
+
20
+ * one papercut (**sparse `buttons`**) does not reproduce through any supported access path — the guard the
21
+ reviewer wrote is dead code;
22
+ * one technical claim (**"full-diagonal magnitude ~0.99"**) is not producible by this code at all — there is no
23
+ rescaling path in `GamepadHandle#update`;
24
+ * one papercut (**"the `.d.ts` doesn't carry the frame"**) is about a file that does not exist — `engine/input`
25
+ contains zero `.d.ts` files, and the frame *is* documented, on the enum that defines it;
26
+ * the headline recommendation (**`pad.getMovement({radialDeadzone})`**) moves gameplay policy, a coordinate
27
+ convention, an options bag, and a per-frame allocation into the driver.
28
+
29
+ The review did, however, bump into a **real structural gap and misdiagnose it**: the gamepad is effectively
30
+ invisible to the engine's input binding layer (`InputSystem` / `InputControllerSystem`). That is *why* the
31
+ reviewer ended up hand-fusing raw device state — not because the device lacks convenience methods. Closing that
32
+ gap removes the "boilerplate every consumer will duplicate" without adding a single convenience method to
33
+ `GamepadHandle`.
34
+
35
+ Two of the underlying observations are worth acting on, in a different shape than proposed.
36
+
37
+ ### Dispositions
38
+
39
+ | # | Review item | Disposition |
40
+ |---|---|---|
41
+ | 1 | `buttons` sparse → add `pad.isDown(i)` | **Reject the mechanism, accept the goal.** Claim doesn't reproduce; fix uniformity at the source (P1), don't add a third accessor. |
42
+ | 2 | `pad.getMovement({radialDeadzone})` | **Reject.** Policy in the driver. Decomposed into two device-agnostic primitives instead (P4, P5). |
43
+ | 3 | Per-axis dead-zone leaks diagonals; shortens full diagonal to ~0.99 | **Half accept.** The `~0.99` claim is fabricated. The genuine defect is different and worse: the gate is destructive, misnamed, and *guesses* a number that varies 6× across hardware. Replaced by learned calibration (P3). |
44
+ | 4 | Frame undocumented "at the type level" | **Reject as stated, accept a sliver.** No `.d.ts` exists; frame is documented in `GamepadAxes.js`. Add a cross-reference on `axes`/`stickLeft`/`stickRight` (P6). |
45
+ | 5 | No digital view of stick / analog view of D-pad; fusion is on the caller | **Accept the observation, keep fusion on the caller.** Ship the two primitives, not the fused result (P5). |
46
+ | 6 | Analog-vs-digital speed is game policy | **Agree, no action.** |
47
+ | — | *(missed)* Gamepad is unbindable through the ISM path layer | **New work.** The actual defect (P1 + P2). |
48
+
49
+ ---
50
+
51
+ ## 1. The layering premise the review is missing
52
+
53
+ meep input devices are **state mirrors of hardware**. They report what the hardware reports, plus the minimum
54
+ hygiene needed to make polled hardware observable (edge detection, stuck-input release on disconnect/stop). They
55
+ contain no game policy. This is not an accident of the gamepad implementation — it is the shape of the whole
56
+ package:
57
+
58
+ * `KeyboardDevice` exposes `keys.w.is_down`. It does not expose `keyboard.getMovement()` from WASD.
59
+ * Nobody asks it to, because the layer that owns that question already exists:
60
+ [`KeyboardCameraController.js`](ecs/controllers/KeyboardCameraController.js) — a *controller* that reads device
61
+ switches and produces a camera-frame pan vector.
62
+
63
+ `pad.getMovement()` is a request to put `KeyboardCameraController`'s job inside `KeyboardDevice`. Five concrete
64
+ reasons it does not belong there:
65
+
66
+ 1. **The game frame is not a property of the stick.** The reviewer wants `+y = up`. Up in *what*? meep's world is
67
+ 3D; "stick up" maps to a world direction that depends on the camera yaw, the projection, and whether the game
68
+ is top-down or third-person. `KeyboardCameraController` resolves exactly this and it needs a
69
+ `TopDownCameraController` to do it. A `Vector2` on a driver cannot know the answer, so any answer it bakes in
70
+ is wrong for some consumer — who then must un-negate it. That is strictly worse than never negating.
71
+
72
+ 2. **Dead-zoning is not one policy.** Radial-with-rescale is right for locomotion; per-axis is right for menu
73
+ navigation; inner+outer with a response curve is right for aiming; square-gate normalization is right for
74
+ pads that report a square gate. `{radialDeadzone}` picks one and demotes the rest to "off the golden path".
75
+
76
+ 3. **`{radialDeadzone}` is an options bag.** The codebase's position is typed and verbose over magic-looking
77
+ configuration. An options object on a per-frame hot call is the opposite of that, and it grows monotonically
78
+ — the next request is `{radialDeadzone, outerDeadzone, curve, squareGate}`.
79
+
80
+ 4. **It allocates.** `getMovement()` returning a fresh `Vector2` allocates once per consumer per frame. The
81
+ engine's convention for vector-producing calls is `f(result, ...)` writing into a caller-owned target.
82
+
83
+ 5. **It creates a dual-mode API.** With `getMovement()` present, `stickLeft` becomes "the raw one" and
84
+ `getMovement()` "the good one" — two ways to ask the same question with a silent policy difference between
85
+ them. Uniform control flow means picking the common case as the *only* case at each layer, and letting
86
+ callers who want something else drop to the lower-level primitive.
87
+
88
+ What the reviewer actually wants is real. It just belongs one layer up, and it should be *composable functions*,
89
+ not a method on the driver.
90
+
91
+ ---
92
+
93
+ ## 2. Item-by-item
94
+
95
+ *Line references in this section point at the code **as reviewed**, before any of P1–P6 landed. They are part of
96
+ the argument about what the reviewer was looking at, not navigation aids for the current tree.*
97
+
98
+ ### 2.1 "`buttons` is lazily populated and sparse, so I wrote a guard"
99
+
100
+ **This does not reproduce.** Trace the code:
101
+
102
+ * [`GamepadHandle.js:140`](devices/gamepad/GamepadHandle.js:140) — `update()` iterates **every** button in the
103
+ native snapshot and calls `getButton(i)` on each. After one update, `buttons[0 … n-1]` are all populated.
104
+ * [`GamepadDevice.js:130`](devices/GamepadDevice.js:130) — `#connect()` calls `pad.update(...)` **before**
105
+ setting `pad.connected = true`.
106
+ * [`GamepadDevice.js:86`](devices/GamepadDevice.js:86) — `main` only returns pads with `connected === true`.
107
+
108
+ So every handle reachable through `gamepad.main` has already had its full button set materialised.
109
+ `pad.buttons[GamepadButtons.a].is_down` is safe, and the `button !== undefined &&` half of the reviewer's guard
110
+ never evaluates false in a connected-pad path. The `?.` in the existing `@example` is belt-and-braces, and reads
111
+ as a warning it isn't.
112
+
113
+ The one residual hole is real but different: a **non-standard mapping** pad reporting fewer than 17 buttons.
114
+ `buttons[GamepadButtons.dpad_up]` is genuinely `undefined` there, because the button does not exist.
115
+ `pad.isDown(15)` would return `false` for it — converting "this hardware has no D-pad" into "the D-pad is not
116
+ pressed", silently, forever. That is a worse API than the honest `undefined`, and it is the reason to reject the
117
+ proposed mechanism specifically.
118
+
119
+ **The goal is still right.** Keyboard/gamepad symmetry should not have an asterisk, and `pads`/`buttons`
120
+ sparseness has a second, much more serious consequence (§3). Fix it at the source: pre-populate (P1/P2), so
121
+ there is nothing to guard and no third accessor.
122
+
123
+ ### 2.2 `getMovement()` — rejected
124
+
125
+ See §1. Replaced by P4 + P5.
126
+
127
+ ### 2.3 "Per-axis dead-zoning leaks diagonal drift and shortens the full diagonal to ~0.99"
128
+
129
+ **First half: correct.** A per-axis gate at 0.1 admits up to `sqrt(0.1² + 0.1²) ≈ 0.141` of resting magnitude,
130
+ and its boundary is anisotropic — a stick pushed to `(0.09, 0.09)` reads dead, `(0.11, 0.0)` reads live.
131
+
132
+ **Second half: not producible by this code.** The gate is
133
+ [`GamepadHandle.js:169`](devices/gamepad/GamepadHandle.js:169):
134
+
135
+ ```js
136
+ if (Math.abs(value) < deadZone) {
137
+ value = 0;
138
+ }
139
+ ```
140
+
141
+ There is no rescale, no normalization, no magnitude clamp anywhere in `update()`. A full-deflection axis passes
142
+ through byte-identical to what the hardware reported. If the reviewer measured 0.99 at full diagonal, that was
143
+ their pad's gate, not ours. This matters because it is the tell that the section was reasoned about rather than
144
+ read — and the actual defect sitting three lines away was missed.
145
+
146
+ **The actual defect** is threefold and worse than "leaks diagonals":
147
+
148
+ 1. **It is destructive.** The gated value is what gets *stored* in `axes`, so a consumer who wants radial
149
+ dead-zoning cannot recover the raw signal — the information is gone before they see it. Policy applied in a
150
+ mirror layer is not just misplaced, it is lossy.
151
+ 2. **It is discontinuous.** `0.0999 → 0`, `0.1001 → 0.1001`. Input magnitude jumps by the full dead-zone width
152
+ the instant the threshold is crossed. Any consumer mapping magnitude to speed gets a visible speed pop.
153
+ 3. **It is named for a policy it should not be implementing.** `deadZone` at `0.1` reads as "the engine has
154
+ decided your gameplay dead-zone", which is precisely how the reviewer read it.
155
+
156
+ There is a fourth problem the review could not have seen without measuring hardware, and it is the one that
157
+ kills the whole "pick a good constant" approach: **the right number varies by more than 6× across pads.** XInput
158
+ ships 0.24 (left stick) and 0.265 (right); SDL treats ±0.098 as at-rest; hall-effect and TMR pads need 0.02–0.03
159
+ and stay there for life; a worn potentiometer pad needs 0.2+ and gets worse over time. Any single constant is
160
+ sized for the worst pad in the population, and every good pad pays for it with lost range.
161
+
162
+ Fixed in P3 + P4: the device *measures* its own stick instead of guessing (learned center + noise radius), and
163
+ gameplay dead-zoning becomes a continuous, rescaling, radial primitive applied by the consumer.
164
+
165
+ ### 2.4 "Frame is undocumented at the type level — the `.d.ts` doesn't carry it"
166
+
167
+ Two problems.
168
+
169
+ * **The frame is documented**, in the file that owns the concept —
170
+ [`GamepadAxes.js:5`](devices/gamepad/GamepadAxes.js:5): *"Negative values are left/up, positive values are
171
+ right/down"*. The review cites having read it, then calls it undocumented.
172
+ * **There is no `.d.ts`.** `find src/engine/input -name "*.d.ts"` returns nothing. Hand-written `.d.ts` are not
173
+ maintained in this project; whatever the reviewer was reading was IDE inference or a stale tree. If a `.d.ts`
174
+ for this package appears, deleting it is the fix.
175
+
176
+ **Accepted sliver:** the frame note lives on the *enum*, and a consumer touching `stickLeft` may never open
177
+ `GamepadAxes.js`. One-line cross-references on `axes`, `stickLeft`, `stickRight` (P6).
178
+
179
+ ### 2.5 "No digital view of the stick, no analog view of the D-pad; fusion is on the caller"
180
+
181
+ Correct, and **fusion stays on the caller** — which of stick and D-pad wins, whether they sum or the last-touched
182
+ device latches, and whether a held D-pad suppresses stick drift are all game decisions with no defensible
183
+ default. What *is* mechanical and duplicated is the conversion on each side, so ship both directions as
184
+ primitives (P5) and leave the `max`/`or`/`latch` to the consumer.
185
+
186
+ ### 2.6 "Analog-vs-digital speed is a caller concern"
187
+
188
+ Agreed, explicitly. No action.
189
+
190
+ ---
191
+
192
+ ## 3. What the review missed: the gamepad is unbindable through the ISM
193
+
194
+ The engine's action-mapping layer resolves bindings by *path* against the device tree —
195
+ [`InputSystem.js:18`](ecs/systems/InputSystem.js:18) and
196
+ [`InputControllerSystem.js:159`](ecs/systems/InputControllerSystem.js:159), both via
197
+ [`resolvePath`](../../core/json/resolvePath.js), which **throws when a path cannot be resolved**.
198
+
199
+ Keyboard works because `KeyboardDevice` pre-populates every key from `KeyCodes` in its constructor, so
200
+ `keyboard/keys/w/down` resolves at load time, before anyone touches the hardware.
201
+
202
+ The gamepad cannot do this:
203
+
204
+ * `pads` is sparse and keyed on the hardware slot, so `gamepad/pads/0/...` throws until a pad connects;
205
+ * `buttons` is sparse until first poll, so `gamepad/pads/0/buttons/0/down` throws until the pad has been read.
206
+
207
+ Consequences: an `InputController` carrying a gamepad binding **cannot be linked until the player has already
208
+ plugged in and pressed something**; whether a given binding works depends on which physical slot the pad landed
209
+ in; and a serialized `InputBinding` referencing a gamepad path is a load-order landmine. (Unlink is safe once
210
+ link succeeded — handles are retained across disconnect — but that is the only part of the lifecycle that is.)
211
+
212
+ This — not the absence of `getMovement()` — is why the integration was "entirely on the caller". The blessed
213
+ mapping mechanism was unavailable, so the reviewer polled raw state and fused by hand, then reported the
214
+ symptoms of doing so as API friction. P1 and P2 close it as a side effect of fixing uniformity.
215
+
216
+ *(Separately: axis bindings have no per-axis granularity — only the aggregate `on.axis`, forcing listeners to
217
+ filter by index. Noted, not proposed. The string-path ISM is already the odd one out against the codebase's
218
+ typed-over-magic position; make it work, don't grow it. Direct typed state access — `pad.buttons[GamepadButtons.a].is_down`
219
+ — remains the blessed path.)*
220
+
221
+ ---
222
+
223
+ ## 4. Proposed work
224
+
225
+ ### P1 — `GamepadHandle` pre-populates the standard mapping
226
+
227
+ ```js
228
+ // gamepad/GamepadStandardMapping.js
229
+ export const GAMEPAD_STANDARD_BUTTON_COUNT = 17;
230
+ export const GAMEPAD_STANDARD_AXIS_COUNT = 4;
231
+ ```
232
+
233
+ `GamepadHandle` materialises those in its constructor: 17 `InputDeviceSwitch`, 17 zeroed `buttonValues`, 4 zeroed
234
+ `axes`. `getButton` stays as-is and keeps growing the array for hardware exposing more than 17 buttons.
235
+
236
+ Effect: `pad.buttons[GamepadButtons.dpad_up].is_down` is total. No guard, no `?.`, no `isDown()`. Exactly the
237
+ keyboard's contract.
238
+
239
+ **Tradeoff, stated explicitly:** on a non-standard pad with 6 buttons, `buttons[12]` now reads "up" rather than
240
+ "absent". Absence is signalled by `pad.mapping !== "standard"`, which is where the Gamepad API puts it, not by
241
+ holes in an array. Uniform beats expressive here — a hole is not a usable absence signal anyway, since the
242
+ consumer sees a hole for "no such button" and (previously) also for "not polled yet".
243
+
244
+ Cost: 17 small objects per handle, allocated once.
245
+
246
+ ### P2 — `main` becomes a persistent handle bound to the active pad
247
+
248
+ *(Replaces revision 1's slot pre-population. This is the better design: it gives the binding layer a stable path
249
+ without pretending four pads exist, and it matches what a single-player consumer actually means by "the
250
+ gamepad".)*
251
+
252
+ `GamepadDevice.main` becomes a `GamepadHandle` constructed with the device, living **outside** `pads[]`, starting
253
+ disconnected:
254
+
255
+ * it binds to the first pad that connects;
256
+ * when its bound pad disconnects, it rebinds to the **oldest still-connected** pad (connection order);
257
+ * when nothing is connected, it stays present and `connected === false`, with all switches released.
258
+
259
+ Mechanically `main` is a real handle fed the *same* native snapshot as its bound pad during `poll()` — not a
260
+ proxy or a getter chain. That matters: `gamepad/main/buttons/0/down` is a stable `Signal` **object** that
261
+ resolves at engine construction and never changes identity, which is exactly what `resolvePath` needs (§3).
262
+
263
+ ```js
264
+ // GamepadDevice
265
+ #connection_sequence = 0;
266
+
267
+ /**
268
+ * The active gamepad. Always present; check {@link GamepadHandle#connected}.
269
+ * Mirrors the first connected pad, falling back to the oldest remaining one when that pad is lost.
270
+ * Not a member of {@link pads}.
271
+ */
272
+ main = new GamepadHandle();
273
+ ```
274
+
275
+ Notes on the implementation:
276
+
277
+ * **Do not** forward `main.on.*` into the device-level `on.*` signals. The pad it mirrors already forwards, so
278
+ wiring both would double-fire every press for every listener.
279
+ * On unbind, `main.reset()` — releases everything, so a yank-the-cable never leaves input stuck. The next
280
+ `update()` from the new source re-presses whatever is genuinely held. Free correctness from the existing edge
281
+ detection.
282
+ * `main.index` / `.id` / `.mapping` follow the mirrored pad, because `update()` already copies them. Useful:
283
+ a settings screen can name the active pad without touching `pads`.
284
+ * Connection order needs one counter — stamp `pad.connectionIndex = this.#connectionSequence++` inside
285
+ `#connect`, pick the smallest among connected on rebind.
286
+ * Binding, rebinding and refreshing all happen in one place at the end of `poll()`. Splitting them across
287
+ `#connect`/`#disconnect` leaves `main` a frame stale on a swap — see §6.3.
288
+
289
+ Cost: one extra handle update per poll (17 buttons + 4 axes) — noise.
290
+
291
+ **Breaking, and an improvement:** `main` was `GamepadHandle | undefined`. It is now always a handle. Existing
292
+ `if (pad !== undefined)` guards still compile and simply never trigger; the check becomes `main.connected`. This
293
+ removes the only sentinel in the gamepad API, which is the direction the codebase wants anyway.
294
+
295
+ **Deliberately unresolved:** per-slot paths (`gamepad/pads/1/...`) still don't resolve, because `pads` keeps its
296
+ honest sparse hardware-slot semantics. Local multiplayer binds through the device-level `on.down`, which already
297
+ dispatches `(buttonIndex, pad)`, or holds handles from the `connected` signal. If per-player path binding is ever
298
+ wanted, the shape is an ordered player-assignment list of which `main` is element 0 — this design doesn't
299
+ preclude it, and I'd rather add it when there's a consumer than guess the assignment policy now.
300
+
301
+ ### P3 — Learned per-stick calibration, and a `GamepadStick` abstraction
302
+
303
+ *(Replaces revision 1's fixed `axisNoiseFloor`. Appendix A is the supporting survey.)*
304
+
305
+ Three findings drive this:
306
+
307
+ 1. **In a browser there is no factory calibration, so learning is the only calibration available.** Native stacks
308
+ can read hardware calibration — a Switch pad stores per-axis min/center/max in SPI flash, XInput and SDL apply
309
+ vendor-tuned constants. The Gamepad API exposes none of it: normalized floats and nothing else. Every native
310
+ stack calibrates; we're the only ones who'd be guessing.
311
+ 2. **The dominant error is a center offset, not symmetric noise.** This is what "stick drift" *is*, and it is why
312
+ every consumer calibration tool works by sampling the resting position and subtracting it. A fixed dead zone
313
+ responds to an offset center by widening the dead area — asymmetrically, so you lose range on one side and
314
+ still drift on the other. Learning the center fixes the actual defect; a dead zone only hides it.
315
+ 3. **The right radius varies 6×+ across the installed base** (§2.3). Measuring is the only way to give a TMR pad
316
+ its 0.02 and a worn pad its 0.15 from one code path.
317
+
318
+ **Layering — why this doesn't contradict §1.** Calibration is *hardware characterization*: learning that this
319
+ stick rests at `(0.03, -0.01)` with `0.018` of dispersion makes the mirror **more accurate**, which is squarely
320
+ the device layer's job. Gameplay dead zone, response curve, and frame conversion remain policy and stay with the
321
+ consumer via `apply_radial_dead_zone`. The line is: *the device removes what the hardware got wrong; the game
322
+ decides what to do with what's left.* Getting this backwards is a known failure mode — SDL applying its own dead
323
+ zone under a game that applies another is a long-standing complaint, and the result is exactly the doubled dead
324
+ zone with all precision gone.
325
+
326
+ #### The abstraction
327
+
328
+ ```js
329
+ export class GamepadStick {
330
+ /** Indices into {@link GamepadHandle#axes} that this stick reads. */
331
+ axisX = 0;
332
+ axisY = 1;
333
+
334
+ /** Hardware value, exactly as reported. */
335
+ raw = new Vector2();
336
+
337
+ /** Calibrated value: center-corrected and noise-gated. This is what gameplay should read. */
338
+ value = new Vector2();
339
+
340
+ /** @type {GamepadStickCalibration} */
341
+ calibration = new GamepadStickCalibration();
342
+
343
+ on = {
344
+ /** Fires when {@link value} changes. A calibrated stick at rest is silent. */
345
+ changed: new Signal()
346
+ };
347
+
348
+ /** Refresh from raw axis values, feeding the calibrator on the way through. */
349
+ update(axes) {}
350
+
351
+ /** Return to neutral, keeping the calibration — the hardware has not changed. */
352
+ reset() {}
353
+
354
+ /** Discard what was learned. For when the handle starts representing *different* hardware. */
355
+ forgetCalibration() {}
356
+ }
357
+
358
+ export class GamepadStickCalibration {
359
+ /** Learned rest position. */
360
+ center = new Vector2();
361
+
362
+ /** Learned dispersion around {@link center}; magnitudes inside this read as 0. */
363
+ noiseRadius = 0;
364
+
365
+ /** When true, learning is suspended and the current values are used as-is. */
366
+ locked = false;
367
+ }
368
+ ```
369
+
370
+ `stickLeft` / `stickRight` become `GamepadStick` rather than `Vector2`. **Breaking:** `pad.stickLeft.x` →
371
+ `pad.stickLeft.value.x`. Changelog line; this is public surface.
372
+
373
+ **Opt-out without a mode flag.** You asked for an opt-out, and the obvious form of it — a boolean that switches
374
+ between two code paths — is the dual-mode shape we rejected for `getMovement()`. It isn't needed here: the
375
+ transform is *always* applied, and an identity calibration (`center = (0,0)`, `noiseRadius = 0`, `locked =
376
+ true`) is a bit-exact passthrough. One code path, and "no filtering" is just a particular calibration. The same
377
+ mechanism covers a settings-screen manual dead zone and a saved per-controller profile — `GamepadStickCalibration`
378
+ gets `to/fromBinaryBuffer`, keyed on `pad.id`.
379
+
380
+ **Calibration belongs to hardware, not to a handle.** A handle outlives the pad it represents: slots get
381
+ re-occupied, and `main` moves between pads. Carrying an estimate across that would apply one pad's correction to
382
+ another — and because the calibrator only ever moves its estimate *closer* to the origin (below), a new pad
383
+ resting further out could never adopt its own rest position at all. So `forgetCalibration()` is called on a fresh
384
+ connection and when `main` binds a new source. It is a no-op on a locked calibration: a supplied profile is not
385
+ ours to discard.
386
+
387
+ #### The learning algorithm
388
+
389
+ **Phase A — rest estimation.** Runs continuously and unattended; there is no separate "on connect" mode.
390
+
391
+ * Collect `REST_SAMPLE_COUNT = 60` raw samples (≈1 s at rAF) as a fixed, non-overlapping window.
392
+ * **Reject the whole window** if any sample magnitude exceeds `REST_CANDIDATE_MAX = 0.08`, or if per-axis spread
393
+ (max − min) exceeds `REST_SPREAD_MAX = 0.015`. Resting and holding cannot be told apart inside one window —
394
+ both are steady — so the bounds are biased hard toward rejection, on the asymmetry that failing to calibrate
395
+ leaves an exact passthrough while calibrating wrongly injects phantom deflection. The spread bound is the
396
+ primary defence, and it exploits a physical difference: a held stick carries hand tremor, a settled one
397
+ carries only sensor noise, and the two differ by roughly an order of magnitude. (§6.1 and §6.4 record how
398
+ these numbers were arrived at — the first version of this section got the reasoning wrong.)
399
+ * **Center = per-axis median** of the window. Median, not mean: one spike shifts a 60-sample mean by 1.7% of its
400
+ amplitude, and shifts the median by nothing.
401
+ * **`noiseRadius` = median(d) + `NOISE_RADIUS_DEVIATIONS`·MAD(d)** where `d` are the sample distances from the
402
+ learned center and MAD is the median absolute deviation. MAD is the standard robust dispersion estimator — a
403
+ high quantile computed from 60 samples is dominated by its own tail, which is precisely the outliers we're
404
+ trying not to fit. No clamp: the spread bound already constrains the result structurally, to
405
+ `NOISE_RADIUS_MAX = REST_SPREAD_MAX · √2 · (1 + NOISE_RADIUS_DEVIATIONS)` ≈ 0.106.
406
+ * **Adopt only if closer in.** A window is written to the calibration only when its center is nearer the origin
407
+ than the accepted one. This is what makes a wrong estimate self-correcting: a stick that was being held when
408
+ sampling started is superseded the moment it is released, with no separate recovery path. The trade is that
409
+ drift *growing* within a session is not followed — a wear process measured in weeks, and calibration restarts
410
+ whenever the pad reconnects.
411
+ * **Recovery takes up to two windows.** Windows are fixed and non-overlapping, so the one straddling a release
412
+ or a rebind still holds pre-transition samples and is rejected on spread; only the window after it is clean.
413
+ This affects how quickly a correct estimate is found, never whether it is correct.
414
+
415
+ **Phase B — range estimation.** Proposed as **optional and off by default.** Pads differ in gate shape (square
416
+ gates reach ~1.41 at full diagonal, circular ones ~1.0), so a learned per-direction max would let us normalize to
417
+ a unit circle. But a running max is a self-poisoning estimator — one spike raises the ceiling permanently and
418
+ silently compresses everything afterwards. If we do it: require K consecutive samples above the current maximum
419
+ before raising it, clamp to `[0.8, 1.5]`, and decay slowly. I'd rather ship Phase A, which is high-value and
420
+ low-risk, and leave this behind a flag until a real pad demands it.
421
+
422
+ **Not proposed, but worth knowing about:** dead-zoning only addresses error *near center*. Jitter while the stick
423
+ is **deflected** is a separate problem, and the state of the art for it is the 1€ filter (Casiez et al., CHI
424
+ 2012) — a speed-adaptive low-pass with two parameters: low cutoff at low speed kills jitter, rising cutoff at
425
+ speed kills lag. It's ~30 lines and would slot in as an optional stage on `GamepadStick` between `raw` and
426
+ `value`. I'd hold it until someone reports jitter that calibration doesn't fix, but the abstraction should leave
427
+ room for it — which it does, since the stage lives inside the stick and consumers only see `value`.
428
+
429
+ #### Consequences for `axes` and `deadZone`
430
+
431
+ * **`pad.axes` becomes raw** — a true mirror, no destructive gating (fixes §2.3's real defect). Non-stick axes on
432
+ exotic mappings are unaffected by stick calibration, as they should be.
433
+ * **`GamepadDevice.deadZone` is removed**, replaced by a `@deprecated` accessor whose setter writes
434
+ `noiseRadius` into every stick — existing and subsequently connected — and locks them. That is a faithful
435
+ migration: the old behaviour *was* a manually-specified fixed gate, and a locked calibration is exactly that.
436
+ Locking also means such a value survives reconnection, unlike a learned one.
437
+ * **`on.axis` now fires at hardware sample rate on a drifting pad**, where the gate used to silence it. Decided
438
+ in favour of leaving it: the raw layer is honest, and the recommended path (`stick.on.changed`) is silent at
439
+ rest because the calibrated value genuinely doesn't change. The rejected alternative was gating `on.axis` at
440
+ an epsilon, which is the destructive gate creeping back in under a smaller number. This is a behaviour change
441
+ for anything bound to `on.axis`.
442
+
443
+ ### P4 — `apply_radial_dead_zone(result, x, y, inner, outer)`
444
+
445
+ `engine/input/analog/apply_radial_dead_zone.js` — device-agnostic, no allocation, no options bag, continuous:
446
+
447
+ ```js
448
+ export function apply_radial_dead_zone(result, x, y, inner, outer) {
449
+ const m = Math.sqrt(x * x + y * y);
450
+
451
+ if (m <= inner) {
452
+ result.set(0, 0);
453
+ return;
454
+ }
455
+
456
+ const scale = Math.min((m - inner) / (outer - inner), 1) / m;
457
+
458
+ result.set(x * scale, y * scale);
459
+ }
460
+ ```
461
+
462
+ Isotropic boundary (no diagonal leak), continuous at `inner` (no speed pop), saturates to unit magnitude at
463
+ `outer` (no `>1` from square-gate pads). Applies equally to a stick, a touch nub, or a mouse delta.
464
+
465
+ ### P5 — `gamepad_write_dpad_vector(result, pad)`
466
+
467
+ `engine/input/devices/gamepad/gamepad_write_dpad_vector.js` — the D-pad as an analog vector, **in hardware
468
+ frame** (`+y` down), so it composes with `stickLeft` without the consumer tracking which of the two is flipped:
469
+
470
+ ```js
471
+ export function gamepad_write_dpad_vector(result, pad) {
472
+ const buttons = pad.buttons;
473
+
474
+ const up = buttons[GamepadButtons.dpad_up].is_down;
475
+ const down = buttons[GamepadButtons.dpad_down].is_down;
476
+ const left = buttons[GamepadButtons.dpad_left].is_down;
477
+ const right = buttons[GamepadButtons.dpad_right].is_down;
478
+
479
+ result.set(
480
+ (right ? 1 : 0) - (left ? 1 : 0),
481
+ (down ? 1 : 0) - (up ? 1 : 0)
482
+ );
483
+ }
484
+ ```
485
+
486
+ (Total only because of P1.) The digital view of the stick is the caller's threshold on
487
+ `apply_radial_dead_zone`'s output, which is a comparison, not an API.
488
+
489
+ ### P6 — Documentation
490
+
491
+ * Cross-reference the frame on `axes`, `stickLeft`, `stickRight`: *"Hardware frame: `+x` right, `+y` down. See
492
+ {@link GamepadAxes}. Game-frame conversion belongs in the controller — see `KeyboardCameraController`."*
493
+ * Drop the misleading `?.` from the `buttons` `@example` once P1 lands.
494
+ * Worked gamepad-locomotion example in the `GamepadDevice` class doc (below), so the next consumer copies the
495
+ intended composition instead of inventing one.
496
+
497
+ ### Tests
498
+
499
+ `GamepadDevice.spec.js` currently has 7 tests and does not cover any of this. Add:
500
+
501
+ * P1: all standard buttons defined on a fresh handle, before any poll; `getButton(20)` still grows.
502
+ * P2: `main` exists and is disconnected on a fresh device; binds to the first pad that connects; mirrors its
503
+ buttons and axes; on disconnect of the bound pad falls back to the oldest remaining connected pad; goes
504
+ disconnected with everything released when the last pad is lost; a button held at disconnect is released
505
+ exactly once; a press on the bound pad fires device-level `on.down` exactly once (double-forwarding guard).
506
+ * §3 regression: `resolvePath(devices, "gamepad/main/buttons/0/down")` resolves to a Signal on a fresh engine
507
+ with no hardware, is the *same object* after connect→disconnect→reconnect, and dispatches across a pad swap.
508
+ * P3 calibration: a window centered at `(0.03, -0.01)` with small noise yields a center within tolerance and a
509
+ non-zero, structurally bounded `noiseRadius`; a window containing a held stick is **rejected**; a window with
510
+ one 0.9 spike is rejected; a swept window is rejected; a window with one mild outlier still yields a
511
+ median-based center unmoved beyond tolerance; identity + `locked` is a bit-exact passthrough of `raw` to
512
+ `value`; calibrated `value` is exactly `(0,0)` for samples inside the learned radius; `axes` are byte-identical
513
+ to source at all deflections (mirror contract); the deprecated `deadZone` setter reaches pads connected later.
514
+ * P3 adversarial (§6.4): connecting while the stick is fully deflected, diagonally deflected, or resting at an
515
+ axis extreme never calibrates; connecting while it is *slightly* deflected stays bounded below a usable
516
+ gameplay dead zone and recovers; `main` and a reused slot handle each forget a previous pad's calibration, and
517
+ can then learn a rest position further out than it; a locked calibration survives reconnection.
518
+ * P4: rest → `(0,0)`; just inside `inner` → `(0,0)`; just outside `inner` → magnitude ≈ 0 (continuity, no jump);
519
+ at `outer` → magnitude 1; beyond `outer` → magnitude 1; full diagonal on a square-gate pad → magnitude 1, not
520
+ 1.41; isotropy — `(0.14, 0.14)` and `(0.198, 0)` land within epsilon of the same magnitude.
521
+ * P5: each direction; opposing pair cancels to 0; diagonal → `(1, 1)` pre-normalization.
522
+
523
+ All black-box, against real `GamepadHandle` / `InputDeviceSwitch` / a plain object standing in for the native
524
+ `Gamepad` snapshot (a platform type we cannot construct in node — the only fake here).
525
+
526
+ ### After this proposal, the reviewer's integration reads:
527
+
528
+ ```js
529
+ const pad = engine.devices.gamepad.main; // always present
530
+
531
+ if (pad.connected) {
532
+ const left = pad.stickLeft.value; // already center-corrected for this specific stick
533
+
534
+ gamepad_write_dpad_vector(dpad, pad);
535
+ apply_radial_dead_zone(stick, left.x, left.y, 0.15, 0.95);
536
+
537
+ // fusion + frame: game policy, and this is the whole of it
538
+ const x = stick.x !== 0 || stick.y !== 0 ? stick.x : dpad.x;
539
+ const y = stick.x !== 0 || stick.y !== 0 ? stick.y : dpad.y;
540
+
541
+ move.set(x, -y); // this game is y-up; the negation is stated once, here, on purpose
542
+ }
543
+ ```
544
+
545
+ Shorter than what the review reported writing, with zero allocation per frame, no `undefined` guard, every policy
546
+ decision visible at the call site instead of hidden behind an options bag — and a gameplay dead zone the game
547
+ picks for feel rather than to paper over hardware, because the hardware error is already gone by this line.
548
+
549
+ Hot-swapping pads mid-session requires no code here at all: `main` rebinds and the loop doesn't notice.
550
+
551
+ ---
552
+
553
+ ## 5. Explicitly not doing
554
+
555
+ * **`pad.isDown(i)`** — a third way to ask a question `buttons[i].is_down` and `getButton(i).is_down` already
556
+ answer, which silently converts absent hardware into an unpressed button. P1 removes the need.
557
+ * **`pad.getMovement()`** — §1.
558
+ * **Frame negation anywhere in the device layer** — the device reports hardware frame, full stop. One negation,
559
+ in the controller, where the camera is known.
560
+ * **Growing the ISM string-path layer with gamepad-specific concepts** — make the existing paths resolve (P1/P2);
561
+ do not build more magic strings.
562
+ * **Per-axis signals on `GamepadHandle`** — noted as a real granularity gap in §3. Partly answered by
563
+ `GamepadStick.on.changed`; the remaining gap is non-stick axes on exotic mappings. Revisit if a consumer needs
564
+ it.
565
+ * **A calibration wizard** ("rotate the stick in circles") — the standard consumer-tool flow, and the only way to
566
+ learn true per-direction range. Out of scope: Phase A needs no UI, and Phase B is deferred. If a settings
567
+ screen wants one later, `GamepadStickCalibration` is already the serializable thing it would write to.
568
+ * **1€ filter** — right tool for deflected-stick jitter, wrong time. Left room for it inside `GamepadStick`; see
569
+ P3.
570
+
571
+ ---
572
+
573
+ ## 6. What changed during implementation
574
+
575
+ Two corrections, both found by tests that failed against the design as written above.
576
+
577
+ ### 6.1 The rest-window guard did not do what §4 claimed
578
+
579
+ *(§4 now describes the shipped bounds; what it said before this correction is quoted here.)*
580
+
581
+ Revision 2's P3 asserted that `REST_CANDIDATE_MAX = 0.30` plus a spread check together catch "the player was holding the
582
+ stick", *"because a stick held steady at 0.25 passes the first test alone"*. That reasoning is wrong: a stick
583
+ held **steady** at 0.25 also has near-zero spread, so it passes the second test too. The first implementation
584
+ duly learned a held position as the rest position, producing a phantom −0.23 deflection once the player let go.
585
+ The test asserting it wouldn't is what caught it.
586
+
587
+ There is no way to tell resting from holding inside a single window — both are steady. So the bounds are now
588
+ biased hard toward rejection, on the reasoning that **failing to calibrate is harmless** (identity is an exact
589
+ passthrough) **while calibrating wrongly is actively harmful**:
590
+
591
+ * `REST_CANDIDATE_MAX` 0.30 → **0.15**. Drift worse than this is a pad heading for replacement, and past some
592
+ deflection a steady reading is likelier to be a hand than a stick. *(Tightened again to 0.08 in §6.4, on a
593
+ better argument than this one.)*
594
+ * `REST_SPREAD_MAX` 0.05 → **0.015**. This is now the primary defence, and it exploits a physical difference the
595
+ original design ignored: a held stick carries the hand's tremor, a settled one carries only sensor noise, and
596
+ the two differ by roughly an order of magnitude. The cost is that an unusually noisy stick never calibrates,
597
+ which is the safe failure.
598
+
599
+ The residual hole is documented rather than papered over: a player parked at a small steady deflection for a
600
+ full second can still poison the estimate until they release, bounded by `REST_CANDIDATE_MAX`, and the
601
+ minimum-magnitude rule then supersedes it. Both the poisoning and the recovery are tested.
602
+
603
+ ### 6.2 `NOISE_RADIUS_MAX` became unreachable, so the clamp went
604
+
605
+ With the spread bound at 0.015, a window that passes it cannot produce a radius anywhere near 0.20 — the result
606
+ is structurally bounded at `REST_SPREAD_MAX · √2 · (1 + NOISE_RADIUS_DEVIATIONS)` ≈ 0.106. The clamp was a guard
607
+ for a condition that can no longer occur, so it was removed and the constant kept as a derived, documented
608
+ bound. The test asserts the structural property instead of the removed clamp.
609
+
610
+ ### 6.3 Two smaller notes
611
+
612
+ * **`main` rebinding was one frame stale.** Binding logic initially lived in `#connect`/`#disconnect`, so a
613
+ successor picked up mid-poll wasn't fed hardware until the *next* poll — `main.connected` read true while
614
+ `main.id` still named the unplugged pad. Binding, rebinding and refreshing now all happen in one place at the
615
+ end of `poll()`, which resolves a swap within a single poll and, incidentally, removed a pre-existing
616
+ duplicate `pad.update()` per poll.
617
+ * **The deprecated `deadZone` setter is plumbed properly**, not just applied to pads that happen to exist when
618
+ it is written — new handles pick the override up in `#obtainHandle`. A half-working compatibility shim would
619
+ have been worse than none.
620
+
621
+ ### 6.4 Adversarial pass: connecting with a deflected stick
622
+
623
+ Two scenarios were put to the implementation afterwards. One was safe, one was not, and chasing them turned up a
624
+ third defect neither scenario named.
625
+
626
+ **Connecting with a *fully* deflected stick — safe by construction.** Every sample is far outside
627
+ `REST_CANDIDATE_MAX`, so every window is rejected for as long as the stick is held, and release leaves an exact
628
+ passthrough rather than a phantom pull the other way. Same for a diagonal hold, and for the non-standard
629
+ mappings that report a released trigger as an axis resting at −1: those never calibrate, which is the correct
630
+ outcome, not a silent wrong one.
631
+
632
+ **Connecting with a *partially* deflected stick — this was the real gap.** A steady hold inside the plausibility
633
+ bound is genuinely indistinguishable from drift in a single window, so it was adopted as the rest position and
634
+ produced a phantom deflection of the same size on release. It self-corrected, but "bounded at 0.15 and recovers
635
+ in about two seconds" is a weaker answer than it needs to be, because the bound was set too generously:
636
+
637
+ * `REST_CANDIDATE_MAX` 0.15 → **0.08**. The reasoning that fixes it is an asymmetry the earlier revisions
638
+ missed. Auto-calibration earns its keep on *small* drift — the kind that sits under a gameplay dead zone and
639
+ still causes slow creep. Drift larger than that is already absorbed by any sane gameplay dead zone (XInput
640
+ ships 0.24), so declining to calibrate it costs almost nothing. Poisoning, on the other hand, costs a phantom
641
+ deflection. Tightening trades away the case that needs us least, and in exchange the worst wrong estimate now
642
+ lands **below any usable gameplay dead zone** — it never reaches the game at all before being superseded.
643
+ That is asserted directly rather than implied.
644
+
645
+ **The defect neither scenario named: a handle outliving the hardware it learned.** `main` rebinding to a
646
+ different pad, and a slot handle being reused when a different pad is plugged into that slot, both carried the
647
+ previous pad's calibration onto new hardware. Worse than a stale offset: because the calibrator only ever moves
648
+ its estimate *closer* to the origin, a new pad whose rest position sat further out than the old one's could
649
+ **never** have its own rest position adopted — the wrong calibration would have been permanent. Both paths now
650
+ call `forgetCalibration()`, which is a no-op on a locked calibration, since a supplied profile is not ours to
651
+ discard. Regression tests cover both, including a new pad resting further out and the other way.
652
+
653
+ **Recovery takes up to two windows, not one.** Windows are fixed and non-overlapping, so the one straddling a
654
+ release or a rebind still contains pre-transition samples and is rejected on spread; only the window after it is
655
+ clean. This affects how fast a correct estimate is found, never whether it is correct. Stated here because the
656
+ first tests written assumed one window and were wrong about the contract, not about the code.
657
+
658
+ **Tests: 101 passing across 13 suites in `engine/input`.** New: `GamepadHandle.spec.js`,
659
+ `GamepadStick.spec.js`, `GamepadStickCalibration.spec.js`, `gamepad_write_dpad_vector.spec.js`,
660
+ `apply_radial_dead_zone.spec.js`, plus P2/P3 coverage and the `resolvePath` regression in
661
+ `GamepadDevice.spec.js`.
662
+
663
+ ---
664
+
665
+ ## Appendix A — What the state of the art actually does
666
+
667
+ Surveyed while designing P3. Three things are worth having on the record.
668
+
669
+ **Nobody good uses a single hard-coded constant, and everybody who ships one ships a different number.**
670
+
671
+ | Stack | At-rest threshold | Notes |
672
+ |---|---|---|
673
+ | XInput (Microsoft) | 7849/32767 ≈ **0.240** left, 8689/32767 ≈ **0.265** right | Vendor-recommended constants, per-stick — even Microsoft doesn't use one number for both sticks on the same pad |
674
+ | SDL | ±3200/32767 ≈ **0.098** | Documented as "consider at rest"; SDL notes advanced UI should let users set or **autodetect** it |
675
+ | Hall-effect / TMR pads (current gen) | **0.02–0.03** | Manufacturer guidance; stable for the life of the pad rather than degrading |
676
+ | Worn potentiometer pads | **0.2+**, rising | The population XInput's 0.24 is sized for |
677
+ | meep today | 0.1, per-axis | Between the two, correct for neither |
678
+
679
+ That spread is the argument: a constant is a bet on the worst pad you expect to see, and the modern population is
680
+ bimodal — drift-free magnetic sticks alongside worn potentiometer ones. Measuring costs 60 samples once.
681
+
682
+ **Native stacks calibrate against hardware data we cannot get.** A Switch pad carries factory calibration in SPI
683
+ flash (per-axis min/center/max, at `0x8010`); desktop stacks apply vendor tables. The Gamepad API gives us
684
+ normalized floats and `id`, and nothing else. So the choice isn't "learn vs. read the real values" — it's "learn
685
+ vs. guess".
686
+
687
+ **Consumer calibration tools all do the same two things**, which is a decent signal about what actually works:
688
+ sample the resting position over a short window (≈60 frames is the common figure) and subtract it; then optionally
689
+ sweep for range. Firmware-level fixes write the corrected center point to controller NVS. This is Phase A and
690
+ Phase B, and it's why P3 puts center estimation first — offset is the defect people call "drift", and a dead zone
691
+ never fixes an offset, it only hides half of one.
692
+
693
+ **Dead-zone geometry.** Josh Sutphin's taxonomy (axial / radial / scaled radial / sloped-scaled-axial / hybrid)
694
+ is still the reference, with a good annotated implementation set at
695
+ [Minimuino/thumbstick-deadzones](https://github.com/Minimuino/thumbstick-deadzones). Scaled radial with inner and
696
+ outer bounds is P4, and it's the right default: isotropic boundary, full `[0,1]` output range preserved,
697
+ continuous at the inner edge. Axial has legitimate uses (menus, anything wanting pure horizontal/vertical), which
698
+ is another reason it belongs in a consumer-side function rather than baked into the device.
699
+
700
+ **Jitter vs. drift are different problems.** Dead zones address error near center. Error while deflected is
701
+ jitter, and the state of the art is the 1€ filter (Casiez, Roussel & Vogel, CHI 2012) — a first-order low-pass
702
+ whose cutoff rises with signal speed, so it stabilizes at rest and doesn't lag under motion. Two parameters,
703
+ trivial to implement, measurably less lag than fixed low-pass at equal jitter reduction. Deferred, not dismissed.
704
+
705
+ Sources:
706
+ [XInput deadzone constants](https://learn.microsoft.com/en-us/previous-versions/windows/xna/bb197229(v=xnagamestudio.42)) ·
707
+ [SDL3 gamepad axis](https://wiki.libsdl.org/SDL3/SDL_GamepadAxis) ·
708
+ [SDL: stacked deadzones issue](https://github.com/libsdl-org/SDL/issues/3781) ·
709
+ [Doing Thumbstick Dead Zones Right — Josh Sutphin](https://joshsutphin.com/blog/doing-thumbstick-dead-zones-right.html) ·
710
+ [Understanding thumbstick deadzones](https://minimuino.github.io/thumbstick-deadzones/) ·
711
+ [Switch SPI calibration layout](https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/spi_flash_notes.md) ·
712
+ [Analog stick calibration data — Hand Held Legend](https://wiki.handheldlegend.com/analog-stick-calibration-data) ·
713
+ [Hall-effect vs traditional thumbsticks](https://www.turtlebeach.com/blog/hall-effect-thumbsticks-vs-traditional-joysticks) ·
714
+ [TMR vs hall-effect](https://www.easysmx.com/blogs/easysmx-controllers/tmr-vs-hall-effect-joysticks) ·
715
+ [Controller calibration & drift — SCUF](https://www.scufgaming.com/us/en/gaming/products/scuf-products/controller-calibration-dead-zones-and-stick-drift-explained/) ·
716
+ [1€ filter (CHI 2012, PDF)](https://direction.bordeaux.inria.fr/~roussel/publications/2012-CHI-one-euro-filter.pdf) ·
717
+ [1€ filter reference implementations](https://github.com/casiez/OneEuroFilter)