@woosh/meep-engine 3.0.2 → 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 (1823) hide show
  1. package/LICENSE +188 -188
  2. package/README.md +152 -145
  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/grid/grid2transform/GridPosition2TransformSystem.d.ts +2 -2
  1072. package/src/engine/grid/grid2transform/GridPosition2TransformSystem.d.ts.map +1 -1
  1073. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +717 -717
  1074. package/src/engine/input/analog/apply_radial_dead_zone.js +38 -38
  1075. package/src/engine/input/devices/GamepadDevice.js +466 -466
  1076. package/src/engine/input/devices/ManualInputDevice.js +152 -152
  1077. package/src/engine/input/devices/PointerCoordinates.js +26 -26
  1078. package/src/engine/input/devices/events/GamepadEvents.js +10 -10
  1079. package/src/engine/input/devices/gamepad/GamepadAxes.js +19 -19
  1080. package/src/engine/input/devices/gamepad/GamepadButtons.js +29 -29
  1081. package/src/engine/input/devices/gamepad/GamepadCoordinates.js +17 -17
  1082. package/src/engine/input/devices/gamepad/GamepadDeviceLayout.js +323 -323
  1083. package/src/engine/input/devices/gamepad/GamepadHandle.js +286 -286
  1084. package/src/engine/input/devices/gamepad/GamepadLayout.js +160 -160
  1085. package/src/engine/input/devices/gamepad/GamepadStandardMapping.js +31 -31
  1086. package/src/engine/input/devices/gamepad/GamepadStick.js +169 -169
  1087. package/src/engine/input/devices/gamepad/GamepadStickCalibration.js +119 -119
  1088. package/src/engine/input/devices/gamepad/GamepadStickCalibrator.js +250 -250
  1089. package/src/engine/input/devices/gamepad/gamepad_layout_database.js +144 -144
  1090. package/src/engine/input/devices/gamepad/gamepad_read_hat_axis.js +61 -61
  1091. package/src/engine/input/devices/gamepad/gamepad_write_dpad_vector.js +30 -30
  1092. package/src/engine/input/devices/gamepad/prototypeGamepadTester.js +2124 -2124
  1093. package/src/engine/input/devices/mouse/MouseButtons.js +22 -22
  1094. package/src/engine/input/ecs/components/Input.js +118 -118
  1095. package/src/engine/input/ecs/components/InputController.js +78 -78
  1096. package/src/engine/input/ecs/ism/ISM_DESIGN.md +1523 -1523
  1097. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +627 -627
  1098. package/src/engine/input/ecs/ism/InputActionEvent.js +40 -40
  1099. package/src/engine/input/ecs/ism/InputBinding.js +71 -71
  1100. package/src/engine/input/ecs/ism/InputCoordinateKind.js +25 -25
  1101. package/src/engine/input/ecs/ism/InputCoordinateSource.js +86 -86
  1102. package/src/engine/input/ecs/ism/InputDirection.js +33 -33
  1103. package/src/engine/input/ecs/ism/InputMapProgram.js +236 -236
  1104. package/src/engine/input/ecs/ism/InputMapSystem.js +976 -976
  1105. package/src/engine/input/ecs/ism/InputOcclusion.js +31 -31
  1106. package/src/engine/input/ecs/ism/InputSource.js +67 -67
  1107. package/src/engine/input/ecs/ism/InputSourceTable.js +107 -107
  1108. package/src/engine/input/ecs/ism/coordinate/InputCoordinateChannel.js +93 -93
  1109. package/src/engine/input/ecs/ism/coordinate/InputCoordinateChannelType.js +11 -11
  1110. package/src/engine/input/ecs/ism/coordinate/InputCoordinateDevice.js +153 -153
  1111. package/src/engine/input/ecs/ism/coordinate/InputCoordinateSwitches.js +160 -160
  1112. package/src/engine/input/ecs/ism/device/GAMEPAD_INPUT_DEVICE_ID.js +9 -9
  1113. package/src/engine/input/ecs/ism/device/GamepadInputDeviceAdapter.js +88 -88
  1114. package/src/engine/input/ecs/ism/device/InputDeviceAdapter.js +72 -72
  1115. package/src/engine/input/ecs/ism/device/KEYBOARD_INPUT_DEVICE_ID.js +9 -9
  1116. package/src/engine/input/ecs/ism/device/KeyboardInputDeviceAdapter.js +63 -63
  1117. package/src/engine/input/ecs/ism/device/ManualInputDeviceAdapter.js +55 -55
  1118. package/src/engine/input/ecs/ism/device/POINTER_INPUT_DEVICE_ID.js +9 -9
  1119. package/src/engine/input/ecs/ism/device/PointerInputDeviceAdapter.js +160 -160
  1120. package/src/engine/input/ecs/ism/map/InputBinding.js +88 -88
  1121. package/src/engine/input/ecs/ism/map/InputCoordinateBinding.js +102 -102
  1122. package/src/engine/input/ecs/ism/map/InputLayer.js +220 -220
  1123. package/src/engine/input/ecs/ism/map/InputMap.js +331 -331
  1124. package/src/engine/input/ecs/ism/prototypeInputMap.js +309 -309
  1125. package/src/engine/input/ecs/ism/trigger/InputTrigger.js +148 -148
  1126. package/src/engine/input/ecs/ism/trigger/InputTriggerChord.js +173 -173
  1127. package/src/engine/input/ecs/ism/trigger/InputTriggerGamepadButton.js +37 -37
  1128. package/src/engine/input/ecs/ism/trigger/InputTriggerHold.js +176 -176
  1129. package/src/engine/input/ecs/ism/trigger/InputTriggerKey.js +39 -39
  1130. package/src/engine/input/ecs/ism/trigger/InputTriggerMouseButton.js +38 -38
  1131. package/src/engine/input/ecs/ism/trigger/InputTriggerRelease.js +120 -120
  1132. package/src/engine/input/ecs/ism/trigger/InputTriggerSequence.js +315 -315
  1133. package/src/engine/input/ecs/ism/trigger/InputTriggerSwitch.js +105 -105
  1134. package/src/engine/input/ecs/ism/trigger/InputTriggerType.js +17 -17
  1135. package/src/engine/input/ecs/systems/InputControllerSystem.js +253 -253
  1136. package/src/engine/input/ecs/systems/InputSystem.js +162 -162
  1137. package/src/engine/intelligence/behavior/primitive/FailingBehaviorSerializationAdapter.js +25 -25
  1138. package/src/engine/intelligence/behavior/primitive/SucceedingBehaviorSerializationAdapter.js +26 -26
  1139. package/src/engine/intelligence/behavior/util/AsynchronousDelayAction.js +55 -55
  1140. package/src/engine/interpolation/BinaryInterpolationAdapter.js +56 -56
  1141. package/src/engine/interpolation/Interpoland.js +49 -49
  1142. package/src/engine/interpolation/Interpolated.js +149 -149
  1143. package/src/engine/interpolation/PoseInterpolationAdapter.js +61 -61
  1144. package/src/engine/interpolation/TransformPoseSerializationAdapter.js +57 -57
  1145. package/src/engine/interpolation/pose_interpoland.js +27 -27
  1146. package/src/engine/navigation/ecs/path_following/PathFollower.js +222 -222
  1147. package/src/engine/navigation/mesh/NavigationMesh.js +145 -145
  1148. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +661 -0
  1149. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +229 -229
  1150. package/src/engine/navigation/mesh/build/clip_soup_against_overhangs.d.ts.map +1 -1
  1151. package/src/engine/navigation/mesh/build/clip_soup_against_overhangs.js +628 -520
  1152. package/src/engine/network/CONGESTION_CONTROL.md +87 -87
  1153. package/src/engine/network/README.md +52 -52
  1154. package/src/engine/network/adapters/QuaternionInterpolationAdapter.js +43 -43
  1155. package/src/engine/network/adapters/TransformInterpolationAdapter.js +84 -84
  1156. package/src/engine/network/adapters/TransformReplicationAdapter.js +87 -87
  1157. package/src/engine/network/adapters/Vector3InterpolationAdapter.js +46 -46
  1158. package/src/engine/network/convertPathToURL.js +2 -2
  1159. package/src/engine/network/core/MalformedPacketError.js +26 -26
  1160. package/src/engine/network/core/quantize/quantize_float.js +73 -73
  1161. package/src/engine/network/core/quantize/quantize_position.js +65 -65
  1162. package/src/engine/network/core/sequence/ack_bitfield.js +77 -77
  1163. package/src/engine/network/core/sequence/seq16.js +69 -69
  1164. package/src/engine/network/core/sequence/seq32.js +73 -73
  1165. package/src/engine/network/ecs/NetworkSystem.js +84 -84
  1166. package/src/engine/network/ecs/components/NetworkIdentity.js +73 -73
  1167. package/src/engine/network/ecs/owner_authorization.js +55 -55
  1168. package/src/engine/network/ecs/serialization/NetworkIdentitySerializationAdapter.js +64 -64
  1169. package/src/engine/network/replication/ScopeFilter.js +71 -71
  1170. package/src/engine/network/sim/ActionLog.js +152 -152
  1171. package/src/engine/network/sim/SimAction.js +273 -273
  1172. package/src/engine/network/sim/Snapshotter.js +222 -222
  1173. package/src/engine/network/state/FrameBufferRing.js +168 -168
  1174. package/src/engine/network/state/InputRing.js +134 -134
  1175. package/src/engine/network/state/PriorityAccumulator.js +180 -180
  1176. package/src/engine/network/time/TimeDilation.js +62 -62
  1177. package/src/engine/network/transport/Channel.js +336 -336
  1178. package/src/engine/network/transport/Transport.js +203 -203
  1179. package/src/engine/network/transport/adapters/NodeUDPTransport.js +186 -186
  1180. package/src/engine/network/transport/adapters/WebRTCDataChannelTransport.js +105 -105
  1181. package/src/engine/network/transport/fragments/fragment_send.js +147 -147
  1182. package/src/engine/network/transport/fragments/packet_size.js +101 -101
  1183. package/src/engine/network/xhr.js +23 -23
  1184. package/src/engine/physics/BULLET_REVIEW.md +945 -945
  1185. package/src/engine/physics/CANNON_REVIEW.md +1300 -1300
  1186. package/src/engine/physics/CONSTRAINT_SOLVER_BENCH_LOG.md +208 -208
  1187. package/src/engine/physics/CONSTRAINT_SOLVER_IMPROVEMENTS_PLAN.md +364 -364
  1188. package/src/engine/physics/INTEPOLATION_SYSTEM_PLAN.md +287 -287
  1189. package/src/engine/physics/JOLT_REVIEW.md +913 -913
  1190. package/src/engine/physics/PLAN.md +1120 -1094
  1191. package/src/engine/physics/RAPIER_REVIEW.md +934 -934
  1192. package/src/engine/physics/REVIEW_001_ACTION_PLAN.md +642 -642
  1193. package/src/engine/physics/REVIEW_002.md +151 -151
  1194. package/src/engine/physics/REVIEW_003.md +166 -166
  1195. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +97 -97
  1196. package/src/engine/physics/constraint/DofMode.js +35 -35
  1197. package/src/engine/physics/constraint/solve_constraints.js +1 -1
  1198. package/src/engine/physics/contact/combine_material.js +35 -35
  1199. package/src/engine/physics/ecs/BodyKind.js +29 -29
  1200. package/src/engine/physics/ecs/Collider.js +177 -177
  1201. package/src/engine/physics/ecs/ColliderFlags.js +15 -15
  1202. package/src/engine/physics/ecs/ColliderSerializationAdapter.js +37 -37
  1203. package/src/engine/physics/ecs/Joint.js +475 -475
  1204. package/src/engine/physics/ecs/JointSerializationAdapter.js +72 -72
  1205. package/src/engine/physics/ecs/PhysicsSystem.d.ts +3 -0
  1206. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  1207. package/src/engine/physics/ecs/PhysicsSystem.js +7 -2
  1208. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.js +37 -37
  1209. package/src/engine/physics/ecs/SleepState.js +12 -12
  1210. package/src/engine/physics/ecs/find_non_finite_physics_state.js +76 -76
  1211. package/src/engine/physics/fluid/FluidField.js +867 -867
  1212. package/src/engine/physics/fluid/FluidSimulator.js +832 -832
  1213. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +243 -243
  1214. package/src/engine/physics/fluid/SliceVisualiser.js +190 -190
  1215. package/src/engine/physics/fluid/ecs/FluidComponent.js +239 -239
  1216. package/src/engine/physics/fluid/ecs/FluidEffectorsComponent.js +89 -89
  1217. package/src/engine/physics/fluid/ecs/FluidObstacle.js +97 -97
  1218. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.js +348 -348
  1219. package/src/engine/physics/fluid/ecs/FluidSystem.js +142 -142
  1220. package/src/engine/physics/fluid/ecs/FluidWorkerCore.js +123 -123
  1221. package/src/engine/physics/fluid/ecs/WorkerFluidSystem.js +395 -395
  1222. package/src/engine/physics/fluid/ecs/fluid.worker.js +12 -12
  1223. package/src/engine/physics/fluid/ecs/fluid_build_world_to_grid.js +32 -32
  1224. package/src/engine/physics/fluid/ecs/fluid_gather_visible_effectors.js +47 -47
  1225. package/src/engine/physics/fluid/ecs/fluid_reanchor_field.js +85 -85
  1226. package/src/engine/physics/fluid/ecs/fluid_sync_effectors_from_transform.js +16 -16
  1227. package/src/engine/physics/fluid/ecs/fluid_worker_protocol.js +111 -111
  1228. package/src/engine/physics/fluid/ecs/makeFluidWorker.js +18 -18
  1229. package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +81 -81
  1230. package/src/engine/physics/fluid/effector/GlobalFluidEffector.js +202 -202
  1231. package/src/engine/physics/fluid/effector/ImpulseFluidEffector.js +257 -257
  1232. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +405 -405
  1233. package/src/engine/physics/fluid/prototype.js +126 -126
  1234. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.js +143 -143
  1235. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +162 -162
  1236. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +107 -107
  1237. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.js +131 -131
  1238. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +90 -90
  1239. package/src/engine/physics/fluid/solver/v3_grid_limit8_at_indices.js +38 -38
  1240. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.js +77 -77
  1241. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_uniform.js +113 -113
  1242. package/src/engine/physics/fluid/solver/v3_grid_sample_scalar_masked.js +92 -92
  1243. package/src/engine/physics/fluid/solver/v3_grid_shift_in_place.js +107 -107
  1244. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +135 -135
  1245. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +511 -511
  1246. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +108 -108
  1247. package/src/engine/physics/fluid/solver/v3_mac_advect_maccormack_velocity.js +317 -317
  1248. package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.js +236 -236
  1249. package/src/engine/physics/fluid/solver/v3_mac_advect_sl_velocity.js +217 -217
  1250. package/src/engine/physics/fluid/solver/v3_mac_apply_vorticity_confinement.js +174 -174
  1251. package/src/engine/physics/fluid/solver/v3_mac_clip_trace.js +95 -95
  1252. package/src/engine/physics/fluid/solver/v3_mac_compute_divergence.js +77 -77
  1253. package/src/engine/physics/fluid/solver/v3_mac_compute_face_solid.js +131 -131
  1254. package/src/engine/physics/fluid/solver/v3_mac_subtract_pressure_gradient.js +104 -104
  1255. package/src/engine/physics/inertia/world_inverse_inertia.js +160 -160
  1256. package/src/engine/physics/integration/integrate_position.js +97 -97
  1257. package/src/engine/physics/narrowphase/box_box_manifold.js +681 -681
  1258. package/src/engine/physics/narrowphase/box_triangle_contact.js +906 -906
  1259. package/src/engine/physics/narrowphase/capsule_triangle_contact.js +395 -395
  1260. package/src/engine/physics/narrowphase/compute_penetration.js +369 -369
  1261. package/src/engine/physics/narrowphase/decomposition/decompose_to_triangles.js +55 -55
  1262. package/src/engine/physics/narrowphase/decomposition/triangle_buffer_layout.js +37 -37
  1263. package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.js +117 -117
  1264. package/src/engine/physics/narrowphase/narrowphase_step.js +1738 -1738
  1265. package/src/engine/physics/narrowphase/reduce_manifold_contacts.js +74 -74
  1266. package/src/engine/physics/narrowphase/refine_ray_hit.d.ts +12 -11
  1267. package/src/engine/physics/narrowphase/refine_ray_hit.d.ts.map +1 -1
  1268. package/src/engine/physics/narrowphase/refine_ray_hit.js +228 -36
  1269. package/src/engine/physics/narrowphase/sphere_sphere_contact.js +52 -52
  1270. package/src/engine/physics/narrowphase/sphere_triangle_contact.js +138 -138
  1271. package/src/engine/physics/persistence/solver_caches.js +309 -309
  1272. package/src/engine/physics/queries/overlap_shape.js +187 -187
  1273. package/src/engine/physics/queries/raycast.d.ts +7 -4
  1274. package/src/engine/physics/queries/raycast.d.ts.map +1 -1
  1275. package/src/engine/physics/queries/raycast.js +11 -5
  1276. package/src/engine/physics/queries/shape_cast.js +417 -417
  1277. package/src/engine/physics/solver/apply_impulse_to_body.js +86 -86
  1278. package/src/engine/physics/solver/friction_cone.js +37 -37
  1279. package/src/engine/physics/solver/solve_contacts.js +1 -1
  1280. package/src/engine/platform/WebEnginePlatform.d.ts.map +1 -1
  1281. package/src/engine/platform/WebEnginePlatform.js +1 -2
  1282. package/src/engine/scene/SerializedScene.d.ts +2 -2
  1283. package/src/engine/scene/SerializedScene.d.ts.map +1 -1
  1284. package/src/engine/scene/transitionToScene.js +121 -121
  1285. package/src/engine/simulation/Ticker.d.ts.map +1 -1
  1286. package/src/engine/simulation/Ticker.js +33 -0
  1287. package/src/engine/sound/ecs/audio/LiveEmitterSet.js +345 -345
  1288. package/src/engine/sound/ecs/audio/SpatialAudioIndex.js +140 -140
  1289. package/src/engine/sound/simulation/AcousticSimulator.js +646 -646
  1290. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +432 -432
  1291. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +250 -250
  1292. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +322 -322
  1293. package/src/engine/sound/simulation/README.md +277 -277
  1294. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +261 -261
  1295. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +121 -121
  1296. package/src/engine/sound/simulation/configureAcousticSimulation.js +48 -48
  1297. package/src/engine/sound/simulation/core/AcousticMedium.js +113 -113
  1298. package/src/engine/sound/simulation/core/AcousticMediumSerializationAdapter.js +27 -27
  1299. package/src/engine/sound/simulation/core/AcousticOccluderIndex.js +312 -312
  1300. package/src/engine/sound/simulation/core/AcousticRegionIndex.js +159 -159
  1301. package/src/engine/sound/simulation/core/AcousticSolution.js +90 -90
  1302. package/src/engine/sound/simulation/core/AcousticSourceState.js +109 -109
  1303. package/src/engine/sound/simulation/core/AcousticVolumeRegion.js +73 -73
  1304. package/src/engine/sound/simulation/core/OcclusionSolver.js +112 -112
  1305. package/src/engine/sound/simulation/core/RayHit.js +50 -50
  1306. package/src/engine/sound/simulation/core/VolumeField.js +149 -149
  1307. package/src/engine/sound/simulation/definition/AcousticDirectivity.js +114 -114
  1308. package/src/engine/sound/simulation/definition/AcousticDirectivitySerializationAdapter.js +30 -30
  1309. package/src/engine/sound/simulation/definition/AcousticMaterial.js +122 -122
  1310. package/src/engine/sound/simulation/definition/AcousticMaterialSerializationAdapter.js +32 -32
  1311. package/src/engine/sound/simulation/ecs/AcousticBody.js +48 -48
  1312. package/src/engine/sound/simulation/ecs/AcousticBodySerializationAdapter.js +34 -34
  1313. package/src/engine/sound/simulation/ecs/AcousticProbeFieldSystem.js +64 -64
  1314. package/src/engine/sound/simulation/ecs/AcousticSimulationSystem.js +75 -75
  1315. package/src/engine/sound/simulation/ecs/AcousticVolume.js +74 -74
  1316. package/src/engine/sound/simulation/ecs/AcousticVolumeSerializationAdapter.js +37 -37
  1317. package/src/engine/sound/simulation/ecs/AcousticVolumeSystem.js +66 -66
  1318. package/src/engine/sound/simulation/probe/AcousticProbeField.js +578 -578
  1319. package/src/engine/sound/simulation/probe/AcousticProbeFieldSerializationAdapter.js +60 -60
  1320. package/src/engine/sound/simulation/probe/ProbeFieldPathingSolution.js +64 -64
  1321. package/src/engine/sound/simulation/probe/ProbeVisibilityRecheck.js +132 -132
  1322. package/src/engine/sound/simulation/probe/acoustic_probe_transfer.js +103 -103
  1323. package/src/engine/sound/simulation/probe/acoustic_trace_energy.js +136 -136
  1324. package/src/engine/sound/simulation/probe/bakeProbeField.js +169 -169
  1325. package/src/engine/sound/simulation/probe/bakeProbeReflectors.js +110 -110
  1326. package/src/engine/sound/simulation/probe/bakeReverbBands.js +110 -110
  1327. package/src/engine/sound/simulation/probe/bakeVisibility.js +148 -148
  1328. package/src/engine/sound/simulation/probe/echogram_band_rt60.js +83 -83
  1329. package/src/engine/sound/simulation/probe/probe_delaunay_edges.js +215 -215
  1330. package/src/engine/sound/simulation/probe/probe_densify_portals.js +140 -140
  1331. package/src/engine/sound/simulation/probe/probe_detect_portals.js +196 -196
  1332. package/src/engine/sound/simulation/probe/probe_edge_key.js +38 -38
  1333. package/src/engine/sound/simulation/probe/probe_edge_visible.js +41 -41
  1334. package/src/engine/sound/simulation/probe/probe_place_sdf_cover.js +82 -82
  1335. package/src/engine/sound/simulation/probe/probe_refine_connectivity.js +181 -181
  1336. package/src/engine/sound/simulation/probe/probe_sdf_grid.js +171 -171
  1337. package/src/engine/sound/simulation/probe/probe_visibility_augment.js +146 -146
  1338. package/src/engine/sound/simulation/probe/probe_visibility_bridge_components.js +167 -167
  1339. package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +354 -354
  1340. package/src/engine/sound/simulation/render/ProbeReverbRenderer.js +231 -231
  1341. package/src/engine/sound/simulation/render/foaReverbImpulseResponse.js +105 -105
  1342. package/src/engine/sound/simulation/render/reverbImpulseResponse.js +66 -66
  1343. package/src/engine/sound/simulation/render/reverb_band_tails.js +93 -93
  1344. package/src/engine/sound/simulation/serialization/populateAcousticSerializationRegistry.js +25 -25
  1345. package/src/engine/sound/sopra/README.md +643 -643
  1346. package/src/engine/sound/sopra/SopraEngine.js +432 -432
  1347. package/src/engine/sound/sopra/asset/AssetManagerBufferProvider.js +71 -71
  1348. package/src/engine/sound/sopra/asset/BufferProvider.js +29 -29
  1349. package/src/engine/sound/sopra/asset/StubBufferProvider.js +58 -58
  1350. package/src/engine/sound/sopra/definition/BusDefinition.js +142 -142
  1351. package/src/engine/sound/sopra/definition/BusDefinitionSerializationAdapter.js +54 -54
  1352. package/src/engine/sound/sopra/definition/DuckingRule.js +106 -106
  1353. package/src/engine/sound/sopra/definition/DuckingRuleSerializationAdapter.js +31 -31
  1354. package/src/engine/sound/sopra/definition/EventDescription.js +262 -262
  1355. package/src/engine/sound/sopra/definition/EventDescriptionSerializationAdapter.js +55 -55
  1356. package/src/engine/sound/sopra/definition/MixerSnapshot.js +83 -83
  1357. package/src/engine/sound/sopra/definition/MixerSnapshotSerializationAdapter.js +39 -39
  1358. package/src/engine/sound/sopra/definition/ParameterDefinition.js +117 -117
  1359. package/src/engine/sound/sopra/definition/ParameterDefinitionSerializationAdapter.js +31 -31
  1360. package/src/engine/sound/sopra/definition/VoiceStealMode.js +18 -18
  1361. package/src/engine/sound/sopra/definition/clip/AbstractAudioClip.js +109 -109
  1362. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClip.js +185 -185
  1363. package/src/engine/sound/sopra/definition/clip/BlendContainerAudioClipSerializationAdapter.js +59 -59
  1364. package/src/engine/sound/sopra/definition/clip/ContainerAudioClip.js +128 -128
  1365. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClip.js +226 -226
  1366. package/src/engine/sound/sopra/definition/clip/RandomContainerAudioClipSerializationAdapter.js +54 -54
  1367. package/src/engine/sound/sopra/definition/clip/SampleAudioClip.js +191 -191
  1368. package/src/engine/sound/sopra/definition/clip/SampleAudioClipSerializationAdapter.js +39 -39
  1369. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClip.js +79 -79
  1370. package/src/engine/sound/sopra/definition/clip/SequenceContainerAudioClipSerializationAdapter.js +42 -42
  1371. package/src/engine/sound/sopra/definition/clip/SilenceAudioClip.js +77 -77
  1372. package/src/engine/sound/sopra/definition/clip/SilenceAudioClipSerializationAdapter.js +27 -27
  1373. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts +5 -0
  1374. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.d.ts.map +1 -1
  1375. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClip.js +125 -125
  1376. package/src/engine/sound/sopra/definition/clip/SwitchContainerAudioClipSerializationAdapter.js +41 -41
  1377. package/src/engine/sound/sopra/definition/effect/AbstractAudioEffect.js +24 -24
  1378. package/src/engine/sound/sopra/definition/effect/CompressorEffect.js +120 -120
  1379. package/src/engine/sound/sopra/definition/effect/CompressorEffectSerializationAdapter.js +31 -31
  1380. package/src/engine/sound/sopra/definition/effect/EqEffect.js +128 -128
  1381. package/src/engine/sound/sopra/definition/effect/EqEffectSerializationAdapter.js +29 -29
  1382. package/src/engine/sound/sopra/definition/effect/ReverbEffect.js +113 -113
  1383. package/src/engine/sound/sopra/definition/effect/ReverbEffectSerializationAdapter.js +25 -25
  1384. package/src/engine/sound/sopra/runtime/BusGraph.js +231 -231
  1385. package/src/engine/sound/sopra/runtime/ParameterStore.js +98 -98
  1386. package/src/engine/sound/sopra/runtime/SopraPlaybackContext.js +68 -68
  1387. package/src/engine/sound/sopra/runtime/Voice.js +145 -145
  1388. package/src/engine/sound/sopra/runtime/VoiceManager.js +136 -136
  1389. package/src/engine/sound/sopra/runtime/VoicePool.js +17 -17
  1390. package/src/engine/sound/sopra/serialization/populateSopraSerializationRegistry.js +42 -42
  1391. package/src/engine/sound/sopra/serialization/sopraJSON.js +99 -99
  1392. package/src/engine/sound/sopra/serialization/sopraSerializationHarness.js +49 -49
  1393. package/src/engine/sound/sopra/util/MockAudioContext.js +224 -224
  1394. package/src/engine/sound/sopra/util/fadeOutAndStop.js +60 -60
  1395. package/src/engine/ui/DraggableAspect.js +115 -115
  1396. package/src/engine/ui/apply_pointer_tilt_3d.js +50 -50
  1397. package/src/generation/COORDINATES.md +54 -54
  1398. package/src/generation/GridGenerationResource.js +24 -24
  1399. package/src/generation/GridTaskGroup.js +214 -214
  1400. package/src/generation/REVIEW_01_ACTION_PLAN.md +628 -628
  1401. package/src/generation/automata/CaveGeneratorCellularAutomata.js +79 -79
  1402. package/src/generation/automata/CellularAutomata.js +22 -22
  1403. package/src/generation/compute_writes_union.js +25 -25
  1404. package/src/generation/filtering/CellFilter.js +117 -117
  1405. package/src/generation/filtering/core/CellFilterBinaryOperation.js +37 -37
  1406. package/src/generation/filtering/core/CellFilterOperationTertiary.js +43 -43
  1407. package/src/generation/filtering/core/CellFilterUnaryOperation.js +29 -29
  1408. package/src/generation/filtering/numeric/process/computeCellFilterSobel.js +36 -36
  1409. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.js +42 -42
  1410. package/src/generation/filtering/numeric/util/populateSampler2DFromCellFilter.js +18 -18
  1411. package/src/generation/filtering/numeric/util/write_cell_filter_to_sampler2d.js +47 -47
  1412. package/src/generation/filtering/util/cell_filter_weights_pick.js +54 -54
  1413. package/src/generation/grid/GridData.js +233 -233
  1414. package/src/generation/grid/coords/grid_to_texel.js +10 -10
  1415. package/src/generation/grid/coords/texel_to_grid.js +10 -10
  1416. package/src/generation/grid/generation/GridTaskApplyActionToCells.js +90 -90
  1417. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.js +388 -388
  1418. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.js +127 -127
  1419. package/src/generation/grid/generation/GridTaskSequence.js +58 -58
  1420. package/src/generation/grid/generation/NoopGridTaskGenerator.js +12 -12
  1421. package/src/generation/grid/generation/discrete/GridTaskActionRuleSet.js +48 -48
  1422. package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.js +146 -146
  1423. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.js +540 -540
  1424. package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +222 -222
  1425. package/src/generation/grid/generation/grid/GridTaskAddNodesFixed.js +44 -44
  1426. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +614 -614
  1427. package/src/generation/markers/GridCellActionPlaceMarker.js +244 -244
  1428. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +86 -86
  1429. package/src/generation/markers/actions/terrain/MarkerNodeActionPaintTerrain.js +266 -266
  1430. package/src/generation/markers/emitter/MarkerNodeEmitterGridCellAction.js +49 -49
  1431. package/src/generation/placement/GridCellActionTransformNearbyMarkers.js +120 -120
  1432. package/src/generation/placement/action/GridCellAction.js +45 -45
  1433. package/src/generation/placement/action/GridCellActionPlaceTags.js +140 -140
  1434. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.js +89 -89
  1435. package/src/generation/placement/action/random/CellActionSelectRandom.js +69 -69
  1436. package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.js +91 -91
  1437. package/src/generation/placement/action/util/GridCellActionSequence.js +61 -61
  1438. package/src/generation/placement/action/util/GridCellDisplacedAction.js +61 -61
  1439. package/src/generation/rules/cell/CellMatcherRemovalPreservesConnectivity.js +183 -183
  1440. package/src/generation/theme/ThemeEngine.js +666 -666
  1441. package/src/shade/RENDERER_CONTRACT.md +568 -0
  1442. package/src/shade/descriptor/texture/format/gpu_texture_format_info.js +267 -267
  1443. package/src/shade/device/ShadeDeviceFailure.js +104 -104
  1444. package/src/shade/device/ShadeDeviceFailureReason.js +41 -41
  1445. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +255 -255
  1446. package/src/shade/device/mock/REVIEW_2026_08_22.md +527 -527
  1447. package/src/shade/device/mock/SoftwareGPUBindGroup.js +23 -23
  1448. package/src/shade/device/mock/SoftwareGPUBindGroupLayout.js +22 -22
  1449. package/src/shade/device/mock/SoftwareGPUError.js +63 -63
  1450. package/src/shade/device/mock/SoftwareGPUPipeline.js +75 -75
  1451. package/src/shade/device/mock/SoftwareGPUQuerySet.js +113 -113
  1452. package/src/shade/device/mock/SoftwareGPUSampler.js +30 -30
  1453. package/src/shade/device/mock/SoftwareGPUShaderModule.js +32 -32
  1454. package/src/shade/device/mock/SoftwareGPUTextureView.js +22 -22
  1455. package/src/shade/device/mock/SoftwareGPUUncapturedErrorEvent.js +23 -23
  1456. package/src/shade/device/mock/normalize_dynamic_offsets.js +26 -26
  1457. package/src/shade/device/mock/texture_copy.js +287 -287
  1458. package/src/shade/device/timing/GPUTimer.js +285 -285
  1459. package/src/shade/device/timing/GPUTimerArray.js +205 -205
  1460. package/src/shade/playground/add_random_lights.js +49 -49
  1461. package/src/shade/playground/add_random_meshes.js +83 -83
  1462. package/src/shade/playground/animation_prototype.js +508 -508
  1463. package/src/shade/playground/animation_prototype_skinning.js +647 -647
  1464. package/src/shade/playground/animation_prototype_stress.js +765 -765
  1465. package/src/shade/playground/enable_picker.js +59 -59
  1466. package/src/shade/playground/gltf_skinned_prototype.js +560 -560
  1467. package/src/shade/playground/gltf_skinned_stress_prototype.js +387 -387
  1468. package/src/shade/playground/gltf_viewer.js +282 -282
  1469. package/src/shade/playground/load_default_environment.js +19 -19
  1470. package/src/shade/playground/main.js +2727 -2727
  1471. package/src/shade/playground/make_animated_instances.js +117 -117
  1472. package/src/shade/playground/prototype_virtual_texture.js +274 -274
  1473. package/src/shade/playground/prototype_volumetrics_01.js +206 -206
  1474. package/src/shade/playground/sample.js +234 -234
  1475. package/src/shade/playground/sample_load_gltf.js +102 -102
  1476. package/src/shade/playground/spread_node3d_grid.js +19 -19
  1477. package/src/shade/renderer/Renderer.js +2436 -2436
  1478. package/src/shade/renderer/ShadeIndirectLightingMode.js +14 -14
  1479. package/src/shade/renderer/animation/ShadeAnimationChannel.js +414 -414
  1480. package/src/shade/renderer/animation/compute_skinned_mesh_clip_bounding_sphere.js +531 -531
  1481. package/src/shade/renderer/animation/pose/PosePlayback.js +55 -55
  1482. package/src/shade/renderer/animation/pose/pose_evaluate_local.js +179 -179
  1483. package/src/shade/renderer/animation/pose/pose_evaluate_world.js +76 -76
  1484. package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +1024 -1024
  1485. package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.js +79 -79
  1486. package/src/shade/renderer/animation/skinning/chunk_skin_blend_mesh_local.js +56 -56
  1487. package/src/shade/renderer/binding/BindGroupManager.js +282 -282
  1488. package/src/shade/renderer/binding/adapt_cache_capacity.js +25 -25
  1489. package/src/shade/renderer/buffer/GPUBufferAllocator.js +116 -116
  1490. package/src/shade/renderer/buffer/buffer_pool_ops.js +123 -123
  1491. package/src/shade/renderer/buffer/table/GPU_DATABASE_PAGE_SIZE.js +9 -9
  1492. package/src/shade/renderer/buffer/table/GPU_DATABASE_UPLOAD_BUFFER_LIMIT.js +8 -8
  1493. package/src/shade/renderer/buffer/table/PageBufferPool.js +71 -71
  1494. package/src/shade/renderer/buffer/table/PageSlotAllocator.js +95 -95
  1495. package/src/shade/renderer/camera/Camera.js +281 -281
  1496. package/src/shade/renderer/camera/GPUCameraContext.js +233 -233
  1497. package/src/shade/renderer/camera/orbital/README.md +84 -84
  1498. package/src/shade/renderer/deferred/shader_composite_volumetrics.js +75 -75
  1499. package/src/shade/renderer/dynamic/DYNAMIC_MESH_VERTEX.js +25 -25
  1500. package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.js +342 -342
  1501. package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +167 -167
  1502. package/src/shade/renderer/dynamic/shader_dynamic_mesh.js +170 -170
  1503. package/src/shade/renderer/extension/FrameContext.js +263 -263
  1504. package/src/shade/renderer/extension/FramePhase.js +104 -104
  1505. package/src/shade/renderer/extension/FrameRecord.js +126 -126
  1506. package/src/shade/renderer/extension/GBufferTextures.js +83 -83
  1507. package/src/shade/renderer/extension/PresentTarget.js +34 -34
  1508. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +918 -918
  1509. package/src/shade/renderer/extension/RenderExtension.js +69 -69
  1510. package/src/shade/renderer/extension/RenderExtensionRegistry.js +319 -319
  1511. package/src/shade/renderer/extension/SceneColor.js +40 -40
  1512. package/src/shade/renderer/extension/ViewTextures.js +78 -78
  1513. package/src/shade/renderer/fow/GPUFogOfWarRenderer.js +182 -182
  1514. package/src/shade/renderer/geometry/Geometry.js +608 -608
  1515. package/src/shade/renderer/geometry/geometry_build_from_meshlet_geometry.js +342 -342
  1516. package/src/shade/renderer/geometry/meshlet_geometry_transfer.js +41 -41
  1517. package/src/shade/renderer/geometry/primitives/make_box_geometry.js +153 -153
  1518. package/src/shade/renderer/geometry/primitives/make_cylinder_geometry.js +240 -240
  1519. package/src/shade/renderer/geometry/primitives/make_plane_geometry.js +145 -145
  1520. package/src/shade/renderer/geometry/primitives/make_polyhedron_geometry.js +327 -327
  1521. package/src/shade/renderer/geometry/primitives/make_torus_geometry.js +107 -107
  1522. package/src/shade/renderer/geometry/primitives/make_torus_knot_geometry.js +165 -165
  1523. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +607 -607
  1524. package/src/shade/renderer/geometry/virtual/build/VGeoBuildOptions.js +66 -66
  1525. package/src/shade/renderer/geometry/virtual/build/VGeoBuildResult.js +32 -32
  1526. package/src/shade/renderer/geometry/virtual/build/VGeoFaceGraph.js +103 -103
  1527. package/src/shade/renderer/geometry/virtual/build/VGeoGatheredFaces.js +25 -25
  1528. package/src/shade/renderer/geometry/virtual/build/VGeoLevel.js +33 -33
  1529. package/src/shade/renderer/geometry/virtual/build/VGeoLevelOptions.js +62 -62
  1530. package/src/shade/renderer/geometry/virtual/build/VGeoLevelSummary.js +49 -49
  1531. package/src/shade/renderer/geometry/virtual/build/VGeoSubmesh.js +20 -20
  1532. package/src/shade/renderer/geometry/virtual/build/VirtualGeometryMesh.js +214 -214
  1533. package/src/shade/renderer/geometry/virtual/build/gltf/GltfByteSource.js +122 -122
  1534. package/src/shade/renderer/geometry/virtual/build/gltf/GltfCollectReport.js +29 -29
  1535. package/src/shade/renderer/geometry/virtual/build/gltf/GltfDocument.js +210 -210
  1536. package/src/shade/renderer/geometry/virtual/build/gltf/GltfGeometry.js +48 -48
  1537. package/src/shade/renderer/geometry/virtual/build/gltf/GltfGeometryInstance.js +25 -25
  1538. package/src/shade/renderer/geometry/virtual/build/gltf/GltfGeometrySelection.js +28 -28
  1539. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_collect_geometries.js +296 -296
  1540. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_open_document.js +166 -166
  1541. package/src/shade/renderer/geometry/virtual/build/gltf/gltf_read_geometry.js +199 -199
  1542. package/src/shade/renderer/geometry/virtual/build/vgeo_assemble_pages.js +173 -173
  1543. package/src/shade/renderer/geometry/virtual/build/vgeo_bounding_sphere.js +28 -28
  1544. package/src/shade/renderer/geometry/virtual/build/vgeo_build.js +200 -200
  1545. package/src/shade/renderer/geometry/virtual/build/vgeo_build_levels.js +1786 -1786
  1546. package/src/shade/renderer/geometry/virtual/build/vgeo_build_page_nodes.js +157 -157
  1547. package/src/shade/renderer/geometry/virtual/build/vgeo_build_root_group.js +26 -26
  1548. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_normals.js +75 -75
  1549. package/src/shade/renderer/geometry/virtual/build/vgeo_compute_vertex_tangents.js +143 -143
  1550. package/src/shade/renderer/geometry/virtual/build/vgeo_containing_sphere.js +44 -44
  1551. package/src/shade/renderer/geometry/virtual/build/vgeo_extract_submesh.js +41 -41
  1552. package/src/shade/renderer/geometry/virtual/build/vgeo_gather_faces.js +71 -71
  1553. package/src/shade/renderer/geometry/virtual/build/vgeo_graph_components.js +123 -123
  1554. package/src/shade/renderer/geometry/virtual/build/vgeo_narrow_indices.js +26 -26
  1555. package/src/shade/renderer/geometry/virtual/build/vgeo_normalize_source.js +112 -112
  1556. package/src/shade/renderer/geometry/virtual/build/vgeo_partition_graph.js +56 -56
  1557. package/src/shade/renderer/geometry/virtual/build/vgeo_sphere_inflate_to_contain.js +70 -70
  1558. package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set.js +187 -187
  1559. package/src/shade/renderer/geometry/virtual/build/vgeo_split_face_set_packed.js +207 -207
  1560. package/src/shade/renderer/geometry/virtual/format/VGEO_DEFECT.js +18 -18
  1561. package/src/shade/renderer/geometry/virtual/format/VGeoDefect.js +38 -38
  1562. package/src/shade/renderer/geometry/virtual/format/VGeoWriteOptions.js +64 -64
  1563. package/src/shade/renderer/geometry/virtual/format/attribute/VGEO_ATTRIBUTE.js +13 -13
  1564. package/src/shade/renderer/geometry/virtual/format/attribute/VGEO_ATTRIBUTES.js +50 -50
  1565. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attribute_allocate.js +28 -28
  1566. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attribute_mask.js +23 -23
  1567. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_attributes_read.js +31 -31
  1568. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_copy_vertex.js +32 -32
  1569. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_declare.js +46 -46
  1570. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_like.js +19 -19
  1571. package/src/shade/renderer/geometry/virtual/format/attribute/vgeo_layers_test_fixtures.js +27 -27
  1572. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_asset_id_preimage.js +62 -62
  1573. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_asset_id.js +13 -13
  1574. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_directory_block_checksum.js +41 -41
  1575. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_frame_checksum.js +41 -41
  1576. package/src/shade/renderer/geometry/virtual/format/checksum/vgeo_compute_header_checksum.js +25 -25
  1577. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_OFFSET.js +20 -20
  1578. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_CLUSTER_RECORD_SIZE.js +5 -5
  1579. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_MAX_CHILD_REF.js +5 -5
  1580. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_MAX_CLUSTER_TRIANGLE_COUNT.js +5 -5
  1581. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_MAX_CLUSTER_VERTEX_COUNT.js +5 -5
  1582. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_NO_CHILD.js +5 -5
  1583. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_NO_GROUP.js +5 -5
  1584. package/src/shade/renderer/geometry/virtual/format/cluster/VGEO_SAME_PAGE.js +6 -6
  1585. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryCluster.js +81 -81
  1586. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryGroup.js +37 -37
  1587. package/src/shade/renderer/geometry/virtual/format/dag/VirtualGeometryPageNode.js +55 -55
  1588. package/src/shade/renderer/geometry/virtual/format/directory/VGEO_DIRECTORY_BLOCK_RECORDS.js +5 -5
  1589. package/src/shade/renderer/geometry/virtual/format/directory/VGEO_DIRECTORY_FLAG_ROOT_PAGE.js +5 -5
  1590. package/src/shade/renderer/geometry/virtual/format/directory/VGEO_DIRECTORY_RECORD_SIZE.js +5 -5
  1591. package/src/shade/renderer/geometry/virtual/format/directory/vgeo_directory_block_count.js +12 -12
  1592. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CHILD_OFFSET.js +11 -11
  1593. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CHILD_TABLE_ENTRY_SIZE.js +5 -5
  1594. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_LZ4.js +11 -11
  1595. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_CODEC_RAW.js +5 -5
  1596. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_FRAME_ALIGNMENT.js +5 -5
  1597. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_FRAME_HEADER_SIZE.js +5 -5
  1598. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_FRAME_OFFSET.js +13 -13
  1599. package/src/shade/renderer/geometry/virtual/format/frame/VGEO_PAGE_MAGIC.js +5 -5
  1600. package/src/shade/renderer/geometry/virtual/format/frame/VGeoFrameBlob.js +21 -21
  1601. package/src/shade/renderer/geometry/virtual/format/frame/VGeoFrameExtent.js +59 -59
  1602. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_codec_name.js +27 -27
  1603. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_decode_frame_blob.js +84 -84
  1604. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_encode_frame_blob.js +56 -56
  1605. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_frame_decode_bound.js +35 -35
  1606. package/src/shade/renderer/geometry/virtual/format/frame/vgeo_scan_frames.js +74 -74
  1607. package/src/shade/renderer/geometry/virtual/format/header/VGEO_FORMAT_VERSION.js +6 -6
  1608. package/src/shade/renderer/geometry/virtual/format/header/VGEO_HASH_ALGO_XXH3.js +5 -5
  1609. package/src/shade/renderer/geometry/virtual/format/header/VGEO_HEADER_OFFSET.js +31 -31
  1610. package/src/shade/renderer/geometry/virtual/format/header/VGEO_HEADER_SIZE.js +5 -5
  1611. package/src/shade/renderer/geometry/virtual/format/header/VGEO_LEVEL_OFFSET.js +20 -20
  1612. package/src/shade/renderer/geometry/virtual/format/header/VGEO_LEVEL_RECORD_SIZE.js +9 -9
  1613. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MAGIC.js +5 -5
  1614. package/src/shade/renderer/geometry/virtual/format/header/VGEO_MIN_READER_VERSION.js +5 -5
  1615. package/src/shade/renderer/geometry/virtual/format/header/VGEO_PAYLOAD_ENCODING_SHADE_MESHLET_V1.js +5 -5
  1616. package/src/shade/renderer/geometry/virtual/format/header/VGeoLevelRecord.js +41 -41
  1617. package/src/shade/renderer/geometry/virtual/format/page/VGEO_GROUP_RECORD_SIZE.js +5 -5
  1618. package/src/shade/renderer/geometry/virtual/format/page/VGEO_MAX_GROUP_CLUSTER_COUNT.js +6 -6
  1619. package/src/shade/renderer/geometry/virtual/format/page/VGEO_METRIC_OFFSET.js +21 -21
  1620. package/src/shade/renderer/geometry/virtual/format/page/VGEO_METRIC_SIZE.js +5 -5
  1621. package/src/shade/renderer/geometry/virtual/format/page/VGEO_NODE_FANOUT.js +9 -9
  1622. package/src/shade/renderer/geometry/virtual/format/page/VGEO_NODE_FLAG_LEAF.js +5 -5
  1623. package/src/shade/renderer/geometry/virtual/format/page/VGEO_NODE_OFFSET.js +10 -10
  1624. package/src/shade/renderer/geometry/virtual/format/page/VGEO_NODE_RECORD_SIZE.js +5 -5
  1625. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_HEADER_SIZE.js +5 -5
  1626. package/src/shade/renderer/geometry/virtual/format/page/VGEO_PAGE_OFFSET.js +16 -16
  1627. package/src/shade/renderer/geometry/virtual/format/payload/VGEO_ENCODING_FLAGS_MASK.js +6 -6
  1628. package/src/shade/renderer/geometry/virtual/format/payload/VGeoEncodedPayload.js +18 -18
  1629. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_encode_cluster_payload.js +200 -200
  1630. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_payload_attribute_offset.js +39 -39
  1631. package/src/shade/renderer/geometry/virtual/format/payload/vgeo_payload_size.js +20 -20
  1632. package/src/shade/renderer/geometry/virtual/format/prototypeVGEOFormatViewer.js +2063 -2063
  1633. package/src/shade/renderer/geometry/virtual/format/vgeo_validate_container.js +1622 -1622
  1634. package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +485 -485
  1635. package/src/shade/renderer/gpu_primitive/sort/ffx/graph_radix_sort.js +115 -115
  1636. package/src/shade/renderer/gpu_primitive/sort/one_sweep/verify_radix_sort_one_sweep.js +110 -110
  1637. package/src/shade/renderer/light/environment/octahedral_resample_kernel.js +50 -50
  1638. package/src/shade/renderer/light/environment/octahedral_uv_to_direction.js +30 -30
  1639. package/src/shade/renderer/light/environment/resample_cube_to_octahedral.js +157 -157
  1640. package/src/shade/renderer/light/make_sunlight.js +35 -35
  1641. package/src/shade/renderer/light/model/io/light_record_point.js +39 -39
  1642. package/src/shade/renderer/loader/gltf/GLTF_PRIMITIVE_MODE.js +23 -23
  1643. package/src/shade/renderer/loader/gltf/MESHOPT_COMPRESSION_PLAN.md +793 -793
  1644. package/src/shade/renderer/loader/gltf/ext/GltfBufferViewExtension.js +54 -54
  1645. package/src/shade/renderer/loader/gltf/ext/GltfBufferViewExtensionSet.js +109 -109
  1646. package/src/shade/renderer/loader/gltf/ext/gltf_apply_buffer_view_extensions.js +69 -69
  1647. package/src/shade/renderer/loader/gltf/ext/gltf_buffer_view_extensions.js +22 -22
  1648. package/src/shade/renderer/loader/gltf/ext/gltf_geometry_extensions.js +39 -39
  1649. package/src/shade/renderer/loader/gltf/ext/meshopt/MeshoptBufferViewExtension.js +301 -301
  1650. package/src/shade/renderer/loader/gltf/gltf_component_type.js +223 -223
  1651. package/src/shade/renderer/loader/gltf/gltf_node_world_matrices.js +137 -137
  1652. package/src/shade/renderer/loader/gltf/gltf_parse_container.js +241 -241
  1653. package/src/shade/renderer/loader/gltf/gltf_read_accessor.js +294 -294
  1654. package/src/shade/renderer/loader/gltf/gltf_used_image_indices.js +49 -49
  1655. package/src/shade/renderer/loader/gltf/load_gltf.js +1253 -1253
  1656. package/src/shade/renderer/loader/gltf/tiny-gltf.js +646 -646
  1657. package/src/shade/renderer/loader/usd/UsdError.js +33 -33
  1658. package/src/shade/renderer/loader/usd/UsdExtensionRegistry.js +69 -69
  1659. package/src/shade/renderer/loader/usd/load_usd.js +226 -226
  1660. package/src/shade/renderer/loader/usd/parse_usda.js +931 -931
  1661. package/src/shade/renderer/loader/usd/unpack_usdz.js +106 -106
  1662. package/src/shade/renderer/loader/usd/usd_build_scene.js +658 -658
  1663. package/src/shade/renderer/loader/usd/usd_compose_transform.js +258 -258
  1664. package/src/shade/renderer/loader/usd/usd_decode_image.js +384 -384
  1665. package/src/shade/renderer/loader/usd/usd_lz4.js +182 -182
  1666. package/src/shade/renderer/loader/usd/usd_triangulate.js +159 -159
  1667. package/src/shade/renderer/material/ShadeMaterial.d.ts +2 -2
  1668. package/src/shade/renderer/material/ShadeMaterial.js +2 -2
  1669. package/src/shade/renderer/material/standard/fragment_gbuffer.js +334 -334
  1670. package/src/shade/renderer/material/standard/fragment_gbuffer_vt.js +169 -169
  1671. package/src/shade/renderer/material/standard/material_gbuffer_vertex.js +45 -45
  1672. package/src/shade/renderer/material/standard_material_to_struct.js +23 -23
  1673. package/src/shade/renderer/particles/prototypeParticleSystem.js +450 -450
  1674. package/src/shade/renderer/particles/runtime/spawn_request_encoding.js +52 -52
  1675. package/src/shade/renderer/pool/TransientResourcePool.js +392 -392
  1676. package/src/shade/renderer/postprocess/bloom/bloom_chain_resolution.js +29 -29
  1677. package/src/shade/renderer/postprocess/bloom/graph_bloom_downsample.js +109 -109
  1678. package/src/shade/renderer/postprocess/bloom/graph_postprocess_bloom.js +155 -155
  1679. package/src/shade/renderer/postprocess/cas/shader_ffx_rcas.js +114 -114
  1680. package/src/shade/renderer/postprocess/dof/DOF_AUTOFOCUS_PARAMS_STRUCT.js +25 -25
  1681. package/src/shade/renderer/postprocess/dof/DOF_FOCUS_STATE_STRUCT.js +23 -23
  1682. package/src/shade/renderer/postprocess/dof/DOF_PRESETS.js +27 -27
  1683. package/src/shade/renderer/postprocess/dof/chunk_dof_coc_band_diameter.js +41 -41
  1684. package/src/shade/renderer/postprocess/dof/chunk_dof_coc_band_radius.js +32 -32
  1685. package/src/shade/renderer/postprocess/dof/chunk_dof_coc_coefficient.js +26 -26
  1686. package/src/shade/renderer/postprocess/dof/compute_dof_autofocus_params.js +64 -64
  1687. package/src/shade/renderer/postprocess/dof/compute_dof_uniform.js +54 -54
  1688. package/src/shade/renderer/postprocess/dof/gather/DOF2_CONFIG.js +91 -91
  1689. package/src/shade/renderer/postprocess/dof/gather/DOF2_PRESETS.js +9 -9
  1690. package/src/shade/renderer/postprocess/dof/gather/DOF2_SETTINGS_STRUCT.js +66 -66
  1691. package/src/shade/renderer/postprocess/dof/gather/DOF2_TEXTURE_FORMAT.js +22 -22
  1692. package/src/shade/renderer/postprocess/dof/gather/DepthOfFieldU.js +292 -292
  1693. package/src/shade/renderer/postprocess/dof/gather/chunk_dof2_coc_to_near_far.js +25 -25
  1694. package/src/shade/renderer/postprocess/dof/gather/chunk_dof2_gather_weight.js +30 -30
  1695. package/src/shade/renderer/postprocess/dof/gather/compute_dof2_uniform.js +54 -54
  1696. package/src/shade/renderer/postprocess/dof/gather/graph_postprocess_dof2.js +194 -194
  1697. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_fill.js +68 -68
  1698. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_gather_far.js +140 -140
  1699. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_gather_near.js +142 -142
  1700. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_recombine.js +99 -99
  1701. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_setup.js +102 -102
  1702. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_tile_dilate.js +75 -75
  1703. package/src/shade/renderer/postprocess/dof/gather/shader_dof2_tile_max.js +73 -73
  1704. package/src/shade/renderer/postprocess/dof/raymarch/DOF_SETTINGS_STRUCT.js +49 -49
  1705. package/src/shade/renderer/postprocess/dof/raymarch/DepthOfField.js +298 -298
  1706. package/src/shade/renderer/postprocess/dof/raymarch/graph_postprocess_dof.js +244 -244
  1707. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_composite.js +91 -91
  1708. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_firefly_cleanup.js +61 -61
  1709. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_prefilter.js +90 -90
  1710. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_raymarch_compute.js +267 -267
  1711. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_slice_compute.js +271 -271
  1712. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_tile_dilate.js +70 -70
  1713. package/src/shade/renderer/postprocess/dof/raymarch/shader_dof_tile_max.js +72 -72
  1714. package/src/shade/renderer/postprocess/dof/shader_dof_autofocus.js +99 -99
  1715. package/src/shade/renderer/postprocess/gtao/generate_magic_square_noise.js +51 -51
  1716. package/src/shade/renderer/postprocess/motion_blur/MotionBlur.js +56 -56
  1717. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +78 -78
  1718. package/src/shade/renderer/postprocess/upscale-dither/UpscaleDither.js +95 -95
  1719. package/src/shade/renderer/postprocess/upscale-dither/fragment_shader_upscale_dither.js +204 -204
  1720. package/src/shade/renderer/rasterize/bucket/construct_primitive_state.js +58 -58
  1721. package/src/shade/renderer/rasterize/fast/graph_rasterize_scene_fast.js +230 -230
  1722. package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.js +278 -278
  1723. package/src/shade/renderer/rasterize/native/oit/chunk_material_side_should_draw.js +26 -26
  1724. package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.js +178 -178
  1725. package/src/shade/renderer/rasterize/standard/graph_rasterize_partial_opaque.js +235 -235
  1726. package/src/shade/renderer/rasterize/standard/graph_rasterize_remaining_opaque.js +208 -208
  1727. package/src/shade/renderer/rasterize/standard/graph_rasterize_scene.js +206 -206
  1728. package/src/shade/renderer/scene/DynamicMesh.js +70 -70
  1729. package/src/shade/renderer/scene/DynamicMeshBatch.js +90 -90
  1730. package/src/shade/renderer/scene/GPUSceneContext.js +901 -901
  1731. package/src/shade/renderer/scene/SceneNodeBinding.js +56 -56
  1732. package/src/shade/renderer/scene/SkinnedMesh.js +55 -55
  1733. package/src/shade/renderer/scene/TransformAuthority.js +33 -33
  1734. package/src/shade/renderer/scene/optimization/deduplicate_geometries.js +38 -38
  1735. package/src/shade/renderer/scene/optimization/deduplicate_images.js +93 -93
  1736. package/src/shade/renderer/scene/optimization/geometry/internal/match_refit_validate.js +127 -127
  1737. package/src/shade/renderer/scene/optimization/geometry/internal/match_solve_transform.js +492 -492
  1738. package/src/shade/renderer/scene/optimization/optimize_texture_set.js +81 -81
  1739. package/src/shade/renderer/scene/optimization/source_to_sampler2d.js +21 -21
  1740. package/src/shade/renderer/scene/serialization/STANDARD_MATERIAL_SERIALIZED_BYTE_SIZE.js +12 -12
  1741. package/src/shade/renderer/shader/chunk/geometry/quaternion/dual/chunk_dual_quat_transform_point.js +26 -26
  1742. package/src/shade/renderer/shader/chunk/noise/chunk_interleaved_gradient_noise.js +20 -20
  1743. package/src/shade/renderer/shader/chunk/spherical_harmonics/dering/chunk_sh2_dering_optimize_positive.js +61 -61
  1744. package/src/shade/renderer/shader/chunk/texture/chunk_texture_filter_fxaa_lite.js +225 -225
  1745. package/src/shade/renderer/shader/chunk/texture/dither/chunk_dither_color_8bit_gradient_noise.js +25 -25
  1746. package/src/shade/renderer/shadow/map/DirectionalLightShadowmap.js +384 -384
  1747. package/src/shade/renderer/shadow/map/PointLightShadowmap.js +105 -105
  1748. package/src/shade/renderer/shadow/map/SpotLightShadowmap.js +63 -63
  1749. package/src/shade/renderer/shadow/map/TetrahedronPointLightShadowmap.js +89 -89
  1750. package/src/shade/renderer/shadow/map/shadowmap_update_score.js +232 -232
  1751. package/src/shade/renderer/texture/GPUTextureAllocator.js +85 -85
  1752. package/src/shade/renderer/texture/texture_pool_ops.js +171 -171
  1753. package/src/shade/renderer/texture/virtual/PageTableQuadAllocator.js +253 -253
  1754. package/src/shade/renderer/texture/virtual/README.md +276 -276
  1755. package/src/shade/renderer/texture/virtual/VTPageTable.js +330 -330
  1756. package/src/shade/renderer/texture/virtual/VTPhysicalCache.js +349 -349
  1757. package/src/shade/renderer/texture/virtual/VT_CONSTANTS.js +154 -154
  1758. package/src/shade/renderer/texture/virtual/VT_STACK_INFO_STRUCT.js +20 -20
  1759. package/src/shade/renderer/texture/virtual/VirtualTextureManager.js +1276 -1276
  1760. package/src/shade/renderer/texture/virtual/VirtualTextureStack.js +106 -106
  1761. package/src/shade/renderer/texture/virtual/build_chunk_vt_lookup.js +150 -150
  1762. package/src/shade/renderer/texture/virtual/build_shader_vt_feedback.js +232 -232
  1763. package/src/shade/renderer/texture/virtual/chunk_vt_request_key.js +28 -28
  1764. package/src/shade/renderer/texture/virtual/source/VTSourceImage.js +207 -207
  1765. package/src/shade/renderer/texture/virtual/source/VTSourceProcedural.js +135 -135
  1766. package/src/shade/renderer/texture/virtual/source/VTSourceTiled.js +132 -132
  1767. package/src/shade/renderer/water/GPUWaterRenderer.js +167 -167
  1768. package/src/shade/renderer/water/shader_water.js +246 -246
  1769. package/src/shade/renderer/water/water_height_texture_from_sampler.js +56 -56
  1770. package/src/shade/vitest.setup.mjs +89 -89
  1771. package/src/shade/wgsl/validate_wgsl_source.js +316 -316
  1772. package/src/view/controller/controls/NumericIntervalControl.js +90 -90
  1773. package/src/view/controller/controls/Vector2Control.js +83 -83
  1774. package/src/view/controller/controls/Vector3Control.js +90 -90
  1775. package/src/view/elements/Group.js +56 -56
  1776. package/src/view/elements/drawCheckers.js +33 -33
  1777. package/src/view/elements/windrose/WindRoseDiagram.js +369 -369
  1778. package/src/view/graphics/WebGLContextFailureView.js +76 -76
  1779. package/src/view/layout/DockPanel.js +51 -51
  1780. package/src/view/layout/SplitView.js +365 -365
  1781. package/src/view/layout/show_popup_menu.js +81 -81
  1782. package/src/view/minimap/MinimapCanvasView.js +411 -411
  1783. package/src/view/minimap/MinimapImageCache.js +88 -88
  1784. package/src/view/minimap/MinimapMarkerCollection.d.ts +0 -1
  1785. package/src/view/minimap/MinimapMarkerCollection.d.ts.map +1 -1
  1786. package/src/view/minimap/MinimapMarkerCollection.js +180 -180
  1787. package/src/view/minimap/dom/MinimapCameraView.js +206 -206
  1788. package/src/view/minimap/minimap_focus_area.js +97 -97
  1789. package/editor/process/symbolic/SocketsSymbolicDisplay.js +0 -192
  1790. package/src/core/geom/3d/topology/struct/binary/io/moved_tests.txt +0 -37
  1791. package/src/engine/ecs/attachment/Attachment.d.ts +0 -40
  1792. package/src/engine/ecs/attachment/Attachment.d.ts.map +0 -1
  1793. package/src/engine/ecs/attachment/Attachment.js +0 -57
  1794. package/src/engine/ecs/attachment/AttachmentBinding.d.ts +0 -28
  1795. package/src/engine/ecs/attachment/AttachmentBinding.d.ts.map +0 -1
  1796. package/src/engine/ecs/attachment/AttachmentBinding.js +0 -41
  1797. package/src/engine/ecs/attachment/AttachmentSystem.d.ts +0 -61
  1798. package/src/engine/ecs/attachment/AttachmentSystem.d.ts.map +0 -1
  1799. package/src/engine/ecs/attachment/AttachmentSystem.js +0 -307
  1800. package/src/engine/ecs/attachment/BoneAttachmentBinding.d.ts +0 -27
  1801. package/src/engine/ecs/attachment/BoneAttachmentBinding.d.ts.map +0 -1
  1802. package/src/engine/ecs/attachment/BoneAttachmentBinding.js +0 -69
  1803. package/src/engine/ecs/attachment/TransformAttachmentBinding.d.ts +0 -4
  1804. package/src/engine/ecs/attachment/TransformAttachmentBinding.d.ts.map +0 -1
  1805. package/src/engine/ecs/attachment/TransformAttachmentBinding.js +0 -51
  1806. package/src/engine/ecs/sockets/AttachmentSocket.d.ts +0 -32
  1807. package/src/engine/ecs/sockets/AttachmentSocket.d.ts.map +0 -1
  1808. package/src/engine/ecs/sockets/AttachmentSocket.js +0 -60
  1809. package/src/engine/ecs/sockets/AttachmentSocketType.d.ts +0 -6
  1810. package/src/engine/ecs/sockets/AttachmentSocketType.d.ts.map +0 -1
  1811. package/src/engine/ecs/sockets/AttachmentSocketType.js +0 -8
  1812. package/src/engine/ecs/sockets/AttachmentSockets.d.ts +0 -57
  1813. package/src/engine/ecs/sockets/AttachmentSockets.d.ts.map +0 -1
  1814. package/src/engine/ecs/sockets/AttachmentSockets.js +0 -130
  1815. package/src/engine/ecs/sockets/BoneAttachmentSocket.d.ts +0 -29
  1816. package/src/engine/ecs/sockets/BoneAttachmentSocket.d.ts.map +0 -1
  1817. package/src/engine/ecs/sockets/BoneAttachmentSocket.js +0 -56
  1818. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts +0 -6
  1819. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts.map +0 -1
  1820. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.js +0 -19
  1821. package/src/shade/renderer/animation/_dump_resolve.d.mts +0 -2
  1822. package/src/shade/renderer/animation/_dump_resolve.d.mts.map +0 -1
  1823. package/src/shade/renderer/animation/_dump_resolve.mjs +0 -5
