@woosh/meep-engine 3.60.4 → 3.60.6

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 (419) hide show
  1. package/CHANGELOG.md +2621 -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 +11 -0
  63. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  64. package/src/shade/renderer/Renderer.js +50 -6
  65. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts +40 -80
  66. package/src/shade/renderer/camera/orbital/OrbitalCameraController.d.ts.map +1 -1
  67. package/src/shade/renderer/camera/orbital/OrbitalCameraController.js +197 -147
  68. package/src/shade/renderer/fluid/GPUFluidCascade.d.ts +3 -3
  69. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +1 -1
  70. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +6 -6
  71. package/src/shade/renderer/fluid/pressure/GPUFluidPressureSolve.d.ts +1 -1
  72. package/src/shade/renderer/fluid/query/GPUFluidQueries.d.ts +1 -1
  73. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +28 -45
  74. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  75. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +111 -119
  76. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts +22 -3
  77. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.d.ts.map +1 -1
  78. package/src/shade/renderer/geometry/sdf/cards/GPUMeshCardSets.js +84 -3
  79. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts +19 -0
  80. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.d.ts.map +1 -0
  81. package/src/shade/renderer/geometry/virtual/proxy/vgeo_proxy_triangle_limit.js +25 -0
  82. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts +31 -0
  83. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.d.ts.map +1 -0
  84. package/src/shade/renderer/geometry/virtual/proxy/vgeo_to_proxy_mesh.js +343 -0
  85. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts +15 -0
  86. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.d.ts.map +1 -1
  87. package/src/shade/renderer/geometry/virtual/runtime/VirtualGeometry.js +38 -0
  88. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts +17 -0
  89. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.d.ts.map +1 -0
  90. package/src/shade/renderer/geometry/virtual/runtime/vgeo_meshlet_metadata_write.js +29 -0
  91. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.d.ts.map +1 -1
  92. package/src/shade/renderer/geometry/virtual/runtime/vgeo_runtime_meshlet_batch.js +7 -13
  93. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts +28 -59
  94. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.d.ts.map +1 -1
  95. package/src/shade/renderer/geometry/virtual/sdf/VGeoSDFProxies.js +84 -789
  96. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  97. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +1 -8
  98. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts +7 -6
  99. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.d.ts.map +1 -1
  100. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSceneHolds.js +12 -11
  101. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.d.ts +2 -2
  102. package/src/shade/renderer/global_illumination/probe_clipmap/brick/mesh/chunk_mesh_brick_instance.js +2 -2
  103. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +1 -4
  104. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  105. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +1 -10
  106. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts +5 -15
  107. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.d.ts.map +1 -1
  108. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_surface.js +6 -34
  109. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.d.ts.map +1 -1
  110. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -7
  111. package/src/shade/renderer/hiz/HZBFootprint.d.ts +14 -0
  112. package/src/shade/renderer/hiz/HZBFootprint.d.ts.map +1 -0
  113. package/src/shade/renderer/hiz/HZBFootprint.js +16 -0
  114. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts +10 -0
  115. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.d.ts.map +1 -0
  116. package/src/shade/renderer/hiz/HZB_FOOTPRINT_X.js +11 -0
  117. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts +10 -0
  118. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.d.ts.map +1 -0
  119. package/src/shade/renderer/hiz/HZB_FOOTPRINT_Y.js +11 -0
  120. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts +0 -7
  121. package/src/shade/renderer/hiz/HierarchicalZBuffer.d.ts.map +1 -1
  122. package/src/shade/renderer/hiz/HierarchicalZBuffer.js +405 -350
  123. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts +12 -0
  124. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.d.ts.map +1 -0
  125. package/src/shade/renderer/hiz/chunk_hzb_footprint_x.js +27 -0
  126. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts +12 -0
  127. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.d.ts.map +1 -0
  128. package/src/shade/renderer/hiz/chunk_hzb_footprint_y.js +27 -0
  129. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts +14 -0
  130. package/src/shade/renderer/hiz/hzb_footprint_texels.d.ts.map +1 -0
  131. package/src/shade/renderer/hiz/hzb_footprint_texels.js +34 -0
  132. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts +0 -5
  133. package/src/shade/renderer/hiz/shader_hzb_reduce_any.d.ts.map +1 -1
  134. package/src/shade/renderer/hiz/shader_hzb_reduce_any.js +37 -57
  135. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts +11 -0
  136. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0.d.ts.map +1 -0
  137. package/src/shade/renderer/hiz/{shader_hzb_reduce_mip0_clip.js → shader_hzb_reduce_mip0.js} +120 -111
  138. package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
  139. package/src/shade/renderer/material/GPUMaterialManager.d.ts +11 -1
  140. package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
  141. package/src/shade/renderer/material/GPUMaterialManager.js +16 -8
  142. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts +12 -12
  143. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
  144. package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +17 -118
  145. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts +7 -3
  146. package/src/shade/renderer/postprocess/gtao/GTAO.d.ts.map +1 -1
  147. package/src/shade/renderer/postprocess/gtao/GTAO.js +26 -13
  148. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts +14 -0
  149. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.d.ts.map +1 -1
  150. package/src/shade/renderer/postprocess/gtao/ao_reproject_shader.js +196 -68
  151. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
  152. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +42 -28
  153. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
  154. package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +429 -414
  155. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts +16 -0
  156. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.d.ts.map +1 -0
  157. package/src/shade/renderer/postprocess/gtao/shader_gtao_spatial_denoise.js +156 -0
  158. package/src/shade/renderer/scene/GPUSceneContext.d.ts +2 -2
  159. package/src/shade/renderer/scene/GPUSceneContext.js +5 -5
  160. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
  161. package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +7 -2
  162. package/src/shade/renderer/water/GPUWaterRenderer.d.ts +0 -6
  163. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  164. package/src/shade/renderer/water/GPUWaterRenderer.js +12 -17
  165. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts +35 -0
  166. package/src/shade/renderer/water/medium/graph_water_meshlets.d.ts.map +1 -0
  167. package/src/shade/renderer/water/medium/graph_water_meshlets.js +89 -0
  168. package/src/shade/renderer/water/query/GPUWaterQueries.d.ts +1 -1
  169. package/src/shade/renderer/water/shader_water.d.ts.map +1 -1
  170. package/src/shade/renderer/water/shader_water.js +22 -13
  171. package/src/shade/renderer/water/shader_water_avboit.d.ts.map +1 -1
  172. package/src/shade/renderer/water/shader_water_avboit.js +7 -7
  173. package/src/shade/renderer/water/surface/graph_water_tessellation.d.ts +1 -1
  174. package/src/shade/renderer/water/surface/graph_water_tessellation.js +1 -1
  175. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +9 -1
  176. package/editor/REWORK_PLAN_2026_08.md +0 -692
  177. package/src/CODEC_LAYOUT_VERIFICATION.md +0 -419
  178. package/src/CORRECTNESS_HUNT_2026_07_24.md +0 -142
  179. package/src/DUPLICATION_AUDIT_2026_08_07/00_core_reuse_surface.md +0 -738
  180. package/src/DUPLICATION_AUDIT_2026_08_07/A_core_math_geom.md +0 -79
  181. package/src/DUPLICATION_AUDIT_2026_08_07/B_core_data.md +0 -93
  182. package/src/DUPLICATION_AUDIT_2026_08_07/C_gfx_render.md +0 -80
  183. package/src/DUPLICATION_AUDIT_2026_08_07/D_gfx_features.md +0 -164
  184. package/src/DUPLICATION_AUDIT_2026_08_07/E_physics.md +0 -69
  185. package/src/DUPLICATION_AUDIT_2026_08_07/F_sound.md +0 -110
  186. package/src/DUPLICATION_AUDIT_2026_08_07/G_net_save.md +0 -129
  187. package/src/DUPLICATION_AUDIT_2026_08_07/H_engine_misc.md +0 -72
  188. package/src/DUPLICATION_AUDIT_2026_08_07/I_generation_view.md +0 -74
  189. package/src/DUPLICATION_AUDIT_2026_08_07/K_crosscutting.md +0 -169
  190. package/src/DUPLICATION_AUDIT_2026_08_07.md +0 -254
  191. package/src/DUPLICATION_AUDIT_REMEDIATION.md +0 -250
  192. package/src/DUPLICATION_REVIEW_2026_10_24.md +0 -1072
  193. package/src/REVIEW_2026_08_06/adv-core.md +0 -511
  194. package/src/REVIEW_2026_08_06/adv-gfx.md +0 -480
  195. package/src/REVIEW_2026_08_06/adv-view.md +0 -446
  196. package/src/REVIEW_2026_08_06/api-core.md +0 -296
  197. package/src/REVIEW_2026_08_06/api-engine.md +0 -195
  198. package/src/REVIEW_2026_08_06/bvh-phys-sound-net.md +0 -507
  199. package/src/REVIEW_2026_08_06/core-binary.md +0 -348
  200. package/src/REVIEW_2026_08_06/core-collection.md +0 -376
  201. package/src/REVIEW_2026_08_06/core-math.md +0 -221
  202. package/src/REVIEW_2026_08_06/core-process.md +0 -266
  203. package/src/REVIEW_2026_08_06/core-science.md +0 -223
  204. package/src/REVIEW_2026_08_06/engine-ai-nav.md +0 -279
  205. package/src/REVIEW_2026_08_06/engine-animation.md +0 -167
  206. package/src/REVIEW_2026_08_06/engine-asset.md +0 -166
  207. package/src/REVIEW_2026_08_06/engine-ecs.md +0 -920
  208. package/src/REVIEW_2026_08_06/engine-input.md +0 -197
  209. package/src/REVIEW_2026_08_06/engine-misc.md +0 -248
  210. package/src/REVIEW_2026_08_06/engine-terrain.md +0 -52
  211. package/src/REVIEW_2026_08_06/generation.md +0 -176
  212. package/src/REVIEW_2026_08_06/geom-2d.md +0 -434
  213. package/src/REVIEW_2026_08_06/geom-3d.md +0 -117
  214. package/src/REVIEW_2026_08_06/gfx-gi.md +0 -143
  215. package/src/REVIEW_2026_08_06/gfx-render.md +0 -740
  216. package/src/REVIEW_2026_08_06/gfx-texture.md +0 -690
  217. package/src/REVIEW_2026_08_06/prior-criticals.md +0 -49
  218. package/src/REVIEW_2026_08_06/prior-highs.md +0 -138
  219. package/src/REVIEW_2026_08_06/test-gaps.md +0 -364
  220. package/src/REVIEW_2026_08_06/view.md +0 -667
  221. package/src/REVIEW_2026_08_06.md +0 -610
  222. package/src/core/binary/lz4/LZ4_HIGH_COMPRESSION_PLAN_2026_09_14.md +0 -542
  223. package/src/core/bvh2/bvh3/NOTES.md +0 -2
  224. package/src/core/bvh8/NOTES.md +0 -63
  225. package/src/core/cache/wtinylfu/benchmark/CacheWTinylfu.bench.md +0 -243
  226. package/src/core/color/COLOR_FIX_PLAN_2026_08_28.md +0 -417
  227. package/src/core/color/COLOR_REVIEW_2026_08_28.md +0 -779
  228. package/src/core/geom/2d/polygon/TRIANGULATION_DESIGN.md +0 -433
  229. package/src/core/geom/3d/atlas/ATLAS_PORT_PLAN.md +0 -486
  230. package/src/core/geom/3d/atlas/BFF_PLAN.md +0 -174
  231. package/src/core/geom/3d/atlas/REVIEW_02.md +0 -392
  232. package/src/core/geom/3d/gjk/GJK_REVIEW_NOTES.md +0 -146
  233. package/src/core/geom/3d/gjk/NOTES.md +0 -8
  234. package/src/core/geom/3d/topology/TOPO_MESH_RETIREMENT_PLAN.md +0 -135
  235. package/src/core/geom/GEOMETRY_REVIEW_002_API_ISSUES.md +0 -381
  236. package/src/core/geom/GEOMETRY_REVIEW_002_NAMING.md +0 -684
  237. package/src/core/geom/MANIFOLD_COMPARISON_2026_08_01.md +0 -554
  238. package/src/core/model/reactive/evaluation/PREDICATE_APPLICABILITY_PROPOSAL.md +0 -446
  239. package/src/engine/REVIEW_2026_07_03.md +0 -211
  240. package/src/engine/asset/loaders/image/IMAGE_CODEC_REVIEW_2026_08_28.md +0 -815
  241. package/src/engine/control/first-person/DESIGN.md +0 -658
  242. package/src/engine/control/first-person/DESIGN_COLLISION.md +0 -382
  243. package/src/engine/control/first-person/DESIGN_EXTENSIONS.md +0 -563
  244. package/src/engine/control/first-person/TODO.md +0 -160
  245. package/src/engine/ecs/ASYNC_SYSTEMS_PROPOSAL.md +0 -531
  246. package/src/engine/ecs/HIERARCHY_REVIEW.md +0 -717
  247. package/src/engine/ecs/async/WORKER_SYSTEM_PLAN.md +0 -262
  248. package/src/engine/ecs/ik/PLAN.md +0 -179
  249. package/src/engine/ecs/storage/binary/SERIALIZATION_COVERAGE.md +0 -272
  250. package/src/engine/ecs/storage/binary/object-v2/DESIGN.md +0 -199
  251. package/src/engine/ecs/transform/TRANSFORM64_MIGRATION_PLAN_2026_09_04.md +0 -521
  252. package/src/engine/graphics/CONTEXT_LOSS_RECOVERY_PLAN.md +0 -463
  253. package/src/engine/graphics/ecs/camera/pp/NOTES.md +0 -48
  254. package/src/engine/graphics/render/frame_graph/CORRECTNESS_FIXES_2026_09_04.md +0 -659
  255. package/src/engine/graphics/render/frame_graph/FRAME_GRAPH_RECOMMENDATIONS.md +0 -235
  256. package/src/engine/graphics/sh3/path_tracer/REVIEW_001_ACTION_PLAN.md +0 -490
  257. package/src/engine/graphics/texture/sampler/compare/FLIP_IMPLEMENTATION_PLAN.md +0 -466
  258. package/src/engine/input/GAMEPAD_API_PROPOSAL.md +0 -717
  259. package/src/engine/input/ecs/ism/ISM_DESIGN.md +0 -1523
  260. package/src/engine/input/ecs/ism/ISM_IMPLEMENTATION_PLAN.md +0 -627
  261. package/src/engine/navigation/mesh/OVERLAPPING_SURFACES_2026_08_25.md +0 -661
  262. package/src/engine/navigation/mesh/PATHFINDING_PLAN.md +0 -229
  263. package/src/engine/network/CONGESTION_CONTROL.md +0 -87
  264. package/src/engine/network/MESSAGE_TRANSPORT.md +0 -364
  265. package/src/engine/network/SMOOTHNESS_DESIGN.md +0 -400
  266. package/src/engine/physics/cloth/MEASUREMENTS.md +0 -5304
  267. package/src/engine/physics/cloth/PLAN.md +0 -3056
  268. package/src/engine/physics/fluid/GPU_FLUID_CASCADES_PROPOSAL_2026_10_16.md +0 -1382
  269. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +0 -243
  270. package/src/engine/physics/fluid/solver/NOTES.md +0 -46
  271. package/src/engine/sound/SOUND_EMITTER_RETIREMENT_PLAN.md +0 -536
  272. package/src/engine/sound/simulation/IMPLEMENTATION_PLAN.md +0 -432
  273. package/src/engine/sound/simulation/PROBE_PLACEMENT.md +0 -250
  274. package/src/engine/sound/simulation/PROBE_TRANSFER_RESEARCH.md +0 -322
  275. package/src/engine/sound/simulation/REFLECTION_IR_PLAN.md +0 -261
  276. package/src/engine/sound/simulation/VISIBILITY_GRAPH_PLAN.md +0 -121
  277. package/src/engine/sound/sopra/IMPLEMENTATION_PLAN.md +0 -999
  278. package/src/format/image/avif/DECISIONS.md +0 -545
  279. package/src/format/image/jpeg/NOTES.md +0 -3
  280. package/src/format/scene/gltf/MESHOPT_COMPRESSION_PLAN.md +0 -814
  281. package/src/generation/COORDINATES.md +0 -54
  282. package/src/generation/REVIEW_01_ACTION_PLAN.md +0 -628
  283. package/src/generation/foliage/ANNUAL_SHOOTS_BRIEF_2026_10_25.md +0 -220
  284. package/src/generation/foliage/CROWN_FILLING_BRIEF_2026_10_26.md +0 -172
  285. package/src/generation/foliage/CROWN_FULLNESS_BRIEF_2026_10_26.md +0 -86
  286. package/src/generation/foliage/FOLIAGE_DESIGN.md +0 -547
  287. package/src/generation/foliage/FOLIAGE_PLAN.md +0 -198
  288. package/src/generation/foliage/LEAF_ARCHITECTURE_BRIEF_2026_10_26.md +0 -158
  289. package/src/generation/foliage/LOD_REWORK_BRIEF_2026_10_27.md +0 -521
  290. package/src/generation/foliage/REAL_TIME_TREES_BRIEF_2026_10_27.md +0 -86
  291. package/src/generation/foliage/SELF_ORGANIZING_FRAMEWORK_BRIEF_2026_10_26.md +0 -347
  292. package/src/generation/foliage/SHOOT_SYSTEMS_ALL_SPECIES_BRIEF_2026_10_26.md +0 -248
  293. package/src/generation/foliage/SPEEDTREE_COMPARISON_2026_10_24.md +0 -694
  294. package/src/generation/foliage/TWO_FRONT_ENDS_BRIEF_2026_10_28.md +0 -552
  295. package/src/shade/RENDERER_CONTRACT.md +0 -697
  296. package/src/shade/SHADER_F16_PROPOSAL_2026_10_24.md +0 -263
  297. package/src/shade/device/IMMEDIATE_DATA_PLAN_2026_08_28.md +0 -569
  298. package/src/shade/device/PASS_ENCODER_PROPOSAL_2026_08_31.md +0 -755
  299. package/src/shade/device/mock/EXTENSION_PROPOSAL_2026_08_22.md +0 -458
  300. package/src/shade/device/mock/IMPLEMENTATION_PLAN.md +0 -255
  301. package/src/shade/device/mock/REVIEW_2026_08_22.md +0 -527
  302. package/src/shade/device/timing/GPU_PROFILER_PROPOSAL_2026_08_28.md +0 -894
  303. package/src/shade/device/timing/profile/SGPT_FORMAT.md +0 -345
  304. package/src/shade/renderer/NOTES.md +0 -78
  305. package/src/shade/renderer/PLAN.md +0 -8
  306. package/src/shade/renderer/animation/ADDITIVE_BLENDING_PLAN.md +0 -145
  307. package/src/shade/renderer/animation/SKINNING_FRAME_PLAN.md +0 -357
  308. package/src/shade/renderer/atmosphere/NOTES.md +0 -6
  309. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts +0 -76
  310. package/src/shade/renderer/camera/orbital/MomentumAxis.d.ts.map +0 -1
  311. package/src/shade/renderer/camera/orbital/MomentumAxis.js +0 -164
  312. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts +0 -45
  313. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.d.ts.map +0 -1
  314. package/src/shade/renderer/camera/orbital/OrbitalCameraConfig.js +0 -66
  315. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts +0 -98
  316. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.d.ts.map +0 -1
  317. package/src/shade/renderer/camera/orbital/OrbitalCameraInput.js +0 -184
  318. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts +0 -175
  319. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.d.ts.map +0 -1
  320. package/src/shade/renderer/camera/orbital/OrbitalCameraRig.js +0 -411
  321. package/src/shade/renderer/camera/orbital/README.md +0 -81
  322. package/src/shade/renderer/camera/orbital/index.d.ts +0 -6
  323. package/src/shade/renderer/camera/orbital/index.d.ts.map +0 -1
  324. package/src/shade/renderer/camera/orbital/index.js +0 -9
  325. package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +0 -964
  326. package/src/shade/renderer/fluid/GPU_FLUID_OCCUPANCY_AND_SOTA_REVIEW_2026_10_26.md +0 -361
  327. package/src/shade/renderer/geometry/bvh/BLAS_REFIT_BATCH_PLAN.md +0 -619
  328. package/src/shade/renderer/geometry/meshlet/COMPACTION_PLAN_2026_09_16.md +0 -674
  329. package/src/shade/renderer/geometry/sdf/NOTES.md +0 -6
  330. package/src/shade/renderer/geometry/virtual/ATTRIBUTE_PLAN_2026_09_18.md +0 -540
  331. package/src/shade/renderer/geometry/virtual/MICRON_COMPARISON_2026_08_20.md +0 -305
  332. package/src/shade/renderer/geometry/virtual/VGEO_FORMAT.md +0 -913
  333. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +0 -787
  334. package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_PLAN.md +0 -481
  335. package/src/shade/renderer/geometry/virtual/VK_LOD_CLUSTERS_COMPARISON_2026_08_20.md +0 -301
  336. package/src/shade/renderer/geometry/virtual/WEDGE_PLAN_2026_09_18.md +0 -448
  337. package/src/shade/renderer/geometry/virtual/runtime/CULL_PLAN_2026_09_16.md +0 -385
  338. package/src/shade/renderer/geometry/virtual/runtime/CUT_PLAN_2026_09_14.md +0 -656
  339. package/src/shade/renderer/geometry/virtual/runtime/REVIEW_LEDGER.md +0 -308
  340. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN.md +0 -657
  341. package/src/shade/renderer/geometry/virtual/runtime/RUNTIME_PLAN_2026_09_14.md +0 -551
  342. package/src/shade/renderer/geometry/virtual/runtime/SHADOW_PLAN_2026_09_28.md +0 -529
  343. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts +0 -47
  344. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.d.ts.map +0 -1
  345. package/src/shade/renderer/geometry/virtual/sdf/VGEO_SDF.js +0 -80
  346. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts +0 -16
  347. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.d.ts.map +0 -1
  348. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_collect.js +0 -67
  349. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts +0 -17
  350. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.d.ts.map +0 -1
  351. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_decode.js +0 -145
  352. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts +0 -12
  353. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.d.ts.map +0 -1
  354. package/src/shade/renderer/geometry/virtual/sdf/shader_vgeo_sdf_traverse.js +0 -105
  355. package/src/shade/renderer/global_illumination/lpv/NOTES.md +0 -3
  356. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_CLIPMAP_PROPOSAL_2026_10_27.md +0 -4306
  357. package/src/shade/renderer/global_illumination/probe_clipmap/PROBE_RAYS_VARIABLE_AND_SORTED_SCOPE_2026_10_30.md +0 -410
  358. package/src/shade/renderer/global_illumination/sharc/NOTES.md +0 -8
  359. package/src/shade/renderer/gpu_primitive/bvh/GPU_BVH_BUILD_PLAN.md +0 -1369
  360. package/src/shade/renderer/gpu_primitive/bvh/PHASE1_HANDOVER.md +0 -202
  361. package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +0 -94
  362. package/src/shade/renderer/hiz/NOTES.md +0 -3
  363. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts +0 -8
  364. package/src/shade/renderer/hiz/shader_hzb_reduce_mip0_clip.d.ts.map +0 -1
  365. package/src/shade/renderer/light/cluster/NOTES.md +0 -11
  366. package/src/shade/renderer/light/cluster/PROPOSAL_ALGORITHM_2026_10_16.md +0 -524
  367. package/src/shade/renderer/light/cluster/PROPOSAL_HIERARCHICAL_2026_10_16.md +0 -1101
  368. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts +0 -24
  369. package/src/shade/renderer/material/resident/shader_resident_texture_means.d.ts.map +0 -1
  370. package/src/shade/renderer/material/resident/shader_resident_texture_means.js +0 -120
  371. package/src/shade/renderer/particles/DESIGN.md +0 -1011
  372. package/src/shade/renderer/particles/EMITTER_GLOBAL_STATE_PLAN_2026_10_29.md +0 -280
  373. package/src/shade/renderer/particles/ORIENTATION_PLAN_2026_10_15.md +0 -453
  374. package/src/shade/renderer/path_tracer/PATH_TRACED_MEDIA_PLAN_2026_10_02.md +0 -520
  375. package/src/shade/renderer/postprocess/bloom/NOTES.md +0 -6
  376. package/src/shade/renderer/postprocess/fsr/NOTES.md +0 -4
  377. package/src/shade/renderer/postprocess/gtao/NOTES.md +0 -6
  378. package/src/shade/renderer/postprocess/nss/NOTES.md +0 -332
  379. package/src/shade/renderer/postprocess/perspective/NOTES.md +0 -3
  380. package/src/shade/renderer/postprocess/sscs/NOTES.md +0 -5
  381. package/src/shade/renderer/postprocess/ssr/NOTES.md +0 -14
  382. package/src/shade/renderer/postprocess/ssr/REPROJECTION_PROPOSAL.md +0 -286
  383. package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +0 -39
  384. package/src/shade/renderer/postprocess/taa/NOTES.md +0 -11
  385. package/src/shade/renderer/postprocess/upscale-dither/NOTES.md +0 -78
  386. package/src/shade/renderer/postprocess/vrs/NOTES.md +0 -4
  387. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +0 -1218
  388. package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +0 -600
  389. package/src/shade/renderer/restir/reservoir/NOTES.md +0 -6
  390. package/src/shade/renderer/shader/chunk/atmosphere/NOTES.md +0 -6
  391. package/src/shade/renderer/shader/chunk/brdf/FRESNEL_BRIEF_2026_10_16.md +0 -391
  392. package/src/shade/renderer/shader/chunk/color/tonemap/ACES_TONE_MAPPING_BRIEF_2026_10_17.md +0 -153
  393. package/src/shade/renderer/shader/chunk/color/tonemap/HDR_TONE_MAPPING_FORMS_BRIEF_2026_10_16.md +0 -322
  394. package/src/shade/renderer/shader/chunk/color/tonemap/SDR_TONE_MAPPING_BRIEF_2026_10_16.md +0 -247
  395. package/src/shade/renderer/shader/chunk/fsr/NOTES.md +0 -3
  396. package/src/shade/renderer/shader/chunk/fsr/spd/NOTES.md +0 -4
  397. package/src/shade/renderer/shader/chunk/geometry/ray/NOTES.md +0 -4
  398. package/src/shade/renderer/shader/chunk/material/MULTISCATTER.md +0 -159
  399. package/src/shade/renderer/shader/chunk/mboit/NOTES.md +0 -38
  400. package/src/shade/renderer/shader/chunk/spherical_harmonics/l1i/NOTES.md +0 -3
  401. package/src/shade/renderer/shader/chunk/spherical_harmonics/sampling/NOTES.md +0 -8
  402. package/src/shade/renderer/shader/compiler/SHADER_SWITCH_PROPOSAL_2026_10_16.md +0 -927
  403. package/src/shade/renderer/shadow/contact/FINDINGS.md +0 -413
  404. package/src/shade/renderer/shadow/map/csm/NOTES.md +0 -5
  405. package/src/shade/renderer/shadow/ray/NOTES.md +0 -31
  406. package/src/shade/renderer/shadow/sdf/NOTES.md +0 -9
  407. package/src/shade/renderer/shadow/sdf/brixelizer/NOTES.md +0 -5
  408. package/src/shade/renderer/shadow/sdf/cascade/NOTES.md +0 -9
  409. package/src/shade/renderer/shadow/vsm/NOTES.md +0 -12
  410. package/src/shade/renderer/shadow/vsm/PLAN.md +0 -442
  411. package/src/shade/renderer/shadow/vsm/REVIEW_LEDGER.md +0 -43
  412. package/src/shade/renderer/texture/COMPRESSED_TEXTURE_PLAN_2026_09_01.md +0 -2444
  413. package/src/shade/renderer/texture/mipmaps/NOTES.md +0 -3
  414. package/src/shade/renderer/volumetrics/NOTES.md +0 -1329
  415. package/src/shade/renderer/volumetrics/VOLUMETRIC_NOISE_PLAN_2026_10_15.md +0 -336
  416. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts +0 -23
  417. package/src/shade/renderer/water/medium/GPUWaterBodies.d.ts.map +0 -1
  418. package/src/shade/renderer/water/medium/GPUWaterBodies.js +0 -75
  419. package/src/shade/wgsl/NOTES.md +0 -4
