@woosh/meep-engine 3.60.4 → 3.60.5

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 (379) hide show
  1. package/CHANGELOG.md +2602 -0
  2. package/CONTRIBUTING.md +7 -0
  3. package/MIGRATION_2_TO_3.md +136 -0
  4. package/SECURITY.md +4 -0
  5. package/editor/EditorCameraNavigation.d.ts +2 -1
  6. package/editor/EditorCameraNavigation.d.ts.map +1 -1
  7. package/editor/EditorCameraNavigation.js +51 -57
  8. package/package.json +6 -2
  9. package/src/engine/EngineHarness.d.ts +3 -9
  10. package/src/engine/EngineHarness.d.ts.map +1 -1
  11. package/src/engine/EngineHarness.js +6 -8
  12. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts +9 -6
  13. package/src/engine/graphics/camera/makeOrbitalCameraController.d.ts.map +1 -1
  14. package/src/engine/graphics/camera/makeOrbitalCameraController.js +44 -71
  15. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts +64 -0
  16. package/src/engine/graphics/camera/orbital/MomentumAxis.d.ts.map +1 -0
  17. package/src/engine/graphics/camera/orbital/MomentumAxis.js +187 -0
  18. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts +86 -0
  19. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.d.ts.map +1 -0
  20. package/src/engine/graphics/camera/orbital/OrbitalCameraRig.js +319 -0
  21. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts +34 -10
  22. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.d.ts.map +1 -1
  23. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +116 -30
  24. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts +1 -7
  25. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.d.ts.map +1 -1
  26. package/src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +1 -37
  27. package/src/engine/graphics/ecs/water/Water.d.ts +8 -0
  28. package/src/engine/graphics/ecs/water/Water.d.ts.map +1 -1
  29. package/src/engine/graphics/ecs/water/Water.js +8 -0
  30. package/src/engine/graphics3/WaterSystem.d.ts.map +1 -1
  31. package/src/engine/graphics3/WaterSystem.js +731 -734
  32. package/src/engine/graphics3/decal/DecalTileShader.d.ts +61 -0
  33. package/src/engine/graphics3/decal/DecalTileShader.d.ts.map +1 -0
  34. package/src/engine/graphics3/decal/DecalTileShader.js +138 -0
  35. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts +10 -4
  36. package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts.map +1 -1
  37. package/src/engine/graphics3/decal/GPUDecalRenderer.js +149 -44
  38. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts +25 -0
  39. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.d.ts.map +1 -0
  40. package/src/engine/graphics3/decal/chunk_decal_tile_vertex.js +55 -0
  41. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts +22 -0
  42. package/src/engine/graphics3/decal/graph_gather_decal_tiles.d.ts.map +1 -0
  43. package/src/engine/graphics3/decal/graph_gather_decal_tiles.js +70 -0
  44. package/src/engine/graphics3/decal/shader_decal_composite.d.ts +7 -5
  45. package/src/engine/graphics3/decal/shader_decal_composite.d.ts.map +1 -1
  46. package/src/engine/graphics3/decal/shader_decal_composite.js +48 -44
  47. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts +12 -0
  48. package/src/engine/graphics3/decal/shader_decal_tile_copy.d.ts.map +1 -0
  49. package/src/engine/graphics3/decal/shader_decal_tile_copy.js +78 -0
  50. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts +11 -0
  51. package/src/engine/graphics3/decal/shader_gather_decal_tiles.d.ts.map +1 -0
  52. package/src/engine/graphics3/decal/shader_gather_decal_tiles.js +80 -0
  53. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts +13 -0
  54. package/src/engine/input/devices/mouse/MouseEventButtons.d.ts.map +1 -0
  55. package/src/engine/input/devices/mouse/MouseEventButtons.js +23 -0
  56. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts +4 -0
  57. package/src/engine/input/ecs/controllers/KeyboardCameraController.d.ts.map +1 -1
  58. package/src/engine/input/ecs/controllers/KeyboardCameraController.js +9 -45
  59. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  60. package/src/shade/playground/water_refraction/README.md +5 -6
  61. package/src/shade/playground/water_refraction/index.html +1 -1
  62. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  63. package/src/shade/renderer/Renderer.js +7 -5
  64. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts +40 -80
  65. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts.map +1 -1
  66. package/src/shade/renderer/camera/orbital/OrbitalCameraController.js +197 -147
  67. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  68. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  69. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  70. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  71. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  72. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +2 -2
  73. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +2 -2
  74. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +2 -1
  75. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
  76. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +18 -1
  77. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts +31 -0
  78. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts.map +1 -0
  79. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.js +343 -0
  80. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts +17 -0
  81. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts.map +1 -0
  82. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.js +29 -0
  83. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -1
  84. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +7 -13
  85. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  86. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +1 -8
  87. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +5 -5
  88. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
  89. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +10 -10
  90. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +1 -4
  91. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  92. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +1 -10
  93. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +5 -15
  94. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +1 -1
  95. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +6 -34
  96. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  97. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -7
  98. package/src/shade/renderer/hiz/HZBFootprint.d.ts +14 -0
  99. package/src/shade/renderer/hiz/HZBFootprint.d.ts.map +1 -0
  100. package/src/shade/renderer/hiz/HZBFootprint.js +16 -0
  101. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts +10 -0
  102. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts.map +1 -0
  103. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.js +11 -0
  104. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts +10 -0
  105. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts.map +1 -0
  106. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.js +11 -0
  107. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +0 -7
  108. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  109. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +405 -350
  110. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts +12 -0
  111. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts.map +1 -0
  112. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.js +27 -0
  113. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts +12 -0
  114. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts.map +1 -0
  115. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.js +27 -0
  116. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts +14 -0
  117. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts.map +1 -0
  118. package/src/shade/renderer/hiz/hzb_footprint_texels.js +34 -0
  119. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +0 -5
  120. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
  121. package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +37 -57
  122. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts +11 -0
  123. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts.map +1 -0
  124. package/src/shade/renderer/hiz/{shader_hzb_reduce_mip0_clip.js → shader_hzb_reduce_mip0.js} +120 -111
  125. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  126. package/src/shade/renderer/material/GPUMaterialManager.d.ts +7 -0
  127. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  128. package/src/shade/renderer/material/GPUMaterialManager.js +11 -0
  129. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +12 -12
  130. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  131. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +17 -118
  132. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  133. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +7 -2
  134. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +0 -6
  135. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  136. package/src/shade/renderer/water/GPUWaterRenderer.js +12 -17
  137. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts +35 -0
  138. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts.map +1 -0
  139. package/src/shade/renderer/water/medium/graph_water_meshlets.js +89 -0
  140. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  141. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  142. package/src/shade/renderer/water/shader_water.js +22 -13
  143. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
  144. package/src/shade/renderer/water/shader_water_avboit.js +7 -7
  145. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +1 -1
  146. package/src/shade/renderer/water/surface/graph_water_tessellation.js +1 -1
  147. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +9 -1
  148. package/editor/REWORK_PLAN_2026_08.md +0 -692
  149. package/src/CODEC_LAYOUT_VERIFICATION.md +0 -419
  150. package/src/CORRECTNESS_HUNT_2026_07_24.md +0 -142
  151. package/src/DUPLICATION_AUDIT_2026_08_07/00_core_reuse_surface.md +0 -738
  152. package/src/DUPLICATION_AUDIT_2026_08_07/A_core_math_geom.md +0 -79
  153. package/src/DUPLICATION_AUDIT_2026_08_07/B_core_data.md +0 -93
  154. package/src/DUPLICATION_AUDIT_2026_08_07/C_gfx_render.md +0 -80
  155. package/src/DUPLICATION_AUDIT_2026_08_07/D_gfx_features.md +0 -164
  156. package/src/DUPLICATION_AUDIT_2026_08_07/E_physics.md +0 -69
  157. package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +0 -110
  158. package/src/DUPLICATION_AUDIT_2026_08_07/G_net_save.md +0 -129
  159. package/src/DUPLICATION_AUDIT_2026_08_07/H_engine_misc.md +0 -72
  160. package/src/DUPLICATION_AUDIT_2026_08_07/I_generation_view.md +0 -74
  161. package/src/DUPLICATION_AUDIT_2026_08_07/K_crosscutting.md +0 -169
  162. package/src/DUPLICATION_AUDIT_2026_08_07.md +0 -254
  163. package/src/DUPLICATION_AUDIT_REMEDIATION.md +0 -250
  164. package/src/DUPLICATION_REVIEW_2026_10_24.md +0 -1072
  165. package/src/REVIEW_2026_08_06/adv-core.md +0 -511
  166. package/src/REVIEW_2026_08_06/adv-gfx.md +0 -480
  167. package/src/REVIEW_2026_08_06/adv-view.md +0 -446
  168. package/src/REVIEW_2026_08_06/api-core.md +0 -296
  169. package/src/REVIEW_2026_08_06/api-engine.md +0 -195
  170. package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +0 -507
  171. package/src/REVIEW_2026_08_06/core-binary.md +0 -348
  172. package/src/REVIEW_2026_08_06/core-collection.md +0 -376
  173. package/src/REVIEW_2026_08_06/core-math.md +0 -221
  174. package/src/REVIEW_2026_08_06/core-process.md +0 -266
  175. package/src/REVIEW_2026_08_06/core-science.md +0 -223
  176. package/src/REVIEW_2026_08_06/engine-ai-nav.md +0 -279
  177. package/src/REVIEW_2026_08_06/engine-animation.md +0 -167
  178. package/src/REVIEW_2026_08_06/engine-asset.md +0 -166
  179. package/src/REVIEW_2026_08_06/engine-ecs.md +0 -920
  180. package/src/REVIEW_2026_08_06/engine-input.md +0 -197
  181. package/src/REVIEW_2026_08_06/engine-misc.md +0 -248
  182. package/src/REVIEW_2026_08_06/engine-terrain.md +0 -52
  183. package/src/REVIEW_2026_08_06/generation.md +0 -176
  184. package/src/REVIEW_2026_08_06/geom-2d.md +0 -434
  185. package/src/REVIEW_2026_08_06/geom-3d.md +0 -117
  186. package/src/REVIEW_2026_08_06/gfx-gi.md +0 -143
  187. package/src/REVIEW_2026_08_06/gfx-render.md +0 -740
  188. package/src/REVIEW_2026_08_06/gfx-texture.md +0 -690
  189. package/src/REVIEW_2026_08_06/prior-criticals.md +0 -49
  190. package/src/REVIEW_2026_08_06/prior-highs.md +0 -138
  191. package/src/REVIEW_2026_08_06/test-gaps.md +0 -364
  192. package/src/REVIEW_2026_08_06/view.md +0 -667
  193. package/src/REVIEW_2026_08_06.md +0 -610
  194. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +0 -542
  195. package/src/core/bvh2/bvh3/NOTES.md +0 -2
  196. package/src/core/bvh8/NOTES.md +0 -63
  197. package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +0 -243
  198. package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +0 -417
  199. package/src/core/color/COLOR_REVIEW_2026_08_28.md +0 -779
  200. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +0 -433
  201. package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +0 -486
  202. package/src/core/geom/3d/atlas/BFF_PLAN.md +0 -174
  203. package/src/core/geom/3d/atlas/REVIEW_02.md +0 -392
  204. package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +0 -146
  205. package/src/core/geom/3d/gjk/NOTES.md +0 -8
  206. package/src/core/geom/3d/topology/TOPO_MESH_RETIREMENT_PLAN.md +0 -135
  207. package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +0 -381
  208. package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +0 -684
  209. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +0 -554
  210. package/src/core/model/reactive/evaluation/PREDICATE_APPLICABILITY_PROPOSAL.md +0 -446
  211. package/src/engine/REVIEW_2026_07_03.md +0 -211
  212. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +0 -815
  213. package/src/engine/control/first-person/DESIGN.md +0 -658
  214. package/src/engine/control/first-person/DESIGN_COLLISION.md +0 -382
  215. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +0 -563
  216. package/src/engine/control/first-person/TODO.md +0 -160
  217. package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +0 -531
  218. package/src/engine/ecs/HIERARCHY_REVIEW.md +0 -717
  219. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +0 -262
  220. package/src/engine/ecs/ik/PLAN.md +0 -179
  221. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +0 -272
  222. package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +0 -199
  223. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +0 -521
  224. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +0 -463
  225. package/src/engine/graphics/ecs/camera/pp/NOTES.md +0 -48
  226. package/src/engine/graphics/render/frame_graph/CORRECTNESS_FIXES_2026_09_04.md +0 -659
  227. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +0 -235
  228. package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +0 -490
  229. package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +0 -466
  230. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +0 -717
  231. package/src/engine/input/ecs/ism/ISM_DESIGN.md +0 -1523
  232. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +0 -627
  233. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +0 -661
  234. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +0 -229
  235. package/src/engine/network/CONGESTION_CONTROL.md +0 -87
  236. package/src/engine/network/MESSAGE_TRANSPORT.md +0 -364
  237. package/src/engine/network/SMOOTHNESS_DESIGN.md +0 -400
  238. package/src/engine/physics/cloth/MEASUREMENTS.md +0 -5304
  239. package/src/engine/physics/cloth/PLAN.md +0 -3056
  240. package/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md +0 -1382
  241. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +0 -243
  242. package/src/engine/physics/fluid/solver/NOTES.md +0 -46
  243. package/src/engine/sound/SOUND_EMITTER_RETIREMENT_PLAN.md +0 -536
  244. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +0 -432
  245. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +0 -250
  246. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +0 -322
  247. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +0 -261
  248. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +0 -121
  249. package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +0 -999
  250. package/src/format/image/avif/DECISIONS.md +0 -545
  251. package/src/format/image/jpeg/NOTES.md +0 -3
  252. package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +0 -814
  253. package/src/generation/COORDINATES.md +0 -54
  254. package/src/generation/REVIEW_01_ACTION_PLAN.md +0 -628
  255. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +0 -220
  256. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +0 -172
  257. package/src/generation/foliage/CROWN_FULLNESS_BRIEF_2026_10_26.md +0 -86
  258. package/src/generation/foliage/FOLIAGE_DESIGN.md +0 -547
  259. package/src/generation/foliage/FOLIAGE_PLAN.md +0 -198
  260. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +0 -158
  261. package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +0 -521
  262. package/src/generation/foliage/REAL_TIME_TREES_BRIEF_2026_10_27.md +0 -86
  263. package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +0 -347
  264. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +0 -248
  265. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +0 -694
  266. package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +0 -552
  267. package/src/shade/RENDERER_CONTRACT.md +0 -697
  268. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +0 -263
  269. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +0 -569
  270. package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +0 -755
  271. package/src/shade/device/mock/EXTENSION_PROPOSAL_2026_08_22.md +0 -458
  272. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +0 -255
  273. package/src/shade/device/mock/REVIEW_2026_08_22.md +0 -527
  274. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +0 -894
  275. package/src/shade/device/timing/profile/SGPT_FORMAT.md +0 -345
  276. package/src/shade/renderer/NOTES.md +0 -78
  277. package/src/shade/renderer/PLAN.md +0 -8
  278. package/src/shade/renderer/animation/ADDITIVE_BLENDING_PLAN.md +0 -145
  279. package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +0 -357
  280. package/src/shade/renderer/atmosphere/NOTES.md +0 -6
  281. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts +0 -76
  282. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts.map +0 -1
  283. package/src/shade/renderer/camera/orbital/MomentumAxis.js +0 -164
  284. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts +0 -45
  285. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts.map +0 -1
  286. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.js +0 -66
  287. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +0 -98
  288. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +0 -1
  289. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +0 -184
  290. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +0 -175
  291. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +0 -1
  292. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +0 -411
  293. package/src/shade/renderer/camera/orbital/README.md +0 -81
  294. package/src/shade/renderer/camera/orbital/index.d.ts +0 -6
  295. package/src/shade/renderer/camera/orbital/index.d.ts.map +0 -1
  296. package/src/shade/renderer/camera/orbital/index.js +0 -9
  297. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +0 -964
  298. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +0 -361
  299. package/src/shade/renderer/geometry/bvh/BLAS_REFIT_BATCH_PLAN.md +0 -619
  300. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +0 -674
  301. package/src/shade/renderer/geometry/sdf/NOTES.md +0 -6
  302. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +0 -540
  303. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +0 -305
  304. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +0 -913
  305. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +0 -787
  306. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +0 -481
  307. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +0 -301
  308. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +0 -448
  309. package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +0 -385
  310. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +0 -656
  311. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +0 -308
  312. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +0 -657
  313. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +0 -551
  314. package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +0 -529
  315. package/src/shade/renderer/global_illumination/lpv/NOTES.md +0 -3
  316. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +0 -4306
  317. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +0 -410
  318. package/src/shade/renderer/global_illumination/sharc/NOTES.md +0 -8
  319. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +0 -1369
  320. package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +0 -202
  321. package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +0 -94
  322. package/src/shade/renderer/hiz/NOTES.md +0 -3
  323. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +0 -8
  324. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +0 -1
  325. package/src/shade/renderer/light/cluster/NOTES.md +0 -11
  326. package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +0 -524
  327. package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +0 -1101
  328. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts +0 -24
  329. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts.map +0 -1
  330. package/src/shade/renderer/material/resident/shader_resident_texture_means.js +0 -120
  331. package/src/shade/renderer/particles/DESIGN.md +0 -1011
  332. package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +0 -280
  333. package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +0 -453
  334. package/src/shade/renderer/path_tracer/PATH_TRACED_MEDIA_PLAN_2026_10_02.md +0 -520
  335. package/src/shade/renderer/postprocess/bloom/NOTES.md +0 -6
  336. package/src/shade/renderer/postprocess/fsr/NOTES.md +0 -4
  337. package/src/shade/renderer/postprocess/gtao/NOTES.md +0 -6
  338. package/src/shade/renderer/postprocess/nss/NOTES.md +0 -332
  339. package/src/shade/renderer/postprocess/perspective/NOTES.md +0 -3
  340. package/src/shade/renderer/postprocess/sscs/NOTES.md +0 -5
  341. package/src/shade/renderer/postprocess/ssr/NOTES.md +0 -14
  342. package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +0 -286
  343. package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +0 -39
  344. package/src/shade/renderer/postprocess/taa/NOTES.md +0 -11
  345. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +0 -78
  346. package/src/shade/renderer/postprocess/vrs/NOTES.md +0 -4
  347. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +0 -1218
  348. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +0 -600
  349. package/src/shade/renderer/restir/reservoir/NOTES.md +0 -6
  350. package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +0 -6
  351. package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +0 -391
  352. package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +0 -153
  353. package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +0 -322
  354. package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +0 -247
  355. package/src/shade/renderer/shader/chunk/fsr/NOTES.md +0 -3
  356. package/src/shade/renderer/shader/chunk/fsr/spd/NOTES.md +0 -4
  357. package/src/shade/renderer/shader/chunk/geometry/ray/NOTES.md +0 -4
  358. package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +0 -159
  359. package/src/shade/renderer/shader/chunk/mboit/NOTES.md +0 -38
  360. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/NOTES.md +0 -3
  361. package/src/shade/renderer/shader/chunk/spherical_harmonics/sampling/NOTES.md +0 -8
  362. package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +0 -927
  363. package/src/shade/renderer/shadow/contact/FINDINGS.md +0 -413
  364. package/src/shade/renderer/shadow/map/csm/NOTES.md +0 -5
  365. package/src/shade/renderer/shadow/ray/NOTES.md +0 -31
  366. package/src/shade/renderer/shadow/sdf/NOTES.md +0 -9
  367. package/src/shade/renderer/shadow/sdf/brixelizer/NOTES.md +0 -5
  368. package/src/shade/renderer/shadow/sdf/cascade/NOTES.md +0 -9
  369. package/src/shade/renderer/shadow/vsm/NOTES.md +0 -12
  370. package/src/shade/renderer/shadow/vsm/PLAN.md +0 -442
  371. package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +0 -43
  372. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +0 -2444
  373. package/src/shade/renderer/texture/mipmaps/NOTES.md +0 -3
  374. package/src/shade/renderer/volumetrics/NOTES.md +0 -1329
  375. package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +0 -336
  376. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +0 -23
  377. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +0 -1
  378. package/src/shade/renderer/water/medium/GPUWaterBodies.js +0 -75
  379. package/src/shade/wgsl/NOTES.md +0 -4
