@woosh/meep-engine 3.1.0 → 3.2.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 (1822) 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/core/binary/BitImage2.js +246 -246
  134. package/src/core/binary/align_32.js +21 -21
  135. package/src/core/binary/data_view/DataType2DataViewReaders.js +23 -23
  136. package/src/core/binary/data_view/DataType2DataViewWriters.js +25 -25
  137. package/src/core/binary/hash/XXH128Hash.js +55 -55
  138. package/src/core/binary/hash/XXH3_SECRET.js +25 -25
  139. package/src/core/binary/hash/xxh3_128.js +341 -341
  140. package/src/core/binary/hash/xxh3_64.js +241 -241
  141. package/src/core/binary/hash/xxh3_common.js +476 -476
  142. package/src/core/binary/lz4/LZ4_MAX_INPUT_SIZE.js +9 -9
  143. package/src/core/binary/lz4/lz4_compress_block.js +385 -385
  144. package/src/core/binary/lz4/lz4_compress_bound.js +25 -25
  145. package/src/core/binary/lz4/lz4_decompress_block.js +139 -139
  146. package/src/core/binary/lz4/lz4_decompress_bound.js +30 -30
  147. package/src/core/binary/meshopt/MESHOPT_GROUP_SIZE.js +18 -18
  148. package/src/core/binary/meshopt/MeshoptCompressionFilter.js +30 -30
  149. package/src/core/binary/meshopt/MeshoptCompressionMode.js +21 -21
  150. package/src/core/binary/meshopt/__meshopt_test_streams.js +237 -237
  151. package/src/core/binary/meshopt/meshopt_decode.js +73 -73
  152. package/src/core/binary/meshopt/meshopt_decode_byte_group.js +67 -67
  153. package/src/core/binary/meshopt/meshopt_decode_data_block.js +59 -59
  154. package/src/core/binary/meshopt/meshopt_decode_filter_color.js +69 -69
  155. package/src/core/binary/meshopt/meshopt_decode_filter_exponential.js +43 -43
  156. package/src/core/binary/meshopt/meshopt_decode_filter_octahedral.js +60 -60
  157. package/src/core/binary/meshopt/meshopt_decode_filter_quaternion.js +71 -71
  158. package/src/core/binary/meshopt/meshopt_decode_index_buffer.js +294 -294
  159. package/src/core/binary/meshopt/meshopt_decode_index_sequence.js +115 -115
  160. package/src/core/binary/meshopt/meshopt_decode_vertex_buffer.js +381 -381
  161. package/src/core/binary/meshopt/meshopt_read_uint_var.js +59 -59
  162. package/src/core/binary/reinterpret_float32_as_uint32.js +13 -13
  163. package/src/core/binary/reinterpret_uint32_as_float32.js +14 -14
  164. package/src/core/binary/type/DataType2TypedArrayConstructorMapping.js +35 -35
  165. package/src/core/bvh2/bvh3/ebvh_geometry_query_any_triangle_ray.js +149 -149
  166. package/src/core/bvh2/bvh3/ebvh_sort_for_traversal_depth_first.js +96 -96
  167. package/src/core/bvh2/bvh3/query/bvh_query_depth_range_in_frustum.js +101 -101
  168. package/src/core/bvh2/bvh3/query/bvh_query_leaves_generic.js +77 -77
  169. package/src/core/bvh2/bvh3/query/bvh_query_leaves_ray.js +90 -90
  170. package/src/core/bvh2/bvh3/query/bvh_query_leaves_ray_segment.js +94 -94
  171. package/src/core/bvh2/bvh3/query/bvh_query_user_data_generic.js +86 -86
  172. package/src/core/bvh2/bvh3/query/bvh_query_user_data_intersects_capsule.js +101 -101
  173. package/src/core/bvh2/bvh3/query/bvh_query_user_data_intersects_sphere.js +92 -92
  174. package/src/core/bvh2/bvh3/query/bvh_query_user_data_ray.js +96 -96
  175. package/src/core/bvh2/bvh3/query/bvh_query_user_data_ray_segment.js +100 -100
  176. package/src/core/bvh2/visual/BVHGeometry.js +131 -131
  177. package/src/core/bvh8/BVH8.js +436 -436
  178. package/src/core/bvh8/aabb3_round_to_float32.js +22 -22
  179. package/src/core/bvh8/build/BVH8Converter.js +588 -588
  180. package/src/core/bvh8/build/TriangleCluster.js +122 -122
  181. package/src/core/bvh8/build/aabb3_compute_merge_cost.js +28 -28
  182. package/src/core/bvh8/build/aabb3_from_triangle_by_index.js +17 -17
  183. package/src/core/bvh8/build/bvh8_build_for_geometry.js +303 -303
  184. package/src/core/bvh8/build/bvh8_from_proxy.js +256 -256
  185. package/src/core/bvh8/build/byte.js +9 -9
  186. package/src/core/bvh8/build/encode_bounds_e.js +11 -11
  187. package/src/core/bvh8/bvh8_convert_to_dot.js +132 -132
  188. package/src/core/bvh8/bvh8_count_primitives.js +98 -98
  189. package/src/core/bvh8/bvh8_geometry_validate.js +138 -138
  190. package/src/core/bvh8/bvh8_geometry_validate_indirect.js +166 -166
  191. package/src/core/bvh8/bvh8_get_node_bounds.js +34 -34
  192. package/src/core/bvh8/bvh8_get_node_child_bounds.js +52 -52
  193. package/src/core/bvh8/bvh8_node_child_surface_area.js +18 -18
  194. package/src/core/bvh8/bvh8_node_count_triangles.js +27 -27
  195. package/src/core/bvh8/bvh8_quality.js +72 -72
  196. package/src/core/bvh8/bvh8_validate_structure.js +87 -87
  197. package/src/core/clipboard/obtainClipBoard.js +29 -29
  198. package/src/core/clipboard/safeClipboardReadText.js +55 -55
  199. package/src/core/clipboard/safeClipboardWriteText.js +23 -23
  200. package/src/core/collection/array/typed/typed_array_value_denormalize.js +52 -52
  201. package/src/core/collection/array/typed/typed_array_value_normalize.js +51 -51
  202. package/src/core/collection/union-find/union_find.js +79 -79
  203. package/src/core/color/YCoCg/rgb_to_ycocg.js +20 -20
  204. package/src/core/color/YCoCg/ycocg_to_rgb.js +17 -17
  205. package/src/core/color/colormap/MAGMA_LUT.js +26 -26
  206. package/src/core/color/illuminant/D65_TRISTIMULUS_XYZ.js +19 -19
  207. package/src/core/color/lab/lab_apply_hunt_adjustment.js +27 -27
  208. package/src/core/color/lab/lab_distance_hyab.js +23 -23
  209. package/src/core/color/lab/xyz_to_lab.js +62 -62
  210. package/src/core/color/operations/color_darken.js +24 -24
  211. package/src/core/color/operations/color_desaturate.js +24 -24
  212. package/src/core/color/operations/color_lighten.js +24 -24
  213. package/src/core/color/operations/color_saturate.js +24 -24
  214. package/src/core/color/operations/color_scale_okhsv_channel.js +45 -45
  215. package/src/core/color/tonemap/tonemap_aces.js +41 -41
  216. package/src/core/color/ycxcz/xyz_to_ycxcz.js +28 -28
  217. package/src/core/color/ycxcz/ycxcz_to_xyz.js +19 -19
  218. package/src/core/dom/isImageBitmap.js +12 -12
  219. package/src/core/function/frameThrottle.js +23 -23
  220. package/src/core/geom/2d/aabb/aabb2_array_combine.js +7 -7
  221. package/src/core/geom/2d/aabb/aabb2_compute_area.js +7 -7
  222. package/src/core/geom/2d/aabb/aabb2_compute_center_from_multiple.js +7 -7
  223. package/src/core/geom/2d/aabb/aabb2_compute_overlap.js +7 -7
  224. package/src/core/geom/2d/aabb/aabb2_from_v2_array.js +7 -7
  225. package/src/core/geom/2d/aabb/aabb2_intersects_point.js +7 -7
  226. package/src/core/geom/2d/aabb/aabb2_overlap_exists.js +7 -7
  227. package/src/core/geom/2d/circle/circle_compute_circle_intersection.js +7 -7
  228. package/src/core/geom/2d/circle/circle_compute_circle_penetration.js +7 -7
  229. package/src/core/geom/2d/circle/circle_intersects_point.js +7 -7
  230. package/src/core/geom/2d/compute_polygon_area_2d.js +7 -7
  231. package/src/core/geom/2d/convex-hull/fixed_convex_hull_humus.js +7 -7
  232. package/src/core/geom/2d/convex-hull/fixed_convex_hull_relaxation.js +7 -7
  233. package/src/core/geom/2d/convex-hull/orientation3_array.js +7 -7
  234. package/src/core/geom/2d/intersect_ray_2d.js +7 -7
  235. package/src/core/geom/2d/line/line2_distance_to_point_sqr.js +7 -7
  236. package/src/core/geom/2d/line/line2_segment_intersection_fraction_2d.js +44 -44
  237. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_2d.js +7 -7
  238. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_array_2d.js +7 -7
  239. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_2d.js +7 -7
  240. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_array_2d.js +7 -7
  241. package/src/core/geom/2d/line/line_segment_intersection_fraction_2d.js +7 -7
  242. package/src/core/geom/2d/line/line_segment_line_segment_intersection_exists_2d.js +7 -7
  243. package/src/core/geom/2d/line/segment2_intersects_segment2_2d.js +25 -25
  244. package/src/core/geom/2d/line/segment2_segment_compute_intersection_array_2d.js +46 -46
  245. package/src/core/geom/2d/line/segment2_segment_intersection_fractions.js +52 -52
  246. package/src/core/geom/2d/oriented-box/min_area_rect_2d.js +69 -69
  247. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +433 -433
  248. package/src/core/geom/2d/polygon/polygon2_clip_axis_halfplane.js +51 -51
  249. package/src/core/geom/2d/polygon/polygon2_clip_halfplane.js +50 -50
  250. package/src/core/geom/2d/polygon/polygon2_is_counter_clockwise.js +84 -84
  251. package/src/core/geom/2d/polygon/polygon2_signed_area.js +52 -52
  252. package/src/core/geom/2d/polygon/polygon2_triangulate.corpus.js +86 -86
  253. package/src/core/geom/2d/polygon/polygon2_triangulate.js +1280 -1280
  254. package/src/core/geom/2d/polygon/polygon2_triangulation_deviation.js +77 -77
  255. package/src/core/geom/2d/quad-tree/qt_collect_by_circle.js +39 -39
  256. package/src/core/geom/2d/quad-tree/qt_match_data_by_circle.js +101 -101
  257. package/src/core/geom/2d/quad-tree/qt_query_data_nearest_to_point.js +7 -7
  258. package/src/core/geom/2d/rectangle_to_aabb.js +7 -7
  259. package/src/core/geom/2d/spline_bezier2_2d.js +7 -7
  260. package/src/core/geom/2d/triangle/tri2_rasterize_conservative.js +99 -99
  261. package/src/core/geom/2d/triangle/tri2_signed_area.js +35 -35
  262. package/src/core/geom/2d/triangle2d_compute_area.js +7 -7
  263. package/src/core/geom/2d/triangle2d_contains_point.js +7 -7
  264. package/src/core/geom/2d/triangle2d_get_barycentric.js +7 -7
  265. package/src/core/geom/2d/v2_morton_encode.js +23 -23
  266. package/src/core/geom/3d/aabb/aabb3_array_intersects_frustum_degree.js +7 -7
  267. package/src/core/geom/3d/aabb/aabb3_box_surface_area_2.js +7 -7
  268. package/src/core/geom/3d/aabb/aabb3_build_frustum.js +5 -5
  269. package/src/core/geom/3d/aabb/aabb3_closest_point_on_surface.js +57 -57
  270. package/src/core/geom/3d/aabb/aabb3_combined_surface_area.js +7 -7
  271. package/src/core/geom/3d/aabb/aabb3_compute_half_surface_area.js +7 -7
  272. package/src/core/geom/3d/aabb/aabb3_compute_projected_area.js +7 -7
  273. package/src/core/geom/3d/aabb/aabb3_compute_surface_area.js +7 -7
  274. package/src/core/geom/3d/aabb/aabb3_detailed_volume_intersection.js +7 -7
  275. package/src/core/geom/3d/aabb/aabb3_estimate_projected_area2.js +7 -7
  276. package/src/core/geom/3d/aabb/aabb3_from_threejs_geometry.js +7 -7
  277. package/src/core/geom/3d/aabb/aabb3_from_triangle_group.js +46 -46
  278. package/src/core/geom/3d/aabb/aabb3_intersects_frustum_degree.js +7 -7
  279. package/src/core/geom/3d/aabb/aabb3_intersects_line_segment.js +7 -7
  280. package/src/core/geom/3d/aabb/aabb3_near_distance_to_intersection_ray_segment.js +7 -7
  281. package/src/core/geom/3d/aabb/aabb3_nearest_point_on_surface.js +7 -7
  282. package/src/core/geom/3d/aabb/aabb3_ray_segment_entry_distance.js +95 -95
  283. package/src/core/geom/3d/aabb/aabb3_raycast.js +7 -7
  284. package/src/core/geom/3d/aabb/aabb3_transform_oriented.js +93 -93
  285. package/src/core/geom/3d/aabb/aabb3_transform_oriented_inverse.js +82 -82
  286. package/src/core/geom/3d/aabb/compute_aabb_from_points.js +7 -7
  287. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.js +7 -7
  288. package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +486 -486
  289. package/src/core/geom/3d/atlas/BFF_PLAN.md +174 -174
  290. package/src/core/geom/3d/atlas/Chart.js +77 -77
  291. package/src/core/geom/3d/atlas/REVIEW_02.md +392 -392
  292. package/src/core/geom/3d/atlas/atlas_bench_lib.js +315 -315
  293. package/src/core/geom/3d/atlas/atlas_chart_type.js +16 -16
  294. package/src/core/geom/3d/atlas/atlas_compute_charts.js +188 -188
  295. package/src/core/geom/3d/atlas/atlas_extract_chart.js +107 -107
  296. package/src/core/geom/3d/atlas/atlas_generate.js +50 -50
  297. package/src/core/geom/3d/atlas/atlas_test_fixtures.js +266 -266
  298. package/src/core/geom/3d/atlas/atlas_write_chart_uvs.js +36 -36
  299. package/src/core/geom/3d/atlas/data/atlas_build_edge_dihedrals.js +62 -62
  300. package/src/core/geom/3d/atlas/data/atlas_build_edge_lengths.js +33 -33
  301. package/src/core/geom/3d/atlas/data/atlas_build_face_areas.js +50 -50
  302. package/src/core/geom/3d/atlas/io/atlas_mesh_weld_colocals.js +39 -39
  303. package/src/core/geom/3d/atlas/io/bt_loop_uv.js +35 -35
  304. package/src/core/geom/3d/atlas/pack/ChartPlacement.js +46 -46
  305. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_bff.js +269 -269
  306. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_lscm.js +209 -209
  307. package/src/core/geom/3d/atlas/param/atlas_chart_parameterize_ortho.js +38 -38
  308. package/src/core/geom/3d/atlas/param/atlas_chart_stretch_metric.js +86 -86
  309. package/src/core/geom/3d/atlas/param/atlas_piecewise_resegment.js +183 -183
  310. package/src/core/geom/3d/atlas/param/fit_plane_basis.js +66 -66
  311. package/src/core/geom/3d/atlas/segment/RegionGraph.js +40 -40
  312. package/src/core/geom/3d/atlas/segment/atlas_build_region_graph.js +136 -136
  313. package/src/core/geom/3d/atlas/segment/atlas_chart_roundness_delta.js +30 -30
  314. package/src/core/geom/3d/atlas/segment/atlas_compute_planar_regions.js +77 -77
  315. package/src/core/geom/3d/atlas/segment/atlas_merge_charts.js +116 -116
  316. package/src/core/geom/3d/atlas/segment/atlas_segment_charts.js +271 -271
  317. package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.js +191 -191
  318. package/src/core/geom/3d/box/box3_projected_half_extent.js +35 -35
  319. package/src/core/geom/3d/capsule/capsule_intersects_aabb3_closed.js +67 -67
  320. package/src/core/geom/3d/capsule/capsule_intersects_aabb3_iterative.js +137 -137
  321. package/src/core/geom/3d/compute_circle_bounding_box.js +7 -7
  322. package/src/core/geom/3d/cone/computeConeBoundingBox.js +7 -7
  323. package/src/core/geom/3d/cone/computeConePlaneSide.js +7 -7
  324. package/src/core/geom/3d/cone/compute_bounding_cone_of_2_cones.js +7 -7
  325. package/src/core/geom/3d/cylinder/cylinder3_raycast.d.ts +38 -0
  326. package/src/core/geom/3d/cylinder/cylinder3_raycast.d.ts.map +1 -0
  327. package/src/core/geom/3d/cylinder/cylinder3_raycast.js +105 -0
  328. package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.js +18 -18
  329. package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.js +24 -24
  330. package/src/core/geom/3d/frustum/clipping_volume_matrix4_project.js +7 -7
  331. package/src/core/geom/3d/frustum/frustum3_computeNearestPointToPoint.js +7 -7
  332. package/src/core/geom/3d/frustum/frustum3_compute_closest_point.js +117 -117
  333. package/src/core/geom/3d/frustum/frustum_matrix4_project.js +7 -7
  334. package/src/core/geom/3d/frustum/hexahedron_from_aabb.js +7 -7
  335. package/src/core/geom/3d/frustum/read_frustum_corner.js +17 -17
  336. package/src/core/geom/3d/frustum/read_three_planes_to_array.js +7 -7
  337. package/src/core/geom/3d/frustum/slice_frustum_linear_to_points.js +7 -7
  338. package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +146 -146
  339. package/src/core/geom/3d/gjk/gjk.js +430 -430
  340. package/src/core/geom/3d/gjk/gjk_epa_penetration.js +520 -520
  341. package/src/core/geom/3d/gjk/minkowski_support.js +71 -71
  342. package/src/core/geom/3d/gjk/mpr.js +368 -368
  343. package/src/core/geom/3d/line/line3_closest_points_segment_segment.js +7 -7
  344. package/src/core/geom/3d/line/line3_compute_nearest_point_to_point.js +7 -7
  345. package/src/core/geom/3d/line/line3_compute_point_segment_point_distance_unfolded.js +64 -64
  346. package/src/core/geom/3d/line/line3_compute_segment_closest_point_to_aabb3_t.js +153 -153
  347. package/src/core/geom/3d/line/line3_compute_segment_nearest_point_to_aabb3_t.js +7 -7
  348. package/src/core/geom/3d/line/line3_compute_segment_nearest_point_to_point_t.js +7 -7
  349. package/src/core/geom/3d/line/line3_compute_segment_segment_closest_points.js +88 -88
  350. package/src/core/geom/3d/line/line3_segment_segment_closest_point_pair.js +71 -71
  351. package/src/core/geom/3d/line/segment3_point_distance_to_segments.js +25 -25
  352. package/src/core/geom/3d/mat4/allocate_m4.js +7 -7
  353. package/src/core/geom/3d/mat4/apply_mat4_transform_to_direction_v3_array.js +7 -7
  354. package/src/core/geom/3d/mat4/apply_mat4_transform_to_v3_array.js +7 -7
  355. package/src/core/geom/3d/mat4/compose_matrix4_array.js +7 -7
  356. package/src/core/geom/3d/mat4/decompose_matrix_4_array.js +7 -7
  357. package/src/core/geom/3d/mat4/eulerAnglesFromMatrix.js +7 -7
  358. package/src/core/geom/3d/mat4/m4_compose.js +22 -22
  359. package/src/core/geom/3d/mat4/m4_compute_normal_matrix3.js +7 -7
  360. package/src/core/geom/3d/mat4/m4_decompose.js +64 -64
  361. package/src/core/geom/3d/mat4/m4_decompose_array.js +157 -157
  362. package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale.js +32 -32
  363. package/src/core/geom/3d/mat4/m4_from_rotation_translation_scale_scalar.js +67 -67
  364. package/src/core/geom/3d/mat4/m4_linear_matrix3.js +29 -29
  365. package/src/core/geom/3d/mat4/m4_look_at.js +96 -96
  366. package/src/core/geom/3d/mat4/m4_make_rotation_x.js +47 -47
  367. package/src/core/geom/3d/mat4/m4_make_rotation_y.js +47 -47
  368. package/src/core/geom/3d/mat4/m4_make_rotation_z.js +47 -47
  369. package/src/core/geom/3d/mat4/m4_normal_matrix3.js +39 -39
  370. package/src/core/geom/3d/mat4/m4_perspective.js +66 -66
  371. package/src/core/geom/3d/mat4/m4_transpose.js +48 -48
  372. package/src/core/geom/3d/morton/mortonEncode_LUT.js +7 -7
  373. package/src/core/geom/3d/morton/mortonEncode_magicbits.js +7 -7
  374. package/src/core/geom/3d/normal/hemioct/encode_unit3_hemioct.js +5 -5
  375. package/src/core/geom/3d/normal/hemioct/encode_unit_to_hemioct.js +28 -28
  376. package/src/core/geom/3d/normal/lambert_azimuth/decode_azimuth_to_unit.js +30 -30
  377. package/src/core/geom/3d/normal/lambert_azimuth/encode_unit_to_azimuth.js +19 -19
  378. package/src/core/geom/3d/normal/spherical/decode_spheremap_to_unit.js +38 -38
  379. package/src/core/geom/3d/normal/spherical/encode_unit_to_spheremap.js +30 -30
  380. package/src/core/geom/3d/plane/is_point_within_planes.js +7 -7
  381. package/src/core/geom/3d/plane/orient3d_fast_point.js +47 -47
  382. package/src/core/geom/3d/plane/plane3_compute_convex_3_plane_intersection.js +7 -7
  383. package/src/core/geom/3d/plane/plane3_compute_plane_intersection.js +7 -7
  384. package/src/core/geom/3d/plane/plane3_intersect_plane.js +7 -7
  385. package/src/core/geom/3d/plane/plane3_three_compute_convex_3_plane_intersection.js +7 -7
  386. package/src/core/geom/3d/point/point3_raycast.d.ts +33 -0
  387. package/src/core/geom/3d/point/point3_raycast.d.ts.map +1 -0
  388. package/src/core/geom/3d/point/point3_raycast.js +47 -0
  389. package/src/core/geom/3d/polygon/polygon3_compute_normal.js +60 -60
  390. package/src/core/geom/3d/polygon/polygon3_triangulate.js +94 -94
  391. package/src/core/geom/3d/polyhedron/convex_polyhedron3_raycast.d.ts +40 -0
  392. package/src/core/geom/3d/polyhedron/convex_polyhedron3_raycast.d.ts.map +1 -0
  393. package/src/core/geom/3d/polyhedron/convex_polyhedron3_raycast.js +94 -0
  394. package/src/core/geom/3d/quadric/QUADRIC3_SIZE.js +14 -14
  395. package/src/core/geom/3d/quadric/Quadric3.js +282 -282
  396. package/src/core/geom/3d/quadric/quadric3_add.js +33 -33
  397. package/src/core/geom/3d/quadric/quadric3_clear.js +25 -25
  398. package/src/core/geom/3d/quadric/quadric3_copy.js +27 -27
  399. package/src/core/geom/3d/quadric/quadric3_distance.js +36 -36
  400. package/src/core/geom/3d/quadric/quadric3_evaluate.js +25 -25
  401. package/src/core/geom/3d/quadric/quadric3_optimize.js +45 -45
  402. package/src/core/geom/3d/quadric/quadric3_scale.js +32 -32
  403. package/src/core/geom/3d/quadric/quadric3_set_from_plane_through_point.js +30 -30
  404. package/src/core/geom/3d/quadric/quadric3_set_from_vector4.js +35 -35
  405. package/src/core/geom/3d/quadric/quadric3_sub.js +36 -36
  406. package/src/core/geom/3d/quadric/quadric3_to_tensor_m3.js +28 -28
  407. package/src/core/geom/3d/quadric/quadric3_to_tensor_m3_inverse.js +56 -56
  408. package/src/core/geom/3d/quadric/quadric3_to_vector3.js +19 -19
  409. package/src/core/geom/3d/quaternion/quat3_createFromAxisAngle.js +7 -7
  410. package/src/core/geom/3d/quaternion/quat3_integrate.js +62 -62
  411. package/src/core/geom/3d/quaternion/quat3_multiply.js +31 -31
  412. package/src/core/geom/3d/quaternion/quat3_nlerp.js +72 -72
  413. package/src/core/geom/3d/quaternion/quat3_to_matrix3.js +69 -69
  414. package/src/core/geom/3d/quaternion/quat_decode_from_uint32.js +7 -7
  415. package/src/core/geom/3d/quaternion/quat_encode_to_uint32.js +7 -7
  416. package/src/core/geom/3d/ray/ray3_array_compose.js +7 -7
  417. package/src/core/geom/3d/ray/ray3_compute_nearest_point_to_point.js +7 -7
  418. package/src/core/geom/3d/ray/ray3_distance_to_point.js +7 -7
  419. package/src/core/geom/3d/ray/ray3_shift_origin_along_direction.js +7 -7
  420. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts +17 -0
  421. package/src/core/geom/3d/shape/ConvexHullShape3D.d.ts.map +1 -1
  422. package/src/core/geom/3d/shape/ConvexHullShape3D.js +43 -0
  423. package/src/core/geom/3d/shape/CylinderShape3D.d.ts +1 -0
  424. package/src/core/geom/3d/shape/CylinderShape3D.d.ts.map +1 -1
  425. package/src/core/geom/3d/shape/CylinderShape3D.js +21 -0
  426. package/src/core/geom/3d/shape/PointShape3D.d.ts +7 -0
  427. package/src/core/geom/3d/shape/PointShape3D.d.ts.map +1 -1
  428. package/src/core/geom/3d/shape/PointShape3D.js +88 -63
  429. package/src/core/geom/3d/shape/PosedShape3D.d.ts +6 -0
  430. package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
  431. package/src/core/geom/3d/shape/PosedShape3D.js +27 -0
  432. package/src/core/geom/3d/shape/TransformedShape3D.d.ts +10 -0
  433. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  434. package/src/core/geom/3d/shape/TransformedShape3D.js +13 -0
  435. package/src/core/geom/3d/shape/Triangle3D.d.ts +1 -0
  436. package/src/core/geom/3d/shape/Triangle3D.d.ts.map +1 -1
  437. package/src/core/geom/3d/shape/Triangle3D.js +26 -0
  438. package/src/core/geom/3d/shape/UnionShape3D.d.ts +6 -0
  439. package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
  440. package/src/core/geom/3d/shape/UnionShape3D.js +7 -0
  441. package/src/core/geom/3d/shape/UnitCubeShape3D.js +45 -45
  442. package/src/core/geom/3d/shape/UnitSphereShape3D.js +44 -44
  443. package/src/core/geom/3d/shape/shape3_mesh_from_geometry.js +64 -64
  444. package/src/core/geom/3d/shape/shape_mesh_from_geometry.js +7 -7
  445. package/src/core/geom/3d/shape/util/compute_signed_distance_gradient_by_sampling.js +51 -51
  446. package/src/core/geom/3d/shape/util/shape3d_voxelize_to_grid.js +7 -7
  447. package/src/core/geom/3d/sphere/compute_bounding_sphere_of_2_spheres.js +7 -7
  448. package/src/core/geom/3d/sphere/harmonics/sh3_convolve_with_zh.js +53 -53
  449. package/src/core/geom/3d/sphere/harmonics/sh3_ggx_zh.js +30 -30
  450. package/src/core/geom/3d/sphere/harmonics/sh3_rotate_bl.js +7 -7
  451. package/src/core/geom/3d/sphere/harmonics/sh_compute_K.js +7 -7
  452. package/src/core/geom/3d/sphere/sphere_array_intersects_point.js +7 -7
  453. package/src/core/geom/3d/sphere/sphere_array_intersects_ray.js +7 -7
  454. package/src/core/geom/3d/sphere/sphere_intersects_point.js +7 -7
  455. package/src/core/geom/3d/sphere/sphere_matrix4_transform.js +5 -5
  456. package/src/core/geom/3d/sphere/sphere_projected_sphere_radius_sqr.js +7 -7
  457. package/src/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.js +7 -7
  458. package/src/core/geom/3d/sphere/spherical_from_cartesian.js +7 -7
  459. package/src/core/geom/3d/tetrahedra/compute_tetrahedral_mesh_from_surface.js +174 -174
  460. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_quality.js +7 -7
  461. package/src/core/geom/3d/tetrahedra/compute_tetrahedron_volume.js +7 -7
  462. package/src/core/geom/3d/tetrahedra/delaunay/fill_in_a_cavity.js +7 -7
  463. package/src/core/geom/3d/tetrahedra/graphics/build_tetrahedral_mesh_geometry.js +39 -39
  464. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_build_vertex_to_tets_map.js +48 -48
  465. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_carve_outside_surface.js +173 -173
  466. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_compute_tet_quality.js +22 -22
  467. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_find_tets_around_edge.js +146 -146
  468. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.js +232 -232
  469. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.js +255 -255
  470. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js +387 -387
  471. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_smooth_vertex.js +140 -140
  472. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_tet_get_neighbours.js +7 -7
  473. package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_vertex_is_boundary.js +97 -97
  474. package/src/core/geom/3d/tetrahedra/tetrahedron_compute_quality.js +66 -66
  475. package/src/core/geom/3d/tetrahedra/triangle/triangle_decode_depth.js +59 -59
  476. package/src/core/geom/3d/tetrahedra/triangle/triangle_rasterized_depth_sample_index.js +54 -54
  477. package/src/core/geom/3d/tetrahedra/validate_neighbour.js +70 -70
  478. package/src/core/geom/3d/topology/struct/binary/BinaryDataBlock.js +314 -314
  479. package/src/core/geom/3d/topology/struct/binary/BinaryDataLayer.js +364 -364
  480. package/src/core/geom/3d/topology/struct/binary/BinaryElementPool.js +567 -567
  481. package/src/core/geom/3d/topology/struct/binary/BinaryTopology.js +1085 -1085
  482. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.js +73 -73
  483. package/src/core/geom/3d/topology/struct/binary/io/bt_loop_kill.js +35 -35
  484. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_append.js +119 -119
  485. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js +84 -84
  486. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compact.js +172 -172
  487. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_face_normals.js +56 -56
  488. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadratics.js +7 -7
  489. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +227 -227
  490. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_decouple.js +161 -161
  491. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_face_island_erode.js +490 -490
  492. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.js +120 -120
  493. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_from_indexed_geometry.js +120 -120
  494. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_collapse.js +52 -52
  495. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_create.js +115 -115
  496. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_flip.js +142 -142
  497. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_get_or_create.js +21 -21
  498. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js +92 -92
  499. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_split.js +179 -179
  500. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_swap_vertex_slots.js +28 -28
  501. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_kill_only_edge.js +8 -8
  502. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_fuse_duplicate_edges.js +83 -83
  503. package/src/core/geom/3d/topology/struct/binary/io/edge/bt_mesh_kill_short_edges.js +89 -89
  504. package/src/core/geom/3d/topology/struct/binary/io/face/bt_face_kill.js +25 -25
  505. package/src/core/geom/3d/topology/struct/binary/io/face/bt_face_poke.js +127 -127
  506. package/src/core/geom/3d/topology/struct/binary/io/face/bt_face_triangulate.js +268 -268
  507. package/src/core/geom/3d/topology/struct/binary/io/face/bt_kill_only_face.js +8 -8
  508. package/src/core/geom/3d/topology/struct/binary/io/face/bt_mesh_kill_degenerate_faces.js +72 -72
  509. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_kill_only_vert.js +7 -7
  510. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_merge_verts_by_distance.js +7 -7
  511. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_mesh_relative_merge_distance.js +48 -48
  512. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_mesh_split_pinched_vertices.js +256 -256
  513. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_mesh_vertex_merge_distance.js +77 -77
  514. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_fuse_duplicate_edges.js +7 -7
  515. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vert_kill.js +7 -7
  516. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.js +148 -148
  517. package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_kill_only.js +7 -7
  518. package/src/core/geom/3d/topology/struct/binary/query/bt_collect_boundary_segments.js +29 -29
  519. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_collapse_breaks_link_condition.js +107 -107
  520. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_flip_is_legal.js +41 -41
  521. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_flip_would_fold.js +120 -120
  522. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.js +42 -42
  523. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_is_boundary.js +20 -20
  524. package/src/core/geom/3d/topology/struct/binary/query/bt_edge_read_diamond.js +96 -96
  525. package/src/core/geom/3d/topology/struct/binary/query/bt_face_compute_newell_normal.js +72 -72
  526. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_attached_faces.js +7 -7
  527. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_edge_adjacent_faces.js +39 -39
  528. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_edge_adjacent_faces_weighted.js +93 -93
  529. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_neighbour_faces.js +7 -7
  530. package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_shared_loop.js +48 -48
  531. package/src/core/geom/3d/topology/struct/binary/query/bt_face_island_flood_fill.js +45 -45
  532. package/src/core/geom/3d/topology/struct/binary/query/bt_face_read_triangle.js +66 -66
  533. package/src/core/geom/3d/topology/struct/binary/query/bt_faces_shared_loop.js +7 -7
  534. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_assert_valid.js +44 -44
  535. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_euclidean_distance_field.js +32 -32
  536. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_compute_face_islands.js +53 -53
  537. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path.js +703 -703
  538. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_sample_interior_grid_points.js +181 -181
  539. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_segment_penetrates_surface.js +133 -133
  540. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_surface_ray_parity.js +82 -82
  541. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_validate.js +599 -599
  542. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_walk_boundary_loops.js +108 -108
  543. package/src/core/geom/3d/topology/struct/binary/query/bt_query_edge_is_boundary.js +7 -7
  544. package/src/core/geom/3d/triangle/computeTriangleClosestPointToPointBarycentric.js +7 -7
  545. package/src/core/geom/3d/triangle/computeTriangleRayIntersection.js +7 -7
  546. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentric.js +7 -7
  547. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentricEdge.js +7 -7
  548. package/src/core/geom/3d/triangle/computeTriangleRayIntersectionBarycentricGeometry.js +7 -7
  549. package/src/core/geom/3d/triangle/compute_triangle_area_3d.js +7 -7
  550. package/src/core/geom/3d/triangle/compute_triangle_normal.js +7 -7
  551. package/src/core/geom/3d/triangle/rayTriangleIntersection.js +7 -7
  552. package/src/core/geom/3d/triangle/tri3_closest_point.js +65 -65
  553. package/src/core/geom/3d/triangle/tri3_closest_point_barycentric.js +171 -171
  554. package/src/core/geom/3d/triangle/tri3_flatten_isometric.js +79 -79
  555. package/src/core/geom/3d/triangle/tri3_ray_intersection.js +160 -160
  556. package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric.js +96 -96
  557. package/src/core/geom/3d/triangle/tri3_raycast.d.ts +42 -0
  558. package/src/core/geom/3d/triangle/tri3_raycast.d.ts.map +1 -0
  559. package/src/core/geom/3d/triangle/tri3_raycast.js +94 -0
  560. package/src/core/geom/3d/triangle/triangle3_incenter.js +7 -7
  561. package/src/core/geom/3d/triangle/triangle_compute_plane_side.js +7 -7
  562. package/src/core/geom/3d/triangle/triangle_compute_signed_volume.js +7 -7
  563. package/src/core/geom/3d/triangle/triangle_intersects_clipping_volume.js +7 -7
  564. package/src/core/geom/3d/triangle/triangle_mesh_compute_signed_volume.js +7 -7
  565. package/src/core/geom/3d/triangle/v3_compute_triangle_normal.js +7 -7
  566. package/src/core/geom/3d/util/make_justified_point_grid.js +7 -7
  567. package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +381 -381
  568. package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +684 -684
  569. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +554 -554
  570. package/src/core/geom/mat3/m3_cm_from_translation.js +7 -7
  571. package/src/core/geom/mat3/m3_cm_invert.js +7 -7
  572. package/src/core/geom/mat3/m3_make_rotation.js +5 -5
  573. package/src/core/geom/mat3/m3_make_rotation_TBN.js +31 -31
  574. package/src/core/geom/mat3/m3_multiply_vec3.js +7 -7
  575. package/src/core/geom/packing/computeBoundingSphereOfSpheres.js +7 -7
  576. package/src/core/geom/packing/max-rect/cost/costByBestShortSide.js +7 -7
  577. package/src/core/geom/packing/max-rect/cost/costByRemainingArea.js +7 -7
  578. package/src/core/geom/packing/max-rect/cutArea.js +7 -7
  579. package/src/core/geom/packing/max-rect/findBestContainer.js +7 -7
  580. package/src/core/geom/packing/max-rect/packMaxRectangles.js +7 -7
  581. package/src/core/geom/packing/max-rect/packOneBox.js +7 -7
  582. package/src/core/geom/packing/max-rect/removeRedundantBoxes.js +7 -7
  583. package/src/core/geom/packing/max-rect/removeRedundantBoxesArray.js +7 -7
  584. package/src/core/geom/random/randomPointInBox.js +7 -7
  585. package/src/core/geom/random/randomPointInCircle.js +7 -7
  586. package/src/core/geom/random/randomPointInPoint.js +7 -7
  587. package/src/core/geom/random/randomPointInSphere.js +7 -7
  588. package/src/core/geom/random/randomPointOnBox.js +7 -7
  589. package/src/core/geom/random/randomPointOnSphere.js +7 -7
  590. package/src/core/geom/random/random_orthonormal_basis.js +31 -31
  591. package/src/core/geom/vec/vector_axpy.js +15 -15
  592. package/src/core/geom/vec/vector_axpy_offset.js +20 -20
  593. package/src/core/geom/vec/vector_copy.js +7 -7
  594. package/src/core/geom/vec/vector_dot_offset.js +25 -25
  595. package/src/core/geom/vec/vector_scale_array.js +7 -7
  596. package/src/core/geom/vec2/v2_rotate.js +21 -21
  597. package/src/core/geom/vec2/v2_rotate_cos_sin.js +21 -21
  598. package/src/core/geom/vec3/v3_angle_atan2_between.js +7 -7
  599. package/src/core/geom/vec3/v3_angle_between.js +7 -7
  600. package/src/core/geom/vec3/v3_angle_cos_between.js +7 -7
  601. package/src/core/geom/vec3/v3_array_add_in_place.js +7 -7
  602. package/src/core/geom/vec3/v3_array_centroid.js +7 -7
  603. package/src/core/geom/vec3/v3_array_copy.js +7 -7
  604. package/src/core/geom/vec3/v3_array_displace_in_direction.js +7 -7
  605. package/src/core/geom/vec3/v3_array_equals.js +7 -7
  606. package/src/core/geom/vec3/v3_array_immediate_add.js +7 -7
  607. package/src/core/geom/vec3/v3_array_matrix4_rotate.js +7 -7
  608. package/src/core/geom/vec3/v3_array_normalize.js +7 -7
  609. package/src/core/geom/vec3/v3_array_scale.js +7 -7
  610. package/src/core/geom/vec3/v3_compute_interior_angle.js +7 -7
  611. package/src/core/geom/vec3/v3_cotangent.js +33 -33
  612. package/src/core/geom/vec3/v3_dot_array_array.js +7 -7
  613. package/src/core/geom/vec3/v3_matrix3_multiply.js +30 -30
  614. package/src/core/geom/vec3/v3_matrix3_rotate.js +49 -49
  615. package/src/core/geom/vec3/v3_matrix4_rotate.js +7 -7
  616. package/src/core/geom/vec3/v3_multiply.js +23 -23
  617. package/src/core/geom/vec3/v3_multiply_scalar.js +7 -7
  618. package/src/core/geom/vec3/v3_orthonormal_matrix_from_normal.js +49 -49
  619. package/src/core/geom/vec3/v3_quat3_apply.js +7 -7
  620. package/src/core/geom/vec3/v3_quat3_apply_inverse.js +7 -7
  621. package/src/core/geom/vec3/v3_quaternion_apply.js +39 -39
  622. package/src/core/geom/vec3/v3_quaternion_apply_inverse.js +41 -41
  623. package/src/core/geom/vec3/v3_reflect.js +24 -24
  624. package/src/core/geom/vec3/v3_scale_array.js +18 -18
  625. package/src/core/geom/vec3/v3_triple_cross.js +45 -45
  626. package/src/core/geom/vec3/v3_triple_cross_product.js +7 -7
  627. package/src/core/geom/vec3/v3_uniform_sample_cone.js +21 -21
  628. package/src/core/geom/vec4/v4_multiply_mat4.js +7 -7
  629. package/src/core/graph/csr/csr_graph_build_distance_field.js +112 -112
  630. package/src/core/graph/csr/csr_graph_find_edge.js +25 -25
  631. package/src/core/graph/csr/csr_graph_find_shortest_path.js +105 -105
  632. package/src/core/graph/csr/csr_graph_from_undirected_edge_list.js +94 -94
  633. package/src/core/graph/graph_k_means_cluster.js +250 -250
  634. package/src/core/graph/layout/CircleLayout.js +1 -1
  635. package/src/core/graph/layout/box/BoxLayouter.js +1 -1
  636. package/src/core/graph/layout/graph_peel_topological_layer.js +45 -45
  637. package/src/core/graph/metis/BinaryTopologyFaceGraph.js +49 -49
  638. package/src/core/graph/metis/bt_mesh_build_face_graph.js +111 -111
  639. package/src/core/graph/metis/cluster_mesh_metis.js +137 -137
  640. package/src/core/graph/metis/native/bisection/bisect_graph.js +100 -100
  641. package/src/core/graph/metis/native/bisection/compute_2way_params.js +86 -86
  642. package/src/core/graph/metis/native/bisection/fm_2way.js +297 -297
  643. package/src/core/graph/metis/native/bisection/grow_bisection.js +137 -137
  644. package/src/core/graph/metis/native/bisection/split_graph_two_way.js +119 -119
  645. package/src/core/graph/metis/native/coarsen/coarsen_graph.js +94 -94
  646. package/src/core/graph/metis/native/coarsen/create_coarse_graph.js +158 -158
  647. package/src/core/graph/metis/native/coarsen/match_shem.js +175 -175
  648. package/src/core/graph/metis/native/initial/initial_kway_bfs.js +122 -122
  649. package/src/core/graph/metis/native/initial/initial_kway_recursive_bisection.js +170 -170
  650. package/src/core/graph/metis/native/metis_partition_kway.js +126 -126
  651. package/src/core/graph/metis/native/refine/RefinementScratch.js +53 -53
  652. package/src/core/graph/metis/native/refine/fm_kway.js +487 -487
  653. package/src/core/graph/metis/native/refine/project_kway.js +43 -43
  654. package/src/core/graph/metis/native/refine/refine_kway.js +43 -43
  655. package/src/core/lang/reactive/pegjs/parser.js +3458 -3458
  656. package/src/core/math/complex/complex_horner_eval.js +31 -31
  657. package/src/core/math/computeWholeDivisorLow.js +33 -33
  658. package/src/core/math/f32_next_down.js +24 -24
  659. package/src/core/math/f32_next_up.js +27 -27
  660. package/src/core/math/hash/hash_mix2.js +22 -22
  661. package/src/core/math/hash/hash_mix3.js +19 -19
  662. package/src/core/math/linalg/cg/cg_solve.js +106 -106
  663. package/src/core/math/linalg/cg/cg_solve_normal_equations.js +59 -59
  664. package/src/core/math/linalg/cubic_residual_times_derivative_accumulate.js +43 -43
  665. package/src/core/math/linalg/eigen/matrix_householder_in_place.js +122 -122
  666. package/src/core/math/linalg/eigen/matrix_qr_in_place.js +190 -190
  667. package/src/core/math/linalg/eigen/matrix_symmetric_3x3_eigen.js +117 -117
  668. package/src/core/math/linalg/givens/givens_apply_rows.js +28 -28
  669. package/src/core/math/linalg/givens/givens_apply_rows_offset.js +30 -30
  670. package/src/core/math/linalg/givens/givens_rotation_coefficients.js +39 -39
  671. package/src/core/math/linalg/lu_factor_linear_system.js +108 -108
  672. package/src/core/math/linalg/lu_solve_linear_system.js +53 -53
  673. package/src/core/math/linalg/polynomial_add_into.js +29 -29
  674. package/src/core/math/linalg/polynomial_complex_roots_aberth_ehrlich.js +159 -159
  675. package/src/core/math/linalg/polynomial_cubic_derivative_eval.js +16 -16
  676. package/src/core/math/linalg/polynomial_cubic_horner_eval.js +19 -19
  677. package/src/core/math/linalg/polynomial_cubic_second_derivative_eval.js +14 -14
  678. package/src/core/math/linalg/polynomial_multiply.js +41 -41
  679. package/src/core/math/linalg/polynomial_real_roots_in_interval.js +211 -211
  680. package/src/core/math/linalg/polynomial_root_bound_cauchy.js +30 -30
  681. package/src/core/math/linalg/polynomial_scale_into.js +17 -17
  682. package/src/core/math/linalg/polynomial_sub_into.js +29 -29
  683. package/src/core/math/linalg/solve_linear_system_GEPP_2x2.js +96 -96
  684. package/src/core/math/linalg/sor_optimal_omega.js +42 -42
  685. package/src/core/math/linalg/sparse/SparseMatrixCSR.js +88 -88
  686. package/src/core/math/linalg/sparse/spm_matvec.js +22 -22
  687. package/src/core/math/linalg/sparse/spm_matvec_transpose.js +29 -29
  688. package/src/core/math/lookup/LUT_HEATMAP.js +30 -30
  689. package/src/core/math/lookup/ParameterLookupTable.js +495 -495
  690. package/src/core/math/lookup/ParameterLookupTableFlags.js +6 -6
  691. package/src/core/math/noise/curl_noise_3d.js +18 -18
  692. package/src/core/math/physics/brdf/cone_cosine_from_roughness.js +28 -28
  693. package/src/core/math/physics/brdf/reflection_sample_weight.js +48 -48
  694. package/src/core/math/physics/kinematics/computeInterceptPoint.js +79 -79
  695. package/src/core/math/random/randomSeed.js +16 -16
  696. package/src/core/math/random/random_pick_weighted_index.js +26 -26
  697. package/src/core/math/round_half_away_from_zero.js +13 -13
  698. package/src/core/math/spline/spline3_hermite_apply_transform.js +107 -107
  699. package/src/core/math/spline/spline3_hermite_intersection_spline3_hermite_1d.js +125 -125
  700. package/src/core/math/spline/spline3_hermite_intersects_spline3_hermite.js +50 -50
  701. package/src/core/math/spline/spline3_hermite_reverse.js +49 -49
  702. package/src/core/math/spline/spline3_hermite_to_monomial.js +37 -37
  703. package/src/core/math/statistics/hammersley_sequence.js +53 -53
  704. package/src/core/model/reactive/model/util/createRandomReactiveExpression.js +185 -185
  705. package/src/core/path/convertPathToURL.js +107 -107
  706. package/src/core/process/delay.js +16 -16
  707. package/src/core/science/units/MEASUREMENT_UNITS_SCIENTIFIC.js +87 -87
  708. package/src/core/science/units/MEASUREMENT_UNITS_SI.js +17 -17
  709. package/src/core/science/units/NamedUnit.js +48 -48
  710. package/src/core/science/units/UNIT_DIMENSION_MAPPING.js +29 -29
  711. package/src/core/science/units/UnitDimension.js +28 -28
  712. package/src/core/science/units/format_quantity.js +74 -74
  713. package/src/core/science/units/magnitude_prefix.js +127 -127
  714. package/src/core/science/units/si/AMPERE.js +13 -13
  715. package/src/core/science/units/si/CANDELA.js +13 -13
  716. package/src/core/science/units/si/DIMENSIONLESS.js +14 -14
  717. package/src/core/science/units/si/KELVIN.js +13 -13
  718. package/src/core/science/units/si/KILOGRAM.js +13 -13
  719. package/src/core/science/units/si/METER.js +13 -13
  720. package/src/core/science/units/si/MOLE.js +13 -13
  721. package/src/core/science/units/si/SECOND.js +13 -13
  722. package/src/core/science/units/si/derived/BECQUEREL.js +16 -16
  723. package/src/core/science/units/si/derived/COULOMB.js +13 -13
  724. package/src/core/science/units/si/derived/FARAD.js +13 -13
  725. package/src/core/science/units/si/derived/GRAY.js +16 -16
  726. package/src/core/science/units/si/derived/HENRY.js +13 -13
  727. package/src/core/science/units/si/derived/HERTZ.js +16 -16
  728. package/src/core/science/units/si/derived/JOULE.js +13 -13
  729. package/src/core/science/units/si/derived/KATAL.js +13 -13
  730. package/src/core/science/units/si/derived/LUMEN.js +14 -14
  731. package/src/core/science/units/si/derived/LUX.js +13 -13
  732. package/src/core/science/units/si/derived/NEWTON.js +13 -13
  733. package/src/core/science/units/si/derived/OHM.js +13 -13
  734. package/src/core/science/units/si/derived/PASCAL.js +13 -13
  735. package/src/core/science/units/si/derived/SIEMENS.js +13 -13
  736. package/src/core/science/units/si/derived/SIEVERT.js +16 -16
  737. package/src/core/science/units/si/derived/TESLA.js +13 -13
  738. package/src/core/science/units/si/derived/VOLT.js +13 -13
  739. package/src/core/science/units/si/derived/WATT.js +13 -13
  740. package/src/core/science/units/si/derived/WEBER.js +13 -13
  741. package/src/core/science/units/unit_matrix_to_string.js +403 -403
  742. package/src/engine/Engine.js +726 -726
  743. package/src/engine/EngineHarness.js +590 -590
  744. package/src/engine/REVIEW_2026_07_03.md +211 -211
  745. package/src/engine/animation/AnimatedActions.js +81 -81
  746. package/src/engine/animation/AnimationUtils.js +252 -252
  747. package/src/engine/animation/async/TimeSeries.js +300 -300
  748. package/src/engine/animation/curve/animation_curve_binary_codec.js +60 -60
  749. package/src/engine/animation/curve/draw/canvas_point_to_curve.js +22 -22
  750. package/src/engine/animation/curve/draw/curve_point_to_canvas.js +38 -38
  751. package/src/engine/animation/curve/draw/position_canvas_to_curve.js +22 -22
  752. package/src/engine/animation/curve/draw/position_curve_to_canvas.js +22 -22
  753. package/src/engine/asset/GameAssetType.d.ts +0 -1
  754. package/src/engine/asset/GameAssetType.js +0 -1
  755. package/src/engine/asset/load_model_scene_bundle.js +27 -27
  756. package/src/engine/asset/loaders/font/FontAsset.js +21 -21
  757. package/src/engine/asset/loaders/font/FontAssetLoader.js +20 -20
  758. package/src/engine/asset/loaders/gltf_test_fixtures.js +358 -358
  759. package/src/engine/asset/loaders/image/ImageBitmapAssetLoader.js +52 -52
  760. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +94 -94
  761. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterAverage.js +59 -59
  762. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterNone.js +55 -55
  763. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterPaeth.js +74 -74
  764. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterSub.js +34 -34
  765. package/src/engine/asset/loaders/image/png/filter/png_filter_unFilterUp.js +46 -46
  766. package/src/engine/control/first-person/DESIGN.md +640 -640
  767. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +563 -563
  768. package/src/engine/control/first-person/FirstPersonMotionPhase.js +134 -134
  769. package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2045 -2045
  770. package/src/engine/control/first-person/mastery/DecisionPoint.js +30 -30
  771. package/src/engine/control/first-person/math/Spring.js +71 -71
  772. package/src/engine/control/first-person/math/computeJumpFromApex.js +23 -23
  773. package/src/engine/control/first-person/math/computeLRCBreathRate.js +41 -41
  774. package/src/engine/control/first-person/math/computeMassRatios.js +44 -44
  775. package/src/engine/control/first-person/math/criticallyDampedSpring.js +34 -34
  776. package/src/engine/control/first-person/math/dampedSpringStep.js +72 -72
  777. package/src/engine/control/first-person/math/jumpDynamics.js +108 -108
  778. package/src/engine/control/first-person/math/stepTowards.js +20 -20
  779. package/src/engine/control/first-person/pose/FirstPersonPose.js +137 -137
  780. package/src/engine/control/first-person/pose/FirstPersonPosture.js +27 -27
  781. package/src/engine/control/first-person/test/buildTestPlayer.js +36 -36
  782. package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +531 -531
  783. package/src/engine/ecs/EntityManager.d.ts +7 -3
  784. package/src/engine/ecs/EntityManager.d.ts.map +1 -1
  785. package/src/engine/ecs/EntityManager.js +10 -5
  786. package/src/engine/ecs/HIERARCHY_REVIEW.md +717 -717
  787. package/src/engine/ecs/async/SystemWorkerHost.js +329 -329
  788. package/src/engine/ecs/async/SystemWorkerLoopback.js +143 -143
  789. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +246 -246
  790. package/src/engine/ecs/async/WorkerSystem.js +702 -702
  791. package/src/engine/ecs/async/WorkerSystemProtocol.js +150 -150
  792. package/src/engine/ecs/fow/FogOfWar.js +707 -707
  793. package/src/engine/ecs/fow/FogOfWarEdgeMode.js +40 -40
  794. package/src/engine/ecs/fow/fog_of_war_mask_world_bounds.js +24 -24
  795. package/src/engine/ecs/fow/fog_of_war_uv_transform.js +30 -30
  796. package/src/engine/ecs/gui/hud/testHudEdgeStick.js +132 -134
  797. package/src/engine/ecs/hierarchy/EntityChildIndex.js +140 -140
  798. package/src/engine/ecs/ik/IKProblem.js +42 -42
  799. package/src/engine/ecs/ik/InverseKinematicsSystem.js +193 -193
  800. package/src/engine/ecs/ik/OneBoneSurfaceAlignmentSolver.js +134 -134
  801. package/src/engine/ecs/ik/TwoBoneInverseKinematicsSolver.js +97 -97
  802. package/src/engine/ecs/ik/ik_bone_chain.js +85 -85
  803. package/src/engine/ecs/ik/ik_probe_terrain_contact.js +119 -119
  804. package/src/engine/ecs/parent/EntityNode.d.ts +1 -1
  805. package/src/engine/ecs/parent/EntityNode.js +2 -2
  806. package/src/engine/ecs/parent/ParentEntitySystem.js +255 -255
  807. package/src/engine/ecs/speaker/VoiceSystem.d.ts +2 -2
  808. package/src/engine/ecs/speaker/VoiceSystem.d.ts.map +1 -1
  809. package/src/engine/ecs/speaker/VoiceSystem.js +13 -7
  810. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +269 -269
  811. package/src/engine/ecs/storage/binary/object-v2/BinaryObjectDeSerializer.js +315 -315
  812. package/src/engine/ecs/storage/binary/object-v2/BinaryObjectSerializer.js +331 -331
  813. package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +199 -199
  814. package/src/engine/ecs/storage/binary/object-v2/ObjectBinaryFormat.js +57 -57
  815. package/src/engine/ecs/storage/binary/object-v2/ObjectSerializationAdapter.js +56 -56
  816. package/src/engine/ecs/storage/binary/object-v2/README.md +110 -110
  817. package/src/engine/ecs/storage/binary/object-v2/objectStringCodec.js +48 -48
  818. package/src/engine/ecs/storage/binary/object-v2/serializerTestHarness.js +44 -44
  819. package/src/engine/ecs/storage/populateEngineSerializationRegistry.js +265 -265
  820. package/src/engine/ecs/terrain/TerrainClouds.js +97 -97
  821. package/src/engine/ecs/terrain/ecs/StubTerrainBuildWorker.js +65 -65
  822. package/src/engine/ecs/terrain/ecs/Terrain.d.ts +4 -0
  823. package/src/engine/ecs/terrain/ecs/Terrain.d.ts.map +1 -1
  824. package/src/engine/ecs/terrain/ecs/Terrain.js +790 -790
  825. package/src/engine/ecs/terrain/ecs/TerrainSystem.js +209 -209
  826. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +316 -316
  827. package/src/engine/ecs/terrain/ecs/layers/TerrainLayers.js +416 -416
  828. package/src/engine/ecs/terrain/ecs/splat/SplatMapping.js +525 -525
  829. package/src/engine/ecs/terrain/overlay/TerrainOverlay.js +302 -302
  830. package/src/engine/ecs/terrain/tiles/TerrainTile.js +561 -561
  831. package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +896 -896
  832. package/src/engine/ecs/terrain/tiles/tile_geometry_to_meshlets.js +36 -36
  833. package/src/engine/ecs/terrain/util/loadVisibleTerrainTiles.js +129 -129
  834. package/src/engine/ecs/transform/Transform64.js +814 -814
  835. package/src/engine/ecs/transform/t64_copy_from_transform.js +35 -35
  836. package/src/engine/ecs/transform/t64_equals_transform.js +55 -55
  837. package/src/engine/ecs/transform/t64_look_rotation.js +36 -36
  838. package/src/engine/ecs/transform/t64_transform_direction.js +25 -25
  839. package/src/engine/ecs/transform/transform_copy_from_t64.js +28 -28
  840. package/src/engine/ecs/transform-attachment/TransformAttachmentSystem.js +345 -345
  841. package/src/engine/ecs/transform-attachment/transform_attachment_find_descendant_by_name.js +65 -65
  842. package/src/engine/ecs/transform-attachment/transform_attachment_parent_of.js +24 -24
  843. package/src/engine/ecs/util/hideEntityGracefully.js +208 -208
  844. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +446 -446
  845. package/src/engine/graphics/FULL_SCREEN_QUAD_VERTEX_SHADER.js +14 -14
  846. package/src/engine/graphics/FrameThrottle.js +2 -2
  847. package/src/engine/graphics/ecs/animation/animator/graph/AnimationState.js +207 -207
  848. package/src/engine/graphics/ecs/animation/animator/graph/AnimationTransition.js +151 -151
  849. package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.js +22 -22
  850. package/src/engine/graphics/ecs/camera/Camera.js +165 -165
  851. package/src/engine/graphics/ecs/camera/camera_active_frustum.js +25 -25
  852. package/src/engine/graphics/ecs/camera/camera_find_active.js +28 -28
  853. package/src/engine/graphics/ecs/camera/camera_traverse_active.js +18 -18
  854. package/src/engine/graphics/ecs/camera/pp/PerfectPanner.js +170 -170
  855. package/src/engine/graphics/ecs/camera/serialization/CameraSerializationAdapter.js +68 -68
  856. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +296 -296
  857. package/src/engine/graphics/ecs/decal/v2/Decal.js +220 -220
  858. package/src/engine/graphics/ecs/decal/v2/DecalSerializationAdapter.js +56 -56
  859. package/src/engine/graphics/ecs/decal/v2/DecalSerializationUpgrader_0_1.js +38 -38
  860. package/src/engine/graphics/ecs/light/shadow/compute_view_frustum_aabb_in_space.js +62 -62
  861. package/src/engine/graphics/ecs/light/shadow/extend_shadow_camera_near_for_casters.js +77 -77
  862. package/src/engine/graphics/ecs/make_bvh_depth_range_computer.js +33 -33
  863. package/src/engine/graphics/ecs/mesh-v2/DeferredBoundsQueue.js +88 -88
  864. package/src/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +428 -428
  865. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js +303 -303
  866. package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.d.ts +1 -1
  867. package/src/engine/graphics/ecs/mesh-v2/aggregate/serialization/SGMeshSerializationAdapter.js +39 -39
  868. package/src/engine/graphics/ecs/mesh-v2/sg_hierarchy_compute_bounding_box_via_parent_entity.js +36 -36
  869. package/src/engine/graphics/ecs/path/tube/build/GeometryStream.js +94 -94
  870. package/src/engine/graphics/ecs/path/tube/build/build_stream_catmullrom.js +310 -310
  871. package/src/engine/graphics/ecs/path/tube/build/build_stream_linear.js +73 -73
  872. package/src/engine/graphics/ecs/path/tube/build/computeFrenetFrames.js +199 -199
  873. package/src/engine/graphics/ecs/path/tube/build/makeTubeStream.js +217 -217
  874. package/src/engine/graphics/ecs/path/tube/build/make_cap.js +340 -340
  875. package/src/engine/graphics/ecs/path/tube/build/make_ring_faces.js +40 -40
  876. package/src/engine/graphics/ecs/path/tube/build/make_ring_vertices.js +153 -153
  877. package/src/engine/graphics/ecs/render_layers_compute_depth_range.js +64 -64
  878. package/src/engine/graphics/ecs/trail3d/Trail3D.js +483 -483
  879. package/src/engine/graphics/ecs/trail3d/Trail3DFlags.js +26 -26
  880. package/src/engine/graphics/ecs/trail3d/advance_trail.js +42 -42
  881. package/src/engine/graphics/ecs/trail3d/make_gradient_stroke.js +58 -58
  882. package/src/engine/graphics/ecs/trail3d/seed_trail_stroke.js +90 -90
  883. package/src/engine/graphics/ecs/trail3d/seed_trail_tube.js +75 -75
  884. package/src/engine/graphics/ecs/trail3d/trail_head_position.js +19 -19
  885. package/src/engine/graphics/ecs/water/Water.js +104 -104
  886. package/src/engine/graphics/geometry/AttributeData.js +84 -84
  887. package/src/engine/graphics/geometry/buffered/geometry_compute_vertex_normals_indexed.js +49 -49
  888. package/src/engine/graphics/geometry/buffered/query/GeometrySpatialQueryAccelerator.js +288 -288
  889. package/src/engine/graphics/geometry/buffered/query/nearest_point_on_triangle_record.js +87 -87
  890. package/src/engine/graphics/geometry/buffered/read_triangle_vertices.js +102 -102
  891. package/src/engine/graphics/geometry/bvh/buffered/bvh32_from_buffered_geometry.js +52 -52
  892. package/src/engine/graphics/geometry/bvh/buffered/bvh32_from_indexed_geometry.js +20 -20
  893. package/src/engine/graphics/geometry/bvh/buffered/bvh32_from_unindexed_geometry.js +19 -19
  894. package/src/engine/graphics/geometry/optimization/geometry_optimize_uv_tension.js +135 -135
  895. package/src/engine/graphics/impostors/voxel/README.md +149 -149
  896. package/src/engine/graphics/impostors/voxel/VoxelImpostorDescription.js +141 -141
  897. package/src/engine/graphics/particles/node-based/codegen/glsl/getTypeByteSize.js +20 -20
  898. package/src/engine/graphics/particles/node-based/nodes/FloatConstant.d.ts +2 -0
  899. package/src/engine/graphics/particles/node-based/nodes/FloatConstant.d.ts.map +1 -1
  900. package/src/engine/graphics/particles/node-based/nodes/ReadFloatUniform.d.ts +2 -0
  901. package/src/engine/graphics/particles/node-based/nodes/ReadFloatUniform.d.ts.map +1 -1
  902. package/src/engine/graphics/particles/node-based/nodes/ReadVelocity.d.ts +2 -0
  903. package/src/engine/graphics/particles/node-based/nodes/ReadVelocity.d.ts.map +1 -1
  904. package/src/engine/graphics/particles/node-based/nodes/ShaderNode.d.ts +1 -2
  905. package/src/engine/graphics/particles/node-based/nodes/ShaderNode.d.ts.map +1 -1
  906. package/src/engine/graphics/particles/node-based/nodes/Vector3Constant.d.ts +2 -0
  907. package/src/engine/graphics/particles/node-based/nodes/Vector3Constant.d.ts.map +1 -1
  908. package/src/engine/graphics/particles/node-based/nodes/Vector3Merge.d.ts +2 -0
  909. package/src/engine/graphics/particles/node-based/nodes/Vector3Merge.d.ts.map +1 -1
  910. package/src/engine/graphics/particles/node-based/nodes/Vector3Split.d.ts +2 -0
  911. package/src/engine/graphics/particles/node-based/nodes/Vector3Split.d.ts.map +1 -1
  912. package/src/engine/graphics/particles/node-based/nodes/WriteVelocity.d.ts +2 -0
  913. package/src/engine/graphics/particles/node-based/nodes/WriteVelocity.d.ts.map +1 -1
  914. package/src/engine/graphics/particles/node-based/nodes/attribute/ReadVector3Attribute.d.ts +2 -0
  915. package/src/engine/graphics/particles/node-based/nodes/attribute/ReadVector3Attribute.d.ts.map +1 -1
  916. package/src/engine/graphics/particles/node-based/nodes/attribute/WriteVector3Attribute.d.ts +2 -0
  917. package/src/engine/graphics/particles/node-based/nodes/attribute/WriteVector3Attribute.d.ts.map +1 -1
  918. package/src/engine/graphics/particles/node-based/nodes/math/AddFloatNode.d.ts +2 -0
  919. package/src/engine/graphics/particles/node-based/nodes/math/AddFloatNode.d.ts.map +1 -1
  920. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Add.d.ts +2 -0
  921. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Add.d.ts.map +1 -1
  922. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Divide.d.ts +2 -0
  923. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Divide.d.ts.map +1 -1
  924. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Multiply.d.ts +2 -0
  925. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Multiply.d.ts.map +1 -1
  926. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Subtract.d.ts +2 -0
  927. package/src/engine/graphics/particles/node-based/nodes/math/Vector3Subtract.d.ts.map +1 -1
  928. package/src/engine/graphics/particles/node-based/nodes/noise/CurlNoiseNode.d.ts +2 -0
  929. package/src/engine/graphics/particles/node-based/nodes/noise/CurlNoiseNode.d.ts.map +1 -1
  930. package/src/engine/graphics/particles/node-based/nodes/particle_data_type_component_count.js +45 -45
  931. package/src/engine/graphics/particles/particular/engine/ParticularEngine.js +229 -229
  932. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts +2 -10
  933. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
  934. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +1149 -1149
  935. package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +472 -472
  936. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +2 -2
  937. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.js +2 -2
  938. package/src/engine/graphics/particles/particular/engine/parameter/ParameterSet.d.ts.map +1 -1
  939. package/src/engine/graphics/particles/particular/engine/parameter/ParameterSet.js +3 -5
  940. package/src/engine/graphics/particles/particular/engine/shader/ShaderManager.js +135 -135
  941. package/src/engine/graphics/particles/particular/engine/utils/distribute_points_on_indexed_triangles.js +168 -168
  942. package/src/engine/graphics/render/forward_plus/plugin/forwardPlusMaterialMarker.js +18 -18
  943. package/src/engine/graphics/render/forward_plus/read_frustum_corner.js +2 -2
  944. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +219 -219
  945. package/src/engine/graphics/render/frame_graph/FrameGraph.js +900 -900
  946. package/src/engine/graphics/render/frame_graph/FrameGraphScope.js +72 -72
  947. package/src/engine/graphics/render/frame_graph/FrameGraphState.js +39 -39
  948. package/src/engine/graphics/render/frame_graph/ResourceEntry.js +96 -96
  949. package/src/engine/graphics/render/gizmo/GizmoShapeBuffer.js +105 -105
  950. package/src/engine/graphics/render/gizmo/GizmoShapeRenderingInterface.js +162 -162
  951. package/src/engine/graphics/render/layers/RenderLayer.js +95 -95
  952. package/src/engine/graphics/sh3/build_injected_shader.js +56 -56
  953. package/src/engine/graphics/sh3/grid_dilate_average.js +175 -175
  954. package/src/engine/graphics/sh3/path_tracer/BufferedGeometryBVH.js +506 -506
  955. package/src/engine/graphics/sh3/path_tracer/PathTracedMesh.js +161 -161
  956. package/src/engine/graphics/sh3/path_tracer/PathTracedRenderer.js +205 -205
  957. package/src/engine/graphics/sh3/path_tracer/PathTracedScene.js +698 -698
  958. package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +490 -490
  959. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.js +2 -2
  960. package/src/engine/graphics/sh3/path_tracer/make_sky_hosek.js +45 -45
  961. package/src/engine/graphics/sh3/path_tracer/populate_path_traced_scene_from_ecd.js +73 -73
  962. package/src/engine/graphics/sh3/path_tracer/ray_hit_apply_transform.js +32 -32
  963. package/src/engine/graphics/sh3/path_tracer/texture/apply_texture_clamping_to_coordinate.js +28 -28
  964. package/src/engine/graphics/sh3/path_tracer/texture/sample_material.js +142 -142
  965. package/src/engine/graphics/sh3/sky/hosek/render_hosek_sky_to_equirectangular.js +70 -70
  966. package/src/engine/graphics/sh3/sky/hosek/sky_hosek_compute_irradiance_by_direction.js +388 -388
  967. package/src/engine/graphics/shaders/chunks/glsl_octahedral_impostor.js +277 -277
  968. package/src/engine/graphics/shaders/chunks/glsl_voxel_impostor_splat.js +57 -57
  969. package/src/engine/graphics/shadows/vsm.glsl.js +43 -43
  970. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.js +81 -81
  971. package/src/engine/graphics/texture/EnvironmentTextureProjection.js +15 -15
  972. package/src/engine/graphics/texture/channel_count_to_format_prefix.js +26 -26
  973. package/src/engine/graphics/texture/isImageBitmap.js +2 -2
  974. package/src/engine/graphics/texture/reflection/convolve_equirectangular_reflection.js +189 -189
  975. package/src/engine/graphics/texture/reflection/equirectangular_reflection_roughness.js +51 -51
  976. package/src/engine/graphics/texture/sampler/HarmonicDiffusionGrid.js +145 -145
  977. package/src/engine/graphics/texture/sampler/Sampler2DArray.js +172 -172
  978. package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +466 -466
  979. package/src/engine/graphics/texture/sampler/compare/flip/FlipParameters.js +18 -18
  980. package/src/engine/graphics/texture/sampler/compare/flip/FlipPooling.js +33 -33
  981. package/src/engine/graphics/texture/sampler/compare/flip/flip_build_feature_kernel.js +147 -147
  982. package/src/engine/graphics/texture/sampler/compare/flip/flip_build_spatial_kernel.js +177 -177
  983. package/src/engine/graphics/texture/sampler/compare/flip/flip_compute_color_difference.js +104 -104
  984. package/src/engine/graphics/texture/sampler/compare/flip/flip_compute_feature_difference.js +76 -76
  985. package/src/engine/graphics/texture/sampler/compare/flip/flip_compute_pixels_per_degree.js +34 -34
  986. package/src/engine/graphics/texture/sampler/compare/flip/flip_constants.js +77 -77
  987. package/src/engine/graphics/texture/sampler/compare/flip/flip_filter_feature.js +48 -48
  988. package/src/engine/graphics/texture/sampler/compare/flip/flip_filter_spatial.js +86 -86
  989. package/src/engine/graphics/texture/sampler/compare/flip/flip_pool.js +71 -71
  990. package/src/engine/graphics/texture/sampler/compare/flip/flip_srgb_to_ycxcz.js +55 -55
  991. package/src/engine/graphics/texture/sampler/compare/flip/sampler2d_flip_ldr.js +80 -80
  992. package/src/engine/graphics/texture/sampler/filter/SeparableKernel.js +82 -82
  993. package/src/engine/graphics/texture/sampler/filter/sampler2d_convolve_separable.js +122 -122
  994. package/src/engine/graphics/texture/sampler/resize/sampler2d_scale_down_lanczos.js +148 -148
  995. package/src/engine/graphics/texture/sampler/sampler2d_channel_apply_lut.js +82 -82
  996. package/src/engine/graphics/texture/sampler/sampler2d_combine.js +67 -67
  997. package/src/engine/graphics/texture/sampler/sampler2d_linear_f16_to_srgb_u8.js +54 -54
  998. package/src/engine/graphics/texture/sampler/sampler2d_sample_equirectangular_direction.js +63 -63
  999. package/src/engine/graphics/texture/sampler/sampler2d_srgb_to_linear.js +33 -33
  1000. package/src/engine/graphics/texture/sampler/sampler2d_srgb_u8_to_linear_f16.js +68 -68
  1001. package/src/engine/graphics/texture/shade_image_preview.js +103 -103
  1002. package/src/engine/graphics/trail/TrailSpawnMode.js +20 -20
  1003. package/src/engine/graphics/trail/tube/TubeX.js +573 -573
  1004. package/src/engine/graphics/trail/tube/TubeXMaterialSpec.js +58 -58
  1005. package/src/engine/graphics/trail/tube/simulator/TubeXFixedPhysicsSimulator.js +34 -34
  1006. package/src/engine/graphics/trail/tube/tube_attributes_spec.js +69 -69
  1007. package/src/engine/graphics/trail/tube/tube_frame.js +83 -83
  1008. package/src/engine/graphics3/AnimationGraphSystem3.js +329 -329
  1009. package/src/engine/graphics3/AnimationSystem3.js +352 -352
  1010. package/src/engine/graphics3/CameraSystem3.js +170 -170
  1011. package/src/engine/graphics3/DecalSystem3.js +441 -441
  1012. package/src/engine/graphics3/FogOfWarSystem3.js +265 -265
  1013. package/src/engine/graphics3/GraphicsEngine3.js +776 -776
  1014. package/src/engine/graphics3/HighlightSystem3.js +241 -241
  1015. package/src/engine/graphics3/LightSystem3.js +211 -211
  1016. package/src/engine/graphics3/MeshSystem3.js +646 -646
  1017. package/src/engine/graphics3/ParticleEmitterSystem3.js +289 -289
  1018. package/src/engine/graphics3/PathDisplaySystem3.js +309 -309
  1019. package/src/engine/graphics3/PickingQuery.js +48 -48
  1020. package/src/engine/graphics3/PickingResult.js +47 -47
  1021. package/src/engine/graphics3/PickingSystem3.js +273 -273
  1022. package/src/engine/graphics3/ShadeCameraAdapter.js +55 -55
  1023. package/src/engine/graphics3/ShadedGeometrySystem3.js +169 -169
  1024. package/src/engine/graphics3/TerrainSystem3.js +566 -566
  1025. package/src/engine/graphics3/TooltipComponentSystem3.js +328 -328
  1026. package/src/engine/graphics3/Trail3DSystem3.js +221 -221
  1027. package/src/engine/graphics3/WaterSystem3.js +293 -293
  1028. package/src/engine/graphics3/animation/ClipPlayback.js +84 -84
  1029. package/src/engine/graphics3/animation/wrap_clip_time.js +23 -23
  1030. package/src/engine/graphics3/animation/write_graph_playback.js +48 -48
  1031. package/src/engine/graphics3/camera_sync_from_transform.js +29 -29
  1032. package/src/engine/graphics3/debug/gizmo_view_from_camera.js +48 -48
  1033. package/src/engine/graphics3/decal/DECAL_CLUSTER.js +61 -61
  1034. package/src/engine/graphics3/decal/DECAL_GPU_RECORD.js +117 -117
  1035. package/src/engine/graphics3/decal/DecalAtlas.js +194 -194
  1036. package/src/engine/graphics3/decal/DecalAtlasFill.js +32 -32
  1037. package/src/engine/graphics3/decal/GPUDecalRenderer.js +360 -360
  1038. package/src/engine/graphics3/decal/chunk_decal_intersects_frustum.js +59 -59
  1039. package/src/engine/graphics3/decal/chunk_decal_sampling_info.js +57 -57
  1040. package/src/engine/graphics3/decal/chunk_decal_surface_frame.js +54 -54
  1041. package/src/engine/graphics3/decal/decal_atlas_border.js +69 -69
  1042. package/src/engine/graphics3/decal/decal_gpu_records.js +120 -120
  1043. package/src/engine/graphics3/decal/decal_material_samplers.js +109 -109
  1044. package/src/engine/graphics3/decal/graph_build_decal_clusters.js +212 -212
  1045. package/src/engine/graphics3/decal/shader_cluster_assign_decals.js +207 -207
  1046. package/src/engine/graphics3/decal/shader_cull_decals_frustum.js +108 -108
  1047. package/src/engine/graphics3/highlight/GPUHighlightRenderer.js +151 -151
  1048. package/src/engine/graphics3/highlight/HIGHLIGHT_OUTLINE.js +23 -23
  1049. package/src/engine/graphics3/highlight/chunk_highlight_lookup.js +53 -53
  1050. package/src/engine/graphics3/highlight/pack_highlight_color.js +44 -44
  1051. package/src/engine/graphics3/highlight/pack_highlight_table.js +74 -74
  1052. package/src/engine/graphics3/highlight/shader_highlight_outline.js +150 -150
  1053. package/src/engine/graphics3/load_cube_environment.js +68 -68
  1054. package/src/engine/graphics3/make_default_environment.js +107 -107
  1055. package/src/engine/graphics3/particles/particle_gpu_records.js +221 -221
  1056. package/src/engine/graphics3/path/build_tube_path_streams.js +98 -98
  1057. package/src/engine/graphics3/path/tube_stream_write_geometry.js +90 -90
  1058. package/src/engine/graphics3/preview/ModelPreviewFraming.js +35 -35
  1059. package/src/engine/graphics3/preview/make_model_preview_scene.js +154 -154
  1060. package/src/engine/graphics3/preview/make_model_thumbnail.js +48 -48
  1061. package/src/engine/graphics3/preview/model_preview_framing.js +70 -70
  1062. package/src/engine/graphics3/shade_bundle_bounds.js +55 -55
  1063. package/src/engine/graphics3/shade_camera_projection_ray.js +77 -77
  1064. package/src/engine/graphics3/shade_node_to_entity_composition.js +84 -84
  1065. package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.js +481 -481
  1066. package/src/engine/graphics3/terrain/chunk_terrain_grid_overlay.js +61 -61
  1067. package/src/engine/graphics3/terrain/chunk_terrain_splat_mix.js +66 -66
  1068. package/src/engine/graphics3/terrain/pack_terrain_row_table.js +53 -53
  1069. package/src/engine/graphics3/terrain/shader_terrain_splat.js +215 -215
  1070. package/src/engine/graphics3/trail/trail_tube_write_geometry.js +158 -158
  1071. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +717 -717
  1072. package/src/engine/input/analog/apply_radial_dead_zone.js +38 -38
  1073. package/src/engine/input/devices/GamepadDevice.js +466 -466
  1074. package/src/engine/input/devices/ManualInputDevice.js +152 -152
  1075. package/src/engine/input/devices/PointerCoordinates.js +26 -26
  1076. package/src/engine/input/devices/events/GamepadEvents.js +10 -10
  1077. package/src/engine/input/devices/gamepad/GamepadAxes.js +19 -19
  1078. package/src/engine/input/devices/gamepad/GamepadButtons.js +29 -29
  1079. package/src/engine/input/devices/gamepad/GamepadCoordinates.js +17 -17
  1080. package/src/engine/input/devices/gamepad/GamepadDeviceLayout.js +323 -323
  1081. package/src/engine/input/devices/gamepad/GamepadHandle.js +286 -286
  1082. package/src/engine/input/devices/gamepad/GamepadLayout.js +160 -160
  1083. package/src/engine/input/devices/gamepad/GamepadStandardMapping.js +31 -31
  1084. package/src/engine/input/devices/gamepad/GamepadStick.js +169 -169
  1085. package/src/engine/input/devices/gamepad/GamepadStickCalibration.js +119 -119
  1086. package/src/engine/input/devices/gamepad/GamepadStickCalibrator.js +250 -250
  1087. package/src/engine/input/devices/gamepad/gamepad_layout_database.js +144 -144
  1088. package/src/engine/input/devices/gamepad/gamepad_read_hat_axis.js +61 -61
  1089. package/src/engine/input/devices/gamepad/gamepad_write_dpad_vector.js +30 -30
  1090. package/src/engine/input/devices/gamepad/prototypeGamepadTester.js +2124 -2124
  1091. package/src/engine/input/devices/mouse/MouseButtons.js +22 -22
  1092. package/src/engine/input/ecs/components/Input.js +118 -118
  1093. package/src/engine/input/ecs/components/InputController.js +78 -78
  1094. package/src/engine/input/ecs/ism/ISM_DESIGN.md +1523 -1523
  1095. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +627 -627
  1096. package/src/engine/input/ecs/ism/InputActionEvent.js +40 -40
  1097. package/src/engine/input/ecs/ism/InputBinding.js +71 -71
  1098. package/src/engine/input/ecs/ism/InputCoordinateKind.js +25 -25
  1099. package/src/engine/input/ecs/ism/InputCoordinateSource.js +86 -86
  1100. package/src/engine/input/ecs/ism/InputDirection.js +33 -33
  1101. package/src/engine/input/ecs/ism/InputMapProgram.js +236 -236
  1102. package/src/engine/input/ecs/ism/InputMapSystem.js +976 -976
  1103. package/src/engine/input/ecs/ism/InputOcclusion.js +31 -31
  1104. package/src/engine/input/ecs/ism/InputSource.js +67 -67
  1105. package/src/engine/input/ecs/ism/InputSourceTable.js +107 -107
  1106. package/src/engine/input/ecs/ism/coordinate/InputCoordinateChannel.js +93 -93
  1107. package/src/engine/input/ecs/ism/coordinate/InputCoordinateChannelType.js +11 -11
  1108. package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.js +153 -153
  1109. package/src/engine/input/ecs/ism/coordinate/InputCoordinateSwitches.js +160 -160
  1110. package/src/engine/input/ecs/ism/device/GAMEPAD_INPUT_DEVICE_ID.js +9 -9
  1111. package/src/engine/input/ecs/ism/device/GamepadInputDeviceAdapter.js +88 -88
  1112. package/src/engine/input/ecs/ism/device/InputDeviceAdapter.js +72 -72
  1113. package/src/engine/input/ecs/ism/device/KEYBOARD_INPUT_DEVICE_ID.js +9 -9
  1114. package/src/engine/input/ecs/ism/device/KeyboardInputDeviceAdapter.js +63 -63
  1115. package/src/engine/input/ecs/ism/device/ManualInputDeviceAdapter.js +55 -55
  1116. package/src/engine/input/ecs/ism/device/POINTER_INPUT_DEVICE_ID.js +9 -9
  1117. package/src/engine/input/ecs/ism/device/PointerInputDeviceAdapter.js +160 -160
  1118. package/src/engine/input/ecs/ism/map/InputBinding.js +88 -88
  1119. package/src/engine/input/ecs/ism/map/InputCoordinateBinding.js +102 -102
  1120. package/src/engine/input/ecs/ism/map/InputLayer.js +220 -220
  1121. package/src/engine/input/ecs/ism/map/InputMap.js +331 -331
  1122. package/src/engine/input/ecs/ism/prototypeInputMap.js +309 -309
  1123. package/src/engine/input/ecs/ism/trigger/InputTrigger.js +148 -148
  1124. package/src/engine/input/ecs/ism/trigger/InputTriggerChord.js +173 -173
  1125. package/src/engine/input/ecs/ism/trigger/InputTriggerGamepadButton.js +37 -37
  1126. package/src/engine/input/ecs/ism/trigger/InputTriggerHold.js +176 -176
  1127. package/src/engine/input/ecs/ism/trigger/InputTriggerKey.js +39 -39
  1128. package/src/engine/input/ecs/ism/trigger/InputTriggerMouseButton.js +38 -38
  1129. package/src/engine/input/ecs/ism/trigger/InputTriggerRelease.js +120 -120
  1130. package/src/engine/input/ecs/ism/trigger/InputTriggerSequence.js +315 -315
  1131. package/src/engine/input/ecs/ism/trigger/InputTriggerSwitch.js +105 -105
  1132. package/src/engine/input/ecs/ism/trigger/InputTriggerType.js +17 -17
  1133. package/src/engine/input/ecs/systems/InputControllerSystem.js +253 -253
  1134. package/src/engine/input/ecs/systems/InputSystem.js +162 -162
  1135. package/src/engine/intelligence/behavior/primitive/FailingBehaviorSerializationAdapter.js +25 -25
  1136. package/src/engine/intelligence/behavior/primitive/SucceedingBehaviorSerializationAdapter.js +26 -26
  1137. package/src/engine/intelligence/behavior/util/AsynchronousDelayAction.js +55 -55
  1138. package/src/engine/interpolation/BinaryInterpolationAdapter.js +56 -56
  1139. package/src/engine/interpolation/Interpoland.js +49 -49
  1140. package/src/engine/interpolation/Interpolated.js +149 -149
  1141. package/src/engine/interpolation/PoseInterpolationAdapter.js +61 -61
  1142. package/src/engine/interpolation/TransformPoseSerializationAdapter.js +57 -57
  1143. package/src/engine/interpolation/pose_interpoland.js +27 -27
  1144. package/src/engine/navigation/ecs/path_following/PathFollower.js +222 -222
  1145. package/src/engine/navigation/mesh/NavigationMesh.js +145 -145
  1146. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +661 -0
  1147. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +229 -229
  1148. package/src/engine/navigation/mesh/build/clip_soup_against_overhangs.d.ts.map +1 -1
  1149. package/src/engine/navigation/mesh/build/clip_soup_against_overhangs.js +628 -520
  1150. package/src/engine/network/CONGESTION_CONTROL.md +87 -87
  1151. package/src/engine/network/README.md +52 -52
  1152. package/src/engine/network/adapters/QuaternionInterpolationAdapter.js +43 -43
  1153. package/src/engine/network/adapters/TransformInterpolationAdapter.js +84 -84
  1154. package/src/engine/network/adapters/TransformReplicationAdapter.js +87 -87
  1155. package/src/engine/network/adapters/Vector3InterpolationAdapter.js +46 -46
  1156. package/src/engine/network/convertPathToURL.js +2 -2
  1157. package/src/engine/network/core/MalformedPacketError.js +26 -26
  1158. package/src/engine/network/core/quantize/quantize_float.js +73 -73
  1159. package/src/engine/network/core/quantize/quantize_position.js +65 -65
  1160. package/src/engine/network/core/sequence/ack_bitfield.js +77 -77
  1161. package/src/engine/network/core/sequence/seq16.js +69 -69
  1162. package/src/engine/network/core/sequence/seq32.js +73 -73
  1163. package/src/engine/network/ecs/NetworkSystem.js +84 -84
  1164. package/src/engine/network/ecs/components/NetworkIdentity.js +73 -73
  1165. package/src/engine/network/ecs/owner_authorization.js +55 -55
  1166. package/src/engine/network/ecs/serialization/NetworkIdentitySerializationAdapter.js +64 -64
  1167. package/src/engine/network/replication/ScopeFilter.js +71 -71
  1168. package/src/engine/network/sim/ActionLog.js +152 -152
  1169. package/src/engine/network/sim/SimAction.js +273 -273
  1170. package/src/engine/network/sim/Snapshotter.js +222 -222
  1171. package/src/engine/network/state/FrameBufferRing.js +168 -168
  1172. package/src/engine/network/state/InputRing.js +134 -134
  1173. package/src/engine/network/state/PriorityAccumulator.js +180 -180
  1174. package/src/engine/network/time/TimeDilation.js +62 -62
  1175. package/src/engine/network/transport/Channel.js +336 -336
  1176. package/src/engine/network/transport/Transport.js +203 -203
  1177. package/src/engine/network/transport/adapters/NodeUDPTransport.js +186 -186
  1178. package/src/engine/network/transport/adapters/WebRTCDataChannelTransport.js +105 -105
  1179. package/src/engine/network/transport/fragments/fragment_send.js +147 -147
  1180. package/src/engine/network/transport/fragments/packet_size.js +101 -101
  1181. package/src/engine/network/xhr.js +23 -23
  1182. package/src/engine/physics/BULLET_REVIEW.md +945 -945
  1183. package/src/engine/physics/CANNON_REVIEW.md +1300 -1300
  1184. package/src/engine/physics/CONSTRAINT_SOLVER_BENCH_LOG.md +208 -208
  1185. package/src/engine/physics/CONSTRAINT_SOLVER_IMPROVEMENTS_PLAN.md +364 -364
  1186. package/src/engine/physics/INTEPOLATION_SYSTEM_PLAN.md +287 -287
  1187. package/src/engine/physics/JOLT_REVIEW.md +913 -913
  1188. package/src/engine/physics/PLAN.md +1120 -1094
  1189. package/src/engine/physics/RAPIER_REVIEW.md +934 -934
  1190. package/src/engine/physics/REVIEW_001_ACTION_PLAN.md +642 -642
  1191. package/src/engine/physics/REVIEW_002.md +151 -151
  1192. package/src/engine/physics/REVIEW_003.md +166 -166
  1193. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +97 -97
  1194. package/src/engine/physics/constraint/DofMode.js +35 -35
  1195. package/src/engine/physics/constraint/solve_constraints.js +1 -1
  1196. package/src/engine/physics/contact/combine_material.js +35 -35
  1197. package/src/engine/physics/ecs/BodyKind.js +29 -29
  1198. package/src/engine/physics/ecs/Collider.js +177 -177
  1199. package/src/engine/physics/ecs/ColliderFlags.js +15 -15
  1200. package/src/engine/physics/ecs/ColliderSerializationAdapter.js +37 -37
  1201. package/src/engine/physics/ecs/Joint.js +475 -475
  1202. package/src/engine/physics/ecs/JointSerializationAdapter.js +72 -72
  1203. package/src/engine/physics/ecs/PhysicsSystem.d.ts +3 -0
  1204. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  1205. package/src/engine/physics/ecs/PhysicsSystem.js +7 -2
  1206. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.js +37 -37
  1207. package/src/engine/physics/ecs/SleepState.js +12 -12
  1208. package/src/engine/physics/ecs/find_non_finite_physics_state.js +76 -76
  1209. package/src/engine/physics/fluid/FluidField.js +867 -867
  1210. package/src/engine/physics/fluid/FluidSimulator.js +832 -832
  1211. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +243 -243
  1212. package/src/engine/physics/fluid/SliceVisualiser.js +190 -190
  1213. package/src/engine/physics/fluid/ecs/FluidComponent.js +239 -239
  1214. package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.js +89 -89
  1215. package/src/engine/physics/fluid/ecs/FluidObstacle.js +97 -97
  1216. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  1217. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.js +348 -348
  1218. package/src/engine/physics/fluid/ecs/FluidSystem.js +142 -142
  1219. package/src/engine/physics/fluid/ecs/FluidWorkerCore.js +123 -123
  1220. package/src/engine/physics/fluid/ecs/WorkerFluidSystem.js +395 -395
  1221. package/src/engine/physics/fluid/ecs/fluid.worker.js +12 -12
  1222. package/src/engine/physics/fluid/ecs/fluid_build_world_to_grid.js +32 -32
  1223. package/src/engine/physics/fluid/ecs/fluid_gather_visible_effectors.js +47 -47
  1224. package/src/engine/physics/fluid/ecs/fluid_reanchor_field.js +85 -85
  1225. package/src/engine/physics/fluid/ecs/fluid_sync_effectors_from_transform.js +16 -16
  1226. package/src/engine/physics/fluid/ecs/fluid_worker_protocol.js +111 -111
  1227. package/src/engine/physics/fluid/ecs/makeFluidWorker.js +18 -18
  1228. package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +81 -81
  1229. package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +202 -202
  1230. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +257 -257
  1231. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +405 -405
  1232. package/src/engine/physics/fluid/prototype.js +126 -126
  1233. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.js +143 -143
  1234. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +162 -162
  1235. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +107 -107
  1236. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.js +131 -131
  1237. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +90 -90
  1238. package/src/engine/physics/fluid/solver/v3_grid_limit8_at_indices.js +38 -38
  1239. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.js +77 -77
  1240. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.js +113 -113
  1241. package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.js +92 -92
  1242. package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.js +107 -107
  1243. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +135 -135
  1244. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +511 -511
  1245. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +108 -108
  1246. package/src/engine/physics/fluid/solver/v3_mac_advect_maccormack_velocity.js +317 -317
  1247. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.js +236 -236
  1248. package/src/engine/physics/fluid/solver/v3_mac_advect_sl_velocity.js +217 -217
  1249. package/src/engine/physics/fluid/solver/v3_mac_apply_vorticity_confinement.js +174 -174
  1250. package/src/engine/physics/fluid/solver/v3_mac_clip_trace.js +95 -95
  1251. package/src/engine/physics/fluid/solver/v3_mac_compute_divergence.js +77 -77
  1252. package/src/engine/physics/fluid/solver/v3_mac_compute_face_solid.js +131 -131
  1253. package/src/engine/physics/fluid/solver/v3_mac_subtract_pressure_gradient.js +104 -104
  1254. package/src/engine/physics/inertia/world_inverse_inertia.js +160 -160
  1255. package/src/engine/physics/integration/integrate_position.js +97 -97
  1256. package/src/engine/physics/narrowphase/box_box_manifold.js +681 -681
  1257. package/src/engine/physics/narrowphase/box_triangle_contact.js +906 -906
  1258. package/src/engine/physics/narrowphase/capsule_triangle_contact.js +395 -395
  1259. package/src/engine/physics/narrowphase/compute_penetration.js +369 -369
  1260. package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.js +55 -55
  1261. package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.js +37 -37
  1262. package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.js +117 -117
  1263. package/src/engine/physics/narrowphase/narrowphase_step.js +1738 -1738
  1264. package/src/engine/physics/narrowphase/reduce_manifold_contacts.js +74 -74
  1265. package/src/engine/physics/narrowphase/refine_ray_hit.d.ts +12 -11
  1266. package/src/engine/physics/narrowphase/refine_ray_hit.d.ts.map +1 -1
  1267. package/src/engine/physics/narrowphase/refine_ray_hit.js +228 -36
  1268. package/src/engine/physics/narrowphase/sphere_sphere_contact.js +52 -52
  1269. package/src/engine/physics/narrowphase/sphere_triangle_contact.js +138 -138
  1270. package/src/engine/physics/persistence/solver_caches.js +309 -309
  1271. package/src/engine/physics/queries/overlap_shape.js +187 -187
  1272. package/src/engine/physics/queries/raycast.d.ts +7 -4
  1273. package/src/engine/physics/queries/raycast.d.ts.map +1 -1
  1274. package/src/engine/physics/queries/raycast.js +11 -5
  1275. package/src/engine/physics/queries/shape_cast.js +417 -417
  1276. package/src/engine/physics/solver/apply_impulse_to_body.js +86 -86
  1277. package/src/engine/physics/solver/friction_cone.js +37 -37
  1278. package/src/engine/physics/solver/solve_contacts.js +1 -1
  1279. package/src/engine/platform/WebEnginePlatform.d.ts.map +1 -1
  1280. package/src/engine/platform/WebEnginePlatform.js +1 -2
  1281. package/src/engine/scene/SerializedScene.d.ts +2 -2
  1282. package/src/engine/scene/SerializedScene.d.ts.map +1 -1
  1283. package/src/engine/scene/transitionToScene.js +121 -121
  1284. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  1285. package/src/engine/simulation/Ticker.js +33 -0
  1286. package/src/engine/sound/ecs/audio/LiveEmitterSet.js +345 -345
  1287. package/src/engine/sound/ecs/audio/SpatialAudioIndex.js +140 -140
  1288. package/src/engine/sound/simulation/AcousticSimulator.js +646 -646
  1289. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +432 -432
  1290. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +250 -250
  1291. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +322 -322
  1292. package/src/engine/sound/simulation/README.md +277 -277
  1293. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +261 -261
  1294. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +121 -121
  1295. package/src/engine/sound/simulation/configureAcousticSimulation.js +48 -48
  1296. package/src/engine/sound/simulation/core/AcousticMedium.js +113 -113
  1297. package/src/engine/sound/simulation/core/AcousticMediumSerializationAdapter.js +27 -27
  1298. package/src/engine/sound/simulation/core/AcousticOccluderIndex.js +312 -312
  1299. package/src/engine/sound/simulation/core/AcousticRegionIndex.js +159 -159
  1300. package/src/engine/sound/simulation/core/AcousticSolution.js +90 -90
  1301. package/src/engine/sound/simulation/core/AcousticSourceState.js +109 -109
  1302. package/src/engine/sound/simulation/core/AcousticVolumeRegion.js +73 -73
  1303. package/src/engine/sound/simulation/core/OcclusionSolver.js +112 -112
  1304. package/src/engine/sound/simulation/core/RayHit.js +50 -50
  1305. package/src/engine/sound/simulation/core/VolumeField.js +149 -149
  1306. package/src/engine/sound/simulation/definition/AcousticDirectivity.js +114 -114
  1307. package/src/engine/sound/simulation/definition/AcousticDirectivitySerializationAdapter.js +30 -30
  1308. package/src/engine/sound/simulation/definition/AcousticMaterial.js +122 -122
  1309. package/src/engine/sound/simulation/definition/AcousticMaterialSerializationAdapter.js +32 -32
  1310. package/src/engine/sound/simulation/ecs/AcousticBody.js +48 -48
  1311. package/src/engine/sound/simulation/ecs/AcousticBodySerializationAdapter.js +34 -34
  1312. package/src/engine/sound/simulation/ecs/AcousticProbeFieldSystem.js +64 -64
  1313. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.js +75 -75
  1314. package/src/engine/sound/simulation/ecs/AcousticVolume.js +74 -74
  1315. package/src/engine/sound/simulation/ecs/AcousticVolumeSerializationAdapter.js +37 -37
  1316. package/src/engine/sound/simulation/ecs/AcousticVolumeSystem.js +66 -66
  1317. package/src/engine/sound/simulation/probe/AcousticProbeField.js +578 -578
  1318. package/src/engine/sound/simulation/probe/AcousticProbeFieldSerializationAdapter.js +60 -60
  1319. package/src/engine/sound/simulation/probe/ProbeFieldPathingSolution.js +64 -64
  1320. package/src/engine/sound/simulation/probe/ProbeVisibilityRecheck.js +132 -132
  1321. package/src/engine/sound/simulation/probe/acoustic_probe_transfer.js +103 -103
  1322. package/src/engine/sound/simulation/probe/acoustic_trace_energy.js +136 -136
  1323. package/src/engine/sound/simulation/probe/bakeProbeField.js +169 -169
  1324. package/src/engine/sound/simulation/probe/bakeProbeReflectors.js +110 -110
  1325. package/src/engine/sound/simulation/probe/bakeReverbBands.js +110 -110
  1326. package/src/engine/sound/simulation/probe/bakeVisibility.js +148 -148
  1327. package/src/engine/sound/simulation/probe/echogram_band_rt60.js +83 -83
  1328. package/src/engine/sound/simulation/probe/probe_delaunay_edges.js +215 -215
  1329. package/src/engine/sound/simulation/probe/probe_densify_portals.js +140 -140
  1330. package/src/engine/sound/simulation/probe/probe_detect_portals.js +196 -196
  1331. package/src/engine/sound/simulation/probe/probe_edge_key.js +38 -38
  1332. package/src/engine/sound/simulation/probe/probe_edge_visible.js +41 -41
  1333. package/src/engine/sound/simulation/probe/probe_place_sdf_cover.js +82 -82
  1334. package/src/engine/sound/simulation/probe/probe_refine_connectivity.js +181 -181
  1335. package/src/engine/sound/simulation/probe/probe_sdf_grid.js +171 -171
  1336. package/src/engine/sound/simulation/probe/probe_visibility_augment.js +146 -146
  1337. package/src/engine/sound/simulation/probe/probe_visibility_bridge_components.js +167 -167
  1338. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +354 -354
  1339. package/src/engine/sound/simulation/render/ProbeReverbRenderer.js +231 -231
  1340. package/src/engine/sound/simulation/render/foaReverbImpulseResponse.js +105 -105
  1341. package/src/engine/sound/simulation/render/reverbImpulseResponse.js +66 -66
  1342. package/src/engine/sound/simulation/render/reverb_band_tails.js +93 -93
  1343. package/src/engine/sound/simulation/serialization/populateAcousticSerializationRegistry.js +25 -25
  1344. package/src/engine/sound/sopra/README.md +643 -643
  1345. package/src/engine/sound/sopra/SopraEngine.js +432 -432
  1346. package/src/engine/sound/sopra/asset/AssetManagerBufferProvider.js +71 -71
  1347. package/src/engine/sound/sopra/asset/BufferProvider.js +29 -29
  1348. package/src/engine/sound/sopra/asset/StubBufferProvider.js +58 -58
  1349. package/src/engine/sound/sopra/definition/BusDefinition.js +142 -142
  1350. package/src/engine/sound/sopra/definition/BusDefinitionSerializationAdapter.js +54 -54
  1351. package/src/engine/sound/sopra/definition/DuckingRule.js +106 -106
  1352. package/src/engine/sound/sopra/definition/DuckingRuleSerializationAdapter.js +31 -31
  1353. package/src/engine/sound/sopra/definition/EventDescription.js +262 -262
  1354. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.js +55 -55
  1355. package/src/engine/sound/sopra/definition/MixerSnapshot.js +83 -83
  1356. package/src/engine/sound/sopra/definition/MixerSnapshotSerializationAdapter.js +39 -39
  1357. package/src/engine/sound/sopra/definition/ParameterDefinition.js +117 -117
  1358. package/src/engine/sound/sopra/definition/ParameterDefinitionSerializationAdapter.js +31 -31
  1359. package/src/engine/sound/sopra/definition/VoiceStealMode.js +18 -18
  1360. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +109 -109
  1361. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.js +185 -185
  1362. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClipSerializationAdapter.js +59 -59
  1363. package/src/engine/sound/sopra/definition/clip/ContainerAudioClip.js +128 -128
  1364. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.js +226 -226
  1365. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClipSerializationAdapter.js +54 -54
  1366. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +191 -191
  1367. package/src/engine/sound/sopra/definition/clip/SampleAudioClipSerializationAdapter.js +39 -39
  1368. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.js +79 -79
  1369. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClipSerializationAdapter.js +42 -42
  1370. package/src/engine/sound/sopra/definition/clip/SilenceAudioClip.js +77 -77
  1371. package/src/engine/sound/sopra/definition/clip/SilenceAudioClipSerializationAdapter.js +27 -27
  1372. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +5 -0
  1373. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
  1374. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.js +125 -125
  1375. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClipSerializationAdapter.js +41 -41
  1376. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.js +24 -24
  1377. package/src/engine/sound/sopra/definition/effect/CompressorEffect.js +120 -120
  1378. package/src/engine/sound/sopra/definition/effect/CompressorEffectSerializationAdapter.js +31 -31
  1379. package/src/engine/sound/sopra/definition/effect/EqEffect.js +128 -128
  1380. package/src/engine/sound/sopra/definition/effect/EqEffectSerializationAdapter.js +29 -29
  1381. package/src/engine/sound/sopra/definition/effect/ReverbEffect.js +113 -113
  1382. package/src/engine/sound/sopra/definition/effect/ReverbEffectSerializationAdapter.js +25 -25
  1383. package/src/engine/sound/sopra/runtime/BusGraph.js +231 -231
  1384. package/src/engine/sound/sopra/runtime/ParameterStore.js +98 -98
  1385. package/src/engine/sound/sopra/runtime/SopraPlaybackContext.js +68 -68
  1386. package/src/engine/sound/sopra/runtime/Voice.js +145 -145
  1387. package/src/engine/sound/sopra/runtime/VoiceManager.js +136 -136
  1388. package/src/engine/sound/sopra/runtime/VoicePool.js +17 -17
  1389. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.js +42 -42
  1390. package/src/engine/sound/sopra/serialization/sopraJSON.js +99 -99
  1391. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.js +49 -49
  1392. package/src/engine/sound/sopra/util/MockAudioContext.js +224 -224
  1393. package/src/engine/sound/sopra/util/fadeOutAndStop.js +60 -60
  1394. package/src/engine/ui/DraggableAspect.js +115 -115
  1395. package/src/engine/ui/apply_pointer_tilt_3d.js +50 -50
  1396. package/src/generation/COORDINATES.md +54 -54
  1397. package/src/generation/GridGenerationResource.js +24 -24
  1398. package/src/generation/GridTaskGroup.js +214 -214
  1399. package/src/generation/REVIEW_01_ACTION_PLAN.md +628 -628
  1400. package/src/generation/automata/CaveGeneratorCellularAutomata.js +79 -79
  1401. package/src/generation/automata/CellularAutomata.js +22 -22
  1402. package/src/generation/compute_writes_union.js +25 -25
  1403. package/src/generation/filtering/CellFilter.js +117 -117
  1404. package/src/generation/filtering/core/CellFilterBinaryOperation.js +37 -37
  1405. package/src/generation/filtering/core/CellFilterOperationTertiary.js +43 -43
  1406. package/src/generation/filtering/core/CellFilterUnaryOperation.js +29 -29
  1407. package/src/generation/filtering/numeric/process/computeCellFilterSobel.js +36 -36
  1408. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.js +42 -42
  1409. package/src/generation/filtering/numeric/util/populateSampler2DFromCellFilter.js +18 -18
  1410. package/src/generation/filtering/numeric/util/write_cell_filter_to_sampler2d.js +47 -47
  1411. package/src/generation/filtering/util/cell_filter_weights_pick.js +54 -54
  1412. package/src/generation/grid/GridData.js +233 -233
  1413. package/src/generation/grid/coords/grid_to_texel.js +10 -10
  1414. package/src/generation/grid/coords/texel_to_grid.js +10 -10
  1415. package/src/generation/grid/generation/GridTaskApplyActionToCells.js +90 -90
  1416. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.js +388 -388
  1417. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.js +127 -127
  1418. package/src/generation/grid/generation/GridTaskSequence.js +58 -58
  1419. package/src/generation/grid/generation/NoopGridTaskGenerator.js +12 -12
  1420. package/src/generation/grid/generation/discrete/GridTaskActionRuleSet.js +48 -48
  1421. package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.js +146 -146
  1422. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.js +540 -540
  1423. package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +222 -222
  1424. package/src/generation/grid/generation/grid/GridTaskAddNodesFixed.js +44 -44
  1425. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +614 -614
  1426. package/src/generation/markers/GridCellActionPlaceMarker.js +244 -244
  1427. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +86 -86
  1428. package/src/generation/markers/actions/terrain/MarkerNodeActionPaintTerrain.js +266 -266
  1429. package/src/generation/markers/emitter/MarkerNodeEmitterGridCellAction.js +49 -49
  1430. package/src/generation/placement/GridCellActionTransformNearbyMarkers.js +120 -120
  1431. package/src/generation/placement/action/GridCellAction.js +45 -45
  1432. package/src/generation/placement/action/GridCellActionPlaceTags.js +140 -140
  1433. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.js +89 -89
  1434. package/src/generation/placement/action/random/CellActionSelectRandom.js +69 -69
  1435. package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.js +91 -91
  1436. package/src/generation/placement/action/util/GridCellActionSequence.js +61 -61
  1437. package/src/generation/placement/action/util/GridCellDisplacedAction.js +61 -61
  1438. package/src/generation/rules/cell/CellMatcherRemovalPreservesConnectivity.js +183 -183
  1439. package/src/generation/theme/ThemeEngine.js +666 -666
  1440. package/src/shade/RENDERER_CONTRACT.md +568 -568
  1441. package/src/shade/descriptor/texture/format/gpu_texture_format_info.js +267 -267
  1442. package/src/shade/device/ShadeDeviceFailure.js +104 -104
  1443. package/src/shade/device/ShadeDeviceFailureReason.js +41 -41
  1444. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +255 -255
  1445. package/src/shade/device/mock/REVIEW_2026_08_22.md +527 -527
  1446. package/src/shade/device/mock/SoftwareGPUBindGroup.js +23 -23
  1447. package/src/shade/device/mock/SoftwareGPUBindGroupLayout.js +22 -22
  1448. package/src/shade/device/mock/SoftwareGPUError.js +63 -63
  1449. package/src/shade/device/mock/SoftwareGPUPipeline.js +75 -75
  1450. package/src/shade/device/mock/SoftwareGPUQuerySet.js +113 -113
  1451. package/src/shade/device/mock/SoftwareGPUSampler.js +30 -30
  1452. package/src/shade/device/mock/SoftwareGPUShaderModule.js +32 -32
  1453. package/src/shade/device/mock/SoftwareGPUTextureView.js +22 -22
  1454. package/src/shade/device/mock/SoftwareGPUUncapturedErrorEvent.js +23 -23
  1455. package/src/shade/device/mock/normalize_dynamic_offsets.js +26 -26
  1456. package/src/shade/device/mock/texture_copy.js +287 -287
  1457. package/src/shade/device/timing/GPUTimer.js +285 -285
  1458. package/src/shade/device/timing/GPUTimerArray.js +205 -205
  1459. package/src/shade/playground/add_random_lights.js +49 -49
  1460. package/src/shade/playground/add_random_meshes.js +83 -83
  1461. package/src/shade/playground/animation_prototype.js +508 -508
  1462. package/src/shade/playground/animation_prototype_skinning.js +647 -647
  1463. package/src/shade/playground/animation_prototype_stress.js +765 -765
  1464. package/src/shade/playground/enable_picker.js +59 -59
  1465. package/src/shade/playground/gltf_skinned_prototype.js +560 -560
  1466. package/src/shade/playground/gltf_skinned_stress_prototype.js +387 -387
  1467. package/src/shade/playground/gltf_viewer.js +282 -282
  1468. package/src/shade/playground/load_default_environment.js +19 -19
  1469. package/src/shade/playground/main.js +2727 -2727
  1470. package/src/shade/playground/make_animated_instances.js +117 -117
  1471. package/src/shade/playground/prototype_virtual_texture.js +274 -274
  1472. package/src/shade/playground/prototype_volumetrics_01.js +206 -206
  1473. package/src/shade/playground/sample.js +234 -234
  1474. package/src/shade/playground/sample_load_gltf.js +102 -102
  1475. package/src/shade/playground/spread_node3d_grid.js +19 -19
  1476. package/src/shade/renderer/Renderer.js +2436 -2436
  1477. package/src/shade/renderer/ShadeIndirectLightingMode.js +14 -14
  1478. package/src/shade/renderer/animation/ShadeAnimationChannel.js +414 -414
  1479. package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.js +531 -531
  1480. package/src/shade/renderer/animation/pose/PosePlayback.js +55 -55
  1481. package/src/shade/renderer/animation/pose/pose_evaluate_local.js +179 -179
  1482. package/src/shade/renderer/animation/pose/pose_evaluate_world.js +76 -76
  1483. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +1024 -1024
  1484. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.js +79 -79
  1485. package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.js +56 -56
  1486. package/src/shade/renderer/binding/BindGroupManager.js +282 -282
  1487. package/src/shade/renderer/binding/adapt_cache_capacity.js +25 -25
  1488. package/src/shade/renderer/buffer/GPUBufferAllocator.js +116 -116
  1489. package/src/shade/renderer/buffer/buffer_pool_ops.js +123 -123
  1490. package/src/shade/renderer/buffer/table/GPU_DATABASE_PAGE_SIZE.js +9 -9
  1491. package/src/shade/renderer/buffer/table/GPU_DATABASE_UPLOAD_BUFFER_LIMIT.js +8 -8
  1492. package/src/shade/renderer/buffer/table/PageBufferPool.js +71 -71
  1493. package/src/shade/renderer/buffer/table/PageSlotAllocator.js +95 -95
  1494. package/src/shade/renderer/camera/Camera.js +281 -281
  1495. package/src/shade/renderer/camera/GPUCameraContext.js +233 -233
  1496. package/src/shade/renderer/camera/orbital/README.md +84 -84
  1497. package/src/shade/renderer/deferred/shader_composite_volumetrics.js +75 -75
  1498. package/src/shade/renderer/dynamic/DYNAMIC_MESH_VERTEX.js +25 -25
  1499. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.js +342 -342
  1500. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +167 -167
  1501. package/src/shade/renderer/dynamic/shader_dynamic_mesh.js +170 -170
  1502. package/src/shade/renderer/extension/FrameContext.js +263 -263
  1503. package/src/shade/renderer/extension/FramePhase.js +104 -104
  1504. package/src/shade/renderer/extension/FrameRecord.js +126 -126
  1505. package/src/shade/renderer/extension/GBufferTextures.js +83 -83
  1506. package/src/shade/renderer/extension/PresentTarget.js +34 -34
  1507. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +918 -918
  1508. package/src/shade/renderer/extension/RenderExtension.js +69 -69
  1509. package/src/shade/renderer/extension/RenderExtensionRegistry.js +319 -319
  1510. package/src/shade/renderer/extension/SceneColor.js +40 -40
  1511. package/src/shade/renderer/extension/ViewTextures.js +78 -78
  1512. package/src/shade/renderer/fow/GPUFogOfWarRenderer.js +182 -182
  1513. package/src/shade/renderer/geometry/Geometry.js +608 -608
  1514. package/src/shade/renderer/geometry/geometry_build_from_meshlet_geometry.js +342 -342
  1515. package/src/shade/renderer/geometry/meshlet_geometry_transfer.js +41 -41
  1516. package/src/shade/renderer/geometry/primitives/make_box_geometry.js +153 -153
  1517. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.js +240 -240
  1518. package/src/shade/renderer/geometry/primitives/make_plane_geometry.js +145 -145
  1519. package/src/shade/renderer/geometry/primitives/make_polyhedron_geometry.js +327 -327
  1520. package/src/shade/renderer/geometry/primitives/make_torus_geometry.js +107 -107
  1521. package/src/shade/renderer/geometry/primitives/make_torus_knot_geometry.js +165 -165
  1522. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +607 -607
  1523. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +66 -66
  1524. package/src/shade/renderer/geometry/virtual/build/VGeoBuildResult.js +32 -32
  1525. package/src/shade/renderer/geometry/virtual/build/VGeoFaceGraph.js +103 -103
  1526. package/src/shade/renderer/geometry/virtual/build/VGeoGatheredFaces.js +25 -25
  1527. package/src/shade/renderer/geometry/virtual/build/VGeoLevel.js +33 -33
  1528. package/src/shade/renderer/geometry/virtual/build/VGeoLevelOptions.js +62 -62
  1529. package/src/shade/renderer/geometry/virtual/build/VGeoLevelSummary.js +49 -49
  1530. package/src/shade/renderer/geometry/virtual/build/VGeoSubmesh.js +20 -20
  1531. package/src/shade/renderer/geometry/virtual/build/VirtualGeometryMesh.js +214 -214
  1532. package/src/shade/renderer/geometry/virtual/build/gltf/GltfByteSource.js +122 -122
  1533. package/src/shade/renderer/geometry/virtual/build/gltf/GltfCollectReport.js +29 -29
  1534. package/src/shade/renderer/geometry/virtual/build/gltf/GltfDocument.js +210 -210
  1535. package/src/shade/renderer/geometry/virtual/build/gltf/GltfGeometry.js +48 -48
  1536. package/src/shade/renderer/geometry/virtual/build/gltf/GltfGeometryInstance.js +25 -25
  1537. package/src/shade/renderer/geometry/virtual/build/gltf/GltfGeometrySelection.js +28 -28
  1538. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_collect_geometries.js +296 -296
  1539. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_open_document.js +166 -166
  1540. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_read_geometry.js +199 -199
  1541. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +173 -173
  1542. package/src/shade/renderer/geometry/virtual/build/vgeo_bounding_sphere.js +28 -28
  1543. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +200 -200
  1544. package/src/shade/renderer/geometry/virtual/build/vgeo_build_levels.js +1786 -1786
  1545. package/src/shade/renderer/geometry/virtual/build/vgeo_build_page_nodes.js +157 -157
  1546. package/src/shade/renderer/geometry/virtual/build/vgeo_build_root_group.js +26 -26
  1547. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_normals.js +75 -75
  1548. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_tangents.js +143 -143
  1549. package/src/shade/renderer/geometry/virtual/build/vgeo_containing_sphere.js +44 -44
  1550. package/src/shade/renderer/geometry/virtual/build/vgeo_extract_submesh.js +41 -41
  1551. package/src/shade/renderer/geometry/virtual/build/vgeo_gather_faces.js +71 -71
  1552. package/src/shade/renderer/geometry/virtual/build/vgeo_graph_components.js +123 -123
  1553. package/src/shade/renderer/geometry/virtual/build/vgeo_narrow_indices.js +26 -26
  1554. package/src/shade/renderer/geometry/virtual/build/vgeo_normalize_source.js +112 -112
  1555. package/src/shade/renderer/geometry/virtual/build/vgeo_partition_graph.js +56 -56
  1556. package/src/shade/renderer/geometry/virtual/build/vgeo_sphere_inflate_to_contain.js +70 -70
  1557. package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set.js +187 -187
  1558. package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set_packed.js +207 -207
  1559. package/src/shade/renderer/geometry/virtual/format/VGEO_DEFECT.js +18 -18
  1560. package/src/shade/renderer/geometry/virtual/format/VGeoDefect.js +38 -38
  1561. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +64 -64
  1562. package/src/shade/renderer/geometry/virtual/format/attribute/VGEO_ATTRIBUTE.js +13 -13
  1563. package/src/shade/renderer/geometry/virtual/format/attribute/VGEO_ATTRIBUTES.js +50 -50
  1564. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attribute_allocate.js +28 -28
  1565. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attribute_mask.js +23 -23
  1566. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attributes_read.js +31 -31
  1567. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_vertex.js +32 -32
  1568. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_declare.js +46 -46
  1569. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_like.js +19 -19
  1570. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_test_fixtures.js +27 -27
  1571. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_asset_id_preimage.js +62 -62
  1572. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_asset_id.js +13 -13
  1573. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_directory_block_checksum.js +41 -41
  1574. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_frame_checksum.js +41 -41
  1575. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_header_checksum.js +25 -25
  1576. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET.js +20 -20
  1577. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_RECORD_SIZE.js +5 -5
  1578. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_MAX_CHILD_REF.js +5 -5
  1579. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_MAX_CLUSTER_TRIANGLE_COUNT.js +5 -5
  1580. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_MAX_CLUSTER_VERTEX_COUNT.js +5 -5
  1581. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_NO_CHILD.js +5 -5
  1582. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_NO_GROUP.js +5 -5
  1583. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_SAME_PAGE.js +6 -6
  1584. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +81 -81
  1585. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryGroup.js +37 -37
  1586. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryPageNode.js +55 -55
  1587. package/src/shade/renderer/geometry/virtual/format/directory/VGEO_DIRECTORY_BLOCK_RECORDS.js +5 -5
  1588. package/src/shade/renderer/geometry/virtual/format/directory/VGEO_DIRECTORY_FLAG_ROOT_PAGE.js +5 -5
  1589. package/src/shade/renderer/geometry/virtual/format/directory/VGEO_DIRECTORY_RECORD_SIZE.js +5 -5
  1590. package/src/shade/renderer/geometry/virtual/format/directory/vgeo_directory_block_count.js +12 -12
  1591. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CHILD_OFFSET.js +11 -11
  1592. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CHILD_TABLE_ENTRY_SIZE.js +5 -5
  1593. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_LZ4.js +11 -11
  1594. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_RAW.js +5 -5
  1595. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_FRAME_ALIGNMENT.js +5 -5
  1596. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_FRAME_HEADER_SIZE.js +5 -5
  1597. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_FRAME_OFFSET.js +13 -13
  1598. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_PAGE_MAGIC.js +5 -5
  1599. package/src/shade/renderer/geometry/virtual/format/frame/VGeoFrameBlob.js +21 -21
  1600. package/src/shade/renderer/geometry/virtual/format/frame/VGeoFrameExtent.js +59 -59
  1601. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_codec_name.js +27 -27
  1602. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_decode_frame_blob.js +84 -84
  1603. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +56 -56
  1604. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_frame_decode_bound.js +35 -35
  1605. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_scan_frames.js +74 -74
  1606. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +6 -6
  1607. package/src/shade/renderer/geometry/virtual/format/header/VGEO_HASH_ALGO_XXH3.js +5 -5
  1608. package/src/shade/renderer/geometry/virtual/format/header/VGEO_HEADER_OFFSET.js +31 -31
  1609. package/src/shade/renderer/geometry/virtual/format/header/VGEO_HEADER_SIZE.js +5 -5
  1610. package/src/shade/renderer/geometry/virtual/format/header/VGEO_LEVEL_OFFSET.js +20 -20
  1611. package/src/shade/renderer/geometry/virtual/format/header/VGEO_LEVEL_RECORD_SIZE.js +9 -9
  1612. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MAGIC.js +5 -5
  1613. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MIN_READER_VERSION.js +5 -5
  1614. package/src/shade/renderer/geometry/virtual/format/header/VGEO_PAYLOAD_ENCODING_SHADE_MESHLET_V1.js +5 -5
  1615. package/src/shade/renderer/geometry/virtual/format/header/VGeoLevelRecord.js +41 -41
  1616. package/src/shade/renderer/geometry/virtual/format/page/VGEO_GROUP_RECORD_SIZE.js +5 -5
  1617. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_GROUP_CLUSTER_COUNT.js +6 -6
  1618. package/src/shade/renderer/geometry/virtual/format/page/VGEO_METRIC_OFFSET.js +21 -21
  1619. package/src/shade/renderer/geometry/virtual/format/page/VGEO_METRIC_SIZE.js +5 -5
  1620. package/src/shade/renderer/geometry/virtual/format/page/VGEO_NODE_FANOUT.js +9 -9
  1621. package/src/shade/renderer/geometry/virtual/format/page/VGEO_NODE_FLAG_LEAF.js +5 -5
  1622. package/src/shade/renderer/geometry/virtual/format/page/VGEO_NODE_OFFSET.js +10 -10
  1623. package/src/shade/renderer/geometry/virtual/format/page/VGEO_NODE_RECORD_SIZE.js +5 -5
  1624. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_HEADER_SIZE.js +5 -5
  1625. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +16 -16
  1626. package/src/shade/renderer/geometry/virtual/format/payload/VGEO_ENCODING_FLAGS_MASK.js +6 -6
  1627. package/src/shade/renderer/geometry/virtual/format/payload/VGeoEncodedPayload.js +18 -18
  1628. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.js +200 -200
  1629. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_payload_attribute_offset.js +39 -39
  1630. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_payload_size.js +20 -20
  1631. package/src/shade/renderer/geometry/virtual/format/prototypeVGEOFormatViewer.js +2063 -2063
  1632. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +1622 -1622
  1633. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +485 -485
  1634. package/src/shade/renderer/gpu_primitive/sort/ffx/graph_radix_sort.js +115 -115
  1635. package/src/shade/renderer/gpu_primitive/sort/one_sweep/verify_radix_sort_one_sweep.js +110 -110
  1636. package/src/shade/renderer/light/environment/octahedral_resample_kernel.js +50 -50
  1637. package/src/shade/renderer/light/environment/octahedral_uv_to_direction.js +30 -30
  1638. package/src/shade/renderer/light/environment/resample_cube_to_octahedral.js +157 -157
  1639. package/src/shade/renderer/light/make_sunlight.js +35 -35
  1640. package/src/shade/renderer/light/model/io/light_record_point.js +39 -39
  1641. package/src/shade/renderer/loader/gltf/GLTF_PRIMITIVE_MODE.js +23 -23
  1642. package/src/shade/renderer/loader/gltf/MESHOPT_COMPRESSION_PLAN.md +793 -793
  1643. package/src/shade/renderer/loader/gltf/ext/GltfBufferViewExtension.js +54 -54
  1644. package/src/shade/renderer/loader/gltf/ext/GltfBufferViewExtensionSet.js +109 -109
  1645. package/src/shade/renderer/loader/gltf/ext/gltf_apply_buffer_view_extensions.js +69 -69
  1646. package/src/shade/renderer/loader/gltf/ext/gltf_buffer_view_extensions.js +22 -22
  1647. package/src/shade/renderer/loader/gltf/ext/gltf_geometry_extensions.js +39 -39
  1648. package/src/shade/renderer/loader/gltf/ext/meshopt/MeshoptBufferViewExtension.js +301 -301
  1649. package/src/shade/renderer/loader/gltf/gltf_component_type.js +223 -223
  1650. package/src/shade/renderer/loader/gltf/gltf_node_world_matrices.js +137 -137
  1651. package/src/shade/renderer/loader/gltf/gltf_parse_container.js +241 -241
  1652. package/src/shade/renderer/loader/gltf/gltf_read_accessor.js +294 -294
  1653. package/src/shade/renderer/loader/gltf/gltf_used_image_indices.js +49 -49
  1654. package/src/shade/renderer/loader/gltf/load_gltf.js +1253 -1253
  1655. package/src/shade/renderer/loader/gltf/tiny-gltf.js +646 -646
  1656. package/src/shade/renderer/loader/usd/UsdError.js +33 -33
  1657. package/src/shade/renderer/loader/usd/UsdExtensionRegistry.js +69 -69
  1658. package/src/shade/renderer/loader/usd/load_usd.js +226 -226
  1659. package/src/shade/renderer/loader/usd/parse_usda.js +931 -931
  1660. package/src/shade/renderer/loader/usd/unpack_usdz.js +106 -106
  1661. package/src/shade/renderer/loader/usd/usd_build_scene.js +658 -658
  1662. package/src/shade/renderer/loader/usd/usd_compose_transform.js +258 -258
  1663. package/src/shade/renderer/loader/usd/usd_decode_image.js +384 -384
  1664. package/src/shade/renderer/loader/usd/usd_lz4.js +182 -182
  1665. package/src/shade/renderer/loader/usd/usd_triangulate.js +159 -159
  1666. package/src/shade/renderer/material/ShadeMaterial.d.ts +2 -2
  1667. package/src/shade/renderer/material/ShadeMaterial.js +2 -2
  1668. package/src/shade/renderer/material/standard/fragment_gbuffer.js +334 -334
  1669. package/src/shade/renderer/material/standard/fragment_gbuffer_vt.js +169 -169
  1670. package/src/shade/renderer/material/standard/material_gbuffer_vertex.js +45 -45
  1671. package/src/shade/renderer/material/standard_material_to_struct.js +23 -23
  1672. package/src/shade/renderer/particles/prototypeParticleSystem.js +450 -450
  1673. package/src/shade/renderer/particles/runtime/spawn_request_encoding.js +52 -52
  1674. package/src/shade/renderer/pool/TransientResourcePool.js +392 -392
  1675. package/src/shade/renderer/postprocess/bloom/bloom_chain_resolution.js +29 -29
  1676. package/src/shade/renderer/postprocess/bloom/graph_bloom_downsample.js +109 -109
  1677. package/src/shade/renderer/postprocess/bloom/graph_postprocess_bloom.js +155 -155
  1678. package/src/shade/renderer/postprocess/cas/shader_ffx_rcas.js +114 -114
  1679. package/src/shade/renderer/postprocess/dof/DOF_AUTOFOCUS_PARAMS_STRUCT.js +25 -25
  1680. package/src/shade/renderer/postprocess/dof/DOF_FOCUS_STATE_STRUCT.js +23 -23
  1681. package/src/shade/renderer/postprocess/dof/DOF_PRESETS.js +27 -27
  1682. package/src/shade/renderer/postprocess/dof/chunk_dof_coc_band_diameter.js +41 -41
  1683. package/src/shade/renderer/postprocess/dof/chunk_dof_coc_band_radius.js +32 -32
  1684. package/src/shade/renderer/postprocess/dof/chunk_dof_coc_coefficient.js +26 -26
  1685. package/src/shade/renderer/postprocess/dof/compute_dof_autofocus_params.js +64 -64
  1686. package/src/shade/renderer/postprocess/dof/compute_dof_uniform.js +54 -54
  1687. package/src/shade/renderer/postprocess/dof/gather/DOF2_CONFIG.js +91 -91
  1688. package/src/shade/renderer/postprocess/dof/gather/DOF2_PRESETS.js +9 -9
  1689. package/src/shade/renderer/postprocess/dof/gather/DOF2_SETTINGS_STRUCT.js +66 -66
  1690. package/src/shade/renderer/postprocess/dof/gather/DOF2_TEXTURE_FORMAT.js +22 -22
  1691. package/src/shade/renderer/postprocess/dof/gather/DepthOfFieldU.js +292 -292
  1692. package/src/shade/renderer/postprocess/dof/gather/chunk_dof2_coc_to_near_far.js +25 -25
  1693. package/src/shade/renderer/postprocess/dof/gather/chunk_dof2_gather_weight.js +30 -30
  1694. package/src/shade/renderer/postprocess/dof/gather/compute_dof2_uniform.js +54 -54
  1695. package/src/shade/renderer/postprocess/dof/gather/graph_postprocess_dof2.js +194 -194
  1696. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_fill.js +68 -68
  1697. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_gather_far.js +140 -140
  1698. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_gather_near.js +142 -142
  1699. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_recombine.js +99 -99
  1700. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_setup.js +102 -102
  1701. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_tile_dilate.js +75 -75
  1702. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_tile_max.js +73 -73
  1703. package/src/shade/renderer/postprocess/dof/raymarch/DOF_SETTINGS_STRUCT.js +49 -49
  1704. package/src/shade/renderer/postprocess/dof/raymarch/DepthOfField.js +298 -298
  1705. package/src/shade/renderer/postprocess/dof/raymarch/graph_postprocess_dof.js +244 -244
  1706. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_composite.js +91 -91
  1707. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_firefly_cleanup.js +61 -61
  1708. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_prefilter.js +90 -90
  1709. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_raymarch_compute.js +267 -267
  1710. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_slice_compute.js +271 -271
  1711. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_tile_dilate.js +70 -70
  1712. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_tile_max.js +72 -72
  1713. package/src/shade/renderer/postprocess/dof/shader_dof_autofocus.js +99 -99
  1714. package/src/shade/renderer/postprocess/gtao/generate_magic_square_noise.js +51 -51
  1715. package/src/shade/renderer/postprocess/motion_blur/MotionBlur.js +56 -56
  1716. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +78 -78
  1717. package/src/shade/renderer/postprocess/upscale-dither/UpscaleDither.js +95 -95
  1718. package/src/shade/renderer/postprocess/upscale-dither/fragment_shader_upscale_dither.js +204 -204
  1719. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.js +58 -58
  1720. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +230 -230
  1721. package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.js +278 -278
  1722. package/src/shade/renderer/rasterize/native/oit/chunk_material_side_should_draw.js +26 -26
  1723. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.js +178 -178
  1724. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +235 -235
  1725. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +208 -208
  1726. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +206 -206
  1727. package/src/shade/renderer/scene/DynamicMesh.js +70 -70
  1728. package/src/shade/renderer/scene/DynamicMeshBatch.js +90 -90
  1729. package/src/shade/renderer/scene/GPUSceneContext.js +901 -901
  1730. package/src/shade/renderer/scene/SceneNodeBinding.js +56 -56
  1731. package/src/shade/renderer/scene/SkinnedMesh.js +55 -55
  1732. package/src/shade/renderer/scene/TransformAuthority.js +33 -33
  1733. package/src/shade/renderer/scene/optimization/deduplicate_geometries.js +38 -38
  1734. package/src/shade/renderer/scene/optimization/deduplicate_images.js +93 -93
  1735. package/src/shade/renderer/scene/optimization/geometry/internal/match_refit_validate.js +127 -127
  1736. package/src/shade/renderer/scene/optimization/geometry/internal/match_solve_transform.js +492 -492
  1737. package/src/shade/renderer/scene/optimization/optimize_texture_set.js +81 -81
  1738. package/src/shade/renderer/scene/optimization/source_to_sampler2d.js +21 -21
  1739. package/src/shade/renderer/scene/serialization/STANDARD_MATERIAL_SERIALIZED_BYTE_SIZE.js +12 -12
  1740. package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_transform_point.js +26 -26
  1741. package/src/shade/renderer/shader/chunk/noise/chunk_interleaved_gradient_noise.js +20 -20
  1742. package/src/shade/renderer/shader/chunk/spherical_harmonics/dering/chunk_sh2_dering_optimize_positive.js +61 -61
  1743. package/src/shade/renderer/shader/chunk/texture/chunk_texture_filter_fxaa_lite.js +225 -225
  1744. package/src/shade/renderer/shader/chunk/texture/dither/chunk_dither_color_8bit_gradient_noise.js +25 -25
  1745. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +384 -384
  1746. package/src/shade/renderer/shadow/map/PointLightShadowmap.js +105 -105
  1747. package/src/shade/renderer/shadow/map/SpotLightShadowmap.js +63 -63
  1748. package/src/shade/renderer/shadow/map/TetrahedronPointLightShadowmap.js +89 -89
  1749. package/src/shade/renderer/shadow/map/shadowmap_update_score.js +232 -232
  1750. package/src/shade/renderer/texture/GPUTextureAllocator.js +85 -85
  1751. package/src/shade/renderer/texture/texture_pool_ops.js +171 -171
  1752. package/src/shade/renderer/texture/virtual/PageTableQuadAllocator.js +253 -253
  1753. package/src/shade/renderer/texture/virtual/README.md +276 -276
  1754. package/src/shade/renderer/texture/virtual/VTPageTable.js +330 -330
  1755. package/src/shade/renderer/texture/virtual/VTPhysicalCache.js +349 -349
  1756. package/src/shade/renderer/texture/virtual/VT_CONSTANTS.js +154 -154
  1757. package/src/shade/renderer/texture/virtual/VT_STACK_INFO_STRUCT.js +20 -20
  1758. package/src/shade/renderer/texture/virtual/VirtualTextureManager.js +1276 -1276
  1759. package/src/shade/renderer/texture/virtual/VirtualTextureStack.js +106 -106
  1760. package/src/shade/renderer/texture/virtual/build_chunk_vt_lookup.js +150 -150
  1761. package/src/shade/renderer/texture/virtual/build_shader_vt_feedback.js +232 -232
  1762. package/src/shade/renderer/texture/virtual/chunk_vt_request_key.js +28 -28
  1763. package/src/shade/renderer/texture/virtual/source/VTSourceImage.js +207 -207
  1764. package/src/shade/renderer/texture/virtual/source/VTSourceProcedural.js +135 -135
  1765. package/src/shade/renderer/texture/virtual/source/VTSourceTiled.js +132 -132
  1766. package/src/shade/renderer/water/GPUWaterRenderer.js +167 -167
  1767. package/src/shade/renderer/water/shader_water.js +246 -246
  1768. package/src/shade/renderer/water/water_height_texture_from_sampler.js +56 -56
  1769. package/src/shade/vitest.setup.mjs +89 -89
  1770. package/src/shade/wgsl/validate_wgsl_source.js +316 -316
  1771. package/src/view/controller/controls/NumericIntervalControl.js +90 -90
  1772. package/src/view/controller/controls/Vector2Control.js +83 -83
  1773. package/src/view/controller/controls/Vector3Control.js +90 -90
  1774. package/src/view/elements/Group.js +56 -56
  1775. package/src/view/elements/drawCheckers.js +33 -33
  1776. package/src/view/elements/windrose/WindRoseDiagram.js +369 -369
  1777. package/src/view/graphics/WebGLContextFailureView.js +76 -76
  1778. package/src/view/layout/DockPanel.js +51 -51
  1779. package/src/view/layout/SplitView.js +365 -365
  1780. package/src/view/layout/show_popup_menu.js +81 -81
  1781. package/src/view/minimap/MinimapCanvasView.js +411 -411
  1782. package/src/view/minimap/MinimapImageCache.js +88 -88
  1783. package/src/view/minimap/MinimapMarkerCollection.d.ts +0 -1
  1784. package/src/view/minimap/MinimapMarkerCollection.d.ts.map +1 -1
  1785. package/src/view/minimap/MinimapMarkerCollection.js +180 -180
  1786. package/src/view/minimap/dom/MinimapCameraView.js +206 -206
  1787. package/src/view/minimap/minimap_focus_area.js +97 -97
  1788. package/editor/process/symbolic/SocketsSymbolicDisplay.js +0 -192
  1789. package/src/core/geom/3d/topology/struct/binary/io/moved_tests.txt +0 -37
  1790. package/src/engine/ecs/attachment/Attachment.d.ts +0 -40
  1791. package/src/engine/ecs/attachment/Attachment.d.ts.map +0 -1
  1792. package/src/engine/ecs/attachment/Attachment.js +0 -57
  1793. package/src/engine/ecs/attachment/AttachmentBinding.d.ts +0 -28
  1794. package/src/engine/ecs/attachment/AttachmentBinding.d.ts.map +0 -1
  1795. package/src/engine/ecs/attachment/AttachmentBinding.js +0 -41
  1796. package/src/engine/ecs/attachment/AttachmentSystem.d.ts +0 -61
  1797. package/src/engine/ecs/attachment/AttachmentSystem.d.ts.map +0 -1
  1798. package/src/engine/ecs/attachment/AttachmentSystem.js +0 -307
  1799. package/src/engine/ecs/attachment/BoneAttachmentBinding.d.ts +0 -27
  1800. package/src/engine/ecs/attachment/BoneAttachmentBinding.d.ts.map +0 -1
  1801. package/src/engine/ecs/attachment/BoneAttachmentBinding.js +0 -69
  1802. package/src/engine/ecs/attachment/TransformAttachmentBinding.d.ts +0 -4
  1803. package/src/engine/ecs/attachment/TransformAttachmentBinding.d.ts.map +0 -1
  1804. package/src/engine/ecs/attachment/TransformAttachmentBinding.js +0 -51
  1805. package/src/engine/ecs/sockets/AttachmentSocket.d.ts +0 -32
  1806. package/src/engine/ecs/sockets/AttachmentSocket.d.ts.map +0 -1
  1807. package/src/engine/ecs/sockets/AttachmentSocket.js +0 -60
  1808. package/src/engine/ecs/sockets/AttachmentSocketType.d.ts +0 -6
  1809. package/src/engine/ecs/sockets/AttachmentSocketType.d.ts.map +0 -1
  1810. package/src/engine/ecs/sockets/AttachmentSocketType.js +0 -8
  1811. package/src/engine/ecs/sockets/AttachmentSockets.d.ts +0 -57
  1812. package/src/engine/ecs/sockets/AttachmentSockets.d.ts.map +0 -1
  1813. package/src/engine/ecs/sockets/AttachmentSockets.js +0 -130
  1814. package/src/engine/ecs/sockets/BoneAttachmentSocket.d.ts +0 -29
  1815. package/src/engine/ecs/sockets/BoneAttachmentSocket.d.ts.map +0 -1
  1816. package/src/engine/ecs/sockets/BoneAttachmentSocket.js +0 -56
  1817. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts +0 -6
  1818. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts.map +0 -1
  1819. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.js +0 -19
  1820. package/src/shade/renderer/animation/_dump_resolve.d.mts +0 -2
  1821. package/src/shade/renderer/animation/_dump_resolve.d.mts.map +0 -1
  1822. package/src/shade/renderer/animation/_dump_resolve.mjs +0 -5