@@ -1,740 +1,740 @@
1
- # Correctness review — `engine/graphics` (ecs, render, shaders, camera, root)
2
-
3
- Scope: every non-spec, non-prototype source file under
4
- `meep/src/engine/graphics/{ecs,render,shaders,camera}` plus the files directly in
5
- `meep/src/engine/graphics/`. three.js r136.
6
-
7
- ---
8
-
9
- ### GFXR-1 `Camera.projectWorldPointOntoNearPlane` projects onto the RIGHT frustum plane
10
- - **Severity**: MAJOR
11
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/camera/Camera.js:279`
12
- - **Defect**: The method takes `scratch_frustum.planes[0]` as "the near plane". `frustum_from_camera`
13
- fills the frustum via three's `Frustum.setFromProjectionMatrix`, whose plane order is
14
- `[0]=right, [1]=left, [2]=bottom, [3]=top, [4]=far, [5]=near`. Index 0 is the RIGHT side plane.
15
- The sibling file `ecs/camera/pp/PerfectPanner.js:9-10` states the correct convention
16
- (`NEAR_PLANE_INDEX = 5; FAR_PLANE_INDEX = 4;`), so the codebase already knows the ordering.
17
- - **Failure scenario**: Camera at the origin looking down `-Z`, 45° fov, near 0.1. Call
18
- `camera.projectWorldPointOntoNearPlane(0, 0, -10, out)`. Expected `out ≈ (0, 0, -0.1)` — the point
19
- pushed onto the near plane in front of the eye. Actual: the point is projected onto the right
20
- side plane of the frustum, landing several units off to the camera's right at a depth of 10.
21
- Any UI/marker/clamping code built on this public method places its output in the wrong place
22
- entirely, and gets *worse* the further off-axis the input point is.
23
- - **Fix**: `const near = scratch_frustum.planes[5];`
24
- - **Confidence**: Confirmed
25
-
26
- ---
27
-
28
- ### GFXR-2 Orthographic aspect correction uses the wrong delta when the viewport narrows
29
- - **Severity**: MAJOR
30
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/camera/set_camera_aspect_ratio.js:35-40`
31
- - **Defect**: The widening branch (`aspectDelta > 0`) grows the horizontal extent by `h * aspectDelta`,
32
- which is exactly right (`w' = w + h·aspect − w = h·aspect`). The narrowing branch grows the vertical
33
- extent by `-h * aspectDelta`, which does **not** solve `w / h' = aspect`. The required delta is
34
- `w/aspect − h`, i.e. `-h * aspectDelta / aspect`.
35
- ```js
36
- } else if (aspectDelta < 0) {
37
- const d = -h * aspectDelta; // <-- missing the /aspect
38
- c.top += d / 2;
39
- c.bottom -= d / 2;
40
- }
41
- ```
42
- - **Failure scenario**: `OrthographicCamera(-10, 10, 10, -10, …)` (square frustum) in a portrait
43
- viewport, `set_camera_aspect_ratio(camera, 100, 200)`. Requested aspect 0.5; the code produces
44
- `top=15, bottom=-15`, i.e. frustum aspect `20/30 = 0.667`. Everything rendered through that camera
45
- is stretched vertically by 33%: circles become ellipses, a square tile is drawn as a rectangle.
46
- Verified numerically. The existing spec (`set_camera_aspect_ratio.spec.js`) only exercises the
47
- widening case, which is why this survives.
48
- - **Fix**: `const d = -h * aspectDelta / aspect;` — or, uniformly for both branches, set
49
- `h' = w / aspect` when `aspect < existingAspect` and `w' = h * aspect` otherwise.
50
- - **Confidence**: Confirmed
51
-
52
- ---
53
-
54
- ### GFXR-3 `CameraSystem` rebuild leaks a THREE camera into the scene on every fov/projection change
55
- - **Severity**: MAJOR
56
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/camera/CameraSystem.js:146-148`
57
- - **Defect**: `rebuild()` replaces `camera.object` with a freshly built THREE camera but never removes
58
- the previous one from `this.scene`. `link()` is the only place that does `this.scene.add(...)`, and
59
- `unlink()` removes only the *current* `camera.object`. The new object gets re-added to the scene by
60
- `GraphicsEngine.render` (`if (scene.children.indexOf(camera) < 0) scene.add(camera)`), so every
61
- rebuild adds one more permanent child. `rebuild` is wired to `camera.fov.onChanged` and
62
- `camera.projectionType.onChanged` (lines 172, 174).
63
- - **Failure scenario**: A fov-zoom effect animates `Camera.fov` (a `Vector1`, observable precisely so
64
- it can be animated) at 60 Hz. Each frame builds a new `THREE.PerspectiveCamera` and appends it to
65
- `graphics.scene.children`, which is never pruned. After one minute `scene.children` holds ~3600 dead
66
- cameras: unbounded memory growth, an O(n) `scene.children.indexOf(camera)` in `GraphicsEngine.render`
67
- every frame, and an O(n) root walk in `NormalFrameBuffer.render`, which traverses `scene.children`
68
- each frame. Frame time degrades continuously for as long as the zoom runs.
69
- - **Fix**: In `rebuild()`, capture the old object, `this.scene.remove(old)` and
70
- `this.scene.add(camera.object)` after building. Better still, do not rebuild for a fov change — set
71
- `camera.object.fov` and call `updateProjectionMatrix()`; only `projectionType` genuinely needs a new
72
- object.
73
- - **Confidence**: Confirmed
74
-
75
- ---
76
-
77
- ### GFXR-4 `Trail2DSystem` seeds the ribbon at a different point from where the head is driven
78
- - **Severity**: MAJOR
79
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/trail2d/Trail2DSystem.js:156-158` vs `:234-235`
80
- - **Defect**: Build-time seeding adds the offset in world space, ignoring the entity's rotation and
81
- scale:
82
- ```js
83
- const position_x = trail_offset.x + transform_position.x; // __build_trail
84
- ```
85
- while the per-frame head update carries the offset through the entity's full transform:
86
- ```js
87
- newPosition.copy(trail.offset);
88
- newPosition.applyMatrix4(transform.matrix); // updateTrailEntity
89
- ```
90
- The sibling `Trail3DSystem` has exactly this invariant written down and enforced via a shared
91
- `compute_head_position` helper (`ecs/trail3d/Trail3DSystem.js:34-53`), whose doc comment describes
92
- the resulting artifact verbatim. `Trail2DSystem` was not given the same treatment.
93
- - **Failure scenario**: A projectile entity with `Trail2D.offset = (0, 0, -1)` (trail emitted from the
94
- tail) rotated 90° about Y so it flies along `+X`. `__build_trail` seeds every ribbon point at
95
- `position + (0, 0, -1)`; the first `updateTrailEntity` puts the head at `position + (-1, 0, 0)`.
96
- The first rendered frame contains a ~1.41-unit ribbon streak pointing in a direction that has
97
- nothing to do with the projectile's travel — a visible flash at every spawn.
98
- - **Fix**: Replace lines 156-158 with the same transform-carried computation used in
99
- `updateTrailEntity` (ideally extract a shared `compute_head_position(result, trail, transform)` as
100
- Trail3D does).
101
- - **Confidence**: Confirmed
102
-
103
- ---
104
-
105
- ### GFXR-5 `loadCubeTexture` calls `ImageUtils.loadTextureCube`, removed from three long before r136
106
- - **Severity**: MAJOR
107
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/loadCubeTexture.js:27`
108
- - **Defect**: `const textureCube = ImageUtils.loadTextureCube(urls);` — in the vendored
109
- `three@0.136.0`, `src/extras/ImageUtils.js` declares exactly one member, `static getDataURL(image)`.
110
- There is no `loadTextureCube`.
111
- - **Failure scenario**: Any caller of this exported (public-surface) helper —
112
- `loadCubeTexture('assets/sky', 'png')` — throws `TypeError: ImageUtils.loadTextureCube is not a
113
- function` on the first line that matters, so no cubemap is ever produced. The function cannot
114
- succeed under any input.
115
- - **Fix**: Delete the function, or reimplement it on `CubeTextureLoader`:
116
- `new CubeTextureLoader().load(urls)` (which already returns a `CubeTexture` with
117
- `CubeReflectionMapping`). Note the package already has a working path for this —
118
- `texture/cubemap/load_environment_map.js`, used by `load_and_set_cubemap_v0.js`.
119
- - **Confidence**: Confirmed
120
-
121
- ---
122
-
123
- ### GFXR-6 `Lines` writes `drawRange.count` in the wrong units (twice, two different wrong values)
124
- - **Severity**: MINOR
125
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/Lines.js:61` and `:105`
126
- - **Defect**: `geometry.drawRange.count` is a **vertex** count for a non-indexed geometry. The
127
- geometry stores `capacity * 2` vertices (2 per line segment).
128
- - `setCount(x)` writes `x * 6` — the *float* count of the position attribute.
129
- - `add_line` then overwrites it with `this.count` — the *line* count.
130
- Neither is `count * 2`. Separately, `ensure_capacity` → `build()` replaces `this.geometry` without
131
- disposing the old `BufferGeometry`, and `dispose()` never disposes `this.mesh.material`.
132
- - **Failure scenario**: `const l = new Lines(); l.add_line([0,0,0],[1,0,0],[1,1,1,1]);` and add
133
- `l.mesh` to a scene. `drawRange.count === 1`; `LineSegments` needs vertex pairs, so zero segments
134
- are drawn. Adding 10 lines draws 5. Had `add_line` not overwritten line 61's value, `x*6` would
135
- exceed the allocated `x*2` vertices and WebGL would raise
136
- `INVALID_OPERATION: attempt to access out of range vertices`.
137
- - **Fix**: `this.geometry.drawRange.count = x * 2;` in `setCount`, and delete the redundant
138
- assignment at line 105. Dispose the replaced geometry in `build()`.
139
- - **Confidence**: Confirmed (the class also logs `'feature not fully implemented'`, so this is
140
- acknowledged WIP — listed for completeness)
141
-
142
- ---
143
-
144
- ### GFXR-7 `OutlineRenderer` caches the ID-pass mesh with a frozen geometry reference
145
- - **Severity**: MINOR
146
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/highlight/renderer/OutlineRenderer.js:96-117`
147
- - **Defect**: `obtain_id_mesh` builds the silhouette proxy once per source `Object3D` and caches it in
148
- a module-level `WeakMap`. On a cache hit it refreshes the skinning state (`bindMatrix`,
149
- `bindMatrixInverse`, `skeleton`) but never re-reads `object.geometry`. The equivalent proxy builder
150
- in the same package, `render/utils/ThreeBypassRenderer.js:101`, *does* re-assign
151
- `mesh.geometry = geometry` on every rebuild — the divergence is the tell.
152
- - **Failure scenario**: A highlighted `SGMesh` entity crosses an LOD threshold and
153
- `SGMeshSystem`/`ShadedGeometrySystem` swaps the `Object3D`'s `geometry` for the next LOD. The
154
- visible mesh changes silhouette; the outline keeps tracing the previous LOD's geometry, so the
155
- highlight no longer hugs the object — offset/oversized outline until the object is unhighlighted.
156
- - **Fix**: In `obtain_id_mesh`, after the cache lookup, add `mesh.geometry = object.geometry;`
157
- unconditionally.
158
- - **Confidence**: Likely
159
-
160
- ---
161
-
162
- ### GFXR-8 `Water.updateShaderForTerrain` leaks a full terrain heightmap texture per call
163
- - **Severity**: MINOR
164
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/water/Water.js:138-152`
165
- - **Defect**: A new `DataTexture` wrapping the whole terrain height sampler is allocated and assigned
166
- to `shader.uniforms.tHeightTexture.value`; the texture previously held by that uniform is never
167
- `.dispose()`d. `WaterSystem.link` pushes the component onto `updateQueue`, so this runs once per
168
- link — and `link` reuses the existing `component.__shader` when the component is re-linked
169
- (`WaterSystem.js:164-175`), so each re-link allocates another one.
170
- - **Failure scenario**: Level reload cycles unlink and re-link the Water component. Each cycle uploads
171
- a fresh `R32F` heightmap — for a 1024×1024 terrain that is 4 MB of GPU memory — and orphans the
172
- previous one. Twenty reloads leak ~80 MB of VRAM that three.js will never reclaim, because nothing
173
- holds a reference to call `dispose()` on.
174
- - **Fix**: Capture `const previous = shader.uniforms.tHeightTexture.value;` before the assignment and
175
- `previous?.dispose()` after — the same replace-then-release shape `GraphicsEngine#bake_environment`
176
- already uses for the PMREM target.
177
- - **Confidence**: Confirmed
178
-
179
- ---
180
-
181
- ### GFXR-9 `FrameGraph.exportToJson` conflates resource-node ids with resource-registry ids
182
- - **Severity**: MINOR
183
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/frame_graph/FrameGraph.js:479-508`
184
- - **Defect**: The two id spaces are independent — `_createResourceEntry` numbers entries by
185
- `__resource_registry.length`, `_createResourceNode` numbers nodes by `__resource_nodes.length` —
186
- and `clone_resource` adds nodes without adding entries, so they diverge. The export passes a
187
- registry id where a node id is required:
188
- ```js
189
- const node = this.getResourceNode(entry.resource_id); // registry id -> node lookup
190
- ...
191
- if (pass.reads(entry.resource_id)) // registry id vs node ids in resource_reads
192
- ```
193
- `getResourceNode`'s only protection is an `assert.equal`, which is compiled out in production.
194
- - **Failure scenario**: `FramePassBuilder.write()` calls `graph.clone_resource()` for any write to a
195
- resource the pass did not create — the normal case as soon as two passes touch one resource. In a
196
- three-pass graph where pass B writes pass A's target, node ids run ahead of registry ids and
197
- `exportToJson()` labels resources with another resource's name and emits reader/writer lists that
198
- point at the wrong passes. The rendered GraphViz/JSON diagram misrepresents the pipeline it exists
199
- to debug.
200
- - **Fix**: Track the owning node per entry (or resolve registry id → node by scanning
201
- `__resource_nodes` for `resource_id === entry.resource_id`), and compare `pass.reads/writes` against
202
- node ids, not registry ids.
203
- - **Confidence**: Confirmed
204
-
205
- ---
206
-
207
- ### GFXR-10 `PathDisplayContext.__build` aborts the whole build on one unknown spec type
208
- - **Severity**: MINOR
209
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/path/PathDisplaySystem.js:135-139`
210
- - **Defect**: Inside the loop over `display.specs`, an unrecognised `spec.type` logs a warning and
211
- `return`s out of the entire method — skipping the remaining specs, the `ParentEntity` attachment
212
- loop, `__build_existing_entities()`, and the `PathDisplayEvents.BuildComplete` dispatch. The
213
- neighbouring failure path in the same loop (a builder that throws, lines 141-146) correctly
214
- `catch`es and continues.
215
- - **Failure scenario**: A `PathDisplay` with two specs, `[Ribbon, <stale type from an old save>]`. The
216
- Ribbon builder runs and pushes its entities into `__owned_entities`, then the second spec hits the
217
- `return`. Those entities are never `build(ecd)`-ed into the dataset, so the path renders nothing at
218
- all — and `BuildComplete` never fires, so anything awaiting that event waits forever.
219
- - **Fix**: `continue;` instead of `return;`.
220
- - **Confidence**: Confirmed
221
-
222
- ---
223
-
224
- ### GFXR-11 `ShadedGeometrySystem.shutdown` never removes its render layer
225
- - **Severity**: CRITICAL
226
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js:254` (create) vs `:280-294` (shutdown)
227
- - **Defect**: `startup` does `this.__render_layer = graphics.layers.create('shaded-geometry')` and installs a
228
- `buildVisibleSet` closure that resolves a per-view context from `this.__view_contexts`. `shutdown`
229
- tears down every view context but never calls `graphics.layers.remove(this.__render_layer)`.
230
- `graphics.layers` lives on the `GraphicsEngine`, which outlives the `EntityManager`. Every peer
231
- system does remove its layer — `MeshSystem.js:247`, `WaterSystem.js:73`, `Trail2DSystem.js:117`,
232
- `Trail3DSystem.js:134`, `GizmoRenderingPlugin.js:18`.
233
- - **Failure scenario**: Level teardown/reload. `EntityManager.shutdown()` runs
234
- `ShadedGeometrySystem.shutdown`, emptying `__view_contexts`; the layer stays registered and visible.
235
- (a) If any frame renders before the new dataset is up, `VisibilityComputer.__processLayer` calls the
236
- stale `buildVisibleSet`, `this.__view_contexts.get(view)` is `undefined`, and
237
- `ctx.collect(...)` throws `TypeError: Cannot read properties of undefined (reading 'collect')` —
238
- which aborts the whole visibility build, so *every* layer stops rendering.
239
- (b) Adding a fresh `ShadedGeometrySystem` for the next level makes
240
- `graphics.layers.create('shaded-geometry')` throw
241
- `RenderLayer named 'shaded-geometry' already exists` (`RenderLayerManager.js:117`) — a hard crash on
242
- level reload. The stale `compute_depth_range` closure also pins the dead BVH.
243
- - **Fix**: In `shutdown`, `graphics.layers.remove(this.__render_layer); this.__render_layer = null;`
244
- - **Confidence**: Confirmed
245
-
246
- ---
247
-
248
- ### GFXR-12 `SGMesh.materialOverride` is applied after `link`, bypassing the Forward+ material transform
249
- - **Severity**: MAJOR
250
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js:205-207`, and the same defect at `aggregate/SGMesh.js:120-131`
251
- - **Defect**: `ShadedGeometrySystem.link` exists precisely to close this hole; its own comment says the
252
- material is forced "through the manager's transform chain, so that shader injection performed by the
253
- lighting engine (Forward+ clustered lights, decals) cannot be skipped by callers that assign
254
- `sg.material` directly" (`ShadedGeometrySystem.js:305-311`). In `SGMeshSystem`,
255
- `entity_node.build(ecd)` (line 179) synchronously drives `ShadedGeometrySystem.link` for every child
256
- `ShadedGeometry`, installing the transformed material — and *then* the traverse at 190-207 overwrites
257
- it with the raw override:
258
- ```js
259
- if (material_override !== null) {
260
- sg.material = material_override;
261
- }
262
- ```
263
- `SGMesh.applyMaterialOverride()`, reached from the `set materialOverride` setter, does the same on an
264
- already-linked hierarchy.
265
- - **Failure scenario**: A unit is spawned with `SGMesh.fromURL('unit.gltf')` and a `materialOverride`
266
- (team tint / ghost preview / damage flash) using a lit `MeshStandardMaterial`. Every part receives
267
- the raw material, which never went through `MaterialManager.obtain`, so the Forward+
268
- `onBeforeCompile` clustered-light injection is absent. The overridden unit renders with *no*
269
- clustered point lights and no decals while every neighbouring unit in the same scene is lit
270
- correctly — it looks flat/black at night. The `assert.ok(!isForwardPlusLightingSkipped(...))` guard
271
- in `link` cannot catch it: it runs before the override, and asserts are stripped in production.
272
- Reference counting is also skipped, so `MaterialManager` can neither dedupe nor reclaim the override.
273
- - **Fix**: Route both sites through the manager
274
- (`sg.material = materialManager.obtain(material_override).getValue()`), tracking/releasing the
275
- reference the same way `ShadedGeometrySystem`'s `#material_references` does.
276
- - **Confidence**: Confirmed (ordering verified; the lighting consequence follows from the contract
277
- documented in `ShadedGeometrySystem.link`)
278
-
279
- ---
280
-
281
- ### GFXR-13 `BoneMapping.build` commits the WORST bone name match first
282
- - **Severity**: MAJOR
283
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/mesh/skeleton/BoneMapping.js:13-15, 55, 61`
284
- - **Defect**: `string_compute_similarity` is Jaro-Winkler and is documented "Higher value means string
285
- are more similar". The comparator sorts **descending** (best first), and the consumption loop then
286
- takes from the tail:
287
- ```js
288
- function byDistance(a, b) { return b.distance - a.distance; } // descending
289
- matches.sort(byDistance);
290
- ...
291
- const match = matches.pop(); // takes the LEAST similar pair
292
- ```
293
- Because the inner loop immediately evicts every remaining entry sharing that `boneIndex` or
294
- `inputIndex`, the worst pairing is locked in permanently — this is a greedy assignment run in
295
- exactly reverse order.
296
- - **Failure scenario**: Load a rigged glTF whose bones are `Hips, Spine, Chest, Neck, Head, …`.
297
- `SkeletonUtils.findSkeletonBoneByType` builds the mapping on first use. The globally least-similar
298
- (bone, name) pair — say (`HumanoidBoneType.Head`, `"toe-right"`) — is committed first and consumes
299
- the `Head` slot. `Mesh.getBonePositionByType(result, HumanoidBoneType.Head)` then returns the world
300
- position of the right toe, so anything anchored to a humanoid bone (weapon socket, head-mounted VFX,
301
- nameplate) attaches to the wrong body part.
302
- - **Fix**: Consume best-first — either flip the comparator to `a.distance - b.distance` and keep
303
- `pop()`, or keep the sort and use `matches.shift()` (with the inner splice loop starting at 0).
304
- - **Confidence**: Confirmed
305
-
306
- ---
307
-
308
- ### GFXR-14 `SGMeshAnimationControllerSystem.update` spins on one unloaded mesh and starves the rest of the queue
309
- - **Severity**: MAJOR
310
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshAnimationControllerSystem.js:159-167` with `:57-68`, `:90-92`
311
- - **Defect**: `update` pops up to 1000 entities per tick and calls `this.#process(entity)` without
312
- awaiting. `#process` re-enqueues synchronously when the mesh has not loaded
313
- (`if (mesh.node === null) { this.#enqueue(entity); return; }`), and `#enqueue` **pushes to the tail**
314
- while `update` **pops from the tail**. The same entity is therefore popped and re-pushed
315
- immediately, for all 1000 iterations.
316
- ```js
317
- const entity = this.#queue.pop();
318
- this.#process(entity); // re-pushes to the same end it was popped from
319
- ```
320
- - **Failure scenario**: Three units spawn in the same frame; A and B have cached meshes, C's glTF is
321
- still downloading. The queue is `[A, B, C]`. Frame 1: `pop()` yields C, C re-queues, `pop()` yields C
322
- again — 1000 times. A and B are never reached. This repeats every frame until C's asset resolves, so
323
- A and B never get `controller.bound` populated and stand completely frozen for the whole duration of
324
- C's download, even though their own meshes were ready immediately. Also burns 1000 pop/push cycles
325
- per frame doing nothing.
326
- - **Fix**: Use FIFO — `this.#queue.shift()` in `update` (or push to the head in `#enqueue`) — and cap
327
- the loop by the queue length captured *before* the loop, so re-queued entities are deferred to the
328
- next tick rather than reprocessed within the same one.
329
- - **Confidence**: Confirmed
330
-
331
- ---
332
-
333
- ### GFXR-15 HiZ occlusion query samples `n_max.y` as an x coordinate
334
- - **Severity**: MAJOR
335
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/visibility/hiz/query/QueryShader.js:108`
336
- - **Defect**: The four taps are meant to be the four corners of the projected AABB. The
337
- bottom-right tap reads `vec2(n_max.y, n_min.y)` — `n_max.y` where `n_max.x` was meant:
338
- ```glsl
339
- float n1 = textureLod(utDepth, vec2(n_min.x, n_max.y), float(mip_to_use)).x;
340
- float n2 = textureLod(utDepth, vec2(n_max.y, n_min.y), float(mip_to_use)).x; // n_max.x
341
- ```
342
- - **Failure scenario**: A wide, short object — a wall whose projected box spans x∈[0.1, 0.9],
343
- y∈[0.40, 0.45]. `n2` samples at x = 0.45 instead of x = 0.9, so the depth in front of the wall's
344
- right-hand half is never read. `n = max(n0..n3)` therefore under-reports the scene depth over that
345
- region and `depth_delta = n - n_min.z` goes negative: the wall is classified occluded and culled
346
- while plainly on screen. The error is silent, view-dependent, and worse the wider the object.
347
- - **Fix**: `float n2 = textureLod(utDepth, vec2(n_max.x, n_min.y), float(mip_to_use)).x;`
348
- - **Confidence**: Confirmed
349
-
350
- ---
351
-
352
- ### GFXR-16 `HierarchicalZBuffer.build_mips` publishes the mip chain on a property three.js never reads
353
- - **Severity**: MINOR
354
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/visibility/hiz/buffer/HierarchicalZBuffer.js:168-169`
355
- - **Defect**: `this.__input_buffer.mips = mips.map(m => m.texture);` — `THREE.Texture` in r136 has no
356
- `mips` field; the array `WebGLTextures` consults when `generateMipmaps === false` is `mipmaps`.
357
- The assignment creates an inert own-property, so the reduction targets are never bound as mip levels
358
- of the texture that `BatchOcclusionQuery.execute` hands to the shader as `utDepth`.
359
- - **Failure scenario**: The reduction pass fills every mip render target correctly, but `utDepth` still
360
- has only level 0 (`minFilter: NearestFilter`, no uploaded chain), so every
361
- `textureLod(utDepth, uv, float(mip_to_use))` clamps to level 0. A distant object whose AABB covers
362
- one texel at `mip_to_use = 6` is tested with four full-resolution point samples instead of the
363
- conservative max over its footprint: the hierarchical test degenerates into a 4-sample point test
364
- and reports visible objects as occluded — geometry pops in and out at distance.
365
- - **Fix**: Bind the reduction targets' textures as explicit `sampler2D` uniforms and index them in the
366
- shader, or build a real `mipmaps` chain on `__input_buffer` that `WebGLTextures` will upload.
367
- Renaming the property alone is not sufficient — `mipmaps` entries are image-like objects, not render
368
- targets.
369
- - **Confidence**: Likely (only in-repo consumer today is `hiz/prototypeHiZ.js`, so this is latent)
370
-
371
- ---
372
-
373
- ### GFXR-17 `SGMesh.copy()` does not copy `flags`, so `clone()` re-enables shadow casting
374
- - **Severity**: MINOR
375
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js:82-88`
376
- - **Defect**: `copy(other)` transfers `__url`, `__node`, `__initial_bounds` and `#material_override`
377
- but not `flags` — the sole backing store for `castShadow`/`receiveShadow`/`Loaded`. `equals()`
378
- (line 68) nonetheless compares `this.flags === other.flags`.
379
- - **Failure scenario**: A prefab `SGMesh` with `castShadow = false` (a flat ground decal mesh, say).
380
- `prefab.clone()` yields a component with `DEFAULT_FLAGS = CastShadow | ReceiveShadow`, so every
381
- cloned instance casts a shadow the original explicitly disabled. Additionally
382
- `prefab.equals(prefab.clone())` is `false`, defeating any equality/hash-keyed reuse of the component.
383
- - **Fix**: Add `this.flags = other.flags & ~SGMeshFlags.Loaded;` to `copy()` (`Loaded` must be cleared
384
- because `__node` is reset to `null`).
385
- - **Confidence**: Confirmed
386
-
387
- ---
388
-
389
- ### GFXR-18 `SGMeshAnimationControllerSystem` has no `unlink`, so destroyed entities stay queued
390
- - **Severity**: MINOR
391
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshAnimationControllerSystem.js:57-68` (no `unlink` anywhere in the class)
392
- - **Defect**: `link` enqueues the entity when its mesh has not loaded. The class defines no `unlink`,
393
- so nothing drains `#queue` when the entity is destroyed. `#process` then does
394
- `ecd.getComponent(entity, SGMesh)` — which returns `undefined` for a removed entity
395
- (`EntityComponentDataset` deletes the slot) — and dereferences `mesh.node`.
396
- - **Failure scenario**: Spawn an entity with `SGMesh.fromURL(...)` + `SGMeshAnimationController`; the
397
- asset is not yet resolved so `link` queues it. Destroy the entity the same frame (unit dies, preview
398
- cancelled). Next tick, `update` pops it and `#process` throws
399
- `TypeError: Cannot read properties of undefined (reading 'node')`. Because `update` calls the async
400
- `#process` without awaiting, this surfaces as an unhandled promise rejection rather than a thrown
401
- frame error — silent in production, and the diagnostics for the real problem are lost.
402
- - **Fix**: Add `unlink(anim, mesh, entity)` that removes `entity` from `#queue`.
403
- - **Confidence**: Confirmed
404
-
405
- ---
406
-
407
- ### GFXR-19 Ambient light with `castShadow` builds a shadow view, then crashes the frame
408
- - **Severity**: MAJOR
409
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js:476-491`
410
- - **Defect**: `__apply_castShadow` calls `__shadowmap_link()` whenever `castShadow` is true, with no check
411
- that the underlying three light actually owns a `shadow`. `THREE.AmbientLight` does not — only
412
- Directional/Spot/Point define one. Every *other* shadow site in the file guards for exactly this
413
- (`applySettings:525` `if (shadow !== undefined)`, `__shadowmap_unlink:316`), and
414
- `LightSystem.__visit_entity_to_update_shadow:210` excludes AMBIENT with the comment "only non-ambient
415
- lights can cast shadow" — so this is a state the code already treats as reachable, not a can't-happen.
416
- - **Failure scenario**: An entity carries `Light{type: AMBIENT, castShadow: true}` —
417
- `Light.fromJSON` and `LightSerializationAdapter.serialize` both persist `castShadow` unconditionally
418
- for every light type, so an editor toggle or a saved blueprint produces it. `link()` registers a
419
- shadow `CameraView` with `graphics.views`. On the next `constructVisibleScene`,
420
- `__shadowmap_prepare_view` does `const shadow = light.shadow;` (undefined) then
421
- `const camera = shadow.camera;` → `TypeError`. That throw propagates out of
422
- `CameraView.build_visibility` → `CameraViewManager.build_visibility` →
423
- `GraphicsEngine.constructVisibleScene`, so the whole frame dies — every frame, permanently.
424
- - **Fix**: `if (v && this.__shadow_map === null && light.shadow !== undefined) { … }`
425
- - **Confidence**: Confirmed (crash mechanism verified against three r136; reachability requires the
426
- ambient+castShadow authoring combination)
427
-
428
- ---
429
-
430
- ### GFXR-20 Shadow cameras have `matrixAutoUpdate = false`, so `LightShadow.updateMatrices` cannot refresh their pose
431
- - **Severity**: MAJOR
432
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js:549`
433
- - **Defect**: `applySettings` sets `shadow.camera.matrixAutoUpdate = false` for directional/spot shadows.
434
- three r136's `LightShadow.updateMatrices` writes `shadowCamera.position` / calls `lookAt(...)` and then
435
- relies on `shadowCamera.updateMatrixWorld()` to recompose — but `Object3D.updateMatrixWorld` only calls
436
- `updateMatrix()` when `matrixAutoUpdate` is true, and `matrixWorldNeedsUpdate` is false at that point,
437
- so neither `matrix` nor `matrixWorld`/`matrixWorldInverse` is updated. (`lookAt` itself calls
438
- `updateWorldMatrix(true,false)`, which is equally inert, so even the look rotation is derived from the
439
- stale world position.) The point-light branch two lines above documents precisely this requirement and
440
- keeps `matrixAutoUpdate = true`; the directional/spot branch does the opposite. `LightSystem.js:325`
441
- even has a comment asserting the opposite of what happens: *"refresh shadow camera world matrix from
442
- the light's pose before we read matrixWorldInverse"* — `shadow.updateMatrices(light, 0)` there is a
443
- no-op with respect to `matrixWorldInverse`.
444
- - **Failure scenario**: The only place that ever bakes the pose is `__shadowmap_prepare_view`
445
- (`camera.updateMatrix(); camera.updateMatrixWorld();`), fired from `preVisibilityBuild` — i.e. earlier
446
- in the frame than `three_update_shadow_camera_extents`, which runs on
447
- `visibilityConstructionEnded`. (a) First frame a light starts casting: `prepare_view` bakes the
448
- constructor pose (origin, identity), so `compute_view_frustum_aabb_in_space` fits the ortho box in
449
- **world** space instead of light space — a visibly wrong/missing shadow flash on level load.
450
- (b) Steady state: a spot light carried by a moving character always renders and fits from the pose
451
- captured on the previous frame, so its shadow trails the light while strafing.
452
- - **Fix**: Leave `matrixAutoUpdate` at three's default `true` for all shadow cameras (three's own
453
- `WebGLShadowMap` never disables it), or explicitly call `shadow.camera.updateMatrix();
454
- shadow.camera.updateMatrixWorld();` after every `shadow.updateMatrices(light, i)`.
455
- - **Confidence**: Confirmed (mechanism verified against `three/src/lights/LightShadow.js` and
456
- `Object3D.updateMatrixWorld` in r136)
457
-
458
- ---
459
-
460
- ### GFXR-21 `three_update_shadow_camera_extents` rebuilds the main camera's projection matrix, discarding every projection modifier
461
- - **Severity**: MAJOR
462
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/light/LightSystem.js:334-345`
463
- - **Defect**: To fit the shadow box, the function truncates `camera.far`, calls
464
- `camera.updateProjectionMatrix()`, reads the matrix, then restores `far` and calls
465
- `updateProjectionMatrix()` again. The in-code claim that "callers downstream see no change" is wrong:
466
- `updateProjectionMatrix()` regenerates the matrix from `fov/aspect/near/far`, restoring the *default*
467
- projection — not whatever the matrix previously contained. `CameraView.set_from_camera:123` writes
468
- modified matrices straight back into `camera.projectionMatrix.elements`, and it runs *earlier* in the
469
- same frame (`GraphicsEngine.constructVisibleScene`: `set_from_camera` at line 707,
470
- `visibilityConstructionEnded` — where this function is hooked — at line 710).
471
- - **Failure scenario**: `TemporalSupersamplingRenderPlugin` is enabled and one shadow-casting
472
- directional light has a finite `maxShadowDistance` below `camera.far` (e.g. 60 vs 1000), so
473
- `needs_truncation` is true. Every frame the jitter written into `elements[8]/[9]` is wiped before the
474
- scene is drawn, so TAA resamples the identical position forever: the image never converges and edge
475
- aliasing is exactly as if TAA were off, while the plugin still pays its full cost. Setting
476
- `maxShadowDistance = Infinity` makes TAA start working — a baffling coupling. Any other registered
477
- `CameraView.projection_modifier` is destroyed the same way.
478
- - **Fix**: Do not mutate the live camera. Build the truncated projection into a scratch `Matrix4` with
479
- `makePerspective(...)` and multiply that by `camera.matrixWorldInverse`; failing that, save and restore
480
- the 16 elements of `projectionMatrix` (and `projectionMatrixInverse`) verbatim.
481
- - **Confidence**: Confirmed (mechanism and frame ordering both verified)
482
-
483
- ---
484
-
485
- ### GFXR-22 Binary light serializer drops POINT `distance` and DIRECTION `maxShadowDistance`
486
- - **Severity**: MAJOR
487
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/light/LightSerializationAdapter.js:22-26` and `:41-45`
488
- - **Defect**: `distance` is written and read only inside `if (type === LightType.SPOT)`, but the
489
- component uses `distance` for POINT as well (`Light.js:51`, `LightBinding.scaled_distance`,
490
- `ThreeLightBinding.__apply_distance`, `FPLightBinding.#updateDistance`). The JSON adapter gets it right
491
- — `Light.toJSON` writes `distance` for `SPOT || POINT` (verified) — which pins this as an oversight
492
- rather than a schema decision. `maxShadowDistance` (written by `toJSON` for DIRECTION) is absent from
493
- the binary format entirely.
494
- - **Failure scenario**: A torch entity `Light{type: POINT, distance: 20}` is saved through the binary ECS
495
- serializer. On load, `deserialize` never reads `distance`, so the component keeps
496
- `DEFAULT_DISTANCE = 1`; `__apply_distance` sets the three `PointLight.distance = 1` (or the Forward+
497
- `radius = 1`). The torch illuminates a 1-unit sphere and the room around it is black — while the exact
498
- same scene loaded from a JSON save looks correct.
499
- - **Fix**: Write/read `distance` in a `SPOT || POINT` branch mirroring `Light.toJSON`, add
500
- `maxShadowDistance` for DIRECTION, and bump `version` from 0 since the byte layout changes.
501
- - **Confidence**: Confirmed
502
-
503
- ---
504
-
505
- ### GFXR-23 `LightSystem.shutdown` never detaches the three light cache
506
- - **Severity**: MAJOR
507
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/light/LightSystem.js:97` (attach, in the constructor) vs `:162-171` (shutdown)
508
- - **Defect**: The constructor does `this.__three_light_cache.attach(this.scene)`. `shutdown()` releases
509
- the Forward+ plugin and detaches the `visibilityConstructionEnded` handler, but never calls the
510
- `ThreeLightCache.detach()` that exists for exactly this purpose. Every three light the cache ever
511
- created — including pooled, currently-unused ones — stays parented to `graphics.scene`, which outlives
512
- the `EntityManager`.
513
- - **Failure scenario**: The host app keeps one `GraphicsEngine` across level loads and rebuilds the
514
- `EntityManager` (a new `LightSystem` each time). After each cycle the previous cycle's
515
- `DirectionalLight`/`PointLight`/`SpotLight`/`AmbientLight` objects remain in the scene.
516
- `WebGLRenderer.projectObject` pushes every visible `isLight` object into `WebGLLights` regardless of
517
- intensity, so `NUM_DIR_LIGHTS`/`NUM_POINT_LIGHTS`/`NUM_SPOT_LIGHTS` grow one generation per load: every
518
- material's program cache key changes so **all** materials recompile on each load (multi-second hitch),
519
- and after a handful of cycles the fragment uniform budget is exceeded and materials fail to link —
520
- black scene.
521
- - **Fix**: Call `this.__three_light_cache.detach()` in `shutdown()`, and move the `attach(this.scene)`
522
- from the constructor into `startup()` so a stopped-then-restarted system still works.
523
- - **Confidence**: Confirmed (leak); the recompile/black-scene escalation depends on the host recycling
524
- the `EntityManager`
525
-
526
- ---
527
-
528
- ### GFXR-24 Shadow texel snapping uses a grid whose spacing changes every frame
529
- - **Severity**: MINOR
530
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/light/shadow/setShadowCameraDimensionsDiscrete.js:28-36`
531
- - **Defect**: `rX = dX / shadow_map_width` where `dX`/`dY` are the light-space extents of the *current*
532
- frame's view-frustum AABB, recomputed every frame by `three_update_shadow_camera_extents`. Snapping a
533
- moving origin to a grid whose spacing also moves does not produce a stable world-space texel lattice —
534
- the step the algorithm depends on ("Fix the overall size of the frustum based on the longest diagonal
535
- … Don't allow the shadow frustum to change size as the camera rotates", `LightSystem.js:201`) is
536
- documented but never implemented. Secondary: for negative `x0`, JS `%` returns a negative remainder, so
537
- `x0_d = x0 - (x0 % rX) - rX/2` can land up to half a texel *inside* `x0`, clipping coverage off the
538
- left/bottom edge (the `(w+1)/w` slack is added only at the far edge).
539
- - **Failure scenario**: Slowly orbit the camera over a static scene lit by one shadow-casting sun. The
540
- shadow map re-quantises onto a different lattice each frame, so shadow boundaries crawl and shimmer
541
- texel by texel — exactly the artifact the discretisation exists to remove. With the camera positioned
542
- so the fit box straddles the origin, up to half a texel of shadow is also missing along one edge.
543
- - **Fix**: Derive a frame-invariant extent from the view frustum's longest diagonal at the shadow
544
- distance and use it for `dX`/`dY`, then snap with `Math.floor(x / rX) * rX` instead of `%`.
545
- - **Confidence**: Likely
546
-
547
- ---
548
-
549
- ### GFXR-25 Forward+ vertex-only lighting reads `gl_Position` before `<project_vertex>` writes it
550
- - **Severity**: MAJOR
551
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/materials/fp_build_vertex_lighting_shared.js:9-13, 26`
552
- - **Defect**: The froxel-lookup preamble is injected immediately after `void main() {`:
553
- ```js
554
- result = insert_after(result, 'void main() {', accumulation_pars);
555
- ```
556
- and `accumulation_pars` begins with
557
- `vec3 fp_normalized_screen_position = ((gl_Position.xyz / gl_Position.w)+vec3(1.0))*0.5;`.
558
- In a three.js vertex shader `gl_Position` is assigned much later, by `#include <project_vertex>`.
559
- This is an unconditional read of a vertex-stage built-in output before it is written.
560
- - **Failure scenario**: A lit material compiled with `defines.LIGHTING_VERTEX_ONLY === true` (the branch
561
- `MaterialTransformer.js:63` selects) computes `clip_v` from an undefined value, so
562
- `v3_cluster_position` indexes a random froxel. Out-of-range `texelFetch` returns 0 →
563
- `fp_cluster_metadata.y == 0` → the mesh receives **zero** clustered light and renders unlit; in-range,
564
- it is lit by an unrelated part of the screen and flickers per vertex as the garbage changes.
565
- - **Fix**: Inject after `#include <project_vertex>` instead, or compute the clip position locally
566
- (`projectionMatrix * modelViewMatrix * vec4(position, 1.0)`) rather than reading `gl_Position`.
567
- - **Confidence**: Confirmed (the read-before-write is unconditional; no in-repo material currently sets
568
- `LIGHTING_VERTEX_ONLY`, so this is public-surface breakage rather than a live regression)
569
-
570
- ---
571
-
572
- ### GFXR-26 `LightManager.dispose()` frees GPU objects but leaves every light still subscribed to the dead manager
573
- - **Severity**: MAJOR
574
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/LightManager.js:1137-1142`
575
- - **Defect**: `dispose()` disposes four textures and nothing else. Three subscription families survive:
576
- `LightRenderMetadata.link` (`LightRenderMetadata.js:52`) binds `this.update` to
577
- `light.position.onChanged` / `light.radius.onChanged` (removed only by `removeLight` → `unlink()`);
578
- `__handle_visible_light_added` (`:596-597`) binds `__handle_light_dimensions_change` /
579
- `__handle_light_appearance_change`; `__handle_visible_decal_added` (`:538-546`) binds to
580
- `patch_uv.position.onChanged` / `patch_uv.size.onChanged` and stores an un-released
581
- `Reference<AtlasPatch>`. `__decal_atlas` is never disposed either.
582
- - **Failure scenario**: `ForwardPlusRenderingPlugin.shutdown()` disposes the manager while a scene with
583
- FP point lights and decals is still loaded (plugin released before entities unlink, or an engine
584
- reconfiguration). Every live `PointLight.position` signal still holds a handler bound to the dead
585
- manager, keeping it, its BVH, its cluster-plane buffers and all atlas patches reachable — a full leak
586
- per plugin cycle. Worse, moving any of those lights afterwards still runs
587
- `LightRenderMetadata.update()`, writing bounds into the abandoned BVH; re-acquiring the plugin creates
588
- a second `LightManager` while the first keeps mutating.
589
- - **Fix**: In `dispose()`, iterate `#metadata_map` calling `data.unlink()` and clear it; drain
590
- `__visible_lights`/`__visible_decals` through the existing `__handle_visible_*_removed` teardown so the
591
- handlers and atlas references are released; dispose `__decal_atlas`.
592
- - **Confidence**: Likely
593
-
594
- ---
595
-
596
- ### GFXR-27 Forward+ `SpotLight` is accepted by `addLight` and then silently never rendered
597
- - **Severity**: MAJOR
598
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/LightManager.js:771-796`
599
- - **Defect**: The visibility dispatch branches on `light.isDecal` then `light.isPointLight` and drops
600
- everything else on the floor. `render/forward_plus/model/SpotLight.js` implements everything `addLight`
601
- requires (`getAABB` via `cone_compute_bounding_box`, `onDimensionChanged`, `toArray`), so
602
- `addLight(spotLight)` succeeds and inserts a BVH leaf — it is simply never binned.
603
- `encode_light_type` would have thrown on it and `spot_light_inside_volume` exists, but neither is
604
- reached.
605
- - **Failure scenario**: A consumer builds a `SpotLight` from `forward_plus/model/SpotLight.js` and adds
606
- it to the manager expecting a cone of light. Nothing appears and nothing is logged — the light silently
607
- contributes zero for the lifetime of the scene. Companion trap: `SpotLight.prototype.ENCODED_SLOT_COUNT`
608
- is never assigned and `toArray` returns 13 (not a multiple of 4), so naively adding the branch makes
609
- `address += undefined` produce `NaN` and trips the "Expected light data size" throw at `:878`.
610
- - **Fix**: Either reject unsupported light types loudly in `addLight`, or complete the spot path —
611
- `SpotLight.prototype.ENCODED_SLOT_COUNT = 16` (pad `toArray` to a 4-slot boundary), a type code in
612
- `encode_light_type`, an `isSpotLight` branch here using `spot_light_inside_volume`, and the matching
613
- branch in `query_bvh_frustum_from_texture`.
614
- - **Confidence**: Likely
615
-
616
- ---
617
-
618
- ### GFXR-28 `decal_filtering_enabled` setter never re-uploads, and leaves a mipmap-incomplete texture
619
- - **Severity**: MINOR
620
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/LightManager.js:359-367` (constructor at `:221-223`)
621
- - **Defect**: The setter flips `t.generateMipmaps` and stops — `texture.version` is never bumped, so
622
- three does not re-upload and the setting has no effect until an unrelated atlas repack. When that
623
- repack eventually happens, `generateMipmaps === false` while `minFilter` is still
624
- `LinearMipMapLinearFilter`; on WebGL2 three's `setTextureParameters` applies `LINEAR_MIPMAP_LINEAR`
625
- verbatim and `uploadTexture` skips `generateMipmap`.
626
- - **Failure scenario**: A game follows the method's own JSDoc ("Please set this to false if you have a
627
- lot of overlapping decals") and sets `lightManager.decal_filtering_enabled = false`. Nothing changes on
628
- screen. Later a new decal texture is registered, the atlas repacks and re-uploads — and every decal now
629
- samples a mipmap-incomplete texture, rendering solid black instead of its diffuse.
630
- - **Fix**: `t.generateMipmaps = v; t.minFilter = v ? LinearMipMapLinearFilter : LinearFilter;
631
- t.needsUpdate = true;`
632
- - **Confidence**: Confirmed (missing re-upload); Likely (black-decal consequence)
633
-
634
- ---
635
-
636
- ### GFXR-29 Debug froxel grid uses a 3-channel stride on the RGBA cluster texture and overruns each axis
637
- - **Severity**: MINOR
638
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/debug/createScreenGrid.js:47-51` and `:272-281`
639
- - **Defect**: `const texel_address = texel_index * 3; // RGB format` — the cluster texture is RGBA:
640
- `LightManager.__assign_lights_to_clusters` writes at `tile_index * 4` (`LightManager.js:970`) and
641
- `LightManager.spec.js:23` asserts a 4-element image for a 1×1×1 grid. Stride 3 aliases into the wrong
642
- texel for every cell but index 0. The loops additionally run `i < resolution.N + 1`, so
643
- `resolution.x - 1 - i_x` reaches `-1` and the z loop reads a slice past the end.
644
- - **Failure scenario**: Open the debug screen grid on a 12×6×4 grid. Cell (3,2,1)'s reported light count
645
- is read from a completely different froxel, so both the heatmap and the click-tooltip light list
646
- describe the wrong cells — the tool actively misleads anyone debugging the binning.
647
- - **Fix**: Use `texel_index * 4` / `index * 4` in both places and drop the `+ 1` from all three loop
648
- bounds.
649
- - **Confidence**: Confirmed
650
-
651
- ---
652
-
653
- ### GFXR-30 Cluster-volume debug widget clones the 3D cluster texture every frame and never disposes it
654
- - **Severity**: MINOR
655
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/debug/buildLightClusterWidget.js:56-64`
656
- - **Defect**: `const t = lm.getTextureClusters().clone(); t.needsUpdate = true; m.uniforms.map.value = t;`
657
- — a fresh `DataTexture3D` per `update()`, with the previous clone dropped without `.dispose()`. Its GL
658
- texture object stays in `WebGLTextures`' property map for the widget's renderer until context loss.
659
- - **Failure scenario**: `update()` is driven from the render loop. At 60 fps with the default
660
- 32×16×16 RGBA16UI volume (~64 KB each) that is ~4 MB/s of leaked GPU memory; a couple of minutes of
661
- debugging and the tab hits out-of-memory / context-lost.
662
- - **Fix**: Clone once outside `update()` (the clone shares `image`, so only `needsUpdate = true` is
663
- needed per frame), or `m.uniforms.map.value?.dispose()` before assigning the new clone.
664
- - **Confidence**: Confirmed
665
-
666
- ---
667
-
668
- ### GFXR-31 `sort_decal_data` uses a moving pivot and sorts on slots that hold colour, not priority
669
- - **Severity**: MINOR
670
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/sort_decal_data.js:20-24, 65-76`
671
- - **Defect**: Two independent errors. (a) The comparator reads `data[address + 20]` as `draw_priority`
672
- and `+ 21` as `id`, but `Decal.toArray` (`model/Decal.js:116-121`) has both of those writes commented
673
- out and `array_copy(this.color, 0, destination, address + 20, 4)` occupies slots 20-23 — so it sorts
674
- decals by their red and green channels. (b) The quicksort pivot is an *index*, not a captured value;
675
- `lookup[pivotIndex]` is itself swapped during partitioning, destroying the scan sentinel. The correct
676
- sibling `core/collection/array/array_sort_quick.js` captures the pivot value before the loop.
677
- - **Failure scenario**: Re-enable the call site the `TODO fix decal sorting artifacts` block at
678
- `LightManager.js:995-1003` currently guards (or call this exported function directly). When the pivot
679
- entry is swapped to a higher-priority value, `i` walks past `right`, `compare_decals` starts reading
680
- `undefined`, and the subsequent `lookup[j] = lookup[i]` stores `0` into a neighbouring froxel's lookup
681
- run — that froxel's decal slot then points at light-data texel 0 and renders the wrong decal. This is
682
- precisely the artifact the TODO describes.
683
- - **Fix**: Capture the pivot record (`const pivot_encoded = lookup[pivotIndex];`) and compare values, not
684
- indices; and restore the `draw_priority`/`id` writes in `Decal.toArray` (widening
685
- `ENCODED_SLOT_COUNT` past 24) or read priority from a slot that is actually written.
686
- - **Confidence**: Likely
687
-
688
- ---
689
-
690
- ## Verified clean / non-issues checked along the way
691
-
692
- - `GraphicsEngine.prepareRenderPass` writes `visibleGroup.length = j` where `children.length` was
693
- meant — harmless: `clearVisibleGroup()` truncates `children` to 0 first, so `children.length`
694
- already equals `j`. No failure scenario, not reported.
695
- - `OutlineRenderer.writeParameters` → `HashMap.forEach` passes `(value, key)`, which matches
696
- `__write_parameters_for_definition(id, definition)`. Correct.
697
- - `OutlineRenderPlugin` subscribe/unsubscribe pairs match (`Vector2.process` adds to `onChanged` with
698
- the same handler + context that `shutdown` removes).
699
- - `AmbientOcclusionPostProcessEffect` startup/shutdown binding pairs all match; all four GPU resources
700
- are disposed.
701
- - TAA jitter indices (`elements[8]`/`[9]`) and magnitude match the pinned spec; the `=` (rather than
702
- `+=`) is deliberate, since `CameraView.set_from_camera` writes the jittered matrix back onto the
703
- camera and `CameraSystem`'s `visibilityConstructionStarted` hook rebuilds it each frame.
704
- - `Water.updateBounds` BVH box agrees with the plane mesh's rotated/offset world extent.
705
- - `FrameBufferManager.computeRenderOrder` splice-while-iterating is correctly compensated
706
- (`i--; openSetCount--`), as is `WaterSystem.processUpdateQueue`.
707
- - `GizmoRenderingPlugin` overrides `RenderLayer.buildVisibleSet` (whose prototype version throws
708
- `'deprecated'`) — but `VisibilityComputer.__processLayer` still calls it, so gizmos do render.
709
- - `RenderLayer.js:59`'s comment claims near is `planes[4]` and far is `planes[5]` (they are the other
710
- way round), but it documents `computeNearFarClippingPlanes`, which unconditionally throws
711
- `'deprecated'`. Stale doc only.
712
- - Forward+ cluster index arithmetic, depth-slice distribution, plane orientation, the near/far swap and
713
- X-flip in `computeFrustumCorners`, texel packing and the light-count overflow/recursion path are all
714
- internally consistent and agree with `cluster_binning.spec.js` /
715
- `light_culling_no_false_exclusion.spec.js`.
716
- - `query_bvh_frustum_from_texture.js:132` masks the light address with `& 0xFFFFFFF8` where the encoding
717
- (`type | address << 2`) calls for `& 0xFFFFFFFC`. Currently harmless — every record length in use
718
- (`PointLight` 8, `Decal` 24) is a multiple of 8 — so no failure scenario exists today. Noted, not filed.
719
- - `LightBinding` / `FPLightBinding` / `LightContext` link-unlink subscription pairs are symmetric;
720
- `ThreeLightCache.release` keys off `light2type(threeObject)` rather than the already-changed component
721
- type, so type-change rebuilds return the light to the correct pool.
722
- - `__shadowmap_unlink` disposes both `shadow.map` and `shadow.mapPass`;
723
- `three_set_shadow_resolution` disposes before resizing; `compute_view_frustum_aabb_in_space`'s plane
724
- ordering and `near = -z1 / far = -z0` are correct.
725
- - `ShadedGeometrySystem.link/unlink`, `SGMeshSystem.process`, `SGMeshHighlightSystem` and
726
- `IncrementalDeltaSet` were checked in detail and are balanced/correct.
727
- - `FPDecalSystem.Context` correctly handles the async texture-load race (`__is_linked` and
728
- `this.__fp_decal === fpDecal` re-checks) — the only defect there is the known `subscribe`/`unsubscribe`
729
- typo.
730
- - `SpriteSystemPE`, `AnimationControllerSystem`, `RenderableHighlightSystem`,
731
- `ShadedGeometryHighlightSystem`, `Trail3DSystem` and `GizmoRenderingPlugin` have matching
732
- subscribe/unsubscribe pairs.
733
-
734
- ## Coverage note
735
-
736
- Not exhaustively reviewed for lack of time: `ecs/path/tube/build/*` and `ecs/path/ribbon/`
737
- (heavily spec-covered geometry builders), `ecs/animation/animator/*` (graph/blend-space state machine,
738
- little graphics-correctness surface), and the GLSL bodies of `shaders/TerrainShader.js` /
739
- `shaders/AmbientOcclusionShader.js` / `render/buffer/simple-fx/ao/SAOShader.js` (the JS-side uniform
740
- wiring for those *was* reviewed and is clean).
1
+ # Correctness review — `engine/graphics` (ecs, render, shaders, camera, root)
2
+
3
+ Scope: every non-spec, non-prototype source file under
4
+ `meep/src/engine/graphics/{ecs,render,shaders,camera}` plus the files directly in
5
+ `meep/src/engine/graphics/`. three.js r136.
6
+
7
+ ---
8
+
9
+ ### GFXR-1 `Camera.projectWorldPointOntoNearPlane` projects onto the RIGHT frustum plane
10
+ - **Severity**: MAJOR
11
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/camera/Camera.js:279`
12
+ - **Defect**: The method takes `scratch_frustum.planes[0]` as "the near plane". `frustum_from_camera`
13
+ fills the frustum via three's `Frustum.setFromProjectionMatrix`, whose plane order is
14
+ `[0]=right, [1]=left, [2]=bottom, [3]=top, [4]=far, [5]=near`. Index 0 is the RIGHT side plane.
15
+ The sibling file `ecs/camera/pp/PerfectPanner.js:9-10` states the correct convention
16
+ (`NEAR_PLANE_INDEX = 5; FAR_PLANE_INDEX = 4;`), so the codebase already knows the ordering.
17
+ - **Failure scenario**: Camera at the origin looking down `-Z`, 45° fov, near 0.1. Call
18
+ `camera.projectWorldPointOntoNearPlane(0, 0, -10, out)`. Expected `out ≈ (0, 0, -0.1)` — the point
19
+ pushed onto the near plane in front of the eye. Actual: the point is projected onto the right
20
+ side plane of the frustum, landing several units off to the camera's right at a depth of 10.
21
+ Any UI/marker/clamping code built on this public method places its output in the wrong place
22
+ entirely, and gets *worse* the further off-axis the input point is.
23
+ - **Fix**: `const near = scratch_frustum.planes[5];`
24
+ - **Confidence**: Confirmed
25
+
26
+ ---
27
+
28
+ ### GFXR-2 Orthographic aspect correction uses the wrong delta when the viewport narrows
29
+ - **Severity**: MAJOR
30
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/camera/set_camera_aspect_ratio.js:35-40`
31
+ - **Defect**: The widening branch (`aspectDelta > 0`) grows the horizontal extent by `h * aspectDelta`,
32
+ which is exactly right (`w' = w + h·aspect − w = h·aspect`). The narrowing branch grows the vertical
33
+ extent by `-h * aspectDelta`, which does **not** solve `w / h' = aspect`. The required delta is
34
+ `w/aspect − h`, i.e. `-h * aspectDelta / aspect`.
35
+ ```js
36
+ } else if (aspectDelta < 0) {
37
+ const d = -h * aspectDelta; // <-- missing the /aspect
38
+ c.top += d / 2;
39
+ c.bottom -= d / 2;
40
+ }
41
+ ```
42
+ - **Failure scenario**: `OrthographicCamera(-10, 10, 10, -10, …)` (square frustum) in a portrait
43
+ viewport, `set_camera_aspect_ratio(camera, 100, 200)`. Requested aspect 0.5; the code produces
44
+ `top=15, bottom=-15`, i.e. frustum aspect `20/30 = 0.667`. Everything rendered through that camera
45
+ is stretched vertically by 33%: circles become ellipses, a square tile is drawn as a rectangle.
46
+ Verified numerically. The existing spec (`set_camera_aspect_ratio.spec.js`) only exercises the
47
+ widening case, which is why this survives.
48
+ - **Fix**: `const d = -h * aspectDelta / aspect;` — or, uniformly for both branches, set
49
+ `h' = w / aspect` when `aspect < existingAspect` and `w' = h * aspect` otherwise.
50
+ - **Confidence**: Confirmed
51
+
52
+ ---
53
+
54
+ ### GFXR-3 `CameraSystem` rebuild leaks a THREE camera into the scene on every fov/projection change
55
+ - **Severity**: MAJOR
56
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/camera/CameraSystem.js:146-148`
57
+ - **Defect**: `rebuild()` replaces `camera.object` with a freshly built THREE camera but never removes
58
+ the previous one from `this.scene`. `link()` is the only place that does `this.scene.add(...)`, and
59
+ `unlink()` removes only the *current* `camera.object`. The new object gets re-added to the scene by
60
+ `GraphicsEngine.render` (`if (scene.children.indexOf(camera) < 0) scene.add(camera)`), so every
61
+ rebuild adds one more permanent child. `rebuild` is wired to `camera.fov.onChanged` and
62
+ `camera.projectionType.onChanged` (lines 172, 174).
63
+ - **Failure scenario**: A fov-zoom effect animates `Camera.fov` (a `Vector1`, observable precisely so
64
+ it can be animated) at 60 Hz. Each frame builds a new `THREE.PerspectiveCamera` and appends it to
65
+ `graphics.scene.children`, which is never pruned. After one minute `scene.children` holds ~3600 dead
66
+ cameras: unbounded memory growth, an O(n) `scene.children.indexOf(camera)` in `GraphicsEngine.render`
67
+ every frame, and an O(n) root walk in `NormalFrameBuffer.render`, which traverses `scene.children`
68
+ each frame. Frame time degrades continuously for as long as the zoom runs.
69
+ - **Fix**: In `rebuild()`, capture the old object, `this.scene.remove(old)` and
70
+ `this.scene.add(camera.object)` after building. Better still, do not rebuild for a fov change — set
71
+ `camera.object.fov` and call `updateProjectionMatrix()`; only `projectionType` genuinely needs a new
72
+ object.
73
+ - **Confidence**: Confirmed
74
+
75
+ ---
76
+
77
+ ### GFXR-4 `Trail2DSystem` seeds the ribbon at a different point from where the head is driven
78
+ - **Severity**: MAJOR
79
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/trail2d/Trail2DSystem.js:156-158` vs `:234-235`
80
+ - **Defect**: Build-time seeding adds the offset in world space, ignoring the entity's rotation and
81
+ scale:
82
+ ```js
83
+ const position_x = trail_offset.x + transform_position.x; // __build_trail
84
+ ```
85
+ while the per-frame head update carries the offset through the entity's full transform:
86
+ ```js
87
+ newPosition.copy(trail.offset);
88
+ newPosition.applyMatrix4(transform.matrix); // updateTrailEntity
89
+ ```
90
+ The sibling `Trail3DSystem` has exactly this invariant written down and enforced via a shared
91
+ `compute_head_position` helper (`ecs/trail3d/Trail3DSystem.js:34-53`), whose doc comment describes
92
+ the resulting artifact verbatim. `Trail2DSystem` was not given the same treatment.
93
+ - **Failure scenario**: A projectile entity with `Trail2D.offset = (0, 0, -1)` (trail emitted from the
94
+ tail) rotated 90° about Y so it flies along `+X`. `__build_trail` seeds every ribbon point at
95
+ `position + (0, 0, -1)`; the first `updateTrailEntity` puts the head at `position + (-1, 0, 0)`.
96
+ The first rendered frame contains a ~1.41-unit ribbon streak pointing in a direction that has
97
+ nothing to do with the projectile's travel — a visible flash at every spawn.
98
+ - **Fix**: Replace lines 156-158 with the same transform-carried computation used in
99
+ `updateTrailEntity` (ideally extract a shared `compute_head_position(result, trail, transform)` as
100
+ Trail3D does).
101
+ - **Confidence**: Confirmed
102
+
103
+ ---
104
+
105
+ ### GFXR-5 `loadCubeTexture` calls `ImageUtils.loadTextureCube`, removed from three long before r136
106
+ - **Severity**: MAJOR
107
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/loadCubeTexture.js:27`
108
+ - **Defect**: `const textureCube = ImageUtils.loadTextureCube(urls);` — in the vendored
109
+ `three@0.136.0`, `src/extras/ImageUtils.js` declares exactly one member, `static getDataURL(image)`.
110
+ There is no `loadTextureCube`.
111
+ - **Failure scenario**: Any caller of this exported (public-surface) helper —
112
+ `loadCubeTexture('assets/sky', 'png')` — throws `TypeError: ImageUtils.loadTextureCube is not a
113
+ function` on the first line that matters, so no cubemap is ever produced. The function cannot
114
+ succeed under any input.
115
+ - **Fix**: Delete the function, or reimplement it on `CubeTextureLoader`:
116
+ `new CubeTextureLoader().load(urls)` (which already returns a `CubeTexture` with
117
+ `CubeReflectionMapping`). Note the package already has a working path for this —
118
+ `texture/cubemap/load_environment_map.js`, used by `load_and_set_cubemap_v0.js`.
119
+ - **Confidence**: Confirmed
120
+
121
+ ---
122
+
123
+ ### GFXR-6 `Lines` writes `drawRange.count` in the wrong units (twice, two different wrong values)
124
+ - **Severity**: MINOR
125
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/Lines.js:61` and `:105`
126
+ - **Defect**: `geometry.drawRange.count` is a **vertex** count for a non-indexed geometry. The
127
+ geometry stores `capacity * 2` vertices (2 per line segment).
128
+ - `setCount(x)` writes `x * 6` — the *float* count of the position attribute.
129
+ - `add_line` then overwrites it with `this.count` — the *line* count.
130
+ Neither is `count * 2`. Separately, `ensure_capacity` → `build()` replaces `this.geometry` without
131
+ disposing the old `BufferGeometry`, and `dispose()` never disposes `this.mesh.material`.
132
+ - **Failure scenario**: `const l = new Lines(); l.add_line([0,0,0],[1,0,0],[1,1,1,1]);` and add
133
+ `l.mesh` to a scene. `drawRange.count === 1`; `LineSegments` needs vertex pairs, so zero segments
134
+ are drawn. Adding 10 lines draws 5. Had `add_line` not overwritten line 61's value, `x*6` would
135
+ exceed the allocated `x*2` vertices and WebGL would raise
136
+ `INVALID_OPERATION: attempt to access out of range vertices`.
137
+ - **Fix**: `this.geometry.drawRange.count = x * 2;` in `setCount`, and delete the redundant
138
+ assignment at line 105. Dispose the replaced geometry in `build()`.
139
+ - **Confidence**: Confirmed (the class also logs `'feature not fully implemented'`, so this is
140
+ acknowledged WIP — listed for completeness)
141
+
142
+ ---
143
+
144
+ ### GFXR-7 `OutlineRenderer` caches the ID-pass mesh with a frozen geometry reference
145
+ - **Severity**: MINOR
146
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/highlight/renderer/OutlineRenderer.js:96-117`
147
+ - **Defect**: `obtain_id_mesh` builds the silhouette proxy once per source `Object3D` and caches it in
148
+ a module-level `WeakMap`. On a cache hit it refreshes the skinning state (`bindMatrix`,
149
+ `bindMatrixInverse`, `skeleton`) but never re-reads `object.geometry`. The equivalent proxy builder
150
+ in the same package, `render/utils/ThreeBypassRenderer.js:101`, *does* re-assign
151
+ `mesh.geometry = geometry` on every rebuild — the divergence is the tell.
152
+ - **Failure scenario**: A highlighted `SGMesh` entity crosses an LOD threshold and
153
+ `SGMeshSystem`/`ShadedGeometrySystem` swaps the `Object3D`'s `geometry` for the next LOD. The
154
+ visible mesh changes silhouette; the outline keeps tracing the previous LOD's geometry, so the
155
+ highlight no longer hugs the object — offset/oversized outline until the object is unhighlighted.
156
+ - **Fix**: In `obtain_id_mesh`, after the cache lookup, add `mesh.geometry = object.geometry;`
157
+ unconditionally.
158
+ - **Confidence**: Likely
159
+
160
+ ---
161
+
162
+ ### GFXR-8 `Water.updateShaderForTerrain` leaks a full terrain heightmap texture per call
163
+ - **Severity**: MINOR
164
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/water/Water.js:138-152`
165
+ - **Defect**: A new `DataTexture` wrapping the whole terrain height sampler is allocated and assigned
166
+ to `shader.uniforms.tHeightTexture.value`; the texture previously held by that uniform is never
167
+ `.dispose()`d. `WaterSystem.link` pushes the component onto `updateQueue`, so this runs once per
168
+ link — and `link` reuses the existing `component.__shader` when the component is re-linked
169
+ (`WaterSystem.js:164-175`), so each re-link allocates another one.
170
+ - **Failure scenario**: Level reload cycles unlink and re-link the Water component. Each cycle uploads
171
+ a fresh `R32F` heightmap — for a 1024×1024 terrain that is 4 MB of GPU memory — and orphans the
172
+ previous one. Twenty reloads leak ~80 MB of VRAM that three.js will never reclaim, because nothing
173
+ holds a reference to call `dispose()` on.
174
+ - **Fix**: Capture `const previous = shader.uniforms.tHeightTexture.value;` before the assignment and
175
+ `previous?.dispose()` after — the same replace-then-release shape `GraphicsEngine#bake_environment`
176
+ already uses for the PMREM target.
177
+ - **Confidence**: Confirmed
178
+
179
+ ---
180
+
181
+ ### GFXR-9 `FrameGraph.exportToJson` conflates resource-node ids with resource-registry ids
182
+ - **Severity**: MINOR
183
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/frame_graph/FrameGraph.js:479-508`
184
+ - **Defect**: The two id spaces are independent — `_createResourceEntry` numbers entries by
185
+ `__resource_registry.length`, `_createResourceNode` numbers nodes by `__resource_nodes.length` —
186
+ and `clone_resource` adds nodes without adding entries, so they diverge. The export passes a
187
+ registry id where a node id is required:
188
+ ```js
189
+ const node = this.getResourceNode(entry.resource_id); // registry id -> node lookup
190
+ ...
191
+ if (pass.reads(entry.resource_id)) // registry id vs node ids in resource_reads
192
+ ```
193
+ `getResourceNode`'s only protection is an `assert.equal`, which is compiled out in production.
194
+ - **Failure scenario**: `FramePassBuilder.write()` calls `graph.clone_resource()` for any write to a
195
+ resource the pass did not create — the normal case as soon as two passes touch one resource. In a
196
+ three-pass graph where pass B writes pass A's target, node ids run ahead of registry ids and
197
+ `exportToJson()` labels resources with another resource's name and emits reader/writer lists that
198
+ point at the wrong passes. The rendered GraphViz/JSON diagram misrepresents the pipeline it exists
199
+ to debug.
200
+ - **Fix**: Track the owning node per entry (or resolve registry id → node by scanning
201
+ `__resource_nodes` for `resource_id === entry.resource_id`), and compare `pass.reads/writes` against
202
+ node ids, not registry ids.
203
+ - **Confidence**: Confirmed
204
+
205
+ ---
206
+
207
+ ### GFXR-10 `PathDisplayContext.__build` aborts the whole build on one unknown spec type
208
+ - **Severity**: MINOR
209
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/path/PathDisplaySystem.js:135-139`
210
+ - **Defect**: Inside the loop over `display.specs`, an unrecognised `spec.type` logs a warning and
211
+ `return`s out of the entire method — skipping the remaining specs, the `ParentEntity` attachment
212
+ loop, `__build_existing_entities()`, and the `PathDisplayEvents.BuildComplete` dispatch. The
213
+ neighbouring failure path in the same loop (a builder that throws, lines 141-146) correctly
214
+ `catch`es and continues.
215
+ - **Failure scenario**: A `PathDisplay` with two specs, `[Ribbon, <stale type from an old save>]`. The
216
+ Ribbon builder runs and pushes its entities into `__owned_entities`, then the second spec hits the
217
+ `return`. Those entities are never `build(ecd)`-ed into the dataset, so the path renders nothing at
218
+ all — and `BuildComplete` never fires, so anything awaiting that event waits forever.
219
+ - **Fix**: `continue;` instead of `return;`.
220
+ - **Confidence**: Confirmed
221
+
222
+ ---
223
+
224
+ ### GFXR-11 `ShadedGeometrySystem.shutdown` never removes its render layer
225
+ - **Severity**: CRITICAL
226
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js:254` (create) vs `:280-294` (shutdown)
227
+ - **Defect**: `startup` does `this.__render_layer = graphics.layers.create('shaded-geometry')` and installs a
228
+ `buildVisibleSet` closure that resolves a per-view context from `this.__view_contexts`. `shutdown`
229
+ tears down every view context but never calls `graphics.layers.remove(this.__render_layer)`.
230
+ `graphics.layers` lives on the `GraphicsEngine`, which outlives the `EntityManager`. Every peer
231
+ system does remove its layer — `MeshSystem.js:247`, `WaterSystem.js:73`, `Trail2DSystem.js:117`,
232
+ `Trail3DSystem.js:134`, `GizmoRenderingPlugin.js:18`.
233
+ - **Failure scenario**: Level teardown/reload. `EntityManager.shutdown()` runs
234
+ `ShadedGeometrySystem.shutdown`, emptying `__view_contexts`; the layer stays registered and visible.
235
+ (a) If any frame renders before the new dataset is up, `VisibilityComputer.__processLayer` calls the
236
+ stale `buildVisibleSet`, `this.__view_contexts.get(view)` is `undefined`, and
237
+ `ctx.collect(...)` throws `TypeError: Cannot read properties of undefined (reading 'collect')` —
238
+ which aborts the whole visibility build, so *every* layer stops rendering.
239
+ (b) Adding a fresh `ShadedGeometrySystem` for the next level makes
240
+ `graphics.layers.create('shaded-geometry')` throw
241
+ `RenderLayer named 'shaded-geometry' already exists` (`RenderLayerManager.js:117`) — a hard crash on
242
+ level reload. The stale `compute_depth_range` closure also pins the dead BVH.
243
+ - **Fix**: In `shutdown`, `graphics.layers.remove(this.__render_layer); this.__render_layer = null;`
244
+ - **Confidence**: Confirmed
245
+
246
+ ---
247
+
248
+ ### GFXR-12 `SGMesh.materialOverride` is applied after `link`, bypassing the Forward+ material transform
249
+ - **Severity**: MAJOR
250
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js:205-207`, and the same defect at `aggregate/SGMesh.js:120-131`
251
+ - **Defect**: `ShadedGeometrySystem.link` exists precisely to close this hole; its own comment says the
252
+ material is forced "through the manager's transform chain, so that shader injection performed by the
253
+ lighting engine (Forward+ clustered lights, decals) cannot be skipped by callers that assign
254
+ `sg.material` directly" (`ShadedGeometrySystem.js:305-311`). In `SGMeshSystem`,
255
+ `entity_node.build(ecd)` (line 179) synchronously drives `ShadedGeometrySystem.link` for every child
256
+ `ShadedGeometry`, installing the transformed material — and *then* the traverse at 190-207 overwrites
257
+ it with the raw override:
258
+ ```js
259
+ if (material_override !== null) {
260
+ sg.material = material_override;
261
+ }
262
+ ```
263
+ `SGMesh.applyMaterialOverride()`, reached from the `set materialOverride` setter, does the same on an
264
+ already-linked hierarchy.
265
+ - **Failure scenario**: A unit is spawned with `SGMesh.fromURL('unit.gltf')` and a `materialOverride`
266
+ (team tint / ghost preview / damage flash) using a lit `MeshStandardMaterial`. Every part receives
267
+ the raw material, which never went through `MaterialManager.obtain`, so the Forward+
268
+ `onBeforeCompile` clustered-light injection is absent. The overridden unit renders with *no*
269
+ clustered point lights and no decals while every neighbouring unit in the same scene is lit
270
+ correctly — it looks flat/black at night. The `assert.ok(!isForwardPlusLightingSkipped(...))` guard
271
+ in `link` cannot catch it: it runs before the override, and asserts are stripped in production.
272
+ Reference counting is also skipped, so `MaterialManager` can neither dedupe nor reclaim the override.
273
+ - **Fix**: Route both sites through the manager
274
+ (`sg.material = materialManager.obtain(material_override).getValue()`), tracking/releasing the
275
+ reference the same way `ShadedGeometrySystem`'s `#material_references` does.
276
+ - **Confidence**: Confirmed (ordering verified; the lighting consequence follows from the contract
277
+ documented in `ShadedGeometrySystem.link`)
278
+
279
+ ---
280
+
281
+ ### GFXR-13 `BoneMapping.build` commits the WORST bone name match first
282
+ - **Severity**: MAJOR
283
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/mesh/skeleton/BoneMapping.js:13-15, 55, 61`
284
+ - **Defect**: `string_compute_similarity` is Jaro-Winkler and is documented "Higher value means string
285
+ are more similar". The comparator sorts **descending** (best first), and the consumption loop then
286
+ takes from the tail:
287
+ ```js
288
+ function byDistance(a, b) { return b.distance - a.distance; } // descending
289
+ matches.sort(byDistance);
290
+ ...
291
+ const match = matches.pop(); // takes the LEAST similar pair
292
+ ```
293
+ Because the inner loop immediately evicts every remaining entry sharing that `boneIndex` or
294
+ `inputIndex`, the worst pairing is locked in permanently — this is a greedy assignment run in
295
+ exactly reverse order.
296
+ - **Failure scenario**: Load a rigged glTF whose bones are `Hips, Spine, Chest, Neck, Head, …`.
297
+ `SkeletonUtils.findSkeletonBoneByType` builds the mapping on first use. The globally least-similar
298
+ (bone, name) pair — say (`HumanoidBoneType.Head`, `"toe-right"`) — is committed first and consumes
299
+ the `Head` slot. `Mesh.getBonePositionByType(result, HumanoidBoneType.Head)` then returns the world
300
+ position of the right toe, so anything anchored to a humanoid bone (weapon socket, head-mounted VFX,
301
+ nameplate) attaches to the wrong body part.
302
+ - **Fix**: Consume best-first — either flip the comparator to `a.distance - b.distance` and keep
303
+ `pop()`, or keep the sort and use `matches.shift()` (with the inner splice loop starting at 0).
304
+ - **Confidence**: Confirmed
305
+
306
+ ---
307
+
308
+ ### GFXR-14 `SGMeshAnimationControllerSystem.update` spins on one unloaded mesh and starves the rest of the queue
309
+ - **Severity**: MAJOR
310
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshAnimationControllerSystem.js:159-167` with `:57-68`, `:90-92`
311
+ - **Defect**: `update` pops up to 1000 entities per tick and calls `this.#process(entity)` without
312
+ awaiting. `#process` re-enqueues synchronously when the mesh has not loaded
313
+ (`if (mesh.node === null) { this.#enqueue(entity); return; }`), and `#enqueue` **pushes to the tail**
314
+ while `update` **pops from the tail**. The same entity is therefore popped and re-pushed
315
+ immediately, for all 1000 iterations.
316
+ ```js
317
+ const entity = this.#queue.pop();
318
+ this.#process(entity); // re-pushes to the same end it was popped from
319
+ ```
320
+ - **Failure scenario**: Three units spawn in the same frame; A and B have cached meshes, C's glTF is
321
+ still downloading. The queue is `[A, B, C]`. Frame 1: `pop()` yields C, C re-queues, `pop()` yields C
322
+ again — 1000 times. A and B are never reached. This repeats every frame until C's asset resolves, so
323
+ A and B never get `controller.bound` populated and stand completely frozen for the whole duration of
324
+ C's download, even though their own meshes were ready immediately. Also burns 1000 pop/push cycles
325
+ per frame doing nothing.
326
+ - **Fix**: Use FIFO — `this.#queue.shift()` in `update` (or push to the head in `#enqueue`) — and cap
327
+ the loop by the queue length captured *before* the loop, so re-queued entities are deferred to the
328
+ next tick rather than reprocessed within the same one.
329
+ - **Confidence**: Confirmed
330
+
331
+ ---
332
+
333
+ ### GFXR-15 HiZ occlusion query samples `n_max.y` as an x coordinate
334
+ - **Severity**: MAJOR
335
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/visibility/hiz/query/QueryShader.js:108`
336
+ - **Defect**: The four taps are meant to be the four corners of the projected AABB. The
337
+ bottom-right tap reads `vec2(n_max.y, n_min.y)` — `n_max.y` where `n_max.x` was meant:
338
+ ```glsl
339
+ float n1 = textureLod(utDepth, vec2(n_min.x, n_max.y), float(mip_to_use)).x;
340
+ float n2 = textureLod(utDepth, vec2(n_max.y, n_min.y), float(mip_to_use)).x; // n_max.x
341
+ ```
342
+ - **Failure scenario**: A wide, short object — a wall whose projected box spans x∈[0.1, 0.9],
343
+ y∈[0.40, 0.45]. `n2` samples at x = 0.45 instead of x = 0.9, so the depth in front of the wall's
344
+ right-hand half is never read. `n = max(n0..n3)` therefore under-reports the scene depth over that
345
+ region and `depth_delta = n - n_min.z` goes negative: the wall is classified occluded and culled
346
+ while plainly on screen. The error is silent, view-dependent, and worse the wider the object.
347
+ - **Fix**: `float n2 = textureLod(utDepth, vec2(n_max.x, n_min.y), float(mip_to_use)).x;`
348
+ - **Confidence**: Confirmed
349
+
350
+ ---
351
+
352
+ ### GFXR-16 `HierarchicalZBuffer.build_mips` publishes the mip chain on a property three.js never reads
353
+ - **Severity**: MINOR
354
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/visibility/hiz/buffer/HierarchicalZBuffer.js:168-169`
355
+ - **Defect**: `this.__input_buffer.mips = mips.map(m => m.texture);` — `THREE.Texture` in r136 has no
356
+ `mips` field; the array `WebGLTextures` consults when `generateMipmaps === false` is `mipmaps`.
357
+ The assignment creates an inert own-property, so the reduction targets are never bound as mip levels
358
+ of the texture that `BatchOcclusionQuery.execute` hands to the shader as `utDepth`.
359
+ - **Failure scenario**: The reduction pass fills every mip render target correctly, but `utDepth` still
360
+ has only level 0 (`minFilter: NearestFilter`, no uploaded chain), so every
361
+ `textureLod(utDepth, uv, float(mip_to_use))` clamps to level 0. A distant object whose AABB covers
362
+ one texel at `mip_to_use = 6` is tested with four full-resolution point samples instead of the
363
+ conservative max over its footprint: the hierarchical test degenerates into a 4-sample point test
364
+ and reports visible objects as occluded — geometry pops in and out at distance.
365
+ - **Fix**: Bind the reduction targets' textures as explicit `sampler2D` uniforms and index them in the
366
+ shader, or build a real `mipmaps` chain on `__input_buffer` that `WebGLTextures` will upload.
367
+ Renaming the property alone is not sufficient — `mipmaps` entries are image-like objects, not render
368
+ targets.
369
+ - **Confidence**: Likely (only in-repo consumer today is `hiz/prototypeHiZ.js`, so this is latent)
370
+
371
+ ---
372
+
373
+ ### GFXR-17 `SGMesh.copy()` does not copy `flags`, so `clone()` re-enables shadow casting
374
+ - **Severity**: MINOR
375
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js:82-88`
376
+ - **Defect**: `copy(other)` transfers `__url`, `__node`, `__initial_bounds` and `#material_override`
377
+ but not `flags` — the sole backing store for `castShadow`/`receiveShadow`/`Loaded`. `equals()`
378
+ (line 68) nonetheless compares `this.flags === other.flags`.
379
+ - **Failure scenario**: A prefab `SGMesh` with `castShadow = false` (a flat ground decal mesh, say).
380
+ `prefab.clone()` yields a component with `DEFAULT_FLAGS = CastShadow | ReceiveShadow`, so every
381
+ cloned instance casts a shadow the original explicitly disabled. Additionally
382
+ `prefab.equals(prefab.clone())` is `false`, defeating any equality/hash-keyed reuse of the component.
383
+ - **Fix**: Add `this.flags = other.flags & ~SGMeshFlags.Loaded;` to `copy()` (`Loaded` must be cleared
384
+ because `__node` is reset to `null`).
385
+ - **Confidence**: Confirmed
386
+
387
+ ---
388
+
389
+ ### GFXR-18 `SGMeshAnimationControllerSystem` has no `unlink`, so destroyed entities stay queued
390
+ - **Severity**: MINOR
391
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshAnimationControllerSystem.js:57-68` (no `unlink` anywhere in the class)
392
+ - **Defect**: `link` enqueues the entity when its mesh has not loaded. The class defines no `unlink`,
393
+ so nothing drains `#queue` when the entity is destroyed. `#process` then does
394
+ `ecd.getComponent(entity, SGMesh)` — which returns `undefined` for a removed entity
395
+ (`EntityComponentDataset` deletes the slot) — and dereferences `mesh.node`.
396
+ - **Failure scenario**: Spawn an entity with `SGMesh.fromURL(...)` + `SGMeshAnimationController`; the
397
+ asset is not yet resolved so `link` queues it. Destroy the entity the same frame (unit dies, preview
398
+ cancelled). Next tick, `update` pops it and `#process` throws
399
+ `TypeError: Cannot read properties of undefined (reading 'node')`. Because `update` calls the async
400
+ `#process` without awaiting, this surfaces as an unhandled promise rejection rather than a thrown
401
+ frame error — silent in production, and the diagnostics for the real problem are lost.
402
+ - **Fix**: Add `unlink(anim, mesh, entity)` that removes `entity` from `#queue`.
403
+ - **Confidence**: Confirmed
404
+
405
+ ---
406
+
407
+ ### GFXR-19 Ambient light with `castShadow` builds a shadow view, then crashes the frame
408
+ - **Severity**: MAJOR
409
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js:476-491`
410
+ - **Defect**: `__apply_castShadow` calls `__shadowmap_link()` whenever `castShadow` is true, with no check
411
+ that the underlying three light actually owns a `shadow`. `THREE.AmbientLight` does not — only
412
+ Directional/Spot/Point define one. Every *other* shadow site in the file guards for exactly this
413
+ (`applySettings:525` `if (shadow !== undefined)`, `__shadowmap_unlink:316`), and
414
+ `LightSystem.__visit_entity_to_update_shadow:210` excludes AMBIENT with the comment "only non-ambient
415
+ lights can cast shadow" — so this is a state the code already treats as reachable, not a can't-happen.
416
+ - **Failure scenario**: An entity carries `Light{type: AMBIENT, castShadow: true}` —
417
+ `Light.fromJSON` and `LightSerializationAdapter.serialize` both persist `castShadow` unconditionally
418
+ for every light type, so an editor toggle or a saved blueprint produces it. `link()` registers a
419
+ shadow `CameraView` with `graphics.views`. On the next `constructVisibleScene`,
420
+ `__shadowmap_prepare_view` does `const shadow = light.shadow;` (undefined) then
421
+ `const camera = shadow.camera;` → `TypeError`. That throw propagates out of
422
+ `CameraView.build_visibility` → `CameraViewManager.build_visibility` →
423
+ `GraphicsEngine.constructVisibleScene`, so the whole frame dies — every frame, permanently.
424
+ - **Fix**: `if (v && this.__shadow_map === null && light.shadow !== undefined) { … }`
425
+ - **Confidence**: Confirmed (crash mechanism verified against three r136; reachability requires the
426
+ ambient+castShadow authoring combination)
427
+
428
+ ---
429
+
430
+ ### GFXR-20 Shadow cameras have `matrixAutoUpdate = false`, so `LightShadow.updateMatrices` cannot refresh their pose
431
+ - **Severity**: MAJOR
432
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/light/binding/three/ThreeLightBinding.js:549`
433
+ - **Defect**: `applySettings` sets `shadow.camera.matrixAutoUpdate = false` for directional/spot shadows.
434
+ three r136's `LightShadow.updateMatrices` writes `shadowCamera.position` / calls `lookAt(...)` and then
435
+ relies on `shadowCamera.updateMatrixWorld()` to recompose — but `Object3D.updateMatrixWorld` only calls
436
+ `updateMatrix()` when `matrixAutoUpdate` is true, and `matrixWorldNeedsUpdate` is false at that point,
437
+ so neither `matrix` nor `matrixWorld`/`matrixWorldInverse` is updated. (`lookAt` itself calls
438
+ `updateWorldMatrix(true,false)`, which is equally inert, so even the look rotation is derived from the
439
+ stale world position.) The point-light branch two lines above documents precisely this requirement and
440
+ keeps `matrixAutoUpdate = true`; the directional/spot branch does the opposite. `LightSystem.js:325`
441
+ even has a comment asserting the opposite of what happens: *"refresh shadow camera world matrix from
442
+ the light's pose before we read matrixWorldInverse"* — `shadow.updateMatrices(light, 0)` there is a
443
+ no-op with respect to `matrixWorldInverse`.
444
+ - **Failure scenario**: The only place that ever bakes the pose is `__shadowmap_prepare_view`
445
+ (`camera.updateMatrix(); camera.updateMatrixWorld();`), fired from `preVisibilityBuild` — i.e. earlier
446
+ in the frame than `three_update_shadow_camera_extents`, which runs on
447
+ `visibilityConstructionEnded`. (a) First frame a light starts casting: `prepare_view` bakes the
448
+ constructor pose (origin, identity), so `compute_view_frustum_aabb_in_space` fits the ortho box in
449
+ **world** space instead of light space — a visibly wrong/missing shadow flash on level load.
450
+ (b) Steady state: a spot light carried by a moving character always renders and fits from the pose
451
+ captured on the previous frame, so its shadow trails the light while strafing.
452
+ - **Fix**: Leave `matrixAutoUpdate` at three's default `true` for all shadow cameras (three's own
453
+ `WebGLShadowMap` never disables it), or explicitly call `shadow.camera.updateMatrix();
454
+ shadow.camera.updateMatrixWorld();` after every `shadow.updateMatrices(light, i)`.
455
+ - **Confidence**: Confirmed (mechanism verified against `three/src/lights/LightShadow.js` and
456
+ `Object3D.updateMatrixWorld` in r136)
457
+
458
+ ---
459
+
460
+ ### GFXR-21 `three_update_shadow_camera_extents` rebuilds the main camera's projection matrix, discarding every projection modifier
461
+ - **Severity**: MAJOR
462
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/light/LightSystem.js:334-345`
463
+ - **Defect**: To fit the shadow box, the function truncates `camera.far`, calls
464
+ `camera.updateProjectionMatrix()`, reads the matrix, then restores `far` and calls
465
+ `updateProjectionMatrix()` again. The in-code claim that "callers downstream see no change" is wrong:
466
+ `updateProjectionMatrix()` regenerates the matrix from `fov/aspect/near/far`, restoring the *default*
467
+ projection — not whatever the matrix previously contained. `CameraView.set_from_camera:123` writes
468
+ modified matrices straight back into `camera.projectionMatrix.elements`, and it runs *earlier* in the
469
+ same frame (`GraphicsEngine.constructVisibleScene`: `set_from_camera` at line 707,
470
+ `visibilityConstructionEnded` — where this function is hooked — at line 710).
471
+ - **Failure scenario**: `TemporalSupersamplingRenderPlugin` is enabled and one shadow-casting
472
+ directional light has a finite `maxShadowDistance` below `camera.far` (e.g. 60 vs 1000), so
473
+ `needs_truncation` is true. Every frame the jitter written into `elements[8]/[9]` is wiped before the
474
+ scene is drawn, so TAA resamples the identical position forever: the image never converges and edge
475
+ aliasing is exactly as if TAA were off, while the plugin still pays its full cost. Setting
476
+ `maxShadowDistance = Infinity` makes TAA start working — a baffling coupling. Any other registered
477
+ `CameraView.projection_modifier` is destroyed the same way.
478
+ - **Fix**: Do not mutate the live camera. Build the truncated projection into a scratch `Matrix4` with
479
+ `makePerspective(...)` and multiply that by `camera.matrixWorldInverse`; failing that, save and restore
480
+ the 16 elements of `projectionMatrix` (and `projectionMatrixInverse`) verbatim.
481
+ - **Confidence**: Confirmed (mechanism and frame ordering both verified)
482
+
483
+ ---
484
+
485
+ ### GFXR-22 Binary light serializer drops POINT `distance` and DIRECTION `maxShadowDistance`
486
+ - **Severity**: MAJOR
487
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/light/LightSerializationAdapter.js:22-26` and `:41-45`
488
+ - **Defect**: `distance` is written and read only inside `if (type === LightType.SPOT)`, but the
489
+ component uses `distance` for POINT as well (`Light.js:51`, `LightBinding.scaled_distance`,
490
+ `ThreeLightBinding.__apply_distance`, `FPLightBinding.#updateDistance`). The JSON adapter gets it right
491
+ — `Light.toJSON` writes `distance` for `SPOT || POINT` (verified) — which pins this as an oversight
492
+ rather than a schema decision. `maxShadowDistance` (written by `toJSON` for DIRECTION) is absent from
493
+ the binary format entirely.
494
+ - **Failure scenario**: A torch entity `Light{type: POINT, distance: 20}` is saved through the binary ECS
495
+ serializer. On load, `deserialize` never reads `distance`, so the component keeps
496
+ `DEFAULT_DISTANCE = 1`; `__apply_distance` sets the three `PointLight.distance = 1` (or the Forward+
497
+ `radius = 1`). The torch illuminates a 1-unit sphere and the room around it is black — while the exact
498
+ same scene loaded from a JSON save looks correct.
499
+ - **Fix**: Write/read `distance` in a `SPOT || POINT` branch mirroring `Light.toJSON`, add
500
+ `maxShadowDistance` for DIRECTION, and bump `version` from 0 since the byte layout changes.
501
+ - **Confidence**: Confirmed
502
+
503
+ ---
504
+
505
+ ### GFXR-23 `LightSystem.shutdown` never detaches the three light cache
506
+ - **Severity**: MAJOR
507
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/light/LightSystem.js:97` (attach, in the constructor) vs `:162-171` (shutdown)
508
+ - **Defect**: The constructor does `this.__three_light_cache.attach(this.scene)`. `shutdown()` releases
509
+ the Forward+ plugin and detaches the `visibilityConstructionEnded` handler, but never calls the
510
+ `ThreeLightCache.detach()` that exists for exactly this purpose. Every three light the cache ever
511
+ created — including pooled, currently-unused ones — stays parented to `graphics.scene`, which outlives
512
+ the `EntityManager`.
513
+ - **Failure scenario**: The host app keeps one `GraphicsEngine` across level loads and rebuilds the
514
+ `EntityManager` (a new `LightSystem` each time). After each cycle the previous cycle's
515
+ `DirectionalLight`/`PointLight`/`SpotLight`/`AmbientLight` objects remain in the scene.
516
+ `WebGLRenderer.projectObject` pushes every visible `isLight` object into `WebGLLights` regardless of
517
+ intensity, so `NUM_DIR_LIGHTS`/`NUM_POINT_LIGHTS`/`NUM_SPOT_LIGHTS` grow one generation per load: every
518
+ material's program cache key changes so **all** materials recompile on each load (multi-second hitch),
519
+ and after a handful of cycles the fragment uniform budget is exceeded and materials fail to link —
520
+ black scene.
521
+ - **Fix**: Call `this.__three_light_cache.detach()` in `shutdown()`, and move the `attach(this.scene)`
522
+ from the constructor into `startup()` so a stopped-then-restarted system still works.
523
+ - **Confidence**: Confirmed (leak); the recompile/black-scene escalation depends on the host recycling
524
+ the `EntityManager`
525
+
526
+ ---
527
+
528
+ ### GFXR-24 Shadow texel snapping uses a grid whose spacing changes every frame
529
+ - **Severity**: MINOR
530
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/ecs/light/shadow/setShadowCameraDimensionsDiscrete.js:28-36`
531
+ - **Defect**: `rX = dX / shadow_map_width` where `dX`/`dY` are the light-space extents of the *current*
532
+ frame's view-frustum AABB, recomputed every frame by `three_update_shadow_camera_extents`. Snapping a
533
+ moving origin to a grid whose spacing also moves does not produce a stable world-space texel lattice —
534
+ the step the algorithm depends on ("Fix the overall size of the frustum based on the longest diagonal
535
+ … Don't allow the shadow frustum to change size as the camera rotates", `LightSystem.js:201`) is
536
+ documented but never implemented. Secondary: for negative `x0`, JS `%` returns a negative remainder, so
537
+ `x0_d = x0 - (x0 % rX) - rX/2` can land up to half a texel *inside* `x0`, clipping coverage off the
538
+ left/bottom edge (the `(w+1)/w` slack is added only at the far edge).
539
+ - **Failure scenario**: Slowly orbit the camera over a static scene lit by one shadow-casting sun. The
540
+ shadow map re-quantises onto a different lattice each frame, so shadow boundaries crawl and shimmer
541
+ texel by texel — exactly the artifact the discretisation exists to remove. With the camera positioned
542
+ so the fit box straddles the origin, up to half a texel of shadow is also missing along one edge.
543
+ - **Fix**: Derive a frame-invariant extent from the view frustum's longest diagonal at the shadow
544
+ distance and use it for `dX`/`dY`, then snap with `Math.floor(x / rX) * rX` instead of `%`.
545
+ - **Confidence**: Likely
546
+
547
+ ---
548
+
549
+ ### GFXR-25 Forward+ vertex-only lighting reads `gl_Position` before `<project_vertex>` writes it
550
+ - **Severity**: MAJOR
551
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/materials/fp_build_vertex_lighting_shared.js:9-13, 26`
552
+ - **Defect**: The froxel-lookup preamble is injected immediately after `void main() {`:
553
+ ```js
554
+ result = insert_after(result, 'void main() {', accumulation_pars);
555
+ ```
556
+ and `accumulation_pars` begins with
557
+ `vec3 fp_normalized_screen_position = ((gl_Position.xyz / gl_Position.w)+vec3(1.0))*0.5;`.
558
+ In a three.js vertex shader `gl_Position` is assigned much later, by `#include <project_vertex>`.
559
+ This is an unconditional read of a vertex-stage built-in output before it is written.
560
+ - **Failure scenario**: A lit material compiled with `defines.LIGHTING_VERTEX_ONLY === true` (the branch
561
+ `MaterialTransformer.js:63` selects) computes `clip_v` from an undefined value, so
562
+ `v3_cluster_position` indexes a random froxel. Out-of-range `texelFetch` returns 0 →
563
+ `fp_cluster_metadata.y == 0` → the mesh receives **zero** clustered light and renders unlit; in-range,
564
+ it is lit by an unrelated part of the screen and flickers per vertex as the garbage changes.
565
+ - **Fix**: Inject after `#include <project_vertex>` instead, or compute the clip position locally
566
+ (`projectionMatrix * modelViewMatrix * vec4(position, 1.0)`) rather than reading `gl_Position`.
567
+ - **Confidence**: Confirmed (the read-before-write is unconditional; no in-repo material currently sets
568
+ `LIGHTING_VERTEX_ONLY`, so this is public-surface breakage rather than a live regression)
569
+
570
+ ---
571
+
572
+ ### GFXR-26 `LightManager.dispose()` frees GPU objects but leaves every light still subscribed to the dead manager
573
+ - **Severity**: MAJOR
574
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/LightManager.js:1137-1142`
575
+ - **Defect**: `dispose()` disposes four textures and nothing else. Three subscription families survive:
576
+ `LightRenderMetadata.link` (`LightRenderMetadata.js:52`) binds `this.update` to
577
+ `light.position.onChanged` / `light.radius.onChanged` (removed only by `removeLight` → `unlink()`);
578
+ `__handle_visible_light_added` (`:596-597`) binds `__handle_light_dimensions_change` /
579
+ `__handle_light_appearance_change`; `__handle_visible_decal_added` (`:538-546`) binds to
580
+ `patch_uv.position.onChanged` / `patch_uv.size.onChanged` and stores an un-released
581
+ `Reference<AtlasPatch>`. `__decal_atlas` is never disposed either.
582
+ - **Failure scenario**: `ForwardPlusRenderingPlugin.shutdown()` disposes the manager while a scene with
583
+ FP point lights and decals is still loaded (plugin released before entities unlink, or an engine
584
+ reconfiguration). Every live `PointLight.position` signal still holds a handler bound to the dead
585
+ manager, keeping it, its BVH, its cluster-plane buffers and all atlas patches reachable — a full leak
586
+ per plugin cycle. Worse, moving any of those lights afterwards still runs
587
+ `LightRenderMetadata.update()`, writing bounds into the abandoned BVH; re-acquiring the plugin creates
588
+ a second `LightManager` while the first keeps mutating.
589
+ - **Fix**: In `dispose()`, iterate `#metadata_map` calling `data.unlink()` and clear it; drain
590
+ `__visible_lights`/`__visible_decals` through the existing `__handle_visible_*_removed` teardown so the
591
+ handlers and atlas references are released; dispose `__decal_atlas`.
592
+ - **Confidence**: Likely
593
+
594
+ ---
595
+
596
+ ### GFXR-27 Forward+ `SpotLight` is accepted by `addLight` and then silently never rendered
597
+ - **Severity**: MAJOR
598
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/LightManager.js:771-796`
599
+ - **Defect**: The visibility dispatch branches on `light.isDecal` then `light.isPointLight` and drops
600
+ everything else on the floor. `render/forward_plus/model/SpotLight.js` implements everything `addLight`
601
+ requires (`getAABB` via `cone_compute_bounding_box`, `onDimensionChanged`, `toArray`), so
602
+ `addLight(spotLight)` succeeds and inserts a BVH leaf — it is simply never binned.
603
+ `encode_light_type` would have thrown on it and `spot_light_inside_volume` exists, but neither is
604
+ reached.
605
+ - **Failure scenario**: A consumer builds a `SpotLight` from `forward_plus/model/SpotLight.js` and adds
606
+ it to the manager expecting a cone of light. Nothing appears and nothing is logged — the light silently
607
+ contributes zero for the lifetime of the scene. Companion trap: `SpotLight.prototype.ENCODED_SLOT_COUNT`
608
+ is never assigned and `toArray` returns 13 (not a multiple of 4), so naively adding the branch makes
609
+ `address += undefined` produce `NaN` and trips the "Expected light data size" throw at `:878`.
610
+ - **Fix**: Either reject unsupported light types loudly in `addLight`, or complete the spot path —
611
+ `SpotLight.prototype.ENCODED_SLOT_COUNT = 16` (pad `toArray` to a 4-slot boundary), a type code in
612
+ `encode_light_type`, an `isSpotLight` branch here using `spot_light_inside_volume`, and the matching
613
+ branch in `query_bvh_frustum_from_texture`.
614
+ - **Confidence**: Likely
615
+
616
+ ---
617
+
618
+ ### GFXR-28 `decal_filtering_enabled` setter never re-uploads, and leaves a mipmap-incomplete texture
619
+ - **Severity**: MINOR
620
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/LightManager.js:359-367` (constructor at `:221-223`)
621
+ - **Defect**: The setter flips `t.generateMipmaps` and stops — `texture.version` is never bumped, so
622
+ three does not re-upload and the setting has no effect until an unrelated atlas repack. When that
623
+ repack eventually happens, `generateMipmaps === false` while `minFilter` is still
624
+ `LinearMipMapLinearFilter`; on WebGL2 three's `setTextureParameters` applies `LINEAR_MIPMAP_LINEAR`
625
+ verbatim and `uploadTexture` skips `generateMipmap`.
626
+ - **Failure scenario**: A game follows the method's own JSDoc ("Please set this to false if you have a
627
+ lot of overlapping decals") and sets `lightManager.decal_filtering_enabled = false`. Nothing changes on
628
+ screen. Later a new decal texture is registered, the atlas repacks and re-uploads — and every decal now
629
+ samples a mipmap-incomplete texture, rendering solid black instead of its diffuse.
630
+ - **Fix**: `t.generateMipmaps = v; t.minFilter = v ? LinearMipMapLinearFilter : LinearFilter;
631
+ t.needsUpdate = true;`
632
+ - **Confidence**: Confirmed (missing re-upload); Likely (black-decal consequence)
633
+
634
+ ---
635
+
636
+ ### GFXR-29 Debug froxel grid uses a 3-channel stride on the RGBA cluster texture and overruns each axis
637
+ - **Severity**: MINOR
638
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/debug/createScreenGrid.js:47-51` and `:272-281`
639
+ - **Defect**: `const texel_address = texel_index * 3; // RGB format` — the cluster texture is RGBA:
640
+ `LightManager.__assign_lights_to_clusters` writes at `tile_index * 4` (`LightManager.js:970`) and
641
+ `LightManager.spec.js:23` asserts a 4-element image for a 1×1×1 grid. Stride 3 aliases into the wrong
642
+ texel for every cell but index 0. The loops additionally run `i < resolution.N + 1`, so
643
+ `resolution.x - 1 - i_x` reaches `-1` and the z loop reads a slice past the end.
644
+ - **Failure scenario**: Open the debug screen grid on a 12×6×4 grid. Cell (3,2,1)'s reported light count
645
+ is read from a completely different froxel, so both the heatmap and the click-tooltip light list
646
+ describe the wrong cells — the tool actively misleads anyone debugging the binning.
647
+ - **Fix**: Use `texel_index * 4` / `index * 4` in both places and drop the `+ 1` from all three loop
648
+ bounds.
649
+ - **Confidence**: Confirmed
650
+
651
+ ---
652
+
653
+ ### GFXR-30 Cluster-volume debug widget clones the 3D cluster texture every frame and never disposes it
654
+ - **Severity**: MINOR
655
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/debug/buildLightClusterWidget.js:56-64`
656
+ - **Defect**: `const t = lm.getTextureClusters().clone(); t.needsUpdate = true; m.uniforms.map.value = t;`
657
+ — a fresh `DataTexture3D` per `update()`, with the previous clone dropped without `.dispose()`. Its GL
658
+ texture object stays in `WebGLTextures`' property map for the widget's renderer until context loss.
659
+ - **Failure scenario**: `update()` is driven from the render loop. At 60 fps with the default
660
+ 32×16×16 RGBA16UI volume (~64 KB each) that is ~4 MB/s of leaked GPU memory; a couple of minutes of
661
+ debugging and the tab hits out-of-memory / context-lost.
662
+ - **Fix**: Clone once outside `update()` (the clone shares `image`, so only `needsUpdate = true` is
663
+ needed per frame), or `m.uniforms.map.value?.dispose()` before assigning the new clone.
664
+ - **Confidence**: Confirmed
665
+
666
+ ---
667
+
668
+ ### GFXR-31 `sort_decal_data` uses a moving pivot and sorts on slots that hold colour, not priority
669
+ - **Severity**: MINOR
670
+ - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/graphics/render/forward_plus/sort_decal_data.js:20-24, 65-76`
671
+ - **Defect**: Two independent errors. (a) The comparator reads `data[address + 20]` as `draw_priority`
672
+ and `+ 21` as `id`, but `Decal.toArray` (`model/Decal.js:116-121`) has both of those writes commented
673
+ out and `array_copy(this.color, 0, destination, address + 20, 4)` occupies slots 20-23 — so it sorts
674
+ decals by their red and green channels. (b) The quicksort pivot is an *index*, not a captured value;
675
+ `lookup[pivotIndex]` is itself swapped during partitioning, destroying the scan sentinel. The correct
676
+ sibling `core/collection/array/array_sort_quick.js` captures the pivot value before the loop.
677
+ - **Failure scenario**: Re-enable the call site the `TODO fix decal sorting artifacts` block at
678
+ `LightManager.js:995-1003` currently guards (or call this exported function directly). When the pivot
679
+ entry is swapped to a higher-priority value, `i` walks past `right`, `compare_decals` starts reading
680
+ `undefined`, and the subsequent `lookup[j] = lookup[i]` stores `0` into a neighbouring froxel's lookup
681
+ run — that froxel's decal slot then points at light-data texel 0 and renders the wrong decal. This is
682
+ precisely the artifact the TODO describes.
683
+ - **Fix**: Capture the pivot record (`const pivot_encoded = lookup[pivotIndex];`) and compare values, not
684
+ indices; and restore the `draw_priority`/`id` writes in `Decal.toArray` (widening
685
+ `ENCODED_SLOT_COUNT` past 24) or read priority from a slot that is actually written.
686
+ - **Confidence**: Likely
687
+
688
+ ---
689
+
690
+ ## Verified clean / non-issues checked along the way
691
+
692
+ - `GraphicsEngine.prepareRenderPass` writes `visibleGroup.length = j` where `children.length` was
693
+ meant — harmless: `clearVisibleGroup()` truncates `children` to 0 first, so `children.length`
694
+ already equals `j`. No failure scenario, not reported.
695
+ - `OutlineRenderer.writeParameters` → `HashMap.forEach` passes `(value, key)`, which matches
696
+ `__write_parameters_for_definition(id, definition)`. Correct.
697
+ - `OutlineRenderPlugin` subscribe/unsubscribe pairs match (`Vector2.process` adds to `onChanged` with
698
+ the same handler + context that `shutdown` removes).
699
+ - `AmbientOcclusionPostProcessEffect` startup/shutdown binding pairs all match; all four GPU resources
700
+ are disposed.
701
+ - TAA jitter indices (`elements[8]`/`[9]`) and magnitude match the pinned spec; the `=` (rather than
702
+ `+=`) is deliberate, since `CameraView.set_from_camera` writes the jittered matrix back onto the
703
+ camera and `CameraSystem`'s `visibilityConstructionStarted` hook rebuilds it each frame.
704
+ - `Water.updateBounds` BVH box agrees with the plane mesh's rotated/offset world extent.
705
+ - `FrameBufferManager.computeRenderOrder` splice-while-iterating is correctly compensated
706
+ (`i--; openSetCount--`), as is `WaterSystem.processUpdateQueue`.
707
+ - `GizmoRenderingPlugin` overrides `RenderLayer.buildVisibleSet` (whose prototype version throws
708
+ `'deprecated'`) — but `VisibilityComputer.__processLayer` still calls it, so gizmos do render.
709
+ - `RenderLayer.js:59`'s comment claims near is `planes[4]` and far is `planes[5]` (they are the other
710
+ way round), but it documents `computeNearFarClippingPlanes`, which unconditionally throws
711
+ `'deprecated'`. Stale doc only.
712
+ - Forward+ cluster index arithmetic, depth-slice distribution, plane orientation, the near/far swap and
713
+ X-flip in `computeFrustumCorners`, texel packing and the light-count overflow/recursion path are all
714
+ internally consistent and agree with `cluster_binning.spec.js` /
715
+ `light_culling_no_false_exclusion.spec.js`.
716
+ - `query_bvh_frustum_from_texture.js:132` masks the light address with `& 0xFFFFFFF8` where the encoding
717
+ (`type | address << 2`) calls for `& 0xFFFFFFFC`. Currently harmless — every record length in use
718
+ (`PointLight` 8, `Decal` 24) is a multiple of 8 — so no failure scenario exists today. Noted, not filed.
719
+ - `LightBinding` / `FPLightBinding` / `LightContext` link-unlink subscription pairs are symmetric;
720
+ `ThreeLightCache.release` keys off `light2type(threeObject)` rather than the already-changed component
721
+ type, so type-change rebuilds return the light to the correct pool.
722
+ - `__shadowmap_unlink` disposes both `shadow.map` and `shadow.mapPass`;
723
+ `three_set_shadow_resolution` disposes before resizing; `compute_view_frustum_aabb_in_space`'s plane
724
+ ordering and `near = -z1 / far = -z0` are correct.
725
+ - `ShadedGeometrySystem.link/unlink`, `SGMeshSystem.process`, `SGMeshHighlightSystem` and
726
+ `IncrementalDeltaSet` were checked in detail and are balanced/correct.
727
+ - `FPDecalSystem.Context` correctly handles the async texture-load race (`__is_linked` and
728
+ `this.__fp_decal === fpDecal` re-checks) — the only defect there is the known `subscribe`/`unsubscribe`
729
+ typo.
730
+ - `SpriteSystemPE`, `AnimationControllerSystem`, `RenderableHighlightSystem`,
731
+ `ShadedGeometryHighlightSystem`, `Trail3DSystem` and `GizmoRenderingPlugin` have matching
732
+ subscribe/unsubscribe pairs.
733
+
734
+ ## Coverage note
735
+
736
+ Not exhaustively reviewed for lack of time: `ecs/path/tube/build/*` and `ecs/path/ribbon/`
737
+ (heavily spec-covered geometry builders), `ecs/animation/animator/*` (graph/blend-space state machine,
738
+ little graphics-correctness surface), and the GLSL bodies of `shaders/TerrainShader.js` /
739
+ `shaders/AmbientOcclusionShader.js` / `render/buffer/simple-fx/ao/SAOShader.js` (the JS-side uniform
740
+ wiring for those *was* reviewed and is clean).