@@ -0,0 +1,319 @@
1
+ import { assert } from "../../../../core/assert.js";
2
+ import { normalize_angle_rad } from "../../../../core/geom/normalize_angle_rad.js";
3
+ import Vector2 from "../../../../core/geom/Vector2.js";
4
+ import Vector3 from "../../../../core/geom/Vector3.js";
5
+ import { clamp } from "../../../../core/math/clamp.js";
6
+ import TopDownCameraController from "../../ecs/camera/topdown/TopDownCameraController.js";
7
+ import { MomentumAxis } from "./MomentumAxis.js";
8
+
9
+ /**
10
+ * Seconds for a throw's velocity to halve once the gesture lets go.
11
+ * @type {number}
12
+ */
13
+ const MOMENTUM_HALF_LIFE = 0.1;
14
+
15
+ /**
16
+ * Seconds of the gesture's end averaged into the throw velocity.
17
+ * @type {number}
18
+ */
19
+ const VELOCITY_WINDOW = 0.1;
20
+
21
+ /**
22
+ * Radians per second below which an orbit throw stops. A pan throw stops at this times the orbit
23
+ * distance, the same speed across the screen at any zoom.
24
+ * @type {number}
25
+ */
26
+ const MOMENTUM_STOP_SPEED = 0.012;
27
+
28
+ /**
29
+ * Factor on the orbit distance per wheel notch towards the target.
30
+ * @type {number}
31
+ */
32
+ const ZOOM_STEP = 0.9;
33
+
34
+ const GESTURE_NONE = 0;
35
+ const GESTURE_ORBIT = 1;
36
+ const GESTURE_PAN = 2;
37
+
38
+ const v2_pan = new Vector2();
39
+
40
+ /**
41
+ * Orbit, pan and zoom of a {@link TopDownCameraController}, with the feel of **direct drive + release
42
+ * momentum**: the "throw" of Google Earth / Cesium, not a spring chasing a goal.
43
+ *
44
+ * - **A drag moves the controller as it happens**, one to one, so the view keeps up with the hand.
45
+ * - **Letting go throws**: the average velocity over the last {@link VELOCITY_WINDOW} carries on and
46
+ * decays with a half life of {@link MOMENTUM_HALF_LIFE}, at the same distance whatever the frame
47
+ * rate. Holding still before letting go throws nothing. Grabbing again stops every throw.
48
+ * - **Zoom is instant and multiplicative**: a wheel notch is a discrete step with nothing to catch up.
49
+ *
50
+ * The rig keeps velocities, not a pose. Each frame the coast is added to the controller as it finds
51
+ * it, so a writer that adds to the controller composes with a throw, and one that sets its values
52
+ * outright wins. A teleport should {@link stop} the rig, or the remains of a throw carry on from the
53
+ * new pose.
54
+ *
55
+ * The rig subscribes to nothing. Its host hands it the gesture — {@link begin}, {@link move},
56
+ * {@link end}, {@link dolly} — from whatever input it listens to, and calls {@link update} once a frame.
57
+ * A drag the device abandons without an end leaves the rig engaged and still, which the next
58
+ * {@link begin} clears.
59
+ *
60
+ * @author Alex Goldring
61
+ * @copyright Company Named Limited (c) 2026
62
+ */
63
+ export class OrbitalCameraRig {
64
+ /**
65
+ * @type {TopDownCameraController}
66
+ */
67
+ #controller;
68
+
69
+ /**
70
+ * @type {number}
71
+ */
72
+ #orbit_buttons;
73
+
74
+ /**
75
+ * @type {number}
76
+ */
77
+ #pan_buttons;
78
+
79
+ /**
80
+ * @type {number}
81
+ */
82
+ #pitch_min;
83
+
84
+ /**
85
+ * @type {number}
86
+ */
87
+ #pitch_max;
88
+
89
+ /**
90
+ * @type {Vector3}
91
+ */
92
+ #pan_axes;
93
+
94
+ #pitch = new MomentumAxis();
95
+ #yaw = new MomentumAxis();
96
+ #target_x = new MomentumAxis();
97
+ #target_y = new MomentumAxis();
98
+ #target_z = new MomentumAxis();
99
+
100
+ /**
101
+ * @type {number}
102
+ */
103
+ #gesture = GESTURE_NONE;
104
+
105
+ /**
106
+ * @param {TopDownCameraController} controller moved by the rig; a host that filters the camera
107
+ * hands over the controller its input is meant to drive
108
+ * @param {Object} options
109
+ * @param {number} options.orbit_buttons {@link MouseEvent.buttons} bits that start an orbit, see
110
+ * {@link MouseEventButtons}
111
+ * @param {number} options.pan_buttons {@link MouseEvent.buttons} bits that start a pan; orbit wins
112
+ * when both are held
113
+ * @param {number} options.pitch_min radians; 0 looks along the horizon
114
+ * @param {number} options.pitch_max radians; π/2 looks straight down
115
+ * @param {Vector3} options.pan_axes per-axis scale on a pan's world displacement, as
116
+ * {@link TopDownCameraController.pan} takes it; zero Y to keep the target on the ground
117
+ */
118
+ constructor(controller, { orbit_buttons, pan_buttons, pitch_min, pitch_max, pan_axes }) {
119
+ assert.defined(controller, 'controller');
120
+ assert.isNonNegativeInteger(orbit_buttons, 'orbit_buttons');
121
+ assert.isNonNegativeInteger(pan_buttons, 'pan_buttons');
122
+ assert.isNumber(pitch_min, 'pitch_min');
123
+ assert.isNumber(pitch_max, 'pitch_max');
124
+ assert.lessThanOrEqual(pitch_min, pitch_max, 'pitch_min must not exceed pitch_max');
125
+ assert.defined(pan_axes, 'pan_axes');
126
+
127
+ this.#controller = controller;
128
+ this.#orbit_buttons = orbit_buttons;
129
+ this.#pan_buttons = pan_buttons;
130
+ this.#pitch_min = pitch_min;
131
+ this.#pitch_max = pitch_max;
132
+ this.#pan_axes = pan_axes;
133
+ }
134
+
135
+ /**
136
+ * Start a drag. Stops every throw, then takes direct control of orbit or pan, chosen by the
137
+ * buttons held; with neither, the drag moves nothing.
138
+ *
139
+ * @param {number} buttons {@link MouseEvent.buttons} of the event that started the drag
140
+ */
141
+ begin(buttons) {
142
+ this.stop();
143
+
144
+ if ((buttons & this.#orbit_buttons) !== 0) {
145
+ this.#gesture = GESTURE_ORBIT;
146
+
147
+ this.#pitch.engage();
148
+ this.#yaw.engage();
149
+ } else if ((buttons & this.#pan_buttons) !== 0) {
150
+ this.#gesture = GESTURE_PAN;
151
+
152
+ this.#target_x.engage();
153
+ this.#target_y.engage();
154
+ this.#target_z.engage();
155
+ }
156
+ }
157
+
158
+ /**
159
+ * The pointer moved during a drag, applied to the controller at once.
160
+ *
161
+ * An orbit turns the view a full turn per viewport height of travel, pitch clamped to the rig's
162
+ * range; a pan carries the world under the pointer along with it.
163
+ *
164
+ * @param {number} delta_x pixels, the pointer's position less where it was
165
+ * @param {number} delta_y pixels, the pointer's position less where it was, down positive
166
+ * @param {number} viewport_height pixels
167
+ * @param {number} fov vertical field of view, in degrees
168
+ */
169
+ move(delta_x, delta_y, viewport_height, fov) {
170
+ if (this.#gesture === GESTURE_ORBIT) {
171
+ this.#orbit(delta_x, delta_y, viewport_height);
172
+ } else if (this.#gesture === GESTURE_PAN) {
173
+ this.#pan(delta_x, delta_y, viewport_height, fov);
174
+ }
175
+ }
176
+
177
+ /**
178
+ * End the drag, throwing with its recent velocity.
179
+ */
180
+ end() {
181
+ if (this.#gesture === GESTURE_ORBIT) {
182
+ this.#pitch.release(VELOCITY_WINDOW);
183
+ this.#yaw.release(VELOCITY_WINDOW);
184
+ } else if (this.#gesture === GESTURE_PAN) {
185
+ this.#target_x.release(VELOCITY_WINDOW);
186
+ this.#target_y.release(VELOCITY_WINDOW);
187
+ this.#target_z.release(VELOCITY_WINDOW);
188
+ }
189
+
190
+ this.#gesture = GESTURE_NONE;
191
+ }
192
+
193
+ /**
194
+ * Drop any drag and every throw, leaving the controller where it is.
195
+ */
196
+ stop() {
197
+ this.#gesture = GESTURE_NONE;
198
+
199
+ this.#pitch.stop();
200
+ this.#yaw.stop();
201
+ this.#target_x.stop();
202
+ this.#target_y.stop();
203
+ this.#target_z.stop();
204
+ }
205
+
206
+ /**
207
+ * Zoom by wheel notches, within the controller's distance range.
208
+ * @param {number} notches positive away from the target, as a wheel scrolled down reports it
209
+ */
210
+ dolly(notches) {
211
+ const controller = this.#controller;
212
+
213
+ controller.distance = clamp(
214
+ controller.distance * Math.pow(ZOOM_STEP, -notches),
215
+ controller.distanceMin,
216
+ controller.distanceMax
217
+ );
218
+ }
219
+
220
+ /**
221
+ * Advance one frame: sample an engaged drag for its throw, or carry a throw on.
222
+ * @param {number} dt seconds
223
+ */
224
+ update(dt) {
225
+ if (!(dt > 0)) {
226
+ return;
227
+ }
228
+
229
+ const controller = this.#controller;
230
+
231
+ const d_pitch = this.#pitch.update(dt, MOMENTUM_HALF_LIFE, MOMENTUM_STOP_SPEED);
232
+
233
+ if (d_pitch !== 0) {
234
+ const pitch = controller.pitch + d_pitch;
235
+
236
+ // a throw stops at the end of the range instead of pressing on into it
237
+ if (pitch <= this.#pitch_min) {
238
+ controller.pitch = this.#pitch_min;
239
+ this.#pitch.stop();
240
+ } else if (pitch >= this.#pitch_max) {
241
+ controller.pitch = this.#pitch_max;
242
+ this.#pitch.stop();
243
+ } else {
244
+ controller.pitch = pitch;
245
+ }
246
+ }
247
+
248
+ const d_yaw = this.#yaw.update(dt, MOMENTUM_HALF_LIFE, MOMENTUM_STOP_SPEED);
249
+
250
+ if (d_yaw !== 0) {
251
+ controller.yaw = normalize_angle_rad(controller.yaw + d_yaw);
252
+ }
253
+
254
+ const pan_stop_speed = MOMENTUM_STOP_SPEED * controller.distance;
255
+
256
+ const d_x = this.#target_x.update(dt, MOMENTUM_HALF_LIFE, pan_stop_speed);
257
+ const d_y = this.#target_y.update(dt, MOMENTUM_HALF_LIFE, pan_stop_speed);
258
+ const d_z = this.#target_z.update(dt, MOMENTUM_HALF_LIFE, pan_stop_speed);
259
+
260
+ if (d_x !== 0 || d_y !== 0 || d_z !== 0) {
261
+ controller.target._add(d_x, d_y, d_z);
262
+ }
263
+ }
264
+
265
+ /**
266
+ * @param {number} delta_x
267
+ * @param {number} delta_y
268
+ * @param {number} viewport_height
269
+ */
270
+ #orbit(delta_x, delta_y, viewport_height) {
271
+ if (!(viewport_height > 0)) {
272
+ return;
273
+ }
274
+
275
+ const controller = this.#controller;
276
+
277
+ const radians_per_pixel = 2 * Math.PI / viewport_height;
278
+
279
+ // a pitch found outside the range is brought into it, and the jump is no part of the gesture
280
+ const pitch_before = clamp(controller.pitch, this.#pitch_min, this.#pitch_max);
281
+ const pitch_after = clamp(pitch_before + delta_y * radians_per_pixel, this.#pitch_min, this.#pitch_max);
282
+
283
+ controller.pitch = pitch_after;
284
+ this.#pitch.record(pitch_after - pitch_before);
285
+
286
+ // dragging right swings the eye the other way around the target, so the world turns with the hand
287
+ const d_yaw = -delta_x * radians_per_pixel;
288
+
289
+ controller.yaw = normalize_angle_rad(controller.yaw + d_yaw);
290
+ this.#yaw.record(d_yaw);
291
+ }
292
+
293
+ /**
294
+ * @param {number} delta_x
295
+ * @param {number} delta_y
296
+ * @param {number} viewport_height
297
+ * @param {number} fov
298
+ */
299
+ #pan(delta_x, delta_y, viewport_height, fov) {
300
+ if (!(viewport_height > 0)) {
301
+ return;
302
+ }
303
+
304
+ const target = this.#controller.target;
305
+
306
+ const x = target.x;
307
+ const y = target.y;
308
+ const z = target.z;
309
+
310
+ // pan takes where the pointer was less where it is
311
+ v2_pan.set(-delta_x, -delta_y);
312
+
313
+ TopDownCameraController.pan(v2_pan, this.#controller, viewport_height, fov, this.#pan_axes);
314
+
315
+ this.#target_x.record(target.x - x);
316
+ this.#target_y.record(target.y - y);
317
+ this.#target_z.record(target.z - z);
318
+ }
319
+ }
@@ -1,11 +1,3 @@
1
- /**
2
- *
3
- * @param {number} displacement_x
4
- * @param {number} displacement_y
5
- * @param {TopDownCameraController} input source thing being rotated
6
- * @param {TopDownCameraController} output target thing where the result is written to
7
- */
8
- export function rotate_from_view(displacement_x: number, displacement_y: number, input: TopDownCameraController, output: TopDownCameraController): void;
9
1
  /**
10
2
  * The orientation a controller looks along. The camera's transform is built from this and the
11
3
  * distance, so anything that needs the view's own axes takes them from here rather than from
@@ -15,7 +7,41 @@ export function rotate_from_view(displacement_x: number, displacement_y: number,
15
7
  * @param {TopDownCameraController} controller
16
8
  */
17
9
  export function top_down_view_rotation(result: Quaternion, controller: TopDownCameraController): void;
10
+ /**
11
+ * Write a controller's pose onto a camera transform: the view rotation, and the eye its distance back
12
+ * from the target along it, the distance held within the controller's range.
13
+ *
14
+ * @param {TopDownCameraController} control
15
+ * @param {Transform64} result
16
+ */
17
+ export function computeTopDownTransform(control: TopDownCameraController, result: Transform64): void;
18
+ /**
19
+ * Move a controller's target `distance` world units along where its view faces: `right` and
20
+ * `forward` pick the direction in the view's own frame, so a target can be flown up or down a slope.
21
+ * A diagonal travels the same distance as a straight move.
22
+ *
23
+ * The viewer's right is the negated X axis of the view rotation, as {@link pan} explains.
24
+ *
25
+ * @param {TopDownCameraController} controller its {@link TopDownCameraController#target} is moved
26
+ * @param {number} right −1 to 1, positive to the viewer's right
27
+ * @param {number} forward −1 to 1, positive into the screen
28
+ * @param {number} distance world units
29
+ */
30
+ export function top_down_truck_in_view(controller: TopDownCameraController, right: number, forward: number, distance: number): void;
31
+ /**
32
+ * Move a controller's target `distance` world units across the ground, along the way its view is
33
+ * turned: `forward` is the view's heading with the pitch taken out, so it keeps its full speed
34
+ * however steeply the view looks down, straight down included, and never moves the target off the
35
+ * ground. A diagonal travels the same distance as a straight move.
36
+ *
37
+ * @param {TopDownCameraController} controller its {@link TopDownCameraController#target} is moved
38
+ * @param {number} right −1 to 1, positive to the viewer's right
39
+ * @param {number} forward −1 to 1, positive along the view's heading
40
+ * @param {number} distance world units
41
+ */
42
+ export function top_down_truck_on_ground(controller: TopDownCameraController, right: number, forward: number, distance: number): void;
18
43
  export default TopDownCameraController;
44
+ import Quaternion from "../../../../../core/geom/Quaternion.js";
19
45
  declare class TopDownCameraController {
20
46
  static fromJSON(j: any): TopDownCameraController;
21
47
  constructor(options: any);
@@ -86,9 +112,7 @@ declare class TopDownCameraController {
86
112
  declare namespace TopDownCameraController {
87
113
  export let typeName: string;
88
114
  export { pan };
89
- export { rotate_from_view as rotate };
90
115
  }
91
- import Quaternion from "../../../../../core/geom/Quaternion.js";
92
116
  import Vector3 from '../../../../../core/geom/Vector3.js';
93
117
  /**
94
118
  * Move a controller's target across the view plane it is looking at, by a displacement given in
@@ -1 +1 @@
1
- {"version":3,"file":"TopDownCameraController.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js"],"names":[],"mappings":"AAyBA;;;;;;GAMG;AACH,iDALW,MAAM,kBACN,MAAM,SACN,uBAAuB,UACvB,uBAAuB,QAiBjC;AAED;;;;;;;GAOG;AACH,+CAHW,UAAU,cACV,uBAAuB,QAIjC;;AAkED;IA+JI,iDAMC;IA5JD,0BAKC;IAbD,gBAAuB;IACvB,cAAU;IACV,YAAQ;IACR,aAAS;IACT,iBAAa;IACb,oBAAgB;IAChB,oBAAkB;IASlB;;;;;;;;;OASG;IACH,yBAJW,OAAO,UACP,OAAO,OACP,OAAO,QAgCjB;IAED;;;;OAIG;IACH,cAHW,uBAAuB,GACrB,OAAO,CAWnB;IAED;;;OAGG;IACH,YAFW,uBAAuB,QAYjC;IAED;;;OAGG;IACH,SAFa,uBAAuB,CAQnC;IAED;;;;;OAKG;IACH,QAJW,uBAAuB,KACvB,uBAAuB,KACvB,MAAM,QAahB;IAED;;;;;;;;;;;;MAYC;IAED;;;;;;;;aAsBC;CASJ;;;;;;uBA7RsB,wCAAwC;oBAC3C,qCAAqC;AAsEzD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,iDAPW,uBAAuB,sBACvB,MAAM,OAEN,MAAM,eACN,OAAO,QA2BjB"}
1
+ {"version":3,"file":"TopDownCameraController.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/ecs/camera/topdown/TopDownCameraController.js"],"names":[],"mappings":"AAyBA;;;;;;;GAOG;AACH,+CAHW,UAAU,cACV,uBAAuB,QAIjC;AAiED;;;;;;GAMG;AACH,iDAHW,uBAAuB,6BA2BjC;AAED;;;;;;;;;;;GAWG;AACH,mDALW,uBAAuB,SACvB,MAAM,WACN,MAAM,YACN,MAAM,QAMhB;AAED;;;;;;;;;;GAUG;AACH,qDALW,uBAAuB,SACvB,MAAM,WACN,MAAM,YACN,MAAM,QAMhB;;uBAhKsB,wCAAwC;AAoM/D;IAyKI,iDAMC;IAtKD,0BAKC;IAbD,gBAAuB;IACvB,cAAU;IACV,YAAQ;IACR,aAAS;IACT,iBAAa;IACb,oBAAgB;IAChB,oBAAkB;IASlB;;;;;;;;;OASG;IACH,yBAJW,OAAO,UACP,OAAO,OACP,OAAO,QA0CjB;IAED;;;;OAIG;IACH,cAHW,uBAAuB,GACrB,OAAO,CAWnB;IAED;;;OAGG;IACH,YAFW,uBAAuB,QAYjC;IAED;;;OAGG;IACH,SAFa,uBAAuB,CAQnC;IAED;;;;;OAKG;IACH,QAJW,uBAAuB,KACvB,uBAAuB,KACvB,MAAM,QAahB;IAED;;;;;;;;;;;;MAYC;IAED;;;;;;;;aAsBC;CASJ;;;;;oBAnXmB,qCAAqC;AA8CzD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,iDAPW,uBAAuB,sBACvB,MAAM,OAEN,MAAM,eACN,OAAO,QA2BjB"}
@@ -6,9 +6,9 @@ import {
6
6
  import { normalize_angle_rad } from "../../../../../core/geom/normalize_angle_rad.js";
7
7
  import Quaternion from "../../../../../core/geom/Quaternion.js";
8
8
  import Vector3 from '../../../../../core/geom/Vector3.js';
9
+ import { clamp } from "../../../../../core/math/clamp.js";
9
10
  import { lerp } from "../../../../../core/math/lerp.js";
10
11
  import { max2 } from "../../../../../core/math/max2.js";
11
- import { sign_not_zero } from "../../../../../core/math/sign_not_zero.js";
12
12
  import { v3_distance } from "../../../../../core/geom/vec3/v3_distance.js";
13
13
 
14
14
  const m4 = [];
@@ -21,31 +21,7 @@ const q_view = new Quaternion();
21
21
 
22
22
  const v3_view_right = new Vector3();
23
23
  const v3_view_up = new Vector3();
24
-
25
-
26
- /**
27
- *
28
- * @param {number} displacement_x
29
- * @param {number} displacement_y
30
- * @param {TopDownCameraController} input source thing being rotated
31
- * @param {TopDownCameraController} output target thing where the result is written to
32
- */
33
- export function rotate_from_view(displacement_x, displacement_y, input, output) {
34
- // crop yaw and pitch to safe range of -PI to PI
35
- const i_pitch = normalize_angle_rad(input.pitch);
36
- const i_yaw = normalize_angle_rad(input.yaw);
37
- const i_roll = normalize_angle_rad(input.roll);
38
-
39
- const quaternion = Quaternion.fromEulerAngles(i_pitch, i_yaw, i_roll);
40
- const forward = Vector3.up.clone();
41
- forward.applyQuaternion(quaternion);
42
-
43
- // flip rotation axis when pitch is over 90deg in either direction, that is UP vector is pointing down
44
- const d_yaw = sign_not_zero(forward.y) * displacement_x;
45
-
46
- output.yaw = i_yaw + d_yaw;
47
- output.pitch = i_pitch - displacement_y;
48
- }
24
+ const v3_view_forward = new Vector3();
49
25
 
50
26
  /**
51
27
  * The orientation a controller looks along. The camera's transform is built from this and the
@@ -122,6 +98,107 @@ function pan(delta, controller, viewport_height_px, fov, multiplier = Vector3.on
122
98
  move_along(target, v3_view_up, -delta.y * m, multiplier);
123
99
  }
124
100
 
101
+ /**
102
+ * Write a controller's pose onto a camera transform: the view rotation, and the eye its distance back
103
+ * from the target along it, the distance held within the controller's range.
104
+ *
105
+ * @param {TopDownCameraController} control
106
+ * @param {Transform64} result
107
+ */
108
+ export function computeTopDownTransform(control, result) {
109
+
110
+ //clamp the distance
111
+ const distance = clamp(control.distance, control.distanceMin, control.distanceMax);
112
+ const target = control.target;
113
+
114
+ // compute rotation. The transform holds its rotation as four numbers rather than a Quaternion,
115
+ // so the euler composition runs in a scratch and lands in the transform afterwards.
116
+ top_down_view_rotation(q_view, control);
117
+
118
+ result.setRotation(q_view.x, q_view.y, q_view.z, q_view.w);
119
+
120
+ // compute camera position
121
+ v3_view_forward.copy(Vector3.forward);
122
+ v3_view_forward.applyQuaternion(q_view);
123
+
124
+ v3_view_forward.multiplyScalar(-distance);
125
+
126
+ v3_view_forward.add(target);
127
+
128
+ result.setTranslation(v3_view_forward.x, v3_view_forward.y, v3_view_forward.z);
129
+
130
+ // the rotation moved, so the matrix owes an update
131
+ result.updateMatrix();
132
+ }
133
+
134
+ /**
135
+ * Move a controller's target `distance` world units along where its view faces: `right` and
136
+ * `forward` pick the direction in the view's own frame, so a target can be flown up or down a slope.
137
+ * A diagonal travels the same distance as a straight move.
138
+ *
139
+ * The viewer's right is the negated X axis of the view rotation, as {@link pan} explains.
140
+ *
141
+ * @param {TopDownCameraController} controller its {@link TopDownCameraController#target} is moved
142
+ * @param {number} right −1 to 1, positive to the viewer's right
143
+ * @param {number} forward −1 to 1, positive into the screen
144
+ * @param {number} distance world units
145
+ */
146
+ export function top_down_truck_in_view(controller, right, forward, distance) {
147
+ top_down_view_rotation(q_view, controller);
148
+
149
+ truck_in_rotation(controller.target, q_view, right, forward, distance);
150
+ }
151
+
152
+ /**
153
+ * Move a controller's target `distance` world units across the ground, along the way its view is
154
+ * turned: `forward` is the view's heading with the pitch taken out, so it keeps its full speed
155
+ * however steeply the view looks down, straight down included, and never moves the target off the
156
+ * ground. A diagonal travels the same distance as a straight move.
157
+ *
158
+ * @param {TopDownCameraController} controller its {@link TopDownCameraController#target} is moved
159
+ * @param {number} right −1 to 1, positive to the viewer's right
160
+ * @param {number} forward −1 to 1, positive along the view's heading
161
+ * @param {number} distance world units
162
+ */
163
+ export function top_down_truck_on_ground(controller, right, forward, distance) {
164
+ q_view.fromEulerAnglesZYX(0, controller.yaw, 0);
165
+
166
+ truck_in_rotation(controller.target, q_view, right, forward, distance);
167
+ }
168
+
169
+ /**
170
+ * @param {Vector3} target
171
+ * @param {Quaternion} rotation
172
+ * @param {number} right
173
+ * @param {number} forward
174
+ * @param {number} distance
175
+ */
176
+ function truck_in_rotation(target, rotation, right, forward, distance) {
177
+ const length = Math.hypot(right, forward);
178
+
179
+ if (length === 0) {
180
+ return;
181
+ }
182
+
183
+ const step = distance / length;
184
+
185
+ v3_view_right.copy(Vector3.right);
186
+ v3_view_right.applyQuaternion(rotation);
187
+
188
+ v3_view_forward.copy(Vector3.forward);
189
+ v3_view_forward.applyQuaternion(rotation);
190
+
191
+ // the viewer's right is the negated X axis
192
+ const along_right = -right * step;
193
+ const along_forward = forward * step;
194
+
195
+ target._add(
196
+ v3_view_right.x * along_right + v3_view_forward.x * along_forward,
197
+ v3_view_right.y * along_right + v3_view_forward.y * along_forward,
198
+ v3_view_right.z * along_right + v3_view_forward.z * along_forward
199
+ );
200
+ }
201
+
125
202
 
126
203
  class TopDownCameraController {
127
204
  target = new Vector3();
@@ -169,9 +246,19 @@ class TopDownCameraController {
169
246
 
170
247
  m4_euler_angles(angles, m4, 2, 1, 0)
171
248
 
172
- this.pitch = angles[2];
173
- this.yaw = angles[1];
174
- this.roll = angles[0];
249
+ if (Math.abs(angles[2]) > Math.PI / 2) {
250
+ // The decomposition holds yaw within ±π/2 and, for about half of all views, answers with the
251
+ // view turned over — pitched past the vertical and rolled half a turn. That is the same
252
+ // rotation as the upright one, half a turn of yaw away, which is the pose an orbit expects:
253
+ // pitch within ±π/2 and, for an up of +Y, no roll.
254
+ this.pitch = normalize_angle_rad(angles[2] + Math.PI);
255
+ this.yaw = normalize_angle_rad(Math.PI - angles[1]);
256
+ this.roll = normalize_angle_rad(angles[0] + Math.PI);
257
+ } else {
258
+ this.pitch = angles[2];
259
+ this.yaw = angles[1];
260
+ this.roll = angles[0];
261
+ }
175
262
 
176
263
  this.distance = v3_distance(eye[0], eye[1], eye[2], target[0], target[1], target[2]);
177
264
 
@@ -294,7 +381,6 @@ class TopDownCameraController {
294
381
  TopDownCameraController.typeName = "TopDownCameraController";
295
382
 
296
383
  TopDownCameraController.pan = pan;
297
- TopDownCameraController.rotate = rotate_from_view;
298
384
 
299
385
  export default TopDownCameraController;
300
386
 
@@ -1,9 +1,3 @@
1
- /**
2
- *
3
- * @param {TopDownCameraController} control
4
- * @param {Transform64} result
5
- */
6
- export function computeTopDownTransform(control: TopDownCameraController, result: Transform64): void;
7
1
  /**
8
2
  *
9
3
  * @param {Transform64} transform
@@ -12,8 +6,8 @@ export function computeTopDownTransform(control: TopDownCameraController, result
12
6
  */
13
7
  export function setCameraControllerFromTransform(transform: Transform64, controller: TopDownCameraController, distance?: number): void;
14
8
  export default TopDownCameraControllerSystem;
15
- import TopDownCameraController from './TopDownCameraController.js';
16
9
  import { Transform64 } from '../../../../ecs/transform/Transform64.js';
10
+ import TopDownCameraController from './TopDownCameraController.js';
17
11
  declare class TopDownCameraControllerSystem extends System<any> {
18
12
  constructor();
19
13
  enabled: ObservedValue<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"TopDownCameraControllerSystem.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js"],"names":[],"mappings":"AAqFA;;;;GAIG;AACH,iDAHW,uBAAuB,UACvB,WAAW,QA0BrB;AAED;;;;;GAKG;AACH,4DAJW,WAAW,cACX,uBAAuB,aACvB,MAAM,QAahB;;oCA1H+D,8BAA8B;4BAHlE,0CAA0C;AAoBtE;;IACI,gCAAkC;IAClC,iDAAyC;IACzC,mEAEE;IAEF;;;;;OAKG;IACH,8BA0BC;IAED,6BAaC;CACJ;uBA9EsB,2BAA2B;0BAHxB,4CAA4C;4CAE1B,0DAA0D"}
1
+ {"version":3,"file":"TopDownCameraControllerSystem.d.ts","sourceRoot":"","sources":["../../../../../../../src/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js"],"names":[],"mappings":"AAgFA;;;;;GAKG;AACH,4DAJW,WAAW,cACX,uBAAuB,aACvB,MAAM,QAahB;;4BA1F2B,0CAA0C;oCAGL,8BAA8B;AAa/F;;IACI,gCAAkC;IAClC,iDAAyC;IACzC,mEAEE;IAEF;;;;;OAKG;IACH,8BA0BC;IAED,6BAaC;CACJ;uBA1EsB,2BAA2B;0BAHxB,4CAA4C;4CAE1B,0DAA0D"}
@@ -1,5 +1,4 @@
1
1
  import Vector3 from "../../../../../core/geom/Vector3.js";
2
- import { clamp } from "../../../../../core/math/clamp.js";
3
2
  import ObservedValue from "../../../../../core/model/ObservedValue.js";
4
3
  import { ResourceAccessKind } from "../../../../../core/model/ResourceAccessKind.js";
5
4
  import { ResourceAccessSpecification } from "../../../../../core/model/ResourceAccessSpecification.js";
@@ -9,14 +8,10 @@ import { t64_read_pose_array } from "../../../../ecs/transform/t64_read_pose_arr
9
8
  import { Transform64 } from '../../../../ecs/transform/Transform64.js';
10
9
 
11
10
 
12
- import TopDownCameraController, { top_down_view_rotation } from './TopDownCameraController.js';
13
- import Quaternion from "../../../../../core/geom/Quaternion.js";
11
+ import TopDownCameraController, { computeTopDownTransform } from './TopDownCameraController.js';
14
12
  import { v3_quaternion_apply } from "../../../../../core/geom/vec3/v3_quaternion_apply.js";
15
13
 
16
14
 
17
- const v3_scratch = new Vector3();
18
- const q_scratch = new Quaternion();
19
-
20
15
  /**
21
16
  * A camera's translation and rotation before and after its controller rewrites them, to tell a move from
22
17
  * a rewrite of the same pose.
@@ -83,37 +78,6 @@ class TopDownCameraControllerSystem extends System {
83
78
  }
84
79
  }
85
80
 
86
- /**
87
- *
88
- * @param {TopDownCameraController} control
89
- * @param {Transform64} result
90
- */
91
- export function computeTopDownTransform(control, result) {
92
-
93
- //clamp the distance
94
- const distance = clamp(control.distance, control.distanceMin, control.distanceMax);
95
- const target = control.target;
96
-
97
- // compute rotation. The transform holds its rotation as four numbers rather than a Quaternion,
98
- // so the euler composition runs in a scratch and lands in the transform afterwards.
99
- top_down_view_rotation(q_scratch, control);
100
-
101
- result.setRotation(q_scratch.x, q_scratch.y, q_scratch.z, q_scratch.w);
102
-
103
- // compute camera position
104
- v3_scratch.copy(Vector3.forward);
105
- v3_scratch.applyQuaternion(q_scratch);
106
-
107
- v3_scratch.multiplyScalar(-distance);
108
-
109
- v3_scratch.add(target);
110
-
111
- result.setTranslation(v3_scratch.x, v3_scratch.y, v3_scratch.z);
112
-
113
- // the rotation moved, so the matrix owes an update
114
- result.updateMatrix();
115
- }
116
-
117
81
  /**
118
82
  *
119
83
  * @param {Transform64} transform
@@ -3,6 +3,14 @@ export default Water;
3
3
  * Optical properties of an authored water surface. MeshletGeometry supplies its shape and
4
4
  * Transform64 supplies its placement.
5
5
  *
6
+ * **The geometry is the body's area: author it with the fewest triangles that cover it.** The renderer tessellates
7
+ * the surface on the GPU from the view, so subdividing a flat area adds no detail to the waves, and it costs every
8
+ * frame. The lattice is cut against each authored triangle: every lattice cell an internal edge crosses is clipped
9
+ * and drawn once per triangle it touches, and no 8 × 8 patch spans an internal edge. Measured on an integrated GPU
10
+ * (the many-waters example at 1280 × 720), a pond and a stream authored as six-segment grids (3,012 triangles) drew
11
+ * 669,324 lattice vertices a pass where two triangles each drew 146,772, and cost 11.65 ms more a frame. Use more
12
+ * triangles only where the area needs them: its outline, a hole, a crease, a change of normal.
13
+ *
6
14
  * Everything optical here is physical and in SI units (WATER_OPTICS_PLAN_2026_10_02.md §7.1): the
7
15
  * index of refraction, the micro-roughness of the surface, and what fills the body — a
8
16
  * {@link ParticipatingMedium}, the same description the path tracer, fog and glass read. Presets
@@ -1 +1 @@
1
- {"version":3,"file":"Water.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/water/Water.js"],"names":[],"mappings":";AAUA;;;;;;;;;;;;;;;GAeG;AACH;IA6CI,0BASC;IArDD;;;OAGG;IACH,KAFU,OAAO,CAEQ;IAEzB;;;;OAIG;IACH,WAFU,OAAO,CAEa;IAE9B;;;;;;;OAOG;IACH,oBAFU,eAAe,CAEuB;IAEhD,8CAA8C;IAC9C,kBAAyB;IAWzB,yCAAyC;IACzC,uCAMC;IAbD;;;;OAIG;IACH,kCAAqC;IAqBrC,0BAoBC;IAED;;;;;MAOC;;CACJ;;;;oBA/GmB,kCAAkC;4BAC1B,2CAA2C;mBAFpD,0CAA0C;oCAGzB,0DAA0D"}
1
+ {"version":3,"file":"Water.d.ts","sourceRoot":"","sources":["../../../../../../src/engine/graphics/ecs/water/Water.js"],"names":[],"mappings":";AAUA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH;IA6CI,0BASC;IArDD;;;OAGG;IACH,KAFU,OAAO,CAEQ;IAEzB;;;;OAIG;IACH,WAFU,OAAO,CAEa;IAE9B;;;;;;;OAOG;IACH,oBAFU,eAAe,CAEuB;IAEhD,8CAA8C;IAC9C,kBAAyB;IAWzB,yCAAyC;IACzC,uCAMC;IAbD;;;;OAIG;IACH,kCAAqC;IAqBrC,0BAoBC;IAED;;;;;MAOC;;CACJ;;;;oBAvHmB,kCAAkC;4BAC1B,2CAA2C;mBAFpD,0CAA0C;oCAGzB,0DAA0D"}