@@ -1,667 +1,667 @@
1
- # Correctness review — `meep/src/view/`
2
-
3
- Scope: all 111 non-spec source files under `H:/git/moh/app/src/mir-engine/meep/src/view/`.
4
- Excluded: `editor/`, `prototype*.js`, `*.spec.js`, `.d.ts`.
5
-
6
- Notes on evidence used while reviewing:
7
- - `View.unlink()` **clears the `Linked` flag before dispatching `on.unlinked`** (`View.js:325` then `:347`). Several
8
- findings below depend on that ordering.
9
- - `Signal` keeps handlers in a `Map` keyed by the handler function; iteration is insertion-ordered, and a handler
10
- removed mid-dispatch by an earlier handler is **not** invoked (`core/events/signal/Signal.js:378-425`).
11
- - `Vector1`/`ObservedInteger` extend `Number` and implement `valueOf()`, so arithmetic directly on them is valid.
12
- - `segment2_segment_compute_intersection_array_2d` leaves `result` **untouched** and returns `false` on a miss.
13
-
14
- ---
15
-
16
- ### VIEW-1 `DomTooltipObserver.unlink()` never actually detaches, because the view is already unlinked
17
- - **Severity**: CRITICAL
18
- - **File**: `src/view/tooltip/DomTooltipObserver.js:156-165`, driven from `src/view/tooltip/DomTooltipManager.js:109-117,178-194`
19
- - **Defect**: `unlink()` only runs `__handleViewUnlinked()` `if (view.isLinked)`. On the `manage()` path the call
20
- arrives from inside the `view.on.unlinked` dispatch, at which point `View.unlink()` has already cleared the
21
- `Linked` flag — so the guard is always false and the teardown is skipped entirely. The observer's own
22
- `on.unlinked` handler cannot compensate: `manage()`'s handler was subscribed first, and it calls
23
- `observer.unlink()`, which does `view.on.unlinked.remove(this.__handleViewUnlinked, this)` mid-dispatch, deleting
24
- the not-yet-visited Map entry so it never fires.
25
- - **Failure scenario**: `gui.viewTooltips.manage(button, factory)` (used in ~20 places, e.g.
26
- `interaction/createInterfaceCommandButton.js:106`, `view/game/scene/strategy/shop/ItemShopView.js:185`). Link the
27
- panel, then unlink it. `mouseenter`/`mouseleave` listeners stay on `button.el`, and the 4 `SignalBinding`s on
28
- `view.position.onChanged`, `view.size.onChanged` and the `DomSizeObserver` stay linked forever. Re-open the panel
29
- and `manage()`'s linked handler calls `add()` again, creating a *second* observer with a second pair of DOM
30
- listeners on the same element. Ten open/close cycles leave ten live observers per button. Worse: hover a button,
31
- and inside the 128 ms `requestShow` delay close the panel — `remove()` calls `hide()` (no-op, tip not added yet),
32
- the observer teardown is skipped so nothing calls `cancelShowRequest()`, the timeout fires, `tipManager.add(tip)`
33
- builds a tooltip for a detached view, and because the element no longer receives mouse events nothing will ever
34
- fire `on.exited` → the tooltip is stuck on screen for the rest of the session.
35
- - **Fix**: drop the `view.isLinked` guard in `unlink()` and make `__handleViewUnlinked()` idempotent (track an
36
- internal `#attached` boolean set in `__handleViewLinked`), and remove the `view.on.*` handlers *before* calling
37
- `__handleViewUnlinked()`. Additionally call `this.cancelShowRequest()` in `DomTooltipManager.remove()`.
38
- - **Confidence**: Confirmed
39
-
40
- ### VIEW-2 `SvgImageView` cannot be imported and crashes on every `link()`
41
- - **Severity**: CRITICAL
42
- - **File**: `src/view/elements/image/SvgImageView.js:1,64-73`
43
- - **Defect**: Two independent hard errors. (a) `import AABB2 from "../../../core/geom/AABB2.js"` — that file does not
44
- exist; the real path is `core/geom/2d/aabb/AABB2.js`, so the module fails to resolve. (b) `update()` is a class
45
- method but its body references `resize` and `self`, which are `const`/`let` bindings local to the *constructor*.
46
- `link()` calls `this.update()` unconditionally.
47
- - **Failure scenario**: any module that does `import SvgImageView from '.../SvgImageView.js'` fails at bundle/resolve
48
- time. If the import path is fixed, `new SvgImageView(url, {assetManager}); parent.addChild(v)` on a linked parent →
49
- `link()` → `update()` → `ReferenceError: resize is not defined` (caught by Signal only if it were dispatched from a
50
- signal; here it propagates out of `addChild`).
51
- - **Fix**: correct the import path; promote `resize` and the icon element to instance state (`#resize()` reading
52
- `this.#elIcon`, `this.size`) so `update()` can reach them.
53
- - **Confidence**: Confirmed
54
-
55
- ### VIEW-3 `MinimapMarkerView` throws on construction — `this` used before `super()`
56
- - **Severity**: CRITICAL
57
- - **File**: `src/view/minimap/dom/MinimapMarkerView.js:17,51-64`
58
- - **Defect**: `super(entity, this.marker, this.transform, this.worldScale)` dereferences `this` before the base
59
- constructor has run, which is a `ReferenceError` in every ES2015+ engine. Even past that, the three handler methods
60
- reference `setPosition` and `size`, which are constructor-local bindings, and they are bound via `bindSignal(...)`
61
- **without a context argument**, so `this` inside them would be `undefined`.
62
- - **Failure scenario**: `new MinimapMarkerView(entity, marker, transform, worldScale)` →
63
- `ReferenceError: Must call super constructor in derived class before accessing 'this'`. The class is unusable.
64
- - **Fix**: `super()` with no arguments; move `setPosition` to a method and pass `this` as the context to every
65
- `bindSignal` call; read `this.size` instead of the free `size`.
66
- - **Confidence**: Confirmed
67
-
68
- ### VIEW-4 `MinimapTerrainView.__setTerrain` references an undefined identifier and has no context
69
- - **Severity**: CRITICAL
70
- - **File**: `src/view/minimap/dom/MinimapTerrainView.js:126,133-143`
71
- - **Defect**: `this.terrain.onChanged.add(this.__setTerrain)` subscribes a *method* with no context, and the method
72
- body calls `updatePreview()` — a function declared inside the constructor and therefore not in scope. It also
73
- dereferences `terrain.preview` with no null check even though `ObservedValue(null)` is the initial state and
74
- `set(null)` is a legal transition.
75
- - **Failure scenario**: `minimapTerrainView.terrain.set(someTerrain)` → `__setTerrain` runs →
76
- `ReferenceError: updatePreview is not defined` (swallowed by Signal's try/catch and logged) → the terrain preview
77
- image is never set, the view renders an empty `<img>`. `terrain.set(null)` →
78
- `TypeError: Cannot read properties of null (reading 'preview')`.
79
- - **Fix**: make `updatePreview`/`setPreview` instance methods, subscribe with `add(this.__setTerrain, this)`, and
80
- guard the `terrain === null` case.
81
- - **Confidence**: Confirmed
82
-
83
- ### VIEW-5 `ViewGroup.remove()` calls a non-existent `Set.remove`; `disconnect()` adds instead of removes
84
- - **Severity**: CRITICAL
85
- - **File**: `src/view/ViewGroup.js:34,74-89`
86
- - **Defect**: `this.elements` is a `Set`; `Set` has `delete`, not `remove`. Separately, `disconnect()` iterates every
87
- member and calls `this.container.addChild(view)` where the whole point of the method is to detach them.
88
- - **Failure scenario**: `group.remove(view)` → `TypeError: this.elements.remove is not a function`.
89
- `group.connect(a); group.connect(b)` → `connect` calls `disconnect()`, which re-adds every view to container `a`
90
- (pushing a duplicate entry into `a.children` and re-appending the DOM node), sets `this.container = null`, then
91
- `connect` adds them all to `b`. Container `a` is left with duplicate `children` entries pointing at views whose
92
- DOM nodes now live under `b`; a later `a.removeAllChildren()` calls `a.el.removeChild(child.el)` on a node that is
93
- no longer its child → `NotFoundError` DOMException.
94
- - **Fix**: `this.elements.delete(view)`; `disconnect()` must call `this.container.removeChild(view)`.
95
- - **Confidence**: Confirmed
96
-
97
- ### VIEW-6 `MinimapView.clear()` adds children instead of removing them
98
- - **Severity**: CRITICAL
99
- - **File**: `src/view/minimap/Minimap.js:183-188` (called from `unlink()` at `:236`)
100
- - **Defect**: The method is documented "remove all existing markers" / "clear out all camera views" but its body is
101
- `this.__worldView.addChild(v)` for each camera view — the views are already children, so each `unlink()` pushes a
102
- duplicate entry into `__worldView.children`.
103
- - **Failure scenario**: Open the minimap, close it, open it again (each cycle = one link/unlink pair). After N
104
- cycles `__worldView.children` holds each `MinimapCameraView` N+1 times. Now the camera entity is destroyed:
105
- `cameraRemoved` → `__worldView.removeChild(cameraView)` splices out *one* entry and detaches the DOM node, leaving
106
- stale duplicates. On the next `unlink()`, `clear()` runs `addChild` on that stale duplicate, which does
107
- `this.el.appendChild(child.el)` — re-inserting the frustum polygon of a camera that no longer exists back into the
108
- minimap, and re-linking it on the next `link()` so it keeps updating against a dead `Transform`.
109
- - **Fix**: `this.__worldView.removeChild(v)` and iterate a copy (or iterate backwards) since `removeChild` mutates.
110
- - **Confidence**: Confirmed
111
-
112
- ### VIEW-7 `TaskProgressView` displays progress where remaining time belongs
113
- - **Severity**: MAJOR
114
- - **File**: `src/view/task/TaskProgressView.js:127-131`
115
- - **Defect**: `const estimate = Number.isNaN(computedEstimate) ? 0 : computedProgressValue;` — the non-NaN branch uses
116
- `computedProgressValue` (the 0..1 progress fraction) instead of `computedEstimate` (the estimator's output). The
117
- computed estimate is discarded.
118
- - **Failure scenario**: A 60-second load at 20% progress. `remainingTimeEstimator.estimate()` returns ~48, but the
119
- `.remaining-time` label is fed `0.2` and formatted with `toFixed(0)` → it reads `0`. The loading screen shows
120
- "0 seconds remaining" for the entire load, then jumps to "1" at completion.
121
- - **Fix**: `const estimate = Number.isNaN(computedEstimate) ? 0 : computedEstimate;`
122
- - **Confidence**: Confirmed
123
-
124
- ### VIEW-8 `ColorPickerView` unsubscribes from the new colour instead of the old one
125
- - **Severity**: MAJOR
126
- - **File**: `src/view/elements/ColorPickerView.js:282-294`
127
- - **Defect**:
128
- ```js
129
- this.model.onChanged.add(function (v, _v) {
130
- if (v !== null) { modelValueChanged(...); v.onChanged.add(modelValueChanged); }
131
- if (_v !== null) { v.onChanged.remove(modelValueChanged); } // <-- v, should be _v
132
- });
133
- ```
134
- The removal targets the *new* value. The old value keeps the listener forever, and the new value gets `add`
135
- immediately followed by `remove`.
136
- - **Failure scenario**: `picker.model.set(colorA)` then `picker.model.set(colorB)`. Afterwards, changing `colorB`
137
- externally does not move the H/S/L/A gauges (its listener was removed), while changing `colorA` — which the picker
138
- no longer edits — does move them. Additionally `picker.model.set(null)` after having a colour executes
139
- `null.onChanged.remove(...)` → `TypeError: Cannot read properties of null (reading 'onChanged')`.
140
- - **Fix**: `if (_v !== null) { _v.onChanged.remove(modelValueChanged); }`, and perform the removal before the add.
141
- - **Confidence**: Confirmed
142
-
143
- ### VIEW-9 `ColorPickerView` value-channel write lock uses a key that does not exist
144
- - **Severity**: MAJOR
145
- - **File**: `src/view/elements/ColorPickerView.js:156-161,214,224,229,257,266`
146
- - **Defect**: `writeLocks` is declared with keys `h, s, l, a`. The `colorV` handler checks and sets `writeLocks.v`
147
- (undefined key), while `modelValueChanged` checks `writeLocks.l`. The lock protecting the value/lightness channel
148
- therefore never engages in either direction.
149
- - **Failure scenario**: Pick a saturated red (h≈0, s=1, v=1), then drag the **L** gauge to 0. `colorV.onChanged` runs
150
- unguarded (`writeLocks.v` is `undefined`), writes rgb `(0,0,0)` into the model, which dispatches
151
- `modelValueChanged`; that handler's guard reads `writeLocks.l` — also never set by the V handler — so it proceeds
152
- and pushes `rgb2hsv(0,0,0)` back into the gauges, snapping H and S to 0. The user's hue and saturation are
153
- destroyed by moving the lightness slider, and cannot be recovered by dragging L back up.
154
- - **Fix**: use one consistent key (`v`) in the declaration, the `colorV` handler, and `modelValueChanged`.
155
- - **Confidence**: Confirmed
156
-
157
- ### VIEW-10 `Vector1Control` binds the write-back handler to the model's change signal
158
- - **Severity**: MAJOR
159
- - **File**: `src/view/controller/controls/Vector1Control.js:61-81`
160
- - **Defect**: `subscribe(v1)` does `v1.onChanged.add(writeBack)`. `writeBack` is the *controller → model* direction
161
- (`vector1.set(v)`); the *model → controller* direction is `syncForward`, which is only ever called once, inside
162
- `subscribe`. `unsubscribe` symmetrically removes `writeBack`, so the mismatch is consistent and silent.
163
- - **Failure scenario**: Bind a `Vector1Control` to a `Vector1` that some other system writes (e.g. an animated
164
- property). The number field shows the value present at subscribe time and never updates again: each external change
165
- invokes `writeBack(newValue)` which writes `newValue` straight back into the same vector (a no-op) instead of
166
- refreshing `cNumber.value`.
167
- - **Fix**: `v1.onChanged.add(syncForward)` in `subscribe` and `v1.onChanged.remove(syncForward)` in `unsubscribe`;
168
- keep `lockForward` to break the echo.
169
- - **Confidence**: Confirmed
170
-
171
- ### VIEW-11 `ListController` removes the wrong view, so deleted rows stay on screen
172
- - **Severity**: MAJOR
173
- - **File**: `src/view/controller/controls/ListController.js:48-74`
174
- - **Defect**: `handleItemAdded` wraps `guiControl` in a `vElementContainer` and adds *that* to `vContainer`.
175
- `handleItemRemoved` then calls `vContainer.removeChild(guiControl)` — `guiControl` is a child of
176
- `vElementContainer`, not of `vContainer`, so `children.indexOf()` returns `-1` and `removeChild` returns `false`
177
- without doing anything.
178
- - **Failure scenario**: Click the `.close` button next to a list item. The item leaves the model
179
- (`list.removeOneOf(item)`), `elementControllers` drops the entry, `guiControl.model.set(null)` blanks the control —
180
- but the row (control + close button) remains in the DOM permanently. Clicking its close button again calls
181
- `list.removeOneOf(item)` on an item that is no longer present. Rebinding the controller to a different list via
182
- `detachList` leaves every old row visible on top of the new ones.
183
- - **Fix**: keep a `Map<item, vElementContainer>` (or store the wrapper on the control) and remove the wrapper.
184
- - **Confidence**: Confirmed
185
-
186
- ### VIEW-12 `HTMLElementCacheKey.initializeFromElement` wipes the styles it just read (shadowed loop variable)
187
- - **Severity**: MAJOR
188
- - **File**: `src/view/common/HTMLElementCacheKey.js:189-217`
189
- - **Defect**:
190
- ```js
191
- let i = 0;
192
- ...
193
- for (let i = 0; i < styleCount; i++) { ... this.style[i] = pair; } // inner `i` shadows outer
194
- this.style.splice(i, this.style.length - i); // outer i is still 0
195
- ```
196
- The truncation call meant to drop leftover entries instead removes the entire array. (The attribute loop below uses
197
- `for (i = 0; ...)` without `let`, so it truncates correctly — proving the intent.) The key therefore always reports
198
- "no inline styles", while `hash()`/`equals()` treat that as a real property of the element.
199
- - **Failure scenario**: `imageViewA.css({ filter: 'grayscale(1)' })` on an `<img src="x.png" class="icon">`, then
200
- `imageViewA.destroy()` → `key.initializeFromElement(el)` records the tag and attributes but **not** the filter →
201
- the element is pooled under a key that claims no styles. Later `new ImageView('x.png', {classList:['icon']})`
202
- builds a style-less key, `view_pool.get(key)` matches, and the recycled element is returned still carrying
203
- `filter: grayscale(1)` → the new image renders greyed out.
204
- - **Fix**: rename the inner loop variable (or hoist it) so the splice truncates from `styleCount`.
205
- - **Confidence**: Confirmed
206
-
207
- ### VIEW-13 `TabbedView` never attaches its toggle and panel containers — it renders nothing
208
- - **Severity**: MAJOR
209
- - **File**: `src/view/common/TabbedView.js:49-57`
210
- - **Defect**: The constructor creates `this.el`, then `this.__panelContainer` and `this.__toggleContainer`, but never
211
- calls `this.addChild(...)` on either, and neither does `link()`. Every toggle and panel is added to a container
212
- that is not in the view tree.
213
- - **Failure scenario**: `const t = new TabbedView({tabs}); parent.addChild(t);` → a bare empty `<div>`. Tab toggles
214
- and the active panel exist as detached DOM and are never linked (so their signal bindings never activate either).
215
- - **Fix**: `this.addChild(this.__toggleContainer); this.addChild(this.__panelContainer);` in the constructor.
216
- - **Confidence**: Confirmed
217
-
218
- ### VIEW-14 `MinimapFogOfWar.enforceAspectRatio` computes the wrong growth in the "too wide" branch
219
- - **Severity**: MAJOR
220
- - **File**: `src/view/minimap/gl/MinimapFogOfWar.js:16-38`
221
- - **Defect**: When `aspectRatioDelta <= 0` the code grows the width by `-aabbWidth * aspectRatioDelta`. Solving,
222
- the resulting ratio is `aabbHeight / (aabbWidth * (1 + aAR - vAR))`, which only equals `vAR` by coincidence. The
223
- height branch is correct (`aabbWidth * delta` yields exactly `aabbWidth * vAR`); the width branch is not the
224
- mirror of it.
225
- - **Failure scenario**: minimap viewport 200×100 (`vAR = 0.5`), revealed fog region a 100×100 square (`aAR = 1`).
226
- `delta = -0.5`, `d = 50`, new bounds 150×100 → ratio 0.667, not 0.5. `focusArea` is set to that region and drives
227
- the orthographic camera in `MinimapWorldGL.updateCameraFocus`, so the minimap world is squashed horizontally by
228
- ~33%: terrain, entity markers and the camera frustum polygon (which are positioned from `worldScale`) no longer
229
- line up with the fog-of-war overlay.
230
- - **Fix**: `const d = aabbHeight / viewportAspectRatio - aabbWidth;` (equivalently grow to `aabbHeight / vAR`).
231
- - **Confidence**: Confirmed
232
-
233
- ### VIEW-15 `ListView.insertOne` dereferences an undefined sibling view when a filter is in play
234
- - **Severity**: MAJOR
235
- - **File**: `src/view/common/ListView.js:182-197`
236
- - **Defect**: For a non-terminal insert it looks up `this.model.get(index + 1)` and calls `nextChild.el` without
237
- checking that a view exists for it. `getChildByElement` returns `undefined` whenever the next element was skipped
238
- by `this.filter` (or when the list contains duplicate elements — `viewMapping` is keyed by element identity, so a
239
- duplicate overwrites the previous entry).
240
- - **Failure scenario**: `new ListView(model, {elementFactory, filter: e => e.visible})`. Model is `[A(visible),
241
- C(hidden)]`; insert `B(visible)` at index 1. `insertOne` creates B's view, sees `model.length (3) !== index+1 (2)`,
242
- fetches `C`, `getChildByElement(C)` → `undefined` → `TypeError: Cannot read properties of undefined (reading 'el')`
243
- inside the `model.on.added` dispatch. Signal logs it and swallows it, so the symptom is a silently mis-ordered list
244
- (B stays appended at the end) plus a console error on every filtered insert.
245
- - **Fix**: scan forward from `index + 1` for the first element that has a view; if none, leave the child appended.
246
- - **Confidence**: Confirmed
247
-
248
- ### VIEW-16 `DomSizeObserver.attach()` unobserves the new element and never observes it
249
- - **Severity**: MAJOR
250
- - **File**: `src/view/util/DomSizeObserver.js:147-153`
251
- - **Defect**:
252
- ```js
253
- attach(element) {
254
- this.element = element; // old reference already lost
255
- if (this.running) { this.__dom_resize_observer.unobserve(this.element); } // unobserves the NEW element
256
- }
257
- ```
258
- The old element is never unobserved (it stays in the `ResizeObserver`), and the new element is never observed
259
- because `attach` only ever calls `unobserve`.
260
- - **Failure scenario**: `o.attach(elA); o.start();` then `o.attach(elB)` while running. `unobserve(elB)` is a no-op
261
- (B was never observed), A remains observed. Resizing B produces no callback at all — `o.dimensions` goes stale.
262
- Resizing A *does* fire the callback, which then measures **B** via `resizeAABB2ToFitBoundingClientRect(this.element…)`
263
- for the position but takes `rect.width/height` from **A's** `contentRect` → `dimensions` is a mix of two elements.
264
- - **Fix**: capture the previous element, `unobserve(previous)` if running, assign, then `observe(element)` if running.
265
- - **Confidence**: Confirmed
266
-
267
- ### VIEW-17 `SimpleWindowView` resize handler accumulates the full drag delta on every pointer move
268
- - **Severity**: MAJOR
269
- - **File**: `src/view/elements/SimpleWindow.js:47-73`
270
- - **Defect**: `anchor` is captured once on pointer-down and never advanced, yet the move handler does
271
- `view.size.add(position - anchor)` — an *incremental* mutation fed an *absolute* delta. Compare
272
- `BottomLeftResizeHandleView` (`elements/BottomLeftResizeHandleView.js:31-40`), which correctly does
273
- `lastPosition.copy(position)` each move.
274
- - **Failure scenario**: `new SimpleWindowView(content, {resizable: true})`. Grab the bottom-right 10 px corner and
275
- drag 10 px right over 5 pointer-move events (deltas 2, 4, 6, 8, 10 relative to the fixed anchor) → the width grows
276
- by 30 px instead of 10. A slow 200 px drag over 100 events grows the window by ~10 000 px; the window runs away
277
- from the cursor and cannot be resized back down.
278
- - **Fix**: either update `anchor` to `position` at the end of each move, or capture `originalSize` on pointer-down and
279
- use `view.size.copy(originalSize).add(delta)`.
280
- - **Confidence**: Confirmed
281
-
282
- ### VIEW-18 `ToastLogView` registers every notification twice in `children`
283
- - **Severity**: MAJOR
284
- - **File**: `src/view/elements/notify/ToastLogView.js:47,72-88`
285
- - **Defect**: The constructor reassigns `this.children = []` (shadowing the base `View.children` array), and `addOne`
286
- then does **both** `self.addChild(childView)` — which pushes onto `this.children` — **and**
287
- `self.children.push(childView)`. Every toast appears twice in the array. `removeChildView` splices out one
288
- occurrence and bypasses `View.removeChild`, so the second entry survives with its DOM node already detached.
289
- - **Failure scenario**: Two notifications A then B. `children` = `[A, A, B, B]`, so `updatePositions` computes
290
- `maxIndex = 3`: A ends at `-(3-1)*24 = -48 px` and B at `0`, instead of `-24` and `0` → a 24 px gap opens between
291
- the two toasts and the stack floats one row too high. After A's fade-out, `children` = `[A, B, B]` and A's stale
292
- entry keeps skewing every subsequent layout. If the view is ever destroyed, `View.destroy`/`removeAllChildren`
293
- walks the duplicates and calls `this.el.removeChild(A.el)` on an already-detached node → `NotFoundError`.
294
- - **Fix**: delete the `this.children = []` reassignment and the manual `push`; use `View.removeChild` in
295
- `removeChildView`. Also cancel the pending `setTimeout` handles on unlink and unsubscribe
296
- `model.elements.on.added` (currently a permanent subscription, `:90`).
297
- - **Confidence**: Confirmed
298
-
299
- ### VIEW-19 `RadialProgressView` subscribes to its external model permanently
300
- - **Severity**: MAJOR
301
- - **File**: `src/view/elements/radial/RadialProgressView.js:55-68`
302
- - **Defect**: `model.on.changed.add(update)` / `model[0].onChanged.add(redraw)` / `model[1].onChanged.add(redraw)` are
303
- raw subscriptions on caller-owned objects, made in the constructor and never removed — the class has no `unlink()`
304
- or `destroy()` override, and does not use `bindSignal`.
305
- - **Failure scenario**: `view/units/UnitRadialPreview.js:23` builds
306
- `new RadialProgressView([unit.healthCurrent, unit.stats.healthMax], …)`. The unit outlives the preview widget
307
- (health is model state). Every time a unit preview is created and discarded, the unit's `healthCurrent` signal
308
- retains `redraw`, which closes over the view, its SVG element and its `thickness` observable — the whole widget is
309
- unreclaimable, and every health tick redraws N dead widgets. Cycling a roster panel a few hundred times leaks
310
- hundreds of SVG subtrees.
311
- - **Fix**: route all three through `this.bindSignal(...)` so they follow the view's link lifecycle.
312
- - **Confidence**: Confirmed
313
-
314
- ### VIEW-20 `createInterfaceCommandButton` subscribes to the command's feature signals twice, one of them forever
315
- - **Severity**: MAJOR
316
- - **File**: `src/view/interaction/createInterfaceCommandButton.js:91-99`
317
- - **Defect**:
318
- ```js
319
- if (interaction.features !== undefined) {
320
- interaction.features.on.added.add(addCommandFeature); // permanent
321
- interaction.features.on.removed.add(removeCommandFeature); // permanent
322
- }
323
- button.bindSignal(interaction.features.on.added, addCommandFeature); // link-scoped (correct)
324
- button.bindSignal(interaction.features.on.removed, removeCommandFeature); // link-scoped (correct)
325
- ```
326
- `InteractionCommand` always constructs `this.features = new List(features)` (`interaction/InteractionCommand.js:40`),
327
- so the `if` is always taken and the first pair is always added. Nothing ever removes them.
328
- - **Failure scenario**: `InteractionCommand` instances are long-lived and shared — `InteractionCommandSet` keys them
329
- by id. A command bar that is rebuilt on every selection change produces a new `ButtonView` per command each time;
330
- each one permanently registers two closures on the shared command's feature list. After 100 selection changes,
331
- `interaction.setFeature('highlighted', true)` invokes `addCommandFeature` on 100 discarded buttons, and all 100
332
- button subtrees are unreclaimable.
333
- - **Fix**: delete the raw `on.added`/`on.removed` subscriptions; the `bindSignal` pair already covers the live case
334
- and `button.on.linked` already replays the current features.
335
- - **Confidence**: Confirmed
336
-
337
- ### VIEW-21 `MeshPreview` multiplies its pointer handlers on every link, and dereferences a null camera
338
- - **Severity**: MAJOR
339
- - **File**: `src/view/elements/MeshPreview.js:204-234`
340
- - **Defect**: (a) `link()` attaches a fresh `self.pContents.then(...)` continuation each time. Because `pContents` is
341
- already settled after the first load, every subsequent link immediately runs `__addInteraction`, which creates a
342
- **new** `PointerDevice`, calls `start()` on it, and adds another `dragStart`/`drag` pair that mutates
343
- `contents.group.rotation` — none of which is ever stopped in `unlink()`. (b) `__update_renderer_size` guards on
344
- `this.renderer !== null` but then touches `this.camera.aspect`; `camera` is only assigned in the asset callback.
345
- - **Failure scenario (a)**: Open a unit-detail panel containing a `MeshPreview`, close it, open it again. Two
346
- `PointerDevice`s are now live on the pooled canvas; one drag rotates the model twice as fast. After ten cycles the
347
- model spins ~10× per pixel of drag. (b): `preview.size.set(256, 256)` after linking but before the glTF resolves —
348
- the bound `size.onChanged` fires with `renderer` set and `camera` still `null` →
349
- `TypeError: Cannot set properties of null (setting 'aspect')`.
350
- - **Fix**: attach the `pContents` continuation once in the constructor and have it store `contents.group`; create the
351
- `PointerDevice` once and `start()`/`stop()` it from `link`/`unlink`. Guard `__update_renderer_size` on
352
- `this.camera !== null` as well (it is genuinely null until the async load lands).
353
- - **Confidence**: Confirmed
354
-
355
- ### VIEW-22 `renderModel` caches the caller's live `size`/`focus` objects, so resizes return the stale image
356
- - **Severity**: MAJOR
357
- - **File**: `src/view/renderModel.js:15-29,85-92`
358
- - **Defect**: The cache entry stores `size: size` and `focus: focus` by reference, and `findInCache` compares with
359
- `piece.size.equals(size)` / component-wise on `focus`. When the caller passes a mutable vector, the cached entry's
360
- key mutates in lockstep with the query, so the comparison always succeeds.
361
- - **Failure scenario**: `MeshView.render()` (`common/MeshView.js:61`) passes `this.size` and `this.focus` straight
362
- through. Render a mesh preview at 50×50 — cached with `piece.size === view.size`. Resize the view to 200×200:
363
- `update()` sees the change and calls `render()`, `findInCache(url, this.size, this.focus)` compares `this.size`
364
- against itself → hit → the 50×50 `dataURL` is returned and stretched to 200×200 (blurry), and no re-render is ever
365
- scheduled. The cache also has no eviction (`cache.push` only), so it grows without bound.
366
- - **Fix**: store `size.clone()` and a copied `AABB2` in the cache entry; add an eviction policy (the codebase already
367
- has `core/cache/Cache`).
368
- - **Confidence**: Confirmed
369
-
370
- ### VIEW-23 `MeshView` never reacts to its own model
371
- - **Severity**: MAJOR
372
- - **File**: `src/view/common/MeshView.js:72-92`
373
- - **Defect**: The view observes `this.size` only. `update()`'s change test compares `size` and `focus` against
374
- `renderedParams` and ignores the model entirely, so even an explicit `update()` after a model change does nothing.
375
- `this.model.onChanged` is never bound.
376
- - **Failure scenario**: `meshView.model.set('models/sword.gltf')` on a linked `MeshView` currently showing
377
- `models/axe.gltf` → nothing happens; a manual `meshView.update()` also short-circuits on "no change". The view keeps
378
- displaying the axe until the element is resized.
379
- - **Fix**: `this.bindSignal(this.model.onChanged, this.render, this)`, and include the rendered URL in
380
- `renderedParams` so `update()` detects it.
381
- - **Confidence**: Confirmed
382
-
383
- ### VIEW-24 `RectangularPieProgressView` assumes a square element; on any other aspect the path becomes invalid
384
- - **Severity**: MAJOR
385
- - **File**: `src/view/elements/progress/RectangularPieProgressView.js:77-107`
386
- - **Defect**: The fraction thresholds `.125 / .375 / .625 / .875` place the corner transitions at 45°, which is only
387
- where the corners are for a square. For a non-square element the sweep ray exits through a different edge than the
388
- branch tests, `segment2_segment_compute_intersection_array_2d` returns `false` and leaves `p` empty, and the path
389
- string is built from `p[0]`/`p[1]` === `undefined`.
390
- - **Failure scenario**: `v.size.set(100, 50); v.model.set(13); v.max.set(100)` (fraction 0.13 → branch 2, which tests
391
- the **right** edge). `angle ≈ 43°` from the centre `(50,25)`: reaching `x = 100` needs `Δy = -47`, i.e. `y = -22`,
392
- outside the edge segment — the ray actually exits through the **top** edge at `x ≈ 76.6`. No intersection is
393
- written, so `d` becomes `"M 50 0 L 50 25 L undefined undefined L 100 50 L 0 50 L 0 0 Z"`. Browsers reject the whole
394
- `d` attribute → the cooldown overlay disappears entirely for that fraction range.
395
- (In-repo the only caller, `view/units/ability/CombatAbilityView.js:30`, sizes it 64×64, so the game path is safe —
396
- but this is a public class with a `size` the caller controls.)
397
- - **Fix**: compute the corner fractions from the actual aspect (`atan2(size_y, size_x)` etc.) instead of hard-coded
398
- eighths, or pick the edge by testing all four and taking whichever intersects.
399
- - **Confidence**: Confirmed
400
-
401
- ### VIEW-25 `EmptyView.absolute` nests the caller's CSS instead of spreading it
402
- - **Severity**: MAJOR
403
- - **File**: `src/view/elements/EmptyView.js:54-72`
404
- - **Defect**:
405
- ```js
406
- css: {
407
- css, // shorthand -> a property literally named "css"
408
- ...CSS_ABSOLUTE_POSITIONING
409
- }
410
- ```
411
- The intent is clearly `...css`. `View.css(hash)` then executes `this.el.style['css'] = {…}`, which the CSSOM
412
- ignores.
413
- - **Failure scenario**: `EmptyView.absolute({ css: { width: '100px', backgroundColor: 'red' } })` produces an element
414
- with only `position/top/left` applied; width and background are silently dropped, so the element collapses to zero
415
- size. No error is raised anywhere.
416
- - **Fix**: `css: { ...css, ...CSS_ABSOLUTE_POSITIONING }`.
417
- - **Confidence**: Confirmed
418
-
419
- ### VIEW-26 `TileGridView` subscribes to the model and the DnD context outside the view lifecycle
420
- - **Severity**: MAJOR
421
- - **File**: `src/view/elements/tiles2d/TileGrid.js:135-136,301-338,411-419`
422
- - **Defect**: `model.tiles.on.added.add(this.addTile, this)` and `.on.removed.add(this.removeTile, this)` are raw
423
- subscriptions (not `bindSignal`) with no counterpart anywhere. Likewise every slot registers a `DropTarget` into
424
- `this.__dragAndDropContext` via `addTarget` (which immediately `link()`s DOM listeners) and every tile registers a
425
- `Draggable` via `addElement`; neither `removeTarget` nor `removeElement` is ever called, and the context is a
426
- constructor parameter, i.e. typically shared across grids.
427
- - **Failure scenario**: An inventory panel builds a 10×6 `TileGridView` against a shared `DragAndDropContext` each
428
- time it opens. Every open/close cycle permanently adds 60 `DropTarget`s (each with 4 DOM listeners) and one
429
- `Draggable` per item to `context.targets`/`context.elements`, and leaves the grid subscribed to `model.tiles`. After
430
- 20 cycles, `DragAndDropContext.finalizeDrag` iterates 1200+ targets on every drop, `getElementById` scans hundreds
431
- of dead draggables, and adding an item to the inventory while all panels are closed calls `addTile` on 20 detached
432
- grids. Removing an item calls `removeTile` on grids where `findTileView` returns `undefined`, so
433
- `this.__hookTileRemoved(undefined, tile)` fires with an undefined view.
434
- - **Fix**: route the two model subscriptions through `bindSignal`; add an `unlink()` that calls
435
- `context.removeTarget(slotView)` for each slot and `context.removeElement(draggable)` for each tile, and rebuild on
436
- `link()`.
437
- - **Confidence**: Confirmed
438
-
439
- ### VIEW-27 `LocalizedLabelView.update()` dereferences a null localization outside the try
440
- - **Severity**: MAJOR
441
- - **File**: `src/view/common/LocalizedLabelView.js:122-154`
442
- - **Defect**: `localization = null` is the constructor default and the class explicitly tests for it at `:60`, so it
443
- is an anticipated state. `update()` wraps only `localization.getString(...)` in `try/catch`; line 143
444
- (`this.__localeKey = localization.locale.getValue()`) and the `$el.text(value)` fallback that follows are outside
445
- it. The throw at 143 skips the fallback text.
446
- - **Failure scenario**: `new TaskProgressView({ task })` — `localization` defaults to `null`
447
- (`task/TaskProgressView.js:20,29-33`) — then link. The `on.linked` handler calls `update()`, `getString` throws,
448
- the catch sets `value = "failed to localize @…"`, then line 143 throws `TypeError: Cannot read properties of null
449
- (reading 'locale')` before the text is written. Signal's dispatch try/catch swallows it, so the loading screen's
450
- task-name label renders completely blank with two console errors per link.
451
- - **Fix**: return early (writing the raw `@id` fallback) when `localization === null`, and move the `__localeKey`
452
- assignment after a successful `getString`.
453
- - **Confidence**: Confirmed
454
-
455
- ### VIEW-28 `MarkerGL` leaks atlas patch references acquired across shutdown / rapid icon changes
456
- - **Severity**: MAJOR
457
- - **File**: `src/view/minimap/gl/MarkerGL.js:57-87,109-118`
458
- - **Defect**: `updateIcon` releases the *current* `this.patch`, then awaits `atlasManager.acquire(newURL)`. The
459
- continuation assigns `this.patch = patch` and then bails on `!this.active` — but the freshly acquired reference is
460
- never released on that path. Similarly, two `updateIcon` calls in flight both release `Reference.NULL` up front and
461
- the first resolved patch is overwritten (and leaked) by the second.
462
- - **Failure scenario**: A unit with a minimap marker is killed while its icon texture is still being fetched
463
- (`MinimapMarkersGL.removeElement` → `markerGL.shutdown()` → `active = false`, releases `Reference.NULL`). The
464
- `acquire` promise then resolves, stores the patch on the dead marker and returns without releasing it → the
465
- `ManagedAtlas` never frees that icon's slot. Repeated over a battle with many short-lived markers, the atlas fills
466
- up and later markers fail to get a patch.
467
- - **Fix**: in the continuation, if `!this.active`, call `patch.release()` before returning; also release the previous
468
- `this.patch` when overwriting it rather than at call time.
469
- - **Confidence**: Confirmed
470
-
471
- ### VIEW-29 `DropTarget` drag-enter tracking has no dedup and splices with `-1`
472
- - **Severity**: MAJOR
473
- - **File**: `src/view/common/dnd/DropTarget.js:72-92,212-236`
474
- - **Defect**: `handleDragEnter` pushes into `isInState_ENTER` unconditionally, and
475
- `attachDropValidityIndicators.handleDragEnter` unconditionally appends a `{draggable, bindings}` record with a fresh
476
- `SignalBinding` on `draggable.on.dragFinalized`. `removeDraggable` removes exactly one record per call.
477
- `handleDragLeave` additionally does `isInState_ENTER.splice(indexOf(e), 1)` without checking for `-1`, and
478
- `splice(-1, 1)` removes the *last* element.
479
- - **Failure scenario**: `Draggable.link()` explicitly routes `dragenter` to the parent drop target
480
- (`common/dnd/Draggable.js:103-106`) *and* the event bubbles to the drop target's own listener — so dragging an item
481
- over another item inside the same slot fires `handleDragEnter` twice for one enter. `current` gains two records and
482
- two live bindings. On drop, `dragFinalized` fires once, `removeDraggable` clears one record, and `update()` still
483
- sees a non-empty `current` → the slot keeps its `drop-target-hover-valid` class permanently after the drag ends,
484
- and each further hover leaks another `SignalBinding` on the draggable.
485
- - **Fix**: dedup on enter (skip if the draggable is already tracked), loop `removeDraggable` until it returns false on
486
- finalize, and guard the `indexOf === -1` case before splicing.
487
- - **Confidence**: Likely
488
-
489
- ### VIEW-30 A throwing tooltip factory disables tooltips globally for the rest of the session
490
- - **Severity**: MAJOR
491
- - **File**: `src/view/tooltip/TooltipManager.js:129-138`
492
- - **Defect**:
493
- ```js
494
- gml.pushState();
495
- gml.setTooltipsEnabled(false);
496
- const factoryProduct = tip.factory.call(tip.factoryContext); // may throw
497
- gml.popState();
498
- ```
499
- There is no `try/finally`. `GMLEngine.compile`/`compileAsText` both use `try { … } finally { this.popState(); }`
500
- (`tooltip/gml/GMLEngine.js:481-493,512-525`), so the omission here is clearly unintended.
501
- - **Failure scenario**: A single tooltip factory throws (e.g. an item tooltip for an item whose data row is missing).
502
- `popState()` is skipped, so `__tooltipsEnabled` stays `false` and one orphan frame stays on `__contextStack`. Every
503
- reference compiler that consults `gml.getTooltipsEnabled()` from then on sees `false` → nested tooltips stop being
504
- attached anywhere in the UI until reload.
505
- - **Fix**: wrap the factory call in `try { … } finally { gml.popState(); }`.
506
- - **Confidence**: Confirmed
507
-
508
- ### VIEW-31 `RadialMenu.init()` leaves the previous element views attached, and shared icon views get stolen
509
- - **Severity**: MAJOR
510
- - **File**: `src/view/elements/radial/RadialMenu.js:194-223`, `src/view/elements/radial/RadialMenuElement.js:70`
511
- - **Defect**: `init()` resets `this.elements = []` but never removes the previously created `RadialMenuElement`
512
- children from `this.vElementContainer`. Separately, `RadialMenuElement`'s constructor does
513
- `this.addChild(description.iconView)` — the icon `View` lives on the caller-owned
514
- `RadialMenuElementDefinition`, and `View.addChild` re-parents it (`child.parent = this; this.el.appendChild(child.el)`).
515
- - **Failure scenario**: (a) `menu.init(newItems)` on an existing menu — the old wedges, labels and icons stay in the
516
- DOM underneath the new ones, and `selectByAngle`/`render` only touch the new set, so the stale wedges are frozen in
517
- place and never highlight. (b) Building two `RadialMenu`s from the same `items` array (definitions are plain data
518
- objects that are easy to reuse) — the second menu's `addChild` moves every `iconView`'s DOM node out of the first
519
- menu, leaving the first menu iconless while both `children` arrays still list it.
520
- - **Fix**: `this.vElementContainer.removeAllChildren()` at the top of `init()`; and either clone the icon view per
521
- element or document/enforce one definition per menu.
522
- - **Confidence**: Confirmed
523
-
524
- ### VIEW-32 `ConfirmationDialogView` builds a class name that can contain a space
525
- - **Severity**: MAJOR
526
- - **File**: `src/view/elements/ConfirmationDialogView.js:38`
527
- - **Defect**: `"button-" + option.name.replace(' ', '-')` — `String.replace` with a string pattern replaces only the
528
- **first** occurrence. The result is handed to `ButtonView`'s `classList`, which reaches `DOMTokenList.add()`.
529
- - **Failure scenario**: `new ConfirmationDialogView(content, [{name: 'cancel all now', displayName: 'Cancel', …}])`
530
- → class token `"button-cancel-all now"` → `classList.add` throws
531
- `InvalidCharacterError: The string contains invalid characters`, aborting the whole dialog construction so no
532
- confirmation dialog is shown at all.
533
- - **Fix**: `option.name.replace(/\s+/g, '-')`, or reuse `string_tag_to_css_class_name`.
534
- - **Confidence**: Confirmed
535
-
536
- ### VIEW-33 `VirtualListView` disables the scrollbar one row too early, and `AlignmentOption.Center` does nothing
537
- - **Severity**: MINOR
538
- - **File**: `src/view/common/VirtualListView.js:181-196`
539
- - **Defect**: The "everything fits" test is
540
- `row_height * (last_visible_line - first_visible_line) < this.size.y`, i.e. it measures `n-1` rows instead of `n`.
541
- Separately, `AlignmentOption.Center` is exported and accepted as `verticalAlignment` but the offset block only
542
- handles `End`, so `Center` silently behaves like `Start`.
543
- - **Failure scenario**: `lineSize = 20, lineSpacing = 0`, 5 elements, `size.y = 90` (content 100 px). `l0 = 0`,
544
- `l1 = 4 = numTotalElements - 1`, and `20 * (4 - 0) = 80 < 90` → `__setScrollBar(false)` and `rowWidth` is not
545
- reduced. The list declares itself fully visible while the 5th row is clipped by 10 px and cannot be scrolled to.
546
- - **Fix**: compare `row_height * (last - first + 1) <= this.size.y`; implement the `Center` branch
547
- (`line_offset_y = (this.size.y - total_lines_height) / 2`).
548
- - **Confidence**: Confirmed
549
-
550
- ### VIEW-34 `DropDownSelectionView.setSelectedValue` uses the model index against always-appended options
551
- - **Severity**: MINOR
552
- - **File**: `src/view/elements/DropDownSelectionView.js:55-68,141-143`
553
- - **Defect**: `handleAdded(el, index)` ignores `index` and always `appendChild`s, while `setSelectedValue` does
554
- `this.el.selectedIndex = this.model.indexOf(v)`. The two orderings only agree when elements are appended.
555
- (`getSelectedValue` correctly resolves through the id map, so the two accessors disagree.) `handleRemoved` also
556
- never deletes the entry from `this.mapping`.
557
- - **Failure scenario**: `model.insert(0, x)` on a populated list — `x`'s `<option>` lands last while `model.indexOf(x)`
558
- is `0`, so `setSelectedValue(x)` selects whatever element was originally first.
559
- - **Fix**: honour `index` in `handleAdded` (`insertBefore` the option at `index`), and delete the mapping entry in
560
- `handleRemoved`.
561
- - **Confidence**: Confirmed
562
-
563
- ### VIEW-35 `MinimapCameraView.castTerrainRay` jitters an origin it never uses
564
- - **Severity**: MINOR
565
- - **File**: `src/view/minimap/dom/MinimapCameraView.js:99-117`
566
- - **Defect**: The retry loop perturbs `oX/oY/oZ` but calls
567
- `terrain.raycastFirstSync(rayContact, originX, originY, originZ, …)` with the *unperturbed* origin every iteration.
568
- `oX/oY/oZ` are written and never read.
569
- - **Failure scenario**: A frustum corner ray that lands exactly on a terrain triangle edge misses. The stated purpose
570
- of the loop — "jitter origin in case of mathematical error at polygon edges" — never happens; instead the identical
571
- raycast runs 10 times and then falls back to the flat `y = 0` plane. On elevated terrain that corner of the minimap
572
- camera-frustum polygon is drawn at the ground-plane intersection instead of the terrain surface, so the frustum
573
- outline visibly snaps outward for that corner.
574
- - **Fix**: pass `oX, oY, oZ` to `raycastFirstSync`.
575
- - **Confidence**: Confirmed
576
-
577
- ### VIEW-36 `DOM.prototype.clear()` does not remove text nodes
578
- - **Severity**: MINOR
579
- - **File**: `src/view/DOM.js:131-137`
580
- - **Defect**: The loop iterates `el.children` (elements only), so text nodes survive a method documented as
581
- "removes all children".
582
- - **Failure scenario**: `const d = domify('div'); d.text('Loading…'); d.clear(); d.append(other);` → the element still
583
- reads "Loading…" followed by the appended content. This is reachable through
584
- `LocalizedLabelView.update()` (`$el.text(value)` on the non-GML path) followed by a switch to a GML-compiled value,
585
- which calls `removeAllChildren()` and then appends compiled views next to the leftover text node; also
586
- `MinimapView.link()` (`minimap/Minimap.js:217-219`) relies on `clear()` before appending the WebGL canvas.
587
- - **Fix**: `while (el.firstChild) el.removeChild(el.firstChild);`
588
- - **Confidence**: Confirmed
589
-
590
- ### VIEW-37 `setElementTransform.js` exports nothing
591
- - **Severity**: MINOR
592
- - **File**: `src/view/setElementTransform.js:13`
593
- - **Defect**: The module declares `function setElementTransform(...)` with no `export` and no default export, so the
594
- file's only purpose is unreachable.
595
- - **Failure scenario**: `import { setElementTransform } from '.../setElementTransform.js'` →
596
- `SyntaxError: The requested module does not provide an export named 'setElementTransform'` at build time.
597
- - **Fix**: `export function setElementTransform(...)`.
598
- - **Confidence**: Confirmed
599
-
600
- ### VIEW-38 `DatGuiUtils.makeDatController` references an undeclared `p` in its cycle branch
601
- - **Severity**: MINOR
602
- - **File**: `src/view/controller/dat/DatGuiUtils.js:377-380`
603
- - **Defect**: ``console.warn(`Detected cycle at "${p}" …`)`` — `p` is the loop variable of `makeDatControllerForObject`,
604
- not of this function. Modules are strict-mode, so this is a `ReferenceError`, not `undefined`. The intended
605
- identifier is `propertyName`.
606
- - **Failure scenario**: `makeDatController` is exported (`:451`). A direct call
607
- `makeDatController(gui, obj, 'child', pathContainingObjChild)` hits the cycle branch and throws
608
- `ReferenceError: p is not defined` instead of warning and returning `0`, aborting the whole controller build.
609
- - **Fix**: use `${propertyName}`.
610
- - **Confidence**: Confirmed
611
-
612
- ### VIEW-39 `GroupView.remove()` leaves the removed child linked; `update()` calls a method `View` does not have
613
- - **Severity**: MINOR
614
- - **File**: `src/view/elements/Group.js:8,11-30`
615
- - **Defect**: `add`/`remove` bypass `View.addChild`/`View.removeChild`: `child.parent` is never set and `remove` never
616
- calls `child.unlink()`. `update()` invokes `c.update()` on each child, but `View` defines no `update`.
617
- - **Failure scenario**: `group.add(labelView); group.link(); group.remove(labelView);` — the label's DOM node is
618
- detached but the view stays linked, so its `bindSignal` subscriptions keep firing and keep writing to a node that is
619
- no longer in the document. `group.update()` with any plain `EmptyView` child →
620
- `TypeError: c.update is not a function`.
621
- - **Fix**: delegate to `View.addChild`/`View.removeChild` (and drop the `this.children = []` reassignment); remove
622
- `update()` or make it guard on the method existing.
623
- - **Confidence**: Confirmed
624
-
625
- ### VIEW-40 `WindRoseDiagram` sizes itself for icons that may not exist, and re-registers tooltips on every draw
626
- - **Severity**: MINOR
627
- - **File**: `src/view/elements/windrose/WindRoseDiagram.js:90-94,197-336`
628
- - **Defect**: (a) `const has_icons = axes.some(isDefined)` tests whether each *axis object* is defined, not whether it
629
- has an `icon`; for any non-empty `axes` array this is always `true`. (b) `draw_canvas()` calls
630
- `container.removeAllChildren()` and rebuilds every label/icon, then calls `this.__tooltips.add(view, …)` for each —
631
- `DomTooltipManager.add` links a `DomTooltipObserver` immediately and is never paired with `remove`.
632
- - **Failure scenario**: (a) `new WindRoseDiagram({axes: [{name:'a'},{name:'b'},{name:'c'}], radius_outer: 100,
633
- icon_size: 32})` (no icons at all) → `size = 200 + 32*1.207*2 ≈ 277` instead of `200`; the widget claims 77 px more
634
- in both axes than it draws, pushing neighbours around in a flex row. (b) `draw()` runs on every `on.linked`; after
635
- 10 open/close cycles each axis label has 10 live `DomTooltipObserver`s with `mouseenter`/`mouseleave` listeners on
636
- detached elements.
637
- - **Fix**: `axes.some(a => a.icon !== undefined)`; use `tooltips.manage(view, …)` (which self-registers on
638
- link/unlink) rather than `add`.
639
- - **Confidence**: Confirmed
640
-
641
- ### VIEW-41 `ImageView`/`VideoView` never re-apply an observed URL on link
642
- - **Severity**: MINOR
643
- - **File**: `src/view/elements/image/ImageView.js:65-71`, `src/view/elements/video/VideoView.js:77-83`
644
- - **Defect**: The `src` is baked into the cache key at construction and thereafter only updated by the
645
- `url.onChanged` → `__setSource` binding, which is a `bindSignal` and therefore inactive while unlinked. There is no
646
- `on.linked` initial-apply.
647
- - **Failure scenario**: An `ImageView` bound to an `ObservedString` icon URL sits in a panel. Close the panel (view
648
- unlinks, binding detaches), the underlying model swaps the icon (equip a different item), reopen the panel — the
649
- binding re-links but is never invoked, so the `<img>` still shows the previous icon until the URL happens to change
650
- again while the panel is open.
651
- - **Fix**: add `this.on.linked.add(() => this.__setSource(url.getValue()), this)` in the observed-URL branch (mirroring
652
- `LabelView.link()`, which re-runs `updateTransform()`).
653
- - **Confidence**: Confirmed
654
-
655
- ### VIEW-42 `ButtonView` never applies its initial enabled/disabled class
656
- - **Severity**: MINOR
657
- - **File**: `src/view/elements/button/ButtonView.js:94,101-110`
658
- - **Defect**: `__enabled` is initialised by direct field assignment, bypassing the setter, and the setter early-returns
659
- when the value is unchanged. A button that is enabled from birth therefore carries **neither** `.enabled` nor
660
- `.disabled`.
661
- - **Failure scenario**: `.ui-button-view.disabled { opacity: .4 }` + `.ui-button-view.enabled { cursor: pointer }`
662
- style rules — a freshly created enabled button matches neither. `createInterfaceCommandButton` masks this because
663
- its `on.linked` handler calls `updateEnableStatus()`, but that only helps when the command's `enabled` differs from
664
- `true`; a permanently-enabled command's button never gets the class.
665
- - **Fix**: set the class explicitly at the end of the constructor (`this.setClass('enabled', true);
666
- this.setClass('disabled', false);`) rather than relying on the setter's change detection.
667
- - **Confidence**: Likely
1
+ # Correctness review — `meep/src/view/`
2
+
3
+ Scope: all 111 non-spec source files under `H:/git/moh/app/src/mir-engine/meep/src/view/`.
4
+ Excluded: `editor/`, `prototype*.js`, `*.spec.js`, `.d.ts`.
5
+
6
+ Notes on evidence used while reviewing:
7
+ - `View.unlink()` **clears the `Linked` flag before dispatching `on.unlinked`** (`View.js:325` then `:347`). Several
8
+ findings below depend on that ordering.
9
+ - `Signal` keeps handlers in a `Map` keyed by the handler function; iteration is insertion-ordered, and a handler
10
+ removed mid-dispatch by an earlier handler is **not** invoked (`core/events/signal/Signal.js:378-425`).
11
+ - `Vector1`/`ObservedInteger` extend `Number` and implement `valueOf()`, so arithmetic directly on them is valid.
12
+ - `segment2_segment_compute_intersection_array_2d` leaves `result` **untouched** and returns `false` on a miss.
13
+
14
+ ---
15
+
16
+ ### VIEW-1 `DomTooltipObserver.unlink()` never actually detaches, because the view is already unlinked
17
+ - **Severity**: CRITICAL
18
+ - **File**: `src/view/tooltip/DomTooltipObserver.js:156-165`, driven from `src/view/tooltip/DomTooltipManager.js:109-117,178-194`
19
+ - **Defect**: `unlink()` only runs `__handleViewUnlinked()` `if (view.isLinked)`. On the `manage()` path the call
20
+ arrives from inside the `view.on.unlinked` dispatch, at which point `View.unlink()` has already cleared the
21
+ `Linked` flag — so the guard is always false and the teardown is skipped entirely. The observer's own
22
+ `on.unlinked` handler cannot compensate: `manage()`'s handler was subscribed first, and it calls
23
+ `observer.unlink()`, which does `view.on.unlinked.remove(this.__handleViewUnlinked, this)` mid-dispatch, deleting
24
+ the not-yet-visited Map entry so it never fires.
25
+ - **Failure scenario**: `gui.viewTooltips.manage(button, factory)` (used in ~20 places, e.g.
26
+ `interaction/createInterfaceCommandButton.js:106`, `view/game/scene/strategy/shop/ItemShopView.js:185`). Link the
27
+ panel, then unlink it. `mouseenter`/`mouseleave` listeners stay on `button.el`, and the 4 `SignalBinding`s on
28
+ `view.position.onChanged`, `view.size.onChanged` and the `DomSizeObserver` stay linked forever. Re-open the panel
29
+ and `manage()`'s linked handler calls `add()` again, creating a *second* observer with a second pair of DOM
30
+ listeners on the same element. Ten open/close cycles leave ten live observers per button. Worse: hover a button,
31
+ and inside the 128 ms `requestShow` delay close the panel — `remove()` calls `hide()` (no-op, tip not added yet),
32
+ the observer teardown is skipped so nothing calls `cancelShowRequest()`, the timeout fires, `tipManager.add(tip)`
33
+ builds a tooltip for a detached view, and because the element no longer receives mouse events nothing will ever
34
+ fire `on.exited` → the tooltip is stuck on screen for the rest of the session.
35
+ - **Fix**: drop the `view.isLinked` guard in `unlink()` and make `__handleViewUnlinked()` idempotent (track an
36
+ internal `#attached` boolean set in `__handleViewLinked`), and remove the `view.on.*` handlers *before* calling
37
+ `__handleViewUnlinked()`. Additionally call `this.cancelShowRequest()` in `DomTooltipManager.remove()`.
38
+ - **Confidence**: Confirmed
39
+
40
+ ### VIEW-2 `SvgImageView` cannot be imported and crashes on every `link()`
41
+ - **Severity**: CRITICAL
42
+ - **File**: `src/view/elements/image/SvgImageView.js:1,64-73`
43
+ - **Defect**: Two independent hard errors. (a) `import AABB2 from "../../../core/geom/AABB2.js"` — that file does not
44
+ exist; the real path is `core/geom/2d/aabb/AABB2.js`, so the module fails to resolve. (b) `update()` is a class
45
+ method but its body references `resize` and `self`, which are `const`/`let` bindings local to the *constructor*.
46
+ `link()` calls `this.update()` unconditionally.
47
+ - **Failure scenario**: any module that does `import SvgImageView from '.../SvgImageView.js'` fails at bundle/resolve
48
+ time. If the import path is fixed, `new SvgImageView(url, {assetManager}); parent.addChild(v)` on a linked parent →
49
+ `link()` → `update()` → `ReferenceError: resize is not defined` (caught by Signal only if it were dispatched from a
50
+ signal; here it propagates out of `addChild`).
51
+ - **Fix**: correct the import path; promote `resize` and the icon element to instance state (`#resize()` reading
52
+ `this.#elIcon`, `this.size`) so `update()` can reach them.
53
+ - **Confidence**: Confirmed
54
+
55
+ ### VIEW-3 `MinimapMarkerView` throws on construction — `this` used before `super()`
56
+ - **Severity**: CRITICAL
57
+ - **File**: `src/view/minimap/dom/MinimapMarkerView.js:17,51-64`
58
+ - **Defect**: `super(entity, this.marker, this.transform, this.worldScale)` dereferences `this` before the base
59
+ constructor has run, which is a `ReferenceError` in every ES2015+ engine. Even past that, the three handler methods
60
+ reference `setPosition` and `size`, which are constructor-local bindings, and they are bound via `bindSignal(...)`
61
+ **without a context argument**, so `this` inside them would be `undefined`.
62
+ - **Failure scenario**: `new MinimapMarkerView(entity, marker, transform, worldScale)` →
63
+ `ReferenceError: Must call super constructor in derived class before accessing 'this'`. The class is unusable.
64
+ - **Fix**: `super()` with no arguments; move `setPosition` to a method and pass `this` as the context to every
65
+ `bindSignal` call; read `this.size` instead of the free `size`.
66
+ - **Confidence**: Confirmed
67
+
68
+ ### VIEW-4 `MinimapTerrainView.__setTerrain` references an undefined identifier and has no context
69
+ - **Severity**: CRITICAL
70
+ - **File**: `src/view/minimap/dom/MinimapTerrainView.js:126,133-143`
71
+ - **Defect**: `this.terrain.onChanged.add(this.__setTerrain)` subscribes a *method* with no context, and the method
72
+ body calls `updatePreview()` — a function declared inside the constructor and therefore not in scope. It also
73
+ dereferences `terrain.preview` with no null check even though `ObservedValue(null)` is the initial state and
74
+ `set(null)` is a legal transition.
75
+ - **Failure scenario**: `minimapTerrainView.terrain.set(someTerrain)` → `__setTerrain` runs →
76
+ `ReferenceError: updatePreview is not defined` (swallowed by Signal's try/catch and logged) → the terrain preview
77
+ image is never set, the view renders an empty `<img>`. `terrain.set(null)` →
78
+ `TypeError: Cannot read properties of null (reading 'preview')`.
79
+ - **Fix**: make `updatePreview`/`setPreview` instance methods, subscribe with `add(this.__setTerrain, this)`, and
80
+ guard the `terrain === null` case.
81
+ - **Confidence**: Confirmed
82
+
83
+ ### VIEW-5 `ViewGroup.remove()` calls a non-existent `Set.remove`; `disconnect()` adds instead of removes
84
+ - **Severity**: CRITICAL
85
+ - **File**: `src/view/ViewGroup.js:34,74-89`
86
+ - **Defect**: `this.elements` is a `Set`; `Set` has `delete`, not `remove`. Separately, `disconnect()` iterates every
87
+ member and calls `this.container.addChild(view)` where the whole point of the method is to detach them.
88
+ - **Failure scenario**: `group.remove(view)` → `TypeError: this.elements.remove is not a function`.
89
+ `group.connect(a); group.connect(b)` → `connect` calls `disconnect()`, which re-adds every view to container `a`
90
+ (pushing a duplicate entry into `a.children` and re-appending the DOM node), sets `this.container = null`, then
91
+ `connect` adds them all to `b`. Container `a` is left with duplicate `children` entries pointing at views whose
92
+ DOM nodes now live under `b`; a later `a.removeAllChildren()` calls `a.el.removeChild(child.el)` on a node that is
93
+ no longer its child → `NotFoundError` DOMException.
94
+ - **Fix**: `this.elements.delete(view)`; `disconnect()` must call `this.container.removeChild(view)`.
95
+ - **Confidence**: Confirmed
96
+
97
+ ### VIEW-6 `MinimapView.clear()` adds children instead of removing them
98
+ - **Severity**: CRITICAL
99
+ - **File**: `src/view/minimap/Minimap.js:183-188` (called from `unlink()` at `:236`)
100
+ - **Defect**: The method is documented "remove all existing markers" / "clear out all camera views" but its body is
101
+ `this.__worldView.addChild(v)` for each camera view — the views are already children, so each `unlink()` pushes a
102
+ duplicate entry into `__worldView.children`.
103
+ - **Failure scenario**: Open the minimap, close it, open it again (each cycle = one link/unlink pair). After N
104
+ cycles `__worldView.children` holds each `MinimapCameraView` N+1 times. Now the camera entity is destroyed:
105
+ `cameraRemoved` → `__worldView.removeChild(cameraView)` splices out *one* entry and detaches the DOM node, leaving
106
+ stale duplicates. On the next `unlink()`, `clear()` runs `addChild` on that stale duplicate, which does
107
+ `this.el.appendChild(child.el)` — re-inserting the frustum polygon of a camera that no longer exists back into the
108
+ minimap, and re-linking it on the next `link()` so it keeps updating against a dead `Transform`.
109
+ - **Fix**: `this.__worldView.removeChild(v)` and iterate a copy (or iterate backwards) since `removeChild` mutates.
110
+ - **Confidence**: Confirmed
111
+
112
+ ### VIEW-7 `TaskProgressView` displays progress where remaining time belongs
113
+ - **Severity**: MAJOR
114
+ - **File**: `src/view/task/TaskProgressView.js:127-131`
115
+ - **Defect**: `const estimate = Number.isNaN(computedEstimate) ? 0 : computedProgressValue;` — the non-NaN branch uses
116
+ `computedProgressValue` (the 0..1 progress fraction) instead of `computedEstimate` (the estimator's output). The
117
+ computed estimate is discarded.
118
+ - **Failure scenario**: A 60-second load at 20% progress. `remainingTimeEstimator.estimate()` returns ~48, but the
119
+ `.remaining-time` label is fed `0.2` and formatted with `toFixed(0)` → it reads `0`. The loading screen shows
120
+ "0 seconds remaining" for the entire load, then jumps to "1" at completion.
121
+ - **Fix**: `const estimate = Number.isNaN(computedEstimate) ? 0 : computedEstimate;`
122
+ - **Confidence**: Confirmed
123
+
124
+ ### VIEW-8 `ColorPickerView` unsubscribes from the new colour instead of the old one
125
+ - **Severity**: MAJOR
126
+ - **File**: `src/view/elements/ColorPickerView.js:282-294`
127
+ - **Defect**:
128
+ ```js
129
+ this.model.onChanged.add(function (v, _v) {
130
+ if (v !== null) { modelValueChanged(...); v.onChanged.add(modelValueChanged); }
131
+ if (_v !== null) { v.onChanged.remove(modelValueChanged); } // <-- v, should be _v
132
+ });
133
+ ```
134
+ The removal targets the *new* value. The old value keeps the listener forever, and the new value gets `add`
135
+ immediately followed by `remove`.
136
+ - **Failure scenario**: `picker.model.set(colorA)` then `picker.model.set(colorB)`. Afterwards, changing `colorB`
137
+ externally does not move the H/S/L/A gauges (its listener was removed), while changing `colorA` — which the picker
138
+ no longer edits — does move them. Additionally `picker.model.set(null)` after having a colour executes
139
+ `null.onChanged.remove(...)` → `TypeError: Cannot read properties of null (reading 'onChanged')`.
140
+ - **Fix**: `if (_v !== null) { _v.onChanged.remove(modelValueChanged); }`, and perform the removal before the add.
141
+ - **Confidence**: Confirmed
142
+
143
+ ### VIEW-9 `ColorPickerView` value-channel write lock uses a key that does not exist
144
+ - **Severity**: MAJOR
145
+ - **File**: `src/view/elements/ColorPickerView.js:156-161,214,224,229,257,266`
146
+ - **Defect**: `writeLocks` is declared with keys `h, s, l, a`. The `colorV` handler checks and sets `writeLocks.v`
147
+ (undefined key), while `modelValueChanged` checks `writeLocks.l`. The lock protecting the value/lightness channel
148
+ therefore never engages in either direction.
149
+ - **Failure scenario**: Pick a saturated red (h≈0, s=1, v=1), then drag the **L** gauge to 0. `colorV.onChanged` runs
150
+ unguarded (`writeLocks.v` is `undefined`), writes rgb `(0,0,0)` into the model, which dispatches
151
+ `modelValueChanged`; that handler's guard reads `writeLocks.l` — also never set by the V handler — so it proceeds
152
+ and pushes `rgb2hsv(0,0,0)` back into the gauges, snapping H and S to 0. The user's hue and saturation are
153
+ destroyed by moving the lightness slider, and cannot be recovered by dragging L back up.
154
+ - **Fix**: use one consistent key (`v`) in the declaration, the `colorV` handler, and `modelValueChanged`.
155
+ - **Confidence**: Confirmed
156
+
157
+ ### VIEW-10 `Vector1Control` binds the write-back handler to the model's change signal
158
+ - **Severity**: MAJOR
159
+ - **File**: `src/view/controller/controls/Vector1Control.js:61-81`
160
+ - **Defect**: `subscribe(v1)` does `v1.onChanged.add(writeBack)`. `writeBack` is the *controller → model* direction
161
+ (`vector1.set(v)`); the *model → controller* direction is `syncForward`, which is only ever called once, inside
162
+ `subscribe`. `unsubscribe` symmetrically removes `writeBack`, so the mismatch is consistent and silent.
163
+ - **Failure scenario**: Bind a `Vector1Control` to a `Vector1` that some other system writes (e.g. an animated
164
+ property). The number field shows the value present at subscribe time and never updates again: each external change
165
+ invokes `writeBack(newValue)` which writes `newValue` straight back into the same vector (a no-op) instead of
166
+ refreshing `cNumber.value`.
167
+ - **Fix**: `v1.onChanged.add(syncForward)` in `subscribe` and `v1.onChanged.remove(syncForward)` in `unsubscribe`;
168
+ keep `lockForward` to break the echo.
169
+ - **Confidence**: Confirmed
170
+
171
+ ### VIEW-11 `ListController` removes the wrong view, so deleted rows stay on screen
172
+ - **Severity**: MAJOR
173
+ - **File**: `src/view/controller/controls/ListController.js:48-74`
174
+ - **Defect**: `handleItemAdded` wraps `guiControl` in a `vElementContainer` and adds *that* to `vContainer`.
175
+ `handleItemRemoved` then calls `vContainer.removeChild(guiControl)` — `guiControl` is a child of
176
+ `vElementContainer`, not of `vContainer`, so `children.indexOf()` returns `-1` and `removeChild` returns `false`
177
+ without doing anything.
178
+ - **Failure scenario**: Click the `.close` button next to a list item. The item leaves the model
179
+ (`list.removeOneOf(item)`), `elementControllers` drops the entry, `guiControl.model.set(null)` blanks the control —
180
+ but the row (control + close button) remains in the DOM permanently. Clicking its close button again calls
181
+ `list.removeOneOf(item)` on an item that is no longer present. Rebinding the controller to a different list via
182
+ `detachList` leaves every old row visible on top of the new ones.
183
+ - **Fix**: keep a `Map<item, vElementContainer>` (or store the wrapper on the control) and remove the wrapper.
184
+ - **Confidence**: Confirmed
185
+
186
+ ### VIEW-12 `HTMLElementCacheKey.initializeFromElement` wipes the styles it just read (shadowed loop variable)
187
+ - **Severity**: MAJOR
188
+ - **File**: `src/view/common/HTMLElementCacheKey.js:189-217`
189
+ - **Defect**:
190
+ ```js
191
+ let i = 0;
192
+ ...
193
+ for (let i = 0; i < styleCount; i++) { ... this.style[i] = pair; } // inner `i` shadows outer
194
+ this.style.splice(i, this.style.length - i); // outer i is still 0
195
+ ```
196
+ The truncation call meant to drop leftover entries instead removes the entire array. (The attribute loop below uses
197
+ `for (i = 0; ...)` without `let`, so it truncates correctly — proving the intent.) The key therefore always reports
198
+ "no inline styles", while `hash()`/`equals()` treat that as a real property of the element.
199
+ - **Failure scenario**: `imageViewA.css({ filter: 'grayscale(1)' })` on an `<img src="x.png" class="icon">`, then
200
+ `imageViewA.destroy()` → `key.initializeFromElement(el)` records the tag and attributes but **not** the filter →
201
+ the element is pooled under a key that claims no styles. Later `new ImageView('x.png', {classList:['icon']})`
202
+ builds a style-less key, `view_pool.get(key)` matches, and the recycled element is returned still carrying
203
+ `filter: grayscale(1)` → the new image renders greyed out.
204
+ - **Fix**: rename the inner loop variable (or hoist it) so the splice truncates from `styleCount`.
205
+ - **Confidence**: Confirmed
206
+
207
+ ### VIEW-13 `TabbedView` never attaches its toggle and panel containers — it renders nothing
208
+ - **Severity**: MAJOR
209
+ - **File**: `src/view/common/TabbedView.js:49-57`
210
+ - **Defect**: The constructor creates `this.el`, then `this.__panelContainer` and `this.__toggleContainer`, but never
211
+ calls `this.addChild(...)` on either, and neither does `link()`. Every toggle and panel is added to a container
212
+ that is not in the view tree.
213
+ - **Failure scenario**: `const t = new TabbedView({tabs}); parent.addChild(t);` → a bare empty `<div>`. Tab toggles
214
+ and the active panel exist as detached DOM and are never linked (so their signal bindings never activate either).
215
+ - **Fix**: `this.addChild(this.__toggleContainer); this.addChild(this.__panelContainer);` in the constructor.
216
+ - **Confidence**: Confirmed
217
+
218
+ ### VIEW-14 `MinimapFogOfWar.enforceAspectRatio` computes the wrong growth in the "too wide" branch
219
+ - **Severity**: MAJOR
220
+ - **File**: `src/view/minimap/gl/MinimapFogOfWar.js:16-38`
221
+ - **Defect**: When `aspectRatioDelta <= 0` the code grows the width by `-aabbWidth * aspectRatioDelta`. Solving,
222
+ the resulting ratio is `aabbHeight / (aabbWidth * (1 + aAR - vAR))`, which only equals `vAR` by coincidence. The
223
+ height branch is correct (`aabbWidth * delta` yields exactly `aabbWidth * vAR`); the width branch is not the
224
+ mirror of it.
225
+ - **Failure scenario**: minimap viewport 200×100 (`vAR = 0.5`), revealed fog region a 100×100 square (`aAR = 1`).
226
+ `delta = -0.5`, `d = 50`, new bounds 150×100 → ratio 0.667, not 0.5. `focusArea` is set to that region and drives
227
+ the orthographic camera in `MinimapWorldGL.updateCameraFocus`, so the minimap world is squashed horizontally by
228
+ ~33%: terrain, entity markers and the camera frustum polygon (which are positioned from `worldScale`) no longer
229
+ line up with the fog-of-war overlay.
230
+ - **Fix**: `const d = aabbHeight / viewportAspectRatio - aabbWidth;` (equivalently grow to `aabbHeight / vAR`).
231
+ - **Confidence**: Confirmed
232
+
233
+ ### VIEW-15 `ListView.insertOne` dereferences an undefined sibling view when a filter is in play
234
+ - **Severity**: MAJOR
235
+ - **File**: `src/view/common/ListView.js:182-197`
236
+ - **Defect**: For a non-terminal insert it looks up `this.model.get(index + 1)` and calls `nextChild.el` without
237
+ checking that a view exists for it. `getChildByElement` returns `undefined` whenever the next element was skipped
238
+ by `this.filter` (or when the list contains duplicate elements — `viewMapping` is keyed by element identity, so a
239
+ duplicate overwrites the previous entry).
240
+ - **Failure scenario**: `new ListView(model, {elementFactory, filter: e => e.visible})`. Model is `[A(visible),
241
+ C(hidden)]`; insert `B(visible)` at index 1. `insertOne` creates B's view, sees `model.length (3) !== index+1 (2)`,
242
+ fetches `C`, `getChildByElement(C)` → `undefined` → `TypeError: Cannot read properties of undefined (reading 'el')`
243
+ inside the `model.on.added` dispatch. Signal logs it and swallows it, so the symptom is a silently mis-ordered list
244
+ (B stays appended at the end) plus a console error on every filtered insert.
245
+ - **Fix**: scan forward from `index + 1` for the first element that has a view; if none, leave the child appended.
246
+ - **Confidence**: Confirmed
247
+
248
+ ### VIEW-16 `DomSizeObserver.attach()` unobserves the new element and never observes it
249
+ - **Severity**: MAJOR
250
+ - **File**: `src/view/util/DomSizeObserver.js:147-153`
251
+ - **Defect**:
252
+ ```js
253
+ attach(element) {
254
+ this.element = element; // old reference already lost
255
+ if (this.running) { this.__dom_resize_observer.unobserve(this.element); } // unobserves the NEW element
256
+ }
257
+ ```
258
+ The old element is never unobserved (it stays in the `ResizeObserver`), and the new element is never observed
259
+ because `attach` only ever calls `unobserve`.
260
+ - **Failure scenario**: `o.attach(elA); o.start();` then `o.attach(elB)` while running. `unobserve(elB)` is a no-op
261
+ (B was never observed), A remains observed. Resizing B produces no callback at all — `o.dimensions` goes stale.
262
+ Resizing A *does* fire the callback, which then measures **B** via `resizeAABB2ToFitBoundingClientRect(this.element…)`
263
+ for the position but takes `rect.width/height` from **A's** `contentRect` → `dimensions` is a mix of two elements.
264
+ - **Fix**: capture the previous element, `unobserve(previous)` if running, assign, then `observe(element)` if running.
265
+ - **Confidence**: Confirmed
266
+
267
+ ### VIEW-17 `SimpleWindowView` resize handler accumulates the full drag delta on every pointer move
268
+ - **Severity**: MAJOR
269
+ - **File**: `src/view/elements/SimpleWindow.js:47-73`
270
+ - **Defect**: `anchor` is captured once on pointer-down and never advanced, yet the move handler does
271
+ `view.size.add(position - anchor)` — an *incremental* mutation fed an *absolute* delta. Compare
272
+ `BottomLeftResizeHandleView` (`elements/BottomLeftResizeHandleView.js:31-40`), which correctly does
273
+ `lastPosition.copy(position)` each move.
274
+ - **Failure scenario**: `new SimpleWindowView(content, {resizable: true})`. Grab the bottom-right 10 px corner and
275
+ drag 10 px right over 5 pointer-move events (deltas 2, 4, 6, 8, 10 relative to the fixed anchor) → the width grows
276
+ by 30 px instead of 10. A slow 200 px drag over 100 events grows the window by ~10 000 px; the window runs away
277
+ from the cursor and cannot be resized back down.
278
+ - **Fix**: either update `anchor` to `position` at the end of each move, or capture `originalSize` on pointer-down and
279
+ use `view.size.copy(originalSize).add(delta)`.
280
+ - **Confidence**: Confirmed
281
+
282
+ ### VIEW-18 `ToastLogView` registers every notification twice in `children`
283
+ - **Severity**: MAJOR
284
+ - **File**: `src/view/elements/notify/ToastLogView.js:47,72-88`
285
+ - **Defect**: The constructor reassigns `this.children = []` (shadowing the base `View.children` array), and `addOne`
286
+ then does **both** `self.addChild(childView)` — which pushes onto `this.children` — **and**
287
+ `self.children.push(childView)`. Every toast appears twice in the array. `removeChildView` splices out one
288
+ occurrence and bypasses `View.removeChild`, so the second entry survives with its DOM node already detached.
289
+ - **Failure scenario**: Two notifications A then B. `children` = `[A, A, B, B]`, so `updatePositions` computes
290
+ `maxIndex = 3`: A ends at `-(3-1)*24 = -48 px` and B at `0`, instead of `-24` and `0` → a 24 px gap opens between
291
+ the two toasts and the stack floats one row too high. After A's fade-out, `children` = `[A, B, B]` and A's stale
292
+ entry keeps skewing every subsequent layout. If the view is ever destroyed, `View.destroy`/`removeAllChildren`
293
+ walks the duplicates and calls `this.el.removeChild(A.el)` on an already-detached node → `NotFoundError`.
294
+ - **Fix**: delete the `this.children = []` reassignment and the manual `push`; use `View.removeChild` in
295
+ `removeChildView`. Also cancel the pending `setTimeout` handles on unlink and unsubscribe
296
+ `model.elements.on.added` (currently a permanent subscription, `:90`).
297
+ - **Confidence**: Confirmed
298
+
299
+ ### VIEW-19 `RadialProgressView` subscribes to its external model permanently
300
+ - **Severity**: MAJOR
301
+ - **File**: `src/view/elements/radial/RadialProgressView.js:55-68`
302
+ - **Defect**: `model.on.changed.add(update)` / `model[0].onChanged.add(redraw)` / `model[1].onChanged.add(redraw)` are
303
+ raw subscriptions on caller-owned objects, made in the constructor and never removed — the class has no `unlink()`
304
+ or `destroy()` override, and does not use `bindSignal`.
305
+ - **Failure scenario**: `view/units/UnitRadialPreview.js:23` builds
306
+ `new RadialProgressView([unit.healthCurrent, unit.stats.healthMax], …)`. The unit outlives the preview widget
307
+ (health is model state). Every time a unit preview is created and discarded, the unit's `healthCurrent` signal
308
+ retains `redraw`, which closes over the view, its SVG element and its `thickness` observable — the whole widget is
309
+ unreclaimable, and every health tick redraws N dead widgets. Cycling a roster panel a few hundred times leaks
310
+ hundreds of SVG subtrees.
311
+ - **Fix**: route all three through `this.bindSignal(...)` so they follow the view's link lifecycle.
312
+ - **Confidence**: Confirmed
313
+
314
+ ### VIEW-20 `createInterfaceCommandButton` subscribes to the command's feature signals twice, one of them forever
315
+ - **Severity**: MAJOR
316
+ - **File**: `src/view/interaction/createInterfaceCommandButton.js:91-99`
317
+ - **Defect**:
318
+ ```js
319
+ if (interaction.features !== undefined) {
320
+ interaction.features.on.added.add(addCommandFeature); // permanent
321
+ interaction.features.on.removed.add(removeCommandFeature); // permanent
322
+ }
323
+ button.bindSignal(interaction.features.on.added, addCommandFeature); // link-scoped (correct)
324
+ button.bindSignal(interaction.features.on.removed, removeCommandFeature); // link-scoped (correct)
325
+ ```
326
+ `InteractionCommand` always constructs `this.features = new List(features)` (`interaction/InteractionCommand.js:40`),
327
+ so the `if` is always taken and the first pair is always added. Nothing ever removes them.
328
+ - **Failure scenario**: `InteractionCommand` instances are long-lived and shared — `InteractionCommandSet` keys them
329
+ by id. A command bar that is rebuilt on every selection change produces a new `ButtonView` per command each time;
330
+ each one permanently registers two closures on the shared command's feature list. After 100 selection changes,
331
+ `interaction.setFeature('highlighted', true)` invokes `addCommandFeature` on 100 discarded buttons, and all 100
332
+ button subtrees are unreclaimable.
333
+ - **Fix**: delete the raw `on.added`/`on.removed` subscriptions; the `bindSignal` pair already covers the live case
334
+ and `button.on.linked` already replays the current features.
335
+ - **Confidence**: Confirmed
336
+
337
+ ### VIEW-21 `MeshPreview` multiplies its pointer handlers on every link, and dereferences a null camera
338
+ - **Severity**: MAJOR
339
+ - **File**: `src/view/elements/MeshPreview.js:204-234`
340
+ - **Defect**: (a) `link()` attaches a fresh `self.pContents.then(...)` continuation each time. Because `pContents` is
341
+ already settled after the first load, every subsequent link immediately runs `__addInteraction`, which creates a
342
+ **new** `PointerDevice`, calls `start()` on it, and adds another `dragStart`/`drag` pair that mutates
343
+ `contents.group.rotation` — none of which is ever stopped in `unlink()`. (b) `__update_renderer_size` guards on
344
+ `this.renderer !== null` but then touches `this.camera.aspect`; `camera` is only assigned in the asset callback.
345
+ - **Failure scenario (a)**: Open a unit-detail panel containing a `MeshPreview`, close it, open it again. Two
346
+ `PointerDevice`s are now live on the pooled canvas; one drag rotates the model twice as fast. After ten cycles the
347
+ model spins ~10× per pixel of drag. (b): `preview.size.set(256, 256)` after linking but before the glTF resolves —
348
+ the bound `size.onChanged` fires with `renderer` set and `camera` still `null` →
349
+ `TypeError: Cannot set properties of null (setting 'aspect')`.
350
+ - **Fix**: attach the `pContents` continuation once in the constructor and have it store `contents.group`; create the
351
+ `PointerDevice` once and `start()`/`stop()` it from `link`/`unlink`. Guard `__update_renderer_size` on
352
+ `this.camera !== null` as well (it is genuinely null until the async load lands).
353
+ - **Confidence**: Confirmed
354
+
355
+ ### VIEW-22 `renderModel` caches the caller's live `size`/`focus` objects, so resizes return the stale image
356
+ - **Severity**: MAJOR
357
+ - **File**: `src/view/renderModel.js:15-29,85-92`
358
+ - **Defect**: The cache entry stores `size: size` and `focus: focus` by reference, and `findInCache` compares with
359
+ `piece.size.equals(size)` / component-wise on `focus`. When the caller passes a mutable vector, the cached entry's
360
+ key mutates in lockstep with the query, so the comparison always succeeds.
361
+ - **Failure scenario**: `MeshView.render()` (`common/MeshView.js:61`) passes `this.size` and `this.focus` straight
362
+ through. Render a mesh preview at 50×50 — cached with `piece.size === view.size`. Resize the view to 200×200:
363
+ `update()` sees the change and calls `render()`, `findInCache(url, this.size, this.focus)` compares `this.size`
364
+ against itself → hit → the 50×50 `dataURL` is returned and stretched to 200×200 (blurry), and no re-render is ever
365
+ scheduled. The cache also has no eviction (`cache.push` only), so it grows without bound.
366
+ - **Fix**: store `size.clone()` and a copied `AABB2` in the cache entry; add an eviction policy (the codebase already
367
+ has `core/cache/Cache`).
368
+ - **Confidence**: Confirmed
369
+
370
+ ### VIEW-23 `MeshView` never reacts to its own model
371
+ - **Severity**: MAJOR
372
+ - **File**: `src/view/common/MeshView.js:72-92`
373
+ - **Defect**: The view observes `this.size` only. `update()`'s change test compares `size` and `focus` against
374
+ `renderedParams` and ignores the model entirely, so even an explicit `update()` after a model change does nothing.
375
+ `this.model.onChanged` is never bound.
376
+ - **Failure scenario**: `meshView.model.set('models/sword.gltf')` on a linked `MeshView` currently showing
377
+ `models/axe.gltf` → nothing happens; a manual `meshView.update()` also short-circuits on "no change". The view keeps
378
+ displaying the axe until the element is resized.
379
+ - **Fix**: `this.bindSignal(this.model.onChanged, this.render, this)`, and include the rendered URL in
380
+ `renderedParams` so `update()` detects it.
381
+ - **Confidence**: Confirmed
382
+
383
+ ### VIEW-24 `RectangularPieProgressView` assumes a square element; on any other aspect the path becomes invalid
384
+ - **Severity**: MAJOR
385
+ - **File**: `src/view/elements/progress/RectangularPieProgressView.js:77-107`
386
+ - **Defect**: The fraction thresholds `.125 / .375 / .625 / .875` place the corner transitions at 45°, which is only
387
+ where the corners are for a square. For a non-square element the sweep ray exits through a different edge than the
388
+ branch tests, `segment2_segment_compute_intersection_array_2d` returns `false` and leaves `p` empty, and the path
389
+ string is built from `p[0]`/`p[1]` === `undefined`.
390
+ - **Failure scenario**: `v.size.set(100, 50); v.model.set(13); v.max.set(100)` (fraction 0.13 → branch 2, which tests
391
+ the **right** edge). `angle ≈ 43°` from the centre `(50,25)`: reaching `x = 100` needs `Δy = -47`, i.e. `y = -22`,
392
+ outside the edge segment — the ray actually exits through the **top** edge at `x ≈ 76.6`. No intersection is
393
+ written, so `d` becomes `"M 50 0 L 50 25 L undefined undefined L 100 50 L 0 50 L 0 0 Z"`. Browsers reject the whole
394
+ `d` attribute → the cooldown overlay disappears entirely for that fraction range.
395
+ (In-repo the only caller, `view/units/ability/CombatAbilityView.js:30`, sizes it 64×64, so the game path is safe —
396
+ but this is a public class with a `size` the caller controls.)
397
+ - **Fix**: compute the corner fractions from the actual aspect (`atan2(size_y, size_x)` etc.) instead of hard-coded
398
+ eighths, or pick the edge by testing all four and taking whichever intersects.
399
+ - **Confidence**: Confirmed
400
+
401
+ ### VIEW-25 `EmptyView.absolute` nests the caller's CSS instead of spreading it
402
+ - **Severity**: MAJOR
403
+ - **File**: `src/view/elements/EmptyView.js:54-72`
404
+ - **Defect**:
405
+ ```js
406
+ css: {
407
+ css, // shorthand -> a property literally named "css"
408
+ ...CSS_ABSOLUTE_POSITIONING
409
+ }
410
+ ```
411
+ The intent is clearly `...css`. `View.css(hash)` then executes `this.el.style['css'] = {…}`, which the CSSOM
412
+ ignores.
413
+ - **Failure scenario**: `EmptyView.absolute({ css: { width: '100px', backgroundColor: 'red' } })` produces an element
414
+ with only `position/top/left` applied; width and background are silently dropped, so the element collapses to zero
415
+ size. No error is raised anywhere.
416
+ - **Fix**: `css: { ...css, ...CSS_ABSOLUTE_POSITIONING }`.
417
+ - **Confidence**: Confirmed
418
+
419
+ ### VIEW-26 `TileGridView` subscribes to the model and the DnD context outside the view lifecycle
420
+ - **Severity**: MAJOR
421
+ - **File**: `src/view/elements/tiles2d/TileGrid.js:135-136,301-338,411-419`
422
+ - **Defect**: `model.tiles.on.added.add(this.addTile, this)` and `.on.removed.add(this.removeTile, this)` are raw
423
+ subscriptions (not `bindSignal`) with no counterpart anywhere. Likewise every slot registers a `DropTarget` into
424
+ `this.__dragAndDropContext` via `addTarget` (which immediately `link()`s DOM listeners) and every tile registers a
425
+ `Draggable` via `addElement`; neither `removeTarget` nor `removeElement` is ever called, and the context is a
426
+ constructor parameter, i.e. typically shared across grids.
427
+ - **Failure scenario**: An inventory panel builds a 10×6 `TileGridView` against a shared `DragAndDropContext` each
428
+ time it opens. Every open/close cycle permanently adds 60 `DropTarget`s (each with 4 DOM listeners) and one
429
+ `Draggable` per item to `context.targets`/`context.elements`, and leaves the grid subscribed to `model.tiles`. After
430
+ 20 cycles, `DragAndDropContext.finalizeDrag` iterates 1200+ targets on every drop, `getElementById` scans hundreds
431
+ of dead draggables, and adding an item to the inventory while all panels are closed calls `addTile` on 20 detached
432
+ grids. Removing an item calls `removeTile` on grids where `findTileView` returns `undefined`, so
433
+ `this.__hookTileRemoved(undefined, tile)` fires with an undefined view.
434
+ - **Fix**: route the two model subscriptions through `bindSignal`; add an `unlink()` that calls
435
+ `context.removeTarget(slotView)` for each slot and `context.removeElement(draggable)` for each tile, and rebuild on
436
+ `link()`.
437
+ - **Confidence**: Confirmed
438
+
439
+ ### VIEW-27 `LocalizedLabelView.update()` dereferences a null localization outside the try
440
+ - **Severity**: MAJOR
441
+ - **File**: `src/view/common/LocalizedLabelView.js:122-154`
442
+ - **Defect**: `localization = null` is the constructor default and the class explicitly tests for it at `:60`, so it
443
+ is an anticipated state. `update()` wraps only `localization.getString(...)` in `try/catch`; line 143
444
+ (`this.__localeKey = localization.locale.getValue()`) and the `$el.text(value)` fallback that follows are outside
445
+ it. The throw at 143 skips the fallback text.
446
+ - **Failure scenario**: `new TaskProgressView({ task })` — `localization` defaults to `null`
447
+ (`task/TaskProgressView.js:20,29-33`) — then link. The `on.linked` handler calls `update()`, `getString` throws,
448
+ the catch sets `value = "failed to localize @…"`, then line 143 throws `TypeError: Cannot read properties of null
449
+ (reading 'locale')` before the text is written. Signal's dispatch try/catch swallows it, so the loading screen's
450
+ task-name label renders completely blank with two console errors per link.
451
+ - **Fix**: return early (writing the raw `@id` fallback) when `localization === null`, and move the `__localeKey`
452
+ assignment after a successful `getString`.
453
+ - **Confidence**: Confirmed
454
+
455
+ ### VIEW-28 `MarkerGL` leaks atlas patch references acquired across shutdown / rapid icon changes
456
+ - **Severity**: MAJOR
457
+ - **File**: `src/view/minimap/gl/MarkerGL.js:57-87,109-118`
458
+ - **Defect**: `updateIcon` releases the *current* `this.patch`, then awaits `atlasManager.acquire(newURL)`. The
459
+ continuation assigns `this.patch = patch` and then bails on `!this.active` — but the freshly acquired reference is
460
+ never released on that path. Similarly, two `updateIcon` calls in flight both release `Reference.NULL` up front and
461
+ the first resolved patch is overwritten (and leaked) by the second.
462
+ - **Failure scenario**: A unit with a minimap marker is killed while its icon texture is still being fetched
463
+ (`MinimapMarkersGL.removeElement` → `markerGL.shutdown()` → `active = false`, releases `Reference.NULL`). The
464
+ `acquire` promise then resolves, stores the patch on the dead marker and returns without releasing it → the
465
+ `ManagedAtlas` never frees that icon's slot. Repeated over a battle with many short-lived markers, the atlas fills
466
+ up and later markers fail to get a patch.
467
+ - **Fix**: in the continuation, if `!this.active`, call `patch.release()` before returning; also release the previous
468
+ `this.patch` when overwriting it rather than at call time.
469
+ - **Confidence**: Confirmed
470
+
471
+ ### VIEW-29 `DropTarget` drag-enter tracking has no dedup and splices with `-1`
472
+ - **Severity**: MAJOR
473
+ - **File**: `src/view/common/dnd/DropTarget.js:72-92,212-236`
474
+ - **Defect**: `handleDragEnter` pushes into `isInState_ENTER` unconditionally, and
475
+ `attachDropValidityIndicators.handleDragEnter` unconditionally appends a `{draggable, bindings}` record with a fresh
476
+ `SignalBinding` on `draggable.on.dragFinalized`. `removeDraggable` removes exactly one record per call.
477
+ `handleDragLeave` additionally does `isInState_ENTER.splice(indexOf(e), 1)` without checking for `-1`, and
478
+ `splice(-1, 1)` removes the *last* element.
479
+ - **Failure scenario**: `Draggable.link()` explicitly routes `dragenter` to the parent drop target
480
+ (`common/dnd/Draggable.js:103-106`) *and* the event bubbles to the drop target's own listener — so dragging an item
481
+ over another item inside the same slot fires `handleDragEnter` twice for one enter. `current` gains two records and
482
+ two live bindings. On drop, `dragFinalized` fires once, `removeDraggable` clears one record, and `update()` still
483
+ sees a non-empty `current` → the slot keeps its `drop-target-hover-valid` class permanently after the drag ends,
484
+ and each further hover leaks another `SignalBinding` on the draggable.
485
+ - **Fix**: dedup on enter (skip if the draggable is already tracked), loop `removeDraggable` until it returns false on
486
+ finalize, and guard the `indexOf === -1` case before splicing.
487
+ - **Confidence**: Likely
488
+
489
+ ### VIEW-30 A throwing tooltip factory disables tooltips globally for the rest of the session
490
+ - **Severity**: MAJOR
491
+ - **File**: `src/view/tooltip/TooltipManager.js:129-138`
492
+ - **Defect**:
493
+ ```js
494
+ gml.pushState();
495
+ gml.setTooltipsEnabled(false);
496
+ const factoryProduct = tip.factory.call(tip.factoryContext); // may throw
497
+ gml.popState();
498
+ ```
499
+ There is no `try/finally`. `GMLEngine.compile`/`compileAsText` both use `try { … } finally { this.popState(); }`
500
+ (`tooltip/gml/GMLEngine.js:481-493,512-525`), so the omission here is clearly unintended.
501
+ - **Failure scenario**: A single tooltip factory throws (e.g. an item tooltip for an item whose data row is missing).
502
+ `popState()` is skipped, so `__tooltipsEnabled` stays `false` and one orphan frame stays on `__contextStack`. Every
503
+ reference compiler that consults `gml.getTooltipsEnabled()` from then on sees `false` → nested tooltips stop being
504
+ attached anywhere in the UI until reload.
505
+ - **Fix**: wrap the factory call in `try { … } finally { gml.popState(); }`.
506
+ - **Confidence**: Confirmed
507
+
508
+ ### VIEW-31 `RadialMenu.init()` leaves the previous element views attached, and shared icon views get stolen
509
+ - **Severity**: MAJOR
510
+ - **File**: `src/view/elements/radial/RadialMenu.js:194-223`, `src/view/elements/radial/RadialMenuElement.js:70`
511
+ - **Defect**: `init()` resets `this.elements = []` but never removes the previously created `RadialMenuElement`
512
+ children from `this.vElementContainer`. Separately, `RadialMenuElement`'s constructor does
513
+ `this.addChild(description.iconView)` — the icon `View` lives on the caller-owned
514
+ `RadialMenuElementDefinition`, and `View.addChild` re-parents it (`child.parent = this; this.el.appendChild(child.el)`).
515
+ - **Failure scenario**: (a) `menu.init(newItems)` on an existing menu — the old wedges, labels and icons stay in the
516
+ DOM underneath the new ones, and `selectByAngle`/`render` only touch the new set, so the stale wedges are frozen in
517
+ place and never highlight. (b) Building two `RadialMenu`s from the same `items` array (definitions are plain data
518
+ objects that are easy to reuse) — the second menu's `addChild` moves every `iconView`'s DOM node out of the first
519
+ menu, leaving the first menu iconless while both `children` arrays still list it.
520
+ - **Fix**: `this.vElementContainer.removeAllChildren()` at the top of `init()`; and either clone the icon view per
521
+ element or document/enforce one definition per menu.
522
+ - **Confidence**: Confirmed
523
+
524
+ ### VIEW-32 `ConfirmationDialogView` builds a class name that can contain a space
525
+ - **Severity**: MAJOR
526
+ - **File**: `src/view/elements/ConfirmationDialogView.js:38`
527
+ - **Defect**: `"button-" + option.name.replace(' ', '-')` — `String.replace` with a string pattern replaces only the
528
+ **first** occurrence. The result is handed to `ButtonView`'s `classList`, which reaches `DOMTokenList.add()`.
529
+ - **Failure scenario**: `new ConfirmationDialogView(content, [{name: 'cancel all now', displayName: 'Cancel', …}])`
530
+ → class token `"button-cancel-all now"` → `classList.add` throws
531
+ `InvalidCharacterError: The string contains invalid characters`, aborting the whole dialog construction so no
532
+ confirmation dialog is shown at all.
533
+ - **Fix**: `option.name.replace(/\s+/g, '-')`, or reuse `string_tag_to_css_class_name`.
534
+ - **Confidence**: Confirmed
535
+
536
+ ### VIEW-33 `VirtualListView` disables the scrollbar one row too early, and `AlignmentOption.Center` does nothing
537
+ - **Severity**: MINOR
538
+ - **File**: `src/view/common/VirtualListView.js:181-196`
539
+ - **Defect**: The "everything fits" test is
540
+ `row_height * (last_visible_line - first_visible_line) < this.size.y`, i.e. it measures `n-1` rows instead of `n`.
541
+ Separately, `AlignmentOption.Center` is exported and accepted as `verticalAlignment` but the offset block only
542
+ handles `End`, so `Center` silently behaves like `Start`.
543
+ - **Failure scenario**: `lineSize = 20, lineSpacing = 0`, 5 elements, `size.y = 90` (content 100 px). `l0 = 0`,
544
+ `l1 = 4 = numTotalElements - 1`, and `20 * (4 - 0) = 80 < 90` → `__setScrollBar(false)` and `rowWidth` is not
545
+ reduced. The list declares itself fully visible while the 5th row is clipped by 10 px and cannot be scrolled to.
546
+ - **Fix**: compare `row_height * (last - first + 1) <= this.size.y`; implement the `Center` branch
547
+ (`line_offset_y = (this.size.y - total_lines_height) / 2`).
548
+ - **Confidence**: Confirmed
549
+
550
+ ### VIEW-34 `DropDownSelectionView.setSelectedValue` uses the model index against always-appended options
551
+ - **Severity**: MINOR
552
+ - **File**: `src/view/elements/DropDownSelectionView.js:55-68,141-143`
553
+ - **Defect**: `handleAdded(el, index)` ignores `index` and always `appendChild`s, while `setSelectedValue` does
554
+ `this.el.selectedIndex = this.model.indexOf(v)`. The two orderings only agree when elements are appended.
555
+ (`getSelectedValue` correctly resolves through the id map, so the two accessors disagree.) `handleRemoved` also
556
+ never deletes the entry from `this.mapping`.
557
+ - **Failure scenario**: `model.insert(0, x)` on a populated list — `x`'s `<option>` lands last while `model.indexOf(x)`
558
+ is `0`, so `setSelectedValue(x)` selects whatever element was originally first.
559
+ - **Fix**: honour `index` in `handleAdded` (`insertBefore` the option at `index`), and delete the mapping entry in
560
+ `handleRemoved`.
561
+ - **Confidence**: Confirmed
562
+
563
+ ### VIEW-35 `MinimapCameraView.castTerrainRay` jitters an origin it never uses
564
+ - **Severity**: MINOR
565
+ - **File**: `src/view/minimap/dom/MinimapCameraView.js:99-117`
566
+ - **Defect**: The retry loop perturbs `oX/oY/oZ` but calls
567
+ `terrain.raycastFirstSync(rayContact, originX, originY, originZ, …)` with the *unperturbed* origin every iteration.
568
+ `oX/oY/oZ` are written and never read.
569
+ - **Failure scenario**: A frustum corner ray that lands exactly on a terrain triangle edge misses. The stated purpose
570
+ of the loop — "jitter origin in case of mathematical error at polygon edges" — never happens; instead the identical
571
+ raycast runs 10 times and then falls back to the flat `y = 0` plane. On elevated terrain that corner of the minimap
572
+ camera-frustum polygon is drawn at the ground-plane intersection instead of the terrain surface, so the frustum
573
+ outline visibly snaps outward for that corner.
574
+ - **Fix**: pass `oX, oY, oZ` to `raycastFirstSync`.
575
+ - **Confidence**: Confirmed
576
+
577
+ ### VIEW-36 `DOM.prototype.clear()` does not remove text nodes
578
+ - **Severity**: MINOR
579
+ - **File**: `src/view/DOM.js:131-137`
580
+ - **Defect**: The loop iterates `el.children` (elements only), so text nodes survive a method documented as
581
+ "removes all children".
582
+ - **Failure scenario**: `const d = domify('div'); d.text('Loading…'); d.clear(); d.append(other);` → the element still
583
+ reads "Loading…" followed by the appended content. This is reachable through
584
+ `LocalizedLabelView.update()` (`$el.text(value)` on the non-GML path) followed by a switch to a GML-compiled value,
585
+ which calls `removeAllChildren()` and then appends compiled views next to the leftover text node; also
586
+ `MinimapView.link()` (`minimap/Minimap.js:217-219`) relies on `clear()` before appending the WebGL canvas.
587
+ - **Fix**: `while (el.firstChild) el.removeChild(el.firstChild);`
588
+ - **Confidence**: Confirmed
589
+
590
+ ### VIEW-37 `setElementTransform.js` exports nothing
591
+ - **Severity**: MINOR
592
+ - **File**: `src/view/setElementTransform.js:13`
593
+ - **Defect**: The module declares `function setElementTransform(...)` with no `export` and no default export, so the
594
+ file's only purpose is unreachable.
595
+ - **Failure scenario**: `import { setElementTransform } from '.../setElementTransform.js'` →
596
+ `SyntaxError: The requested module does not provide an export named 'setElementTransform'` at build time.
597
+ - **Fix**: `export function setElementTransform(...)`.
598
+ - **Confidence**: Confirmed
599
+
600
+ ### VIEW-38 `DatGuiUtils.makeDatController` references an undeclared `p` in its cycle branch
601
+ - **Severity**: MINOR
602
+ - **File**: `src/view/controller/dat/DatGuiUtils.js:377-380`
603
+ - **Defect**: ``console.warn(`Detected cycle at "${p}" …`)`` — `p` is the loop variable of `makeDatControllerForObject`,
604
+ not of this function. Modules are strict-mode, so this is a `ReferenceError`, not `undefined`. The intended
605
+ identifier is `propertyName`.
606
+ - **Failure scenario**: `makeDatController` is exported (`:451`). A direct call
607
+ `makeDatController(gui, obj, 'child', pathContainingObjChild)` hits the cycle branch and throws
608
+ `ReferenceError: p is not defined` instead of warning and returning `0`, aborting the whole controller build.
609
+ - **Fix**: use `${propertyName}`.
610
+ - **Confidence**: Confirmed
611
+
612
+ ### VIEW-39 `GroupView.remove()` leaves the removed child linked; `update()` calls a method `View` does not have
613
+ - **Severity**: MINOR
614
+ - **File**: `src/view/elements/Group.js:8,11-30`
615
+ - **Defect**: `add`/`remove` bypass `View.addChild`/`View.removeChild`: `child.parent` is never set and `remove` never
616
+ calls `child.unlink()`. `update()` invokes `c.update()` on each child, but `View` defines no `update`.
617
+ - **Failure scenario**: `group.add(labelView); group.link(); group.remove(labelView);` — the label's DOM node is
618
+ detached but the view stays linked, so its `bindSignal` subscriptions keep firing and keep writing to a node that is
619
+ no longer in the document. `group.update()` with any plain `EmptyView` child →
620
+ `TypeError: c.update is not a function`.
621
+ - **Fix**: delegate to `View.addChild`/`View.removeChild` (and drop the `this.children = []` reassignment); remove
622
+ `update()` or make it guard on the method existing.
623
+ - **Confidence**: Confirmed
624
+
625
+ ### VIEW-40 `WindRoseDiagram` sizes itself for icons that may not exist, and re-registers tooltips on every draw
626
+ - **Severity**: MINOR
627
+ - **File**: `src/view/elements/windrose/WindRoseDiagram.js:90-94,197-336`
628
+ - **Defect**: (a) `const has_icons = axes.some(isDefined)` tests whether each *axis object* is defined, not whether it
629
+ has an `icon`; for any non-empty `axes` array this is always `true`. (b) `draw_canvas()` calls
630
+ `container.removeAllChildren()` and rebuilds every label/icon, then calls `this.__tooltips.add(view, …)` for each —
631
+ `DomTooltipManager.add` links a `DomTooltipObserver` immediately and is never paired with `remove`.
632
+ - **Failure scenario**: (a) `new WindRoseDiagram({axes: [{name:'a'},{name:'b'},{name:'c'}], radius_outer: 100,
633
+ icon_size: 32})` (no icons at all) → `size = 200 + 32*1.207*2 ≈ 277` instead of `200`; the widget claims 77 px more
634
+ in both axes than it draws, pushing neighbours around in a flex row. (b) `draw()` runs on every `on.linked`; after
635
+ 10 open/close cycles each axis label has 10 live `DomTooltipObserver`s with `mouseenter`/`mouseleave` listeners on
636
+ detached elements.
637
+ - **Fix**: `axes.some(a => a.icon !== undefined)`; use `tooltips.manage(view, …)` (which self-registers on
638
+ link/unlink) rather than `add`.
639
+ - **Confidence**: Confirmed
640
+
641
+ ### VIEW-41 `ImageView`/`VideoView` never re-apply an observed URL on link
642
+ - **Severity**: MINOR
643
+ - **File**: `src/view/elements/image/ImageView.js:65-71`, `src/view/elements/video/VideoView.js:77-83`
644
+ - **Defect**: The `src` is baked into the cache key at construction and thereafter only updated by the
645
+ `url.onChanged` → `__setSource` binding, which is a `bindSignal` and therefore inactive while unlinked. There is no
646
+ `on.linked` initial-apply.
647
+ - **Failure scenario**: An `ImageView` bound to an `ObservedString` icon URL sits in a panel. Close the panel (view
648
+ unlinks, binding detaches), the underlying model swaps the icon (equip a different item), reopen the panel — the
649
+ binding re-links but is never invoked, so the `<img>` still shows the previous icon until the URL happens to change
650
+ again while the panel is open.
651
+ - **Fix**: add `this.on.linked.add(() => this.__setSource(url.getValue()), this)` in the observed-URL branch (mirroring
652
+ `LabelView.link()`, which re-runs `updateTransform()`).
653
+ - **Confidence**: Confirmed
654
+
655
+ ### VIEW-42 `ButtonView` never applies its initial enabled/disabled class
656
+ - **Severity**: MINOR
657
+ - **File**: `src/view/elements/button/ButtonView.js:94,101-110`
658
+ - **Defect**: `__enabled` is initialised by direct field assignment, bypassing the setter, and the setter early-returns
659
+ when the value is unchanged. A button that is enabled from birth therefore carries **neither** `.enabled` nor
660
+ `.disabled`.
661
+ - **Failure scenario**: `.ui-button-view.disabled { opacity: .4 }` + `.ui-button-view.enabled { cursor: pointer }`
662
+ style rules — a freshly created enabled button matches neither. `createInterfaceCommandButton` masks this because
663
+ its `on.linked` handler calls `updateEnableStatus()`, but that only helps when the command's `enabled` differs from
664
+ `true`; a permanently-enabled command's button never gets the class.
665
+ - **Fix**: set the class explicitly at the end of the constructor (`this.setClass('enabled', true);
666
+ this.setClass('disabled', false);`) rather than relying on the setter's change detection.
667
+ - **Confidence**: Likely