@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,521 +0,0 @@
1
- # Transform → Transform64 migration plan
2
-
3
- *Revision 3, 2026-09-04. Revision 2 was rejected on three counts, all correctly: it invented a
4
- change-detection mechanism next to one the ECS already has, it proposed deleting engine code on
5
- "no importers" evidence, and its facade would have left the abstraction layers Transform64 exists to
6
- remove. This revision replaces the architecture; the survey work underneath it stands.*
7
-
8
- *Update, 2026-09-05: the change-detection mechanism specified below - `EventType.ComponentChanged`
9
- carrying `{klass, instance}` - has been replaced by one event name per component that announces
10
- itself: `TRANSFORM64_EVENT_CHANGE` (`@transform64/change`) and `TRANSFORM_ATTACHMENT_EVENT_CHANGE`
11
- (`@transform_attachment/change`), each sent with no payload, so a listener is woken only by the
12
- thing it asked about and has nothing to filter. `EventType.ComponentChanged` is gone, and with it
13
- the residual unknown about broadening it. Everything else here stands; read `ComponentChanged`
14
- throughout as "the changed component's own event".*
15
-
16
- ---
17
-
18
- ## Where things stand
19
-
20
- `Transform64` is a `Float64Array` subclass, 23 elements: a column-major matrix at `[0..15]` whose
21
- translation column `[12..14]` **is** the translation, a rotation quaternion at `[16..19]`, a scale at
22
- `[20..22]`. One buffer, one allocation, no sub-objects, no signals, no flags. Thirty-six source files
23
- use it — `Node3D`, `Mesh`, the pose and skinning pipeline, the glTF loader, `MeshSystem`,
24
- `m4_decompose_array`.
25
-
26
- `Transform` is the registered ECS component: a class holding a live `Vector3` position, a live
27
- `Quaternion` rotation, a live `Vector3` scale, and a `Float32Array` matrix, whose constructor
28
- subscribes to all three sub-object signals and recomposes the matrix on every change. **256 files**
29
- import it across `src`, `editor` and `samples` — **100 production, 156 spec**.
30
-
31
- The origin commit `71ae86be1` calls Transform64 "a passive Float64Array transform **component**". The
32
- ECS side was always the destination. The work stalled at the renderer seam, and the seam is where the
33
- engine currently loses precision.
34
-
35
- ### The gap
36
-
37
- `Transform` tells the world it moved. `Transform64` cannot, and — by design — must not learn how:
38
- it is one prototype over a `Float64Array` and nothing else. No fields, no callbacks, no version
39
- counter, no cached views. Anything that would widen the buffer or hang state off the instance
40
- defeats the reason the type exists.
41
-
42
- So notification has to live where notification already lives: in the dataset.
43
-
44
- ---
45
-
46
- ## The three decisions this revision makes
47
-
48
- ### 1. Change detection is `EventType.ComponentChanged`, sent through `sendEvent`
49
-
50
- The ECS already has a per-entity event channel, and component lifecycle already travels on it:
51
-
52
- ```js
53
- // EntityComponentDataset.js:1202
54
- this.sendEvent(entity_id, EventType.ComponentAdded, { klass: componentClass, instance: component_instance });
55
- // EntityComponentDataset.js:1068
56
- this.sendEvent(entity_id, EventType.ComponentRemoved, { klass: componentClass, instance: componentInstance });
57
- ```
58
-
59
- `EventType` (`src/engine/ecs/EventType.js`) has exactly three members today. The addition is a
60
- fourth, with the identical payload shape:
61
-
62
- ```js
63
- export const EventType = {
64
- EntityRemoved: "entityRemoved",
65
- ComponentAdded: "componentAdded",
66
- ComponentRemoved: "componentRemoved",
67
- ComponentChanged: "componentChanged" // <- new: { klass, instance }
68
- };
69
- ```
70
-
71
- A writer that mutates a component in place announces it:
72
-
73
- ```js
74
- ecd.sendEvent(entity, EventType.ComponentChanged, { klass: Transform64, instance: t64 });
75
- ```
76
-
77
- A consumer subscribes the way `PathDisplaySystem.js:125` already does, in `link`, and filters on
78
- `klass`. `addEntityEventListener` / `removeEntityEventListener` need no change, and the existing
79
- "any event" listener path picks it up for free.
80
-
81
- **Why coarse, and not per-field channels.** An earlier draft proposed a per-channel version column
82
- (translation / rotation / scale). That is wrong on its own terms: after
83
- `Transform64.multiplyTransforms` or `fromMatrix` rewrites the buffer wholesale, there is no channel
84
- the write belongs to — the honest answer is "all of them", which is the same as no channel at all.
85
- It also duplicates a distinction the dataset already draws: added / removed / changed is the
86
- component's lifecycle, and a second, finer axis running beside it is two mechanisms where one will
87
- do. Fine granularity is only meaningful when component data is flat, and a transform's is not.
88
-
89
- Making it the consumer's problem to work out what changed is the correct trade. **Over-reaction is
90
- acceptable** — a consumer that only cares about translation waking on a rotation write does redundant
91
- work, not wrong work. Where a consumer genuinely cannot afford that, it compares against its own
92
- retained copy; that cost sits with the one consumer that needs it rather than in the type everyone
93
- pays for.
94
-
95
- ### 2. Nothing gets deleted on reachability evidence
96
-
97
- Revision 2 proposed deleting `EntityPath` / `EntityPathMarker`, `PerfectPanner`, `createDebugLabel`,
98
- `fabrik_solve`, `SpriteSystemPE` / `Sprite`, `setMesh` and `updateNodeByTransformAndBBB`, on the
99
- grounds that nothing in the repository imports them.
100
-
101
- **That reasoning does not hold for a library.** meep is an engine; its consumers are downstream
102
- applications, and `package.json` exports `./src/*`, `./editor/*` and `./samples/*` wholesale with all
103
- three in `files`. Every source file is published API. "No internal importer" is a statement about
104
- this repository, not about whether anyone calls it.
105
-
106
- There is no delete stage. Those files migrate like everything else. Two notes carried forward, as
107
- observations rather than licence:
108
-
109
- - `engine/graphics/ecs/mesh/setMesh.js:47` calls `component.internalApplyTransform`, which a
110
- repository-wide grep finds at exactly that one call site. It would throw if reached. That is a bug
111
- to fix or report, not evidence of death.
112
- - `src/view/minimap/**` imports `../../../../model/game/...` from the parent `moh` repository, and
113
- `vitest.config.mjs:14-19` excludes its spec for that reason, in its own words. It is live code
114
- whose dependency and whose consumer both sit outside this tree. Do not remove that exclude line.
115
-
116
- ### 3. No facade, no views. `Transform` survives untouched and ends up unused
117
-
118
- Revision 2 proposed making `Transform` a subclass of `Transform64` with live `Vector3`/`Quaternion`
119
- views over its buffer, so the 256 importers would keep compiling unchanged. Rejected, for the reason
120
- that motivates the whole exercise: persisting a view layer reinstates exactly the abstraction
121
- Transform64 was built to strip. A `Transform64` is a bare `Float64Array` with one prototype in the
122
- chain. Views over its buffer, held anywhere durable, are the old design wearing new storage.
123
-
124
- The end state instead:
125
-
126
- | | |
127
- |---|---|
128
- | `Transform.js` | **Unchanged.** Byte-identical to today, still exported, still serializable |
129
- | `Transform64.js` | **Unchanged in shape.** 23 elements, no added fields |
130
- | Engine use of `Transform` | **None.** Every system, every editor tool, every spec is on `Transform64` |
131
- | `EventType.ComponentChanged` | The one new mechanism, in the ECS where it belongs |
132
-
133
- `Transform` becomes what an engine keeps for its consumers: a supported type that the engine itself
134
- no longer builds on. No shim to remove, no deprecation cliff, no deletion to schedule.
135
-
136
- **What replaces the facade as the migration vehicle** is the bridge that already exists and already
137
- works. `TerrainSystem` and `MeshSystem` do this today: hold a `Transform64`, poll the entity's
138
- `Transform`, and use `t64_equals_transform` to skip the copy when nothing moved. That is the
139
- sanctioned temporary state — one side owns the value, the other mirrors it — and it is temporary per
140
- subsystem, not per codebase.
141
-
142
- **The allocating getters stay as they are.** `t.translation` returning a fresh `Float64Array` view is
143
- the correct behaviour for a type that holds no state; caching it would mean a field. Hot paths use
144
- the scalar accessors (`translation_x`, `rotation_w`, …) and free functions that take
145
- `(array, offset)`. That is a call-site rule, enforced by the audit in Stage 2, not a type change.
146
-
147
- ---
148
-
149
- ## Stages
150
-
151
- Ordering is by dependency, not by size. Every stage leaves the repository green.
152
-
153
- ### Stage 0 — `Transform64` becomes a registered component · **M**
154
-
155
- **Goal:** an entity can carry a `Transform64`, and it survives a save round-trip.
156
-
157
- **Touches** `engine/ecs/transform/Transform64SerializationAdapter.js` (new),
158
- `engine/ecs/storage/populateEngineSerializationRegistry.js`, `engine/ecs/EntityComponentDataset.js`
159
- (verification only).
160
-
161
- **Work.** `registerComponentType` (`EntityComponentDataset.js:802`) keys off the class reference and
162
- imposes no shape requirement, so a `Float64Array` subclass registers as-is — but confirm the storage
163
- path, the clone path and `getAllComponents` before relying on it, since a typed-array subclass is
164
- unlike every component registered so far. Then add the adapter, modelled directly on
165
- `TransformSerializationAdapter`:
166
-
167
- ```js
168
- export class Transform64SerializationAdapter extends BinaryClassSerializationAdapter {
169
- klass = Transform64;
170
- version = 1;
171
- // translation: 3 × Float64, as TransformSerializationAdapter already does
172
- // rotation: quat3_encode_to_uint32, as today
173
- // scale: v3_binary_equality_encode, as today
174
- // matrix: NOT serialized — derived by updateMatrix() on load
175
- }
176
- ```
177
-
178
- Register it beside the existing one at `populateEngineSerializationRegistry.js:200`.
179
-
180
- **Note on the save format.** `TransformSerializationAdapter` already writes `writeFloat64` for
181
- position (`:24-26`) and already encodes rotation to a uint32. The byte layout for a `Transform64` is
182
- therefore *the same layout*, and the two adapters can share an encoding. Save compatibility is a
183
- smaller problem than it looks; the open question is the type name the registry keys on, which
184
- Stage 8 settles.
185
-
186
- **Proves it** A new `Transform64SerializationAdapter.spec.js` round-tripping through `BinaryBuffer`,
187
- plus a dataset spec that registers `Transform64`, links it to an entity, reads it back by class, and
188
- removes it.
189
-
190
- **Unblocks** everything.
191
-
192
- ---
193
-
194
- ### Stage 1 — `EventType.ComponentChanged` · **S**
195
-
196
- **Goal:** the signalling mechanism exists and is documented, before anything sends it.
197
-
198
- **Touches** `engine/ecs/EventType.js`, `engine/ecs/EntityComponentDataset.js` (doc only).
199
-
200
- **Work.** Add the enum member. Document the `{ klass, instance }` payload contract on `sendEvent`
201
- next to the `@see` block at `:1721`. Nothing dispatches it yet, and no consumer subscribes — this
202
- stage is deliberately inert so the mechanism can be reviewed on its own.
203
-
204
- Decide here, and write down, whether the dataset itself should send it from any built-in path
205
- (it should not: the dataset cannot know a caller finished mutating a buffer, and a write-through
206
- accessor is the field-carrying design this plan rejects).
207
-
208
- **Proves it** `EventType.spec.js`: sending `ComponentChanged` reaches a listener registered with
209
- `addEntityEventListener`, reaches an "any event" listener, and does not fire on unrelated entities.
210
-
211
- **Unblocks** every migrated writer.
212
-
213
- ---
214
-
215
- ### Stage 2 — Tripwires and the enrolment ratchet · **M**
216
-
217
- **Goal:** "the migration progressed" and "no hot path regressed" both become machine-checkable.
218
-
219
- **Touches** a new `engine/ecs/transform/migration_enrolment.spec.js`; a dev-only allocation counter.
220
-
221
- **Work.** Two guards.
222
-
223
- *The ratchet.* A spec holding the explicit list of files still importing `Transform.js`, scanning
224
- `src`, `editor` and `samples`. It fails if a file not on the list imports it (new coupling) and fails
225
- if a listed file no longer does (stale list — update it, and the number only falls). This is the
226
- progress meter for every later stage and the exit criterion at the end.
227
-
228
- *The allocation audit.* A dev-mode counter incremented by `Transform64`'s `translation` / `rotation` /
229
- `scale` getters — **behind a build flag, not a field on the instance**, so the shipped type is
230
- unchanged. Specs for the hot paths (physics step, `MeshSystem` update, first-person camera
231
- composition) assert the count is zero across a simulated frame. This is what makes "hot paths use
232
- scalar accessors" enforceable rather than a review convention.
233
-
234
- **Proves it** Both specs, red before the guard exists and green after.
235
-
236
- **Unblocks** every claim of progress made below.
237
-
238
- ---
239
-
240
- ### Stage 3 — The scalar and free-function vocabulary · **M**
241
-
242
- **Goal:** every read and write a migrated call site needs, without allocating and without a view.
243
-
244
- **Touches** `core/geom/vec3/**`, `core/geom/3d/quaternion/**`, `core/geom/3d/mat4/**`,
245
- `engine/ecs/transform/t64_*.js`.
246
-
247
- **Work.** Inventory what the 256 files actually call — the census is dominated by `.position.set`,
248
- `.position.x/y/z`, `.rotation.set`, quaternion conversions (`toEulerAnglesYXZ`,
249
- `fromEulerAnglesYXZ`, `fromAxisAngle`, `multiplyQuaternions`, `rotateTowards`, `computeTwistAngle`)
250
- and `.scale.setScalar`. Map each to an existing `v3_*` / `quat3_*` free function; write only the ones
251
- genuinely missing. Follow the established convention — free functions over methods, no variant
252
- factories.
253
-
254
- The reading vocabulary is already there: `translation_x`, `rotation_w`, `scale_z`, and raw indexing
255
- via the exported offset constants. The writing vocabulary is `setTranslation` / `setRotation` /
256
- `setScale` plus `updateMatrix`.
257
-
258
- **The one rule that matters.** A write to rotation or scale needs `updateMatrix()`; a translation-only
259
- write does not, because the translation *is* the matrix column. Both then need the Stage 1 event.
260
- Where a call site does several writes, one `updateMatrix()` and one event at the end — not per write.
261
-
262
- **Proves it** Each new free function gets a spec. No behaviour change yet.
263
-
264
- **Unblocks** Stages 4–10.
265
-
266
- ---
267
-
268
- ### Stage 4 — The graphics3 ↔ shade seam · **S**
269
-
270
- **Goal:** close the half-migrated seam first, because it is the one place both types already meet and
271
- the pattern the rest copies.
272
-
273
- **Touches** `engine/graphics3/MeshSystem.js`, `TerrainSystem.js`, `pose/query_entity_node_world_pose.js`,
274
- `shade_node_to_entity_composition.js`, `camera_sync_from_transform.js`, `DecalSystem.js`.
275
-
276
- **Work.** These systems hold a `Transform64` and mirror an entity's `Transform` into it. Once the
277
- entity carries a `Transform64` directly, the mirror and the poll both go away: the system reads the
278
- component. `t64_copy_from_transform` loses callers here; keep it until its last caller anywhere is
279
- gone.
280
-
281
- **The trap, verified.** `TerrainSystem.js:352` guards with `t64_equals_transform`, which compares
282
- *components only, by deliberate design* — its own doc says a matrix comparison "would answer a
283
- question about the lossy half", because `Transform`'s matrix is f32 while its components are f64.
284
- `Transform64.equals` is the opposite: "strict equality across the whole transform, `matrix` included".
285
- Swapping one for the other turns the guard matrix-inclusive, so a stale matrix on either side reads
286
- as a move, and the per-frame top-level acceleration structure rebuild this guard exists to prevent
287
- comes back. The replacement is a components-only comparison between two `Transform64`s — a new
288
- `t64_equals_components`, not `equals`.
289
-
290
- **Proves it** Existing `MeshSystem.spec.js` / `TerrainSystem.spec.js` green, plus a new spec asserting
291
- the tile guard still skips when only the matrix differs.
292
-
293
- **Unblocks** the pattern every later system follows.
294
-
295
- ---
296
-
297
- ### Stage 5 — Readers · **L**
298
-
299
- **Goal:** migrate every site that only reads a transform. No event, no ordering question.
300
-
301
- **Touches** roughly 34 production files across `engine/sound/**`, `engine/navigation/ecs/**`,
302
- `engine/grid/**`, `engine/intelligence/behavior/**`, `engine/achievements/**`,
303
- `generation/markers/**`, `engine/ecs/terrain/**`, `engine/ecs/fow/**`, and the read half of
304
- `engine/graphics3/*System.js`.
305
-
306
- **Work.** Switch `dependencies` from `Transform` to `Transform64`; replace `.position.x` with
307
- `.translation_x` and friends. Hot loops take the scalar accessors; cold sites may use the allocating
308
- getters. Mechanical, one commit per subsystem, each independently revertible.
309
-
310
- **Proves it** Each subsystem's existing spec, unchanged in intent, with its fixture switched.
311
-
312
- ---
313
-
314
- ### Stage 6 — Writers, and physics determinism · **L**
315
-
316
- **Goal:** migrate every site that writes a transform, and settle what f64 does to determinism.
317
-
318
- **Touches** `engine/physics/**` (the largest cluster), `engine/ecs/parent`,
319
- `engine/ecs/transform-attachment`, `engine/graphics3` write paths, `engine/animation/**`.
320
-
321
- **Work.** Each writer: write through the scalar setters, call `updateMatrix()` once if rotation or
322
- scale changed, then send `EventType.ComponentChanged`. Subscribers that previously hung off
323
- `position.onChanged` move to `addEntityEventListener` in `link` and drop it in `unlink`.
324
-
325
- **The precision change, and it is a fix.** `Transform.multiplyTransforms` composes through a
326
- module-level `const scratch_matrix = new Float32Array(16)` (`Transform.js:15`, used at `:361`), and
327
- that is the method `TransformAttachmentSystem.UpdateContext.update()` (`:63-67`) calls for **every
328
- attached entity's world pose**. Measured: `16777218` where exact is `16777217.75`. Every attachment's
329
- world transform is quantised to f32 today. Moving to `Transform64.multiplyTransforms` removes the
330
- quantisation — which means `engine/physics/determinism.spec.js` will see different numbers. They will
331
- be *more* accurate, and determinism is preserved (f64 arithmetic is as reproducible as f32 across
332
- platforms), but any fixture with baked-in expected values must be re-baselined deliberately, in its
333
- own commit, with the diff reviewed rather than accepted wholesale.
334
-
335
- **Proves it** Physics suite green after a reviewed re-baseline; a new spec asserting a rotation write
336
- emits exactly one `ComponentChanged` and a translation write emits one without an `updateMatrix`.
337
-
338
- ---
339
-
340
- ### Stage 7 — Retained sub-object references · **M**
341
-
342
- **Goal:** close the pattern that has no `Transform64` equivalent.
343
-
344
- **Touches** roughly 14 sites in `engine/sound/**` and `engine/animation/**`, plus anything the
345
- Stage 2 ratchet surfaces.
346
-
347
- **Work.** These hold `transform.position` past the statement that fetched it — stored in a field,
348
- captured in a closure, or handed to an animation track. A `Transform64` getter returns a fresh view
349
- each call, so the reference is not live and identity comparison is meaningless. Each site becomes
350
- either a retained *copy* (when it wanted a snapshot) or a retained `{ entity, dataset }` pair re-read
351
- on use (when it wanted liveness). Animation tracks that write into a retained sub-object become
352
- writes through the component plus a Stage 1 event.
353
-
354
- **Proves it** A spec per converted site asserting the value tracks (or deliberately does not track)
355
- subsequent writes.
356
-
357
- ---
358
-
359
- ### Stage 8 — Serialization identity, network, rollback · **M**
360
-
361
- **Goal:** decide what the persisted type is called, and what goes on the wire.
362
-
363
- **Touches** `Transform64SerializationAdapter`, `populateEngineSerializationRegistry.js`,
364
- `engine/network/adapters/TransformReplicationAdapter.js`, `engine/interpolation/**`.
365
-
366
- **Work.** Two decisions, both one-way.
367
-
368
- *Save identity.* The registry keys on the adapter's `klass`. Entities saved with a `Transform` load
369
- as `Transform`; entities saved with a `Transform64` load as `Transform64`. Whether old saves upgrade
370
- in place (via `TransformSerializationUpgrader_0_1`, extended) or the engine simply reads both is a
371
- product decision, not a technical one — state it and move on.
372
-
373
- *Wire format.* `TransformReplicationAdapter` deliberately uses Float32 for position and says so at
374
- `:19-30`: distinct from the save adapter precisely so saves keep full precision while the wire stays
375
- cheap. **That reasoning survives the migration unchanged** — the replication adapter keeps quantising
376
- on the wire regardless of the component's internal precision. This is not a bandwidth regression, and
377
- any claim that f64 doubles the packet is wrong.
378
-
379
- **Rollback.** Snapshot/restore must copy the buffer, not alias it. A `Transform64` is a
380
- `Float64Array`, so `set()` on a same-length buffer is the copy; `slice()` returns a plain
381
- `Float64Array` by the type's `Symbol.species`, which is correct for a snapshot but is *not* a
382
- `Transform64` — restore paths must not assume the prototype survived.
383
-
384
- **Proves it** Round-trip specs both ways; the existing network end-to-end and rollback specs green.
385
-
386
- ---
387
-
388
- ### Stage 9 — Editor and samples · **L**
389
-
390
- **Goal:** the 19 production and 14 spec files in `editor/`, plus 2 in `samples/`.
391
-
392
- **Touches** `editor/ecs/component/{prototypeObjectEditor,registerEngineComponentEditors}.js`,
393
- `editor/tools/{TransformToolV2.js,v2/TransformControls.js,v2/GizmoNode.js}`,
394
- `editor/actions/concrete/TransformModifyAction.js`, the six `process/symbolic/*SymbolicDisplay.js`,
395
- `editor/selection/editor_pick.js`, `editor/templates/entity_templates.js`,
396
- `editor/persistence/buildNewSceneDataset.js`, `editor/camera/camera_framing.js`,
397
- `editor/view/prepareMeshLibrary.js`.
398
-
399
- **Work.** Two genuinely hard files and a mechanical tail.
400
-
401
- *The inspector.* `prototypeObjectEditor` builds a UI by walking a component's shape. A `Transform64`
402
- is 23 indexed numbers with accessors on the prototype — walked naively it renders 23 unlabelled
403
- fields. It needs a dedicated `Transform64Editor` registered by constructor identity, ahead of any
404
- generic `Float64Array` handling, presenting translation / rotation / scale as the three groups a user
405
- expects.
406
-
407
- *Undo/redo.* `TransformModifyAction` captures and restores a transform. Establish exactly what it
408
- captures; a captured `Transform64` must be a copied buffer, and a captured sub-object view is not a
409
- capture at all. This is Stage 7's problem in the one place where getting it wrong silently corrupts a
410
- user's edit history.
411
-
412
- **Proves it** Editor specs green; a new spec asserting an undo after a gizmo drag restores the exact
413
- prior buffer.
414
-
415
- **Unblocks** the exit criterion, which scans `editor/` too.
416
-
417
- ---
418
-
419
- ### Stage 10 — First-person · **L**
420
-
421
- **Goal:** the largest single cluster — 32 files, of which 3 are production.
422
-
423
- **Touches** `engine/control/first-person/**`.
424
-
425
- **Work.** The survey's useful finding is that the cluster is 29 specs over a small production
426
- surface, concentrated in `FirstPersonPlayerControllerSystem.js`. The work is mostly fixture
427
- migration. The production work is the euler/quaternion conversions and the `forward`/`up`/`right`
428
- axes, all of which `Transform64` already offers directly — including as setters, which `Transform`
429
- does not have.
430
-
431
- **Proves it** The 29 specs, migrated fixture by fixture.
432
-
433
- ---
434
-
435
- ### Stage 11 — Specs, docs, and the exit · **L**
436
-
437
- **Goal:** the remaining spec tree, the published surface, and a checkable finish.
438
-
439
- **Touches** the residual specs across all three roots, `README.md`, any shipped `.md` naming
440
- `Transform`, `npm run generate-types` output.
441
-
442
- **Work.** Migrate remaining fixtures. Regenerate declarations and confirm the consumer type-check
443
- budget has not risen. Note in the CHANGELOG that the engine now builds on `Transform64` and that
444
- `Transform` remains supported and unchanged — this is an addition, not a break, so it needs no major.
445
-
446
- **Exit criterion**
447
-
448
- ```bash
449
- # 1. the engine no longer builds on the legacy component
450
- npx vitest run src/engine/ecs/transform/migration_enrolment.spec.js
451
- # ALLOWED list === [] , roots = ["src", "editor", "samples"]
452
-
453
- # 2. Transform is byte-identical to where it started
454
- git diff --stat <migration-base>..HEAD -- src/engine/ecs/transform/Transform.js # expect: EMPTY
455
-
456
- # 3. Transform64 gained no fields
457
- git diff <migration-base>..HEAD -- src/engine/ecs/transform/Transform64.js | grep '^+' | grep -v '^+++'
458
- # expect: no new instance fields; TRANSFORM64_SIZE still 23
459
-
460
- # 4. no hot path allocates a view
461
- npx vitest run -t "allocates no component views"
462
-
463
- # 5. everything still passes
464
- npx vitest run && npm run check-types && npm run build-module
465
- ```
466
-
467
- Checks 2 and 3 are the ones that distinguish this plan from the revision it replaces: the migration
468
- is done when the engine stopped using `Transform`, **not** when `Transform` changed.
469
-
470
- ---
471
-
472
- ## Risk register
473
-
474
- | Risk | Early sign | Mitigation |
475
- |---|---|---|
476
- | Two sources of truth on one entity — a system reads `Transform` while another writes `Transform64` | A value that updates one frame late, or not at all, in a partially migrated subsystem | Migrate by entity archetype, not by file. The bridge helpers are the sanctioned interim, and only one side owns the value at a time |
477
- | Missing `updateMatrix()` after a rotation or scale write | A stale matrix reaching the renderer — visible as an object rendering at its previous orientation | The Stage 2 audit spec; and the rule that one write group ends in one `updateMatrix` + one event |
478
- | Over-reaction becomes a perf problem, not just redundant work | Frame time rising in a subsystem after its Stage 6 commit | Accepted by design; where it bites, the one affected consumer retains a copy and compares. Do not reintroduce channels |
479
- | Determinism fixtures re-baselined without review | A physics fixture diff accepted wholesale in a large commit | Re-baseline in its own commit, diff reviewed, and only after Stage 6's precision change is understood |
480
- | `Float64Array` subclass breaks something in component storage that only shows at scale | Clone, snapshot or serialization behaving oddly for `Transform64` but not other components | Stage 0 verifies the storage, clone and `getAllComponents` paths explicitly before anything depends on them |
481
- | Undo/redo captures a view instead of a copy | An undo that restores the *current* value, i.e. does nothing | Stage 9's dedicated spec |
482
- | `Symbol.species` surprises — `slice()` returns a plain `Float64Array` | A restore path producing an object without `Transform64`'s prototype | Called out in Stage 8; snapshot with `set()` into a real `Transform64` |
483
-
484
- ---
485
-
486
- ## Summary
487
-
488
- | # | Stage | Effort | Blocked by |
489
- |---|---|---|---|
490
- | 0 | `Transform64` registered as a component + serialization adapter | M | — |
491
- | 1 | `EventType.ComponentChanged` | S | — |
492
- | 2 | Tripwires: enrolment ratchet + allocation audit | M | — |
493
- | 3 | Scalar and free-function vocabulary | M | — |
494
- | 4 | graphics3 ↔ shade seam | S | 0, 3 |
495
- | 5 | Readers | L | 3, 4 |
496
- | 6 | Writers + physics determinism | L | 1, 3, 5 |
497
- | 7 | Retained sub-object references | M | 3, 6 |
498
- | 8 | Serialization identity, network, rollback | M | 0 |
499
- | 9 | Editor and samples | L | 3, 6 |
500
- | 10 | First-person | L | 3, 6 |
501
- | 11 | Specs, docs, exit | L | 4–10 |
502
-
503
- **Critical path:** 0 → 3 → 4 → 5 → 6 → 11. Stages 1, 2 and 8 run alongside. Stages 9 and 10 are
504
- large but parallel to each other once 6 lands.
505
-
506
- ---
507
-
508
- ## Residual unknowns
509
-
510
- - **Whether component storage handles a typed-array subclass cleanly.** Registration does — it keys
511
- on the class reference and imposes no shape. Storage, cloning and any structured-clone path are
512
- unverified. Stage 0 exists to settle this, and if it fails, the shape of the answer changes (a thin
513
- subclass carrying ECS metadata, which would be a departure from "one prototype, nothing more" and
514
- would need your call).
515
- - **Whether `EventType.ComponentChanged` should be sent for components other than transforms.** It is
516
- a general mechanism and this plan only uses it for one type. Broadening it is a separate decision.
517
- - **The migration-by-archetype boundary.** Which entities carry which transform during the interim is
518
- the highest-risk part of this plan and the least specified. Stage 4 establishes the pattern on the
519
- smallest cluster deliberately, so the boundary is learned somewhere cheap.
520
- - **File counts** are `256 / 100 / 156` by direct grep across `src`, `editor` and `samples` on
521
- 2026-09-04. Re-derive before building the Stage 2 ratchet rather than trusting this number.