@@ -1,166 +0,0 @@
1
- # Correctness review — `meep/src/engine/asset/`
2
-
3
- Scope: 81 non-spec source files under `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/`.
4
- Existing suite state at review time: 18 suites / 119 tests pass, 1 suite skipped (`NativeImageDecoder.spec.js`).
5
-
6
- ---
7
-
8
- ### ASSET-1 Adam7 de-interlacing overflows its scanline buffer on pass 7
9
- - **Severity**: CRITICAL
10
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/loaders/image/png/PNGReader.js:497` (allocation) and `:523` (offset)
11
- - **Defect**: `interlaceAdam7` uses a double-buffered scanline (`line_offset = (y % 2) * passLineBytes`) but allocates only **one** line: `new Uint8Array(width * bytes_per_pixel)`. Pass 7 has `pass_width === width`, so `passLineBytes === width * bytes_per_pixel` — the whole buffer. Every odd-`y` scanline of pass 7 is therefore written entirely past the end of the typed array (writes silently dropped) and read back as `undefined` → stored as 0. The same odd-`y` region is also handed to the next line as `output_offset_previous`, so Up/Average/Paeth rows in pass 7 predict from zeros as well.
12
- - **Failure scenario**: Any Adam7-interlaced PNG at least 4 pixels tall. Verified with a synthetic 2x4 8-bit grayscale interlaced PNG whose pixels are `[10,11, 20,21, 30,31, 40,41]`; `PNGReader.parse()` returns `[10,11, 20,21, 30,31, 0,0]`. Same test in RGB (colorType 2) returns the last row as `0,0,0, 0,0,0`. On a real interlaced PNG this blacks out output rows 3, 7, 11, 15, … (≈25% of the image) and corrupts more when non-`None` filters are used.
13
- - **Fix**: allocate two lines — `new Uint8Array(2 * width * bytes_per_pixel)` (or `2 * max_pass_line_bytes`). Note pass 5 with an odd width also overruns by `bytes_per_pixel` today, and the same fix covers it.
14
- - **Confidence**: Confirmed (reproduced by execution)
15
-
16
- ---
17
-
18
- ### ASSET-2 Fetch stream error during download hangs the load forever
19
- - **Severity**: CRITICAL
20
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/loaders/ArrayBufferLoader.js:43-63`
21
- - **Defect**: `observeResponseProgress`'s `pump()` does `reader.read().then(({done, value}) => {...})` with **no rejection handler**. If the underlying body stream errors mid-download (dropped connection, TLS reset, server abort, `net::ERR_INCOMPLETE_CHUNKED_ENCODING`), the read promise rejects; `controller.close()` / `controller.error()` are never called, so the wrapper `ReadableStream` stays open forever. `await response.arrayBuffer()` on line 154 never settles, so `load()` neither calls `success` nor `failure` and never rejects.
22
- - **Failure scenario**: `assetManager.promise('data/models/big.glb', 'arraybuffer')`, server drops the connection after 3 MB of a 10 MB body → the `PendingAsset` stays in `request_map` and in `#pending_asset_active_load_set` forever. With a finite `load_concurrency` it also permanently consumes a concurrency slot. `AssetPreloader` never fires `levelFinished` for that level, so the loading screen never advances, and a graceful `AssetManager.shutdown()` never resolves (`#drain` waits on `request_map.size === 0`). Also produces an unhandled promise rejection. All PNG loads go through this loader (`ImageRGBADataLoader.__decode_via_worker`), so this is on the default image path.
23
- - **Fix**: attach a rejection handler in `pump()` that calls `controller.error(e)` (and stop pumping), e.g. `reader.read().then(onChunk, e => controller.error(e))`. A `cancel(reason)` on the stream prototype that calls `reader.cancel(reason)` is also worth adding so an aborted consumer releases the reader.
24
- - **Confidence**: Confirmed
25
-
26
- ---
27
-
28
- ### ASSET-3 Alpha-tested GLTF meshes never receive their custom depth material
29
- - **Severity**: MAJOR
30
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/loaders/GLTFAssetLoader.js:260-272`
31
- - **Defect**: The comment says a custom depth material is needed whenever `alphaTest !== 0`, and a `MeshDepthMaterial` is constructed unconditionally in that branch — but the assignment to `object.customDepthMaterial` sits inside `if (this.__enable_texture_cache)`. `__enable_texture_cache` is initialised to `false` (line 171) and there is no setter anywhere in the repo, so the branch is never taken. The freshly built `MeshDepthMaterial` is allocated and immediately dropped.
32
- - **Failure scenario**: Load a GLTF whose foliage/decal material has `alphaTest = 0.5`. `object.customDepthMaterial` stays undefined → three renders the shadow pass with the default depth material, which ignores `alphaTest`+`map`, so a cut-out leaf plane casts a solid rectangular shadow. Every such mesh also allocates a throwaway `MeshDepthMaterial` per load.
33
- - **Fix**: always assign, and only route through the cache when de-duplication is enabled:
34
- `object.customDepthMaterial = this.__enable_texture_cache ? materialCache.acquire(depthMaterial) : depthMaterial;`
35
- - **Confidence**: Confirmed
36
-
37
- ---
38
-
39
- ### ASSET-4 Texture loader rejects `jpeg` — including every `data:image/jpeg` URI
40
- - **Severity**: MAJOR
41
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/loaders/texture/TextureAssetLoader.js:33-44`
42
- - **Defect**: The dispatch switch handles only `'dds'`, `'png'`, `'jpg'`. The data-URI branch above it extracts the extension from the MIME subtype (`match[1]`), and the canonical MIME type for JPEG is `image/jpeg` — never `image/jpg`. So the one input format the data-URI branch exists to support cannot reach a loader. Plain files named `*.jpeg` fail the same way.
43
- - **Failure scenario**: `assetManager.promise('data:image/jpeg;base64,/9j/4AAQSkZJRg...', 'texture')` → `computeFileExtension` returns `null` (base64 contains no `.`), the regex matches, `fileExtension = 'jpeg'`, the switch falls to `default` and throws `Unsupported texture file format: 'jpeg'`. The manager catches the synchronous throw and fails the request. Same for `assetManager.promise('data/ui/portrait.jpeg', 'texture')`.
44
- - **Fix**: add `case 'jpeg':` (and `case 'webp':`, which `loadStandardImageTexture` handles fine via three's `TextureLoader`) alongside `case 'jpg':`.
45
- - **Confidence**: Confirmed
46
-
47
- ---
48
-
49
- ### ASSET-5 Texture loaders violate the `progress(current, total)` contract
50
- - **Severity**: MAJOR
51
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/loaders/texture/loadStandardImageTexture.js:37` and `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/loaders/texture/loadDDSTexture.js:36`
52
- - **Defect**: Both pass the manager's `progress` callback straight into three.js's `onProgress` slot. three invokes `onProgress(progressEvent)` with a *single* `ProgressEvent` argument, but `AssetLoader.load`'s documented contract (and everything downstream) is `progress(current: number, total: number)`. `GLTFAssetLoader.load:443-445` gets this right (`progress(xhr.loaded, xhr.total)`); the texture loaders do not.
53
- - **Failure scenario**: `assetManager.promise('data/t/rock.png', 'texture', { progress: (loaded, total) => bar.set(loaded / total) })` → `loaded` is a `ProgressEvent`, `total` is `undefined`, so `bar.set(NaN)`. Independently, `AssetManager.#dispatch_pending_asset`'s `progress` closure does `pendingAsset.progress.setValue(progressEvent)` / `setUpperLimit(undefined)` on a `BoundedValue`, which accepts them without validation (`BoundedValue.setValue` has no numeric guard) — any UI reading `PendingAsset.progress` gets a non-numeric value and a NaN ratio.
54
- - **Fix**: wrap, as GLTFAssetLoader does: `e => progress(e.loaded, e.total)`.
55
- - **Confidence**: Confirmed
56
-
57
- ---
58
-
59
- ### ASSET-6 `NativeImageDecoder.decodeSync` always throws — it reads the image before it has loaded
60
- - **Severity**: MAJOR
61
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/loaders/image/codec/NativeImageDecoder.js:71-85`
62
- - **Defect**: `decodeSync` sets `image.src = objectURL` and calls `make_decoded_data(image)` on the next line. Loading a blob URL into an `HTMLImageElement` is asynchronous — at that point `image.width`/`image.height` are still `0`. `decode()` sizes the canvas to `0x0` and calls `context.getImageData(0, 0, 0, 0)`, which per the HTML spec throws `IndexSizeError` when `sw` or `sh` is zero. There is no code path in which this method can return a decoded image.
63
- - **Failure scenario**: `new NativeImageDecoder().decodeSync(pngBytes)` → `IndexSizeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The source width is 0.` The only test for it (`NativeImageDecoder.spec.js:18`) is `test.skip`ped, and its expectation asserts a `channels: 4` field the implementation never produces — the method has never been executed.
64
- - **Fix**: there is no synchronous path from encoded bytes to pixels in the DOM; either delete `decodeSync` or reimplement it over an already-decoded source (`ImageBitmap`/`ImageData`) rather than raw bytes.
65
- - **Confidence**: Confirmed
66
-
67
- ---
68
-
69
- ### ASSET-7 Palette PNG: indices past the end of `tRNS` become fully transparent instead of opaque
70
- - **Severity**: MAJOR
71
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/loaders/image/png/PNG.js:216-230` (specifically `:219-221`)
72
- - **Defect**: `getPixel`, colour-type 3, does `a = this.transparency_lookup[pixels[i]]` with no bounds check. The PNG spec allows a `tRNS` chunk shorter than the palette; missing entries are fully opaque (255). Reading past the `Uint8Array` yields `undefined`, which a `Uint8Array` destination stores as **0** — fully transparent. `getUint8Data_case3` (`PNG.js:369-377`) implements the spec rule correctly, so the two readers of the same PNG disagree.
73
- - **Failure scenario**: An indexed PNG with a 256-entry PLTE and a 2-entry tRNS (the common "index 0 and 1 are the transparent ones" encoding produced by pngquant/optipng). `png.getRGBA8Array()` → `getRGBA8Array_generic` → `getPixel`: every pixel using palette index ≥ 2 gets alpha 0, i.e. the whole opaque body of the image is returned invisible.
74
- - **Fix**: mirror `getUint8Data_case3`: `const idx = pixels[i]; a = idx < this.transparency_lookup.length ? this.transparency_lookup[idx] : 255;`
75
- - **Confidence**: Confirmed
76
-
77
- ---
78
-
79
- ### ASSET-8 `decodetEXt` / `decodeiEXt` parse the whole PNG file instead of the chunk
80
- - **Severity**: MAJOR
81
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/loaders/image/png/PNGReader.js:260-267` and `:273-295`
82
- - **Defect**: `PNGReader.readBytes` returns `new Uint8Array(buffer.data, buffer.position, length)` — a *view* into the whole-file `ArrayBuffer` with a non-zero `byteOffset`. Both text decoders then do `BinaryBuffer.fromArrayBuffer(chunk.buffer)`, which binds the **entire PNG file** and resets `position` to 0, discarding `chunk.byteOffset` entirely. `png_chunk_decode_zTXt`/`png_chunk_decode_iTXt` handle this correctly (they explicitly set `buffer.position = chunk.byteOffset`); these two do not. `decodetEXt` additionally computes the value length as `keyword.length - 1`, which has no relation to the value's actual length (it should be `chunk.length - keyword.length - 1`).
83
- - **Failure scenario**: `reader.decodetEXt(chunk)` on any PNG → the keyword is read from byte 0 of the file, i.e. the PNG signature `\x89PNG\r\n\x1a\n…`, stopping at the first NUL; `png.text` is keyed by that garbage and holds a value sliced at an arbitrary length. Never the chunk's real keyword/value.
84
- - **Fix**: bind the chunk's own range in both methods, as the `png_chunk_decode_*` helpers do (`fromArrayBuffer(chunk.buffer)` + `position = chunk.byteOffset`, bounded by `chunk.byteLength`), and compute the tEXt value length as `chunk.byteLength - (position - chunk.byteOffset)`.
85
- - **Confidence**: Confirmed
86
-
87
- ---
88
-
89
- ### ASSET-9 Stale `Asset` value returned from `STATIC_ASSET_CACHE` after an asset is replaced
90
- - **Severity**: MAJOR
91
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/STATIC_ASSET_CACHE.js:9-16` (with `Asset.equals`/`Asset.hash` at `Asset.js:45-63`)
92
- - **Defect**: The cache is keyed by `Asset` using `invokeObjectEquals`/`invokeObjectHash`, and `Asset.equals` treats two *distinct* `Asset` objects as equal whenever their `description` matches (`AssetManager.#settle` stamps `value.description = assetDescription` on every load). So the cache key identifies the *description*, not the instance, and a replacement `Asset` for the same `(path, type)` collides with the old one's cached materialisation.
93
- - **Failure scenario**: `assetManager.remove('data/models/hero.glb', 'model/gltf')` (or `insert()` with a rebuilt asset — `AssetManager.insert:664` explicitly supports replacement and only warns) followed by a fresh load produces a new `Asset` B with the same description as the evicted `Asset` A. `SGMeshSystem` (`engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js:144`) calls `STATIC_ASSET_CACHE.get(B)`, hits A's entry, and renders the *old* `Object3D` — the replacement is silently ignored until the cache evicts. Secondarily, every `Asset` whose `description` is still `null` hashes to 0, so all pre-settle assets pile into one bucket.
94
- - **Fix**: key the cache by identity (a `Map`/`WeakMap` on the `Asset` instance) rather than by description equality, or purge the entry for a description on `AssetManager.remove`/`insert`.
95
- - **Confidence**: Confirmed (mechanism); trigger requires an asset replacement flow
96
-
97
- ---
98
-
99
- ### ASSET-10 `guessAssetType` mis-slices any URL that does not contain `data/`
100
- - **Severity**: MINOR
101
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/guessAssetType.js:12`
102
- - **Defect**: `url.substring(url.indexOf('data/') + 'data/'.length)` — when `'data/'` is absent, `indexOf` returns `-1` and the expression becomes `substring(4)`, silently chopping the first four characters of the URL and then deriving the "asset directory" from the mangled remainder. There is no `-1` branch.
103
- - **Failure scenario**: `guessAssetType('assets/models/hero.json')` → `indexOf` is `-1` → `substring(4)` = `'ts/models/hero.json'` → directory `'ts'` → returns `'json'` instead of `'three.js'`. `GameCreationScene.js:153` and `view/renderModel.js:77` feed the result straight into `assetManager.get({ type })`, so the model is handed to `JsonAssetLoader` and the caller receives a raw object where an `Object3D` factory was expected.
104
- - **Fix**: `const i = url.indexOf(assetRootPath); let assetDirectory = i === -1 ? url : url.substring(i + assetRootPath.length);`
105
- - **Confidence**: Confirmed
106
-
107
- ---
108
-
109
- ### ASSET-11 `textureMipmapEqual` compares height against width
110
- - **Severity**: MINOR
111
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/loaders/material/computeTextureEquality.js:207`
112
- - **Defect**: `if (a.height !== b.width) { return false; }` — copy-paste; should be `a.height !== b.height`.
113
- - **Failure scenario**: Two byte-identical 512x256 compressed-texture mip levels: `a.width === b.width` passes, then `a.height (256) !== b.width (512)` returns `false`. `computeTextureEquality` therefore reports identical non-square textures as different, so `GLTFAssetLoader.__texture_cache` and `StaticMaterialCache.textureCache` never de-duplicate non-square DDS/compressed textures — every GLTF instance keeps its own GPU upload.
114
- - **Fix**: `if (a.height !== b.height) { return false; }`
115
- - **Confidence**: Confirmed
116
-
117
- ---
118
-
119
- ### ASSET-12 `computeImageBitmapHash` hashes the red channel `itemSize` times and ignores G/B/A
120
- - **Severity**: MINOR
121
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/loaders/material/computeImageBitmapHash.js:31-36`
122
- - **Defect**: The inner loop reads `sampler_data[address]` — `address` is never offset by the loop variable `i`, so channel 0 is folded into the hash four times and channels 1..3 are never read.
123
- - **Failure scenario**: Two 8x8 `ImageBitmap`s that share the red channel but differ entirely in green/blue/alpha (e.g. a red-channel-packed roughness map vs. a metalness map baked from the same source) hash identically. Every such texture lands in the same `HashSet` bucket in `GLTFAssetLoader.__texture_cache` (capacity 2048), degrading the de-dup pass to a linear scan with a full `computeImageBitmapEquality` (GPU readback + array compare) per collision. The result stays correct because equality is exact; the cost is not.
124
- - **Fix**: `const v = sampler_data[address + i];`
125
- - **Confidence**: Confirmed
126
-
127
- ---
128
-
129
- ### ASSET-13 `NativeImageDecoder.decode` leaks the object URL when decoding fails
130
- - **Severity**: MINOR
131
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/loaders/image/codec/NativeImageDecoder.js:87-104`
132
- - **Defect**: `URL.revokeObjectURL(url)` runs only after `await image.decode()` resolves. If `decode()` rejects (corrupt/unsupported bytes) the function throws and the blob URL — and the blob it pins — is never released.
133
- - **Failure scenario**: `CodecWithFallback` routes every non-PNG through `NativeImageDecoder`. A batch of truncated or unsupported image assets (a CDN serving an HTML error page under an image path, so `image.decode()` rejects) leaks one `Blob` per failed asset for the lifetime of the document.
134
- - **Fix**: wrap in `try { … } finally { URL.revokeObjectURL(url); }`.
135
- - **Confidence**: Confirmed
136
-
137
- ---
138
-
139
- ### ASSET-14 Preloader global progress never reaches 1 once any asset fails
140
- - **Severity**: MINOR
141
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/preloader/AssetPreloader.js:264-281` and `:291-304`
142
- - **Defect**: `on.progress` is dispatched only from `assetLoadSuccess`, and the global ratio is `#asset_count_loaded / #asset_count`. Failures increment `#asset_count_failed` (which counts toward `#try_finish`) but are excluded from the progress numerator and emit no progress event at all. The last progress event a listener ever sees is therefore `(total - failures) / total`.
143
- - **Failure scenario**: 20 queued assets, one 404s. The final `on.progress` reports `0.95`; `on.resolved` then fires with `(19, 1)`. A loading bar driven by `on.progress` freezes at 95% and the scene switches under it. (Note the previously-suspected missing level-completion check in `assetLoadFailed` is present and correct at lines 299-301 — a failure does close its level batch.)
144
- - **Fix**: dispatch progress from `assetLoadFailed` too, and compute the ratio from processed count: `(#asset_count_loaded + #asset_count_failed) / #asset_count`, keeping the loaded count as a separate field on the payload.
145
- - **Confidence**: Confirmed
146
-
147
- ---
148
-
149
- ### ASSET-15 JPEG malformed-APP1 recovery compares a 16-bit marker against 8-bit constants
150
- - **Severity**: MINOR
151
- - **File**: `H:/git/moh/app/src/mir-engine/meep/src/engine/asset/loaders/image/jpeg/JpegImage.js:365`
152
- - **Defect**: `fileMarker` comes from `readUint16()`, so APP0/APP1 are `0xFFE0`/`0xFFE1`. The recovery branch tests `fileMarker === 0xE0 || fileMarker === 0xE1`, which can never be true. The whole `malformedDataOffset` recovery path (lines 365-377), added per the comment to handle "malformed APP1 markers popular in some phone models", is unreachable.
153
- - **Failure scenario**: A phone-camera JPEG with a malformed APP1 segment reaches the `default` case; instead of resynchronising it falls through to `throw new Error("unknown JPEG marker " + …)` and `jpeg_decode` fails outright, where the intended behaviour was to skip the bad segment and decode.
154
- - **Fix**: compare against `0xFFE0`/`0xFFE1`.
155
- - **Confidence**: Confirmed
156
-
157
- ---
158
-
159
- ## Status of the pre-declared "already known" items
160
-
161
- | Item | Status |
162
- | --- | --- |
163
- | `AssetPreloader.assetLoadFailed` missing the level-completion check | **FIXED** — the `(batchElementLoadedCount + batchElementFailedCount) >= batch_size` guard is present at `AssetPreloader.js:299-301`; a failure closes its level. (Separate, still-live progress accounting issue filed as ASSET-14.) |
164
- | 1-bit and sub-8-bit palette PNG decoding to garbage | **STILL PRESENT** — `png_filter_unFilterNone` unpacks sub-byte samples one-per-byte while filters 1–4 (`Sub`/`Up`/`Average`/`Paeth`) copy packed bytes, and `interlaceNone` sizes both `pixels` and `length` as *packed* bytes (`ceil(bpp*width)`), so even the None path only emits `ceil(width/2)` of `width` nibbles. `PNG.getUint8Data_case3` compounds it with `d = colors * ceil(bitDepth/8)` → 1, reading two 4-bit indices as one. Interlaced sub-8-bit is worse still: `interlaceAdam7`'s `bytes_per_pixel` is fractional, so `new Uint8Array(fractional)` truncates to a zero/short buffer. |
165
- | `SVGAssetLoader` hanging on any non-200 response | **STILL PRESENT** — `SVGAssetLoader.js:9-21`: the `load` handler only acts when `status === 200`, and the `error` listener does not fire for HTTP error statuses, so 404/500/3xx neither resolve nor reject. Additionally the 200 path never checks for a `<parsererror>` root, so malformed SVG resolves as a "successful" asset whose `create()` clones an error node. |
166
- | Worker image decoder detaching a cached `ArrayBuffer` | **STILL PRESENT** — `ThreadedImageDecoder.decode` passes `[data.buffer]` to `OnDemandWorkerManager.request`, transferring/neutering the buffer that `ImageRGBADataLoader.__decode_via_worker` obtained from the cached `arraybuffer` `Asset`. Second request for the same path re-uses the cached (now detached) asset → zero-length image. It also kills the `CodecWithFallback` chain: after the threaded codec fails, `NativeImageDecoder` receives a detached `data` and can only produce an empty blob. |