@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
@@ -1,174 +0,0 @@
1
- # Plan: fix LSCM self-intersection (shape-aware boundary → BFF)
2
-
3
- Status: **planning** (2026-06-26). No build started. Goal: rescue the LSCM
4
- boundary-self-intersection charts that currently explode into piecewise
5
- sub-charts, **with low distortion** — the one lever the metrics validated
6
- ([REVIEW_02.md §5.0](REVIEW_02.md), [atlas_metrics.bench.spec.js](atlas_metrics.bench.spec.js)).
7
-
8
- ## 0. Problem recap (measured, not assumed)
9
-
10
- On the decimated-terrain bench: 970 charts, of which 31 LSCM charts fail
11
- bijectivity, **all 31 on boundary self-intersection** (free-boundary conformal
12
- LSCM has no injectivity guarantee → the patch curls so its UV outline overlaps).
13
- Each explodes into ~4 ortho piecewise pieces (+96 charts).
14
-
15
- The convex-boundary rescue (`atlas_chart_parameterize_tutte.js`, built then removed —
16
- see §5) eliminated the explosion (−96 charts, util 71.9 %→86.3 %,
17
- **guaranteed bijective**) **but at catastrophic distortion** (mean stretch 2.55→70.9,
18
- p99 4.27→2467). Confirmed **boundary-dominated**: uniform→mean-value interior
19
- weights changed nothing (70.82→70.88). The charts are thin/curled, so a *circle*
20
- is the wrong target. We need a **low-distortion boundary** that is still safe.
21
-
22
- ## 1. Reuse inventory (what already exists in meep)
23
-
24
- **Directly reusable — no rebuild:**
25
-
26
- | Need | Reuse |
27
- |---|---|
28
- | Cotangent edge weight (Laplacian core) | `core/geom/vec3/v3_cotangent.js` |
29
- | Sparse assembly + matvec | `core/math/linalg/sparse/SparseMatrixCSR.js` (`from_triplets`), `spm_matvec`, `spm_matvec_transpose` |
30
- | SPD / least-squares iterative solve | `core/math/linalg/cg/cg_solve.js`, `cg_solve_normal_equations.js` (used by LSCM + BFF) |
31
- | Boundary-loop trace, disk detection, interior/boundary re-index, UV write-back | (prototyped in the now-removed Tutte module; carried into `param/atlas_chart_parameterize_bff.js`) |
32
- | Pipeline slot: cascade + `param.*` option + bijectivity gate + new `CHART_TYPE` | `atlas_compute_charts.js`, `atlas_chart_type.js` |
33
- | **Acceptance harness**: metrics + A/B + failure-reason diagnostic + the Tutte A/B (mirror it) | `atlas_bench_lib.js`, `atlas_metrics.bench.spec.js` |
34
-
35
- **Must build new (no existing primitive):**
36
-
37
- - Cotangent-**Laplacian assembly** (chart-local → `SparseMatrixCSR` via `v3_cotangent`). Small.
38
- - Interior **angle-defect** (Gaussian curvature) + boundary **exterior/geodesic angle**. From triangle geometry.
39
- - **Obtuse-triangle handling**: cotangent weights go negative on obtuse triangles → the Laplacian can be indefinite (CG divergence / interior flips). v1: **clamp negative weights to 0** (simple, slight bias); intrinsic-Delaunay flips are the better-but-heavier option, deferred.
40
- - (BFF only) **DtN / Schur boundary operator**, the discrete-Yamabe **scale-factor solve**, boundary-**curve integration** (cumulative turning angles → 2D), and the **conformal interior extension** (harmonic + conjugate/Hilbert).
41
-
42
- There is **no** existing discrete Laplacian, curvature, or conjugate operator in meep (the `harmonic`/`geodesic` hits are spherical-harmonics and pathfinding). The reusable scaffolding is the Tutte module + the linalg/cotangent primitives.
43
-
44
- ## 2. Staged plan — cheap variant first, BFF only if it fails the gate
45
-
46
- ### Phase A — shape-aware **convex** boundary (cheap; ~all reuse) — TRIED, FAILED ❌
47
-
48
- Mapped the boundary to an aspect-matched convex **ellipse** (aspect from the prior
49
- LSCM-layout PCA) instead of a circle; still convex ⇒ still guaranteed-injective.
50
- **Measured: no improvement** — decimated terrain mean stretch **71.67 vs the
51
- circle's 70.9** (and util 86.9 % vs 86.3 %). Reverted.
52
-
53
- Root cause — a **catch-22**: a curled chart's LSCM layout curls into a roughly
54
- *round* blob, so its PCA aspect ≈ 1 (the ellipse collapses back to a circle); and
55
- 3D PCA is no better (a curled strip is 3D-compact). **You cannot estimate the
56
- flattened aspect of a curled chart without first flattening it.** No *pre-guessed*
57
- convex boundary escapes this. The whole convex-boundary family is now ruled out by
58
- measurement: circle 70.9, aspect-ellipse 71.67, mean-value-weights 70.88 — all
59
- catastrophic. **The boundary MUST be derived from the chart's intrinsic geometry
60
- (curvature), which is exactly what BFF does and nothing cheaper can.** Proceed to
61
- Phase B.
62
-
63
- ### Phase B — full **BFF** (only if Phase A insufficient)
64
-
65
- Boundary First Flattening computes a *minimal-distortion, non-convex* boundary
66
- (not a forced convex shape) and a conformal interior, so it is the only method
67
- that can be both low-distortion AND (in practice) non-self-intersecting. Staged so
68
- each sub-phase is independently testable:
69
-
70
- - **B1 — analytic infra (de-risk first).** Cotangent-Laplacian assembly + interior
71
- angle-defect + boundary geodesic curvature + obtuse clamping. *Test:* the
72
- Laplacian reproduces a known harmonic field on a flat grid; angle defects sum to
73
- 2πχ (Gauss–Bonnet). Reuses `v3_cotangent` + `SparseMatrixCSR` + `cg_solve`.
74
- - **B2 — BFF boundary.** Discrete-Yamabe scale-factor solve (interior flat,
75
- least-area-distortion boundary via the Neumann↔Dirichlet relation on the
76
- boundary; small dense system → `lu_factor`/`lu_solve`), then integrate scaled
77
- boundary edge lengths + target turning angles into a 2D boundary curve. *Test:* a
78
- developable patch (cone/cylinder) flattens to ~zero stretch; boundary curve
79
- closes up.
80
- - **B3 — conformal interior extension** (the riskiest). Harmonic extension of the
81
- boundary curve + the conjugate (discrete Hilbert) recovery, via two Laplace
82
- solves (`cg_solve`). *Test:* on a disk, stretch ≪ Tutte; bijective. If the
83
- conjugate step proves too costly/risky, fall back to plain harmonic extension
84
- (loses the guarantee) + the validity gate + piecewise as last resort.
85
- - **B4 — wire in.** New `CHART_TYPE.BFF`, behind `param.bff`, inserted in the
86
- cascade before piecewise (ortho → LSCM → BFF → piecewise); accept only if it
87
- comes out bijective, else piecewise. Mirror the Tutte A/B test.
88
-
89
- *Effort: substantial. B3 is the principal risk. BFF does not *strictly* guarantee
90
- non-self-intersection, so any chart it can't flatten validly still falls to
91
- piecewise — never worse than today.*
92
-
93
- ## 3. Acceptance gate (the candidate must beat BOTH baselines)
94
-
95
- Measured via the existing A/B harness on the **decimated terrain** plus a second
96
- curved fixture (e.g. a noisy sphere), candidate (`param.{tutteShaped|bff}=true`)
97
- vs the piecewise baseline (`tutte=false`):
98
-
99
- 1. **Fewer charts** — `cand.chart_count < base.chart_count` (eliminates the
100
- piecewise explosion). *Tutte already passes this.*
101
- 2. **Distortion not worse than piecewise** — `cand.mean_stretch ≤ base.mean_stretch`
102
- (≈ 2.55) **and** `cand.p99_stretch ≤ ~2× base.p99_stretch`. **This is the gate
103
- Tutte fails (70.9 vs 2.55) — the whole point.** A candidate that cuts charts but
104
- balloons distortion does not ship default-on.
105
- 3. **Bijective** — every rescued chart: no flips, no self-intersection, no
106
- zero-area (`atlas_chart_param_validity`).
107
- 4. **Deterministic** — bit-identical UVs across reruns.
108
- 5. **No regression on clean fixtures** — cube / plane / uv-sphere / cylinder / cone
109
- unchanged (the rescue triggers only on LSCM-self-intersecting disk charts).
110
- 6. **Bounded cost** — per-chart solve only on the self-intersecting charts; no
111
- global slowdown on clean meshes.
112
-
113
- **Ship rules:**
114
- - Pass **1 + 2 + 3** → **default-on** (a genuine quality win over both piecewise and Tutte).
115
- - Pass **1 + 3** but fail **2** → **off-by-default** opt-in knob (chart-count vs distortion trade-off), like Tutte.
116
- - Fail **3** → **reject**.
117
-
118
- ## 4. Risks & mitigations
119
-
120
- | Risk | Mitigation |
121
- |---|---|
122
- | Obtuse triangles → indefinite cot-Laplacian (CG divergence / interior flips) | Clamp negative cotangents to 0 (v1); intrinsic-Delaunay flips deferred. Phase A's convex boundary keeps injectivity regardless of clamping. |
123
- | BFF conjugate/Hilbert step (B3) too costly/subtle | Fall back to harmonic extension + validity gate; worst case piecewise (no regression). |
124
- | BFF boundary may still self-intersect on pathological charts | Accept only if bijective; else piecewise — strictly ≤ today's chart count. |
125
- | Effort for a ~10 % over-segmentation win on curved/decimated assets only | Phase A is cheap and may suffice; only escalate to BFF if the metric demands it. Clean assets are unaffected either way. |
126
-
127
- ## 5. Status / next action
128
-
129
- > **FINAL STATE (2026-06-26).** BFF is built ([atlas_chart_parameterize_bff.js](param/atlas_chart_parameterize_bff.js),
130
- > `CHART_TYPE.BFF`) with the intrinsic boundary + DtN-optimal curvature + conformal
131
- > interior, and is **folded into the single always-on cascade** (ortho → LSCM → BFF →
132
- > piecewise, no flags) — free (compute Δ ~−0.3 %, runs only post-LSCM-failure) and
133
- > strictly Pareto-safe (accepts only bijective + near-isometric whole charts). The
134
- > **Tutte convex-boundary path was removed** (dominated). Net effect on the
135
- > decimated terrain: 970 → 964 charts, mean stretch 2.553 → 2.508. The history below
136
- > records how each variant was measured and ruled in/out.
137
-
138
- - **Phase A — done, failed the gate (§2).** Reverted. Convex-boundary family ruled
139
- out by measurement (catch-22 on the aspect estimate).
140
- - **Phase B v1 — done, built + measured ([atlas_chart_parameterize_bff.js](param/atlas_chart_parameterize_bff.js),
141
- `CHART_TYPE.BFF`, `param.bff`, default off).** Intrinsic boundary (uniform
142
- curvature redistribution) + **conformal** pinned-boundary interior (harmonic was
143
- tried first and flipped 26/31; conformal is far less flip-prone). **Clears the
144
- gate** (decimated terrain: −4 charts, mean stretch 2.553 → 2.509 *better*, all
145
- BFF charts bijective, no clean-fixture regression — a Pareto-safe win, unlike
146
- Tutte's 70×) **but at tiny magnitude: only 1 of 31** self-intersecting charts is
147
- rescued. Diagnosed: the other 30 fail because the v1 **uniform** curvature
148
- redistribution leaves the boundary too contorted (25 flip the conformal interior,
149
- 5 self-intersect at the boundary).
150
- - **Phase B v2 — DtN boundary, done + measured.** Replaced the uniform
151
- redistribution with the optimal Dirichlet-to-Neumann curvature (fix boundary
152
- scale 0, solve interior Poisson `L_II u = Ω_I` via `cg_solve`, `k̃_b = (π−θ_b) −
153
- (L u)_b`; ∑ k̃ = 2π keeps it closed). **The DtN boundary fixed the interior**
154
- (conformal-interior flips 25 → 2). Still Pareto-safe (−6 charts, mean 2.553 →
155
- 2.508, p99 4.27 → 3.99, bijective, torus unchanged) **but still only ~2 of 31
156
- rescued — the flattened BOUNDARY now self-intersects on ~27/31.**
157
-
158
- - **CONCLUSION: these charts are intrinsically un-flattenable-whole.** The boundary
159
- self-intersection is **fundamental, not an implementation gap** — true unclamped
160
- cotangents made it *worse* (1 rescue, 30 self-intersections). A high-curvature
161
- decimated chart cannot be *developed* to a SIMPLE planar boundary while
162
- preserving edge lengths (the curvature forces the flat boundary to overlap
163
- itself), so **cutting (piecewise) is the correct injective answer** for them; BFF
164
- rescues only the ~2 low-curvature ones. BFF is the right tool and is kept
165
- off-by-default (correct, tested, Pareto-safe), but it does NOT unlock the
166
- majority. The metrics conclusively show the **piecewise explosion is largely
167
- correct behavior** for decimated/high-curvature assets.
168
-
169
- - **If a future need demands keeping these whole:** the only remaining option is a
170
- method that allows the *boundary to be cut* as part of the optimization
171
- (OptCuts-style joint cut+flatten) or a guaranteed-injective nonlinear map with a
172
- scaffold (SLIM + boundary-band scaffold). Both are large, separate builds, and
173
- the metrics say the payoff (~29 hard charts on decimated assets) is modest. Not
174
- recommended unless the asset mix shifts toward heavily-decimated content.
@@ -1,392 +0,0 @@
1
- # Atlas Review 02 — meep vs xatlas (quality) + recent-literature survey
2
-
3
- Status: **research & planning only** (2026-06-25). No code changes proposed for now.
4
- Scope: chart (segmentation + parameterization) quality and packing quality of the meep
5
- UV-atlas port versus [jpcy/xatlas](https://github.com/jpcy/xatlas), plus a survey of recent
6
- (≈2017–2026) literature on charting, parameterization, and packing.
7
-
8
- Companion to [ATLAS_PORT_PLAN.md](ATLAS_PORT_PLAN.md) (the build contract + bench findings).
9
-
10
- ---
11
-
12
- ## 0. Executive summary
13
-
14
- meep is a faithful, deterministic, robustness-hardened port of xatlas's **core** algorithms —
15
- the same chart cost model, the same ortho→LSCM→piecewise parameterization cascade with the same
16
- acceptance thresholds, the same planar-region-atomic growth, and the same silhouette bitmap packer
17
- for small atlases. Where it differs, it has **deliberately omitted xatlas's quality-refinement
18
- passes** (chart merging, Lloyd seed relocation, a per-growth validity gate, best-fit packing, and
19
- silhouette packing at production scale) in favour of determinism, simplicity, and — above all —
20
- **speed at scale**.
21
-
22
- | Axis | Verdict vs xatlas | Magnitude (estimated) |
23
- |---|---|---|
24
- | **Parameterization** | **On par** | Algorithmically equivalent. xatlas marginally more robust LSCM assembly (ABF-angle rows); both share the same "no area control" limitation. |
25
- | **Chart segmentation** | **Modestly behind** on complex/curved meshes; **near parity** on flat/CAD content | ≈ **10–30 % more charts**, longer/raggier seams on organic meshes (missing `mergeCharts`, per-add validity gate, straightness term, largest-area seeding). Identical on planar-dominant content. |
26
- | **Packing** | **Behind at production scale** (deliberate speed trade); **near parity** on flat/rectangular charts and small atlases | ≈ **10–25 % lower utilization** on irregular/curved charts at ≥2048², in exchange for **~100–1000× faster** packing (3–43 ms vs xatlas's ~2 s random / ~43 s brute). |
27
-
28
- **Bottom line.** On clean, flat/CAD-like content meep is essentially at parity with xatlas. On
29
- complex curved/organic meshes it produces somewhat more charts and looser packing, while running
30
- dramatically faster. The two highest-value, lowest-risk quality wins, both classical and
31
- deterministic, are: (1) a **chart-merge + best-fit-packing** pass to close most of the structural
32
- gap, and (2) an **ARAP/SLIM-style isometric relaxation** (reusing the existing sparse-CG core) to
33
- kill the documented max-stretch outliers (133–359) that conformal LSCM cannot fix.
34
-
35
- > **Confidence / caveat.** The *direction* of every verdict is high-confidence (grounded in a
36
- > line-by-line read of both codebases — xatlas web-verified against `xatlas.cpp`/`xatlas.h` at
37
- > `master`). The *magnitudes* are **estimates**: there is **no head-to-head benchmark on identical
38
- > inputs** yet. In particular the chart-count (~10–30 %) and utilization (~10–25 %) percentages are
39
- > **extrapolated from the nature of the missing features**, not measured — they are the softest
40
- > numbers here. The single most useful follow-up is a same-mesh A/B harness (§5, item P0) to turn
41
- > these ranges into measured numbers.
42
-
43
- ---
44
-
45
- ## 1. Method
46
-
47
- - **meep side** — line-by-line read of `atlas_compute_charts.js`, `segment/*`, `param/*`,
48
- `pack/*`, the `core/math/linalg/{cg,sparse}` solvers, and the 2D packing primitives
49
- (`skyline.js`, `BitImage2.js`, `tri2_rasterize_conservative.js`, `min_area_rect_2d.js`), plus the
50
- bench (`atlas_generate.bench.spec.js`) and ATLAS_PORT_PLAN findings.
51
- - **xatlas side** — web-verified extraction from `source/xatlas/xatlas.cpp` + `xatlas.h` (`master`):
52
- `ChartOptions`/`PackOptions` defaults, `ClusteredCharts`/`PlanarCharts`, `computeCost`,
53
- `computeLeastSquaresConformalMap`, `Chart::parameterize`, `PiecewiseParam`, `pack::Atlas::addCharts`,
54
- `findChartLocation_{bruteForce,random}`. Corroborated against Castaño's "Lightmap Parameterization"
55
- lineage and the TABI (2026) benchmark numbers for xatlas.
56
- - **Literature** — web searches across charting/cutting, parameterization/flattening, and packing;
57
- each entry below is web-verified with a URL.
58
-
59
- ---
60
-
61
- ## 2. Chart segmentation (charting)
62
-
63
- ### 2.1 What is identical
64
-
65
- meep's region-grow charter is a faithful port of xatlas's `ClusteredCharts` **cost core and growth
66
- substrate**:
67
-
68
- | Parameter / mechanism | meep | xatlas | Match |
69
- |---|---|---|---|
70
- | `maxCost` | 2 | 2.0 | ✅ |
71
- | `normalDeviationWeight` | 2 | 2.0 | ✅ |
72
- | `normalSeamWeight` | 4 | 4.0 | ✅ |
73
- | `roundnessWeight` | 0.01 | 0.01 | ✅ |
74
- | Hard normal reject | `1−dot ≥ 0.707` (~73°) | `≥ 0.707f` | ✅ |
75
- | Coplanar-region epsilon | `dot ≥ 1−1e-4` | `1e-4` | ✅ |
76
- | Planar-region **atomic** growth | default (regions are growth atoms) | yes (chart swallows whole coplanar region) | ✅ |
77
- | Greedy global-min candidate w/ lazy re-eval | yes (`IndexedFloatMinHeap`, stale-requeue) | yes (`CostQueue`, lazy pop) | ✅ |
78
- | Determinism + total coverage | yes (ascending seed, fixed reductions) | yes (deterministic tie-breaks) | ✅ |
79
-
80
- The three implemented cost terms — normal deviation `N = min(1−dot, 1)`, length-weighted normal
81
- seam `NS = Σ len·(1−dot)/Σ len`, and relative-isoperimetric roundness
82
- `R = 1 − (B²/A)_old/(B²/A)_new` — are the **exact xatlas formulas**, with identical weights.
83
-
84
- ### 2.2 Where meep is behind
85
-
86
- | Feature xatlas has | meep status | Quality impact |
87
- |---|---|---|
88
- | **`straightnessWeight = 6.0`** (clamped ≤0; pulls boundaries onto concave creases / closes gaps) | **Absent** (only 3 of 5 terms implemented) | Raggier, slightly longer chart boundaries; this is xatlas's *highest-weighted* term. |
89
- | **`mergeCharts`** (merges slivers, embedded quads, contained charts; proxy-dot ≥ 0.5) | **Absent** | More, less-balanced charts; over-segmentation never cleaned up. **The single biggest gap.** |
90
- | **Per-add validity gate** (each candidate face is ortho-projected and rejected if it flips/overlaps; failed regions blacklisted) | **Absent** — validity is deferred to the parameterization stage | meep can grow a non-developable chart that only gets split *downstream* by an LSCM-failure → `atlas_piecewise_resegment`. xatlas keeps charts developable *at growth time*. |
91
- | **Lloyd seed relocation** (`relocateSeeds`→`resetCharts`, then re-grow) | **Absent** | Charts depend on seed order, not iterated centroid/best-fit relocation. (Modest: xatlas's default `maxIterations = 1` runs just one relocate pass.) |
92
- | **Largest-area-region seeding** | meep seeds by **ascending id** | Less well-centred initial charts. |
93
- | `textureSeamWeight = 0.5` | **Intentionally dropped** (no authored UVs in scope) | N/A — correct per locked scope. |
94
-
95
- ### 2.3 Verdict — segmentation: **modestly behind**
96
-
97
- On **planar-dominant / CAD / architectural** meshes the planar-region fast path dominates and the
98
- two are effectively identical (a flat surface of any tessellation → one chart in both). On
99
- **curved / organic / decimated** meshes meep produces **~10–30 % more charts** with longer, less
100
- regular seams, and is more prone to the documented **max-stretch outliers (133–359)** because
101
- nothing splits a chart on a stretch criterion until parameterization fails. The dominant missing
102
- pieces, in order of impact: `mergeCharts` > per-add validity gate > straightness term >
103
- largest-area seeding ≈ Lloyd relocation.
104
-
105
- ---
106
-
107
- ## 3. Parameterization
108
-
109
- ### 3.1 What is identical
110
-
111
- | Mechanism | meep | xatlas | Match |
112
- |---|---|---|---|
113
- | Cascade | Ortho → LSCM → Piecewise | Planar → Ortho → LSCM → Piecewise | ✅ (meep folds Planar into Ortho) |
114
- | Ortho-accept mean (L2) stretch | ≤ 1.1 | ≤ 1.1 | ✅ |
115
- | Ortho-accept max (L∞) stretch | ≤ 1.25 | ≤ 1.25 | ✅ |
116
- | Ortho-accept flips / zero-area / boundary self-intersect | all required clean | all required clean | ✅ |
117
- | Ortho plane fit | PCA smallest-eigenvector | least-squares fit (+eigen fallback) | ✅ (equivalent) |
118
- | LSCM | least-squares conformal, **2 diameter pins** | least-squares conformal, **2 diameter pins** | ✅ |
119
- | LSCM accept gate | **bijectivity only (not stretch)** | **bijectivity only (not stretch)** | ✅ (shared limitation) |
120
- | Piecewise fallback | greedy ortho region-grow into valid sub-charts | greedy ortho region-grow (`PiecewiseParam`) | ✅ |
121
- | Stretch metric | Sander/Hoppe L2+L∞, scale-normalized (similarity = 1.0) | same family | ✅ |
122
-
123
- ### 3.2 The only real differences (both minor)
124
-
125
- - **LSCM row assembly.** meep uses the classic Lévy complex-edge formulation (`1/√area` weights)
126
- for *every* triangle. xatlas uses an **ABF-angle formulation** (`setup_abf_relations`, interior
127
- angles with a largest-angle swap for stability) and falls back to the complex-edge form only for
128
- degenerate triangles. xatlas's is marginally more numerically robust; results are otherwise the
129
- same conformal map.
130
- - **Solver.** meep: matrix-free **normal-equations** CG, cap `max(200, 10·free_cols)`. xatlas:
131
- OpenNL CG, cap `5·V`. meep allows more iterations but the normal equations square the condition
132
- number; xatlas's is slightly better conditioned. Both are CG-based least-squares; no practical
133
- quality difference on the well-conditioned per-chart systems.
134
-
135
- ### 3.3 Verdict — parameterization: **on par**
136
-
137
- meep is algorithmically equivalent to xatlas here. Same cascade, same thresholds, same 2-pin
138
- conformal LSCM, same bijectivity-only acceptance, same guaranteed-terminating piecewise fallback.
139
- xatlas's only edge is the ABF-angle LSCM rows (a hair more robust). **Both share the same ceiling:**
140
- conformal LSCM preserves angles but not area, and neither minimizes stretch after the solve — so the
141
- 133–359 max-stretch outliers exist by design in *both*. This is the axis where literature (§4.2)
142
- offers the clearest upgrade for *both*.
143
-
144
- ---
145
-
146
- ## 4-prelude. Packing
147
-
148
- ### Packing — what is identical
149
-
150
- | Mechanism | meep | xatlas | Match |
151
- |---|---|---|---|
152
- | Utilization sizing target | 0.75 | 0.75 | ✅ |
153
- | Per-chart scale `√(surf/param)·density` | yes | yes | ✅ |
154
- | Rotate-to-min-area-OBB | yes (`rotateChartsToAxis`) | yes | ✅ |
155
- | 90° placement rotation | yes (`rotateCharts`, mask+transpose) | yes (0°/90° only — *not* 4-way) | ✅ |
156
- | Sort order | perimeter descending | perimeter descending | ✅ |
157
- | Small-atlas packer | bitmap **silhouette** canBlit (shifted-OR + or_blit) | bitmap silhouette | ✅ |
158
- | Conservative raster + padding dilation | yes | yes (+ optional `bilinear` expand) | ✅ |
159
- | Multi-page spill / pow-2 growing page | yes | yes | ✅ |
160
-
161
- ### Packing — where meep is behind
162
-
163
- | Feature | meep | xatlas | Impact |
164
- |---|---|---|---|
165
- | **Placement selection** | **first-fit** (lowest-then-leftmost, no scoring) | **best-fit** — scores candidates by `max(extent)² + area` (square-biasing), via stepped brute-force or 4096 random attempts | Looser, less-square atlases. Best-fit vs first-fit is a well-known density gap. |
166
- | **Packer at production scale (>256²)** | switches to **skyline rectangle** packer (bounding boxes, simple skyline overhang waste) | keeps the **bitmap silhouette** packer at *all* sizes | meep packs rectangles where xatlas interlocks silhouettes → notably lower utilization on irregular charts at scale — but **100–1000× faster** (3–43 ms vs xatlas ~2 s/~43 s). A deliberate trade (meep measured the bitmap path at 13–22 s/2048²). |
167
- | **`blockAlign` 4×4** (BC/DXT block safety) | **Absent** (backlog) | optional (default off) | Charts can straddle compression-block edges → bleed under BC/ETC/ASTC. |
168
- | **bilinear-tap expansion** | `dilate(padding)` only | `bilinearExpand` + dilate | Cosmetic; meep's conservative raster + dilate covers most of it. |
169
- | Density search | **elastic**: re-pack up to 40× at 0.8× density | scale solved ~once | meep-specific robustness, but up to 40× redundant packing work in the worst case. |
170
-
171
- ### Packing — verdict: **behind at production scale, near parity small/flat**
172
-
173
- - **≤256² atlases:** same silhouette-interlocking class, but first-fit vs best-fit → meep slightly
174
- looser.
175
- - **Flat / rectangular charts:** skyline does fine (bench high end ~95 %) → near parity.
176
- - **Irregular / curved charts at ≥2048²:** meep's rectangle skyline leaves more waste than xatlas's
177
- silhouette best-fit → **~10–25 % lower utilization (estimated)**, bought with a **~100–1000×
178
- speedup**. xatlas is the offline quality reference (TABI 2026: xatlas-random ≈ 1.89 avg L2
179
- stretch, the best of the compared methods, at ~2 s/model; brute ~43 s).
180
-
181
- ---
182
-
183
- ## 4. Literature survey (≈2017–2026)
184
-
185
- Web-verified; URLs included. Grouped by axis. The recurring meta-finding: the field has moved past
186
- the 2002-LSCM / 2005-D-Charts lineage that xatlas (and thus meep) implements, but **the best ideas
187
- for a deterministic, dependency-free, real-time library are the classical-compatible ones** — the
188
- neural/RL methods contribute *objectives* (distortion-driven cuts, fewer charts) far more than
189
- *portable algorithms*.
190
-
191
- ### 4.1 Charting / cutting / seam placement
192
-
193
- | Work | Year | One-line | Relevance to meep |
194
- |---|---|---|---|
195
- | [D-Charts: Quasi-Developable Mesh Segmentation](https://www.cs.ubc.ca/~sheffa/papers/EG05.pdf) | 2005 | Region-grow with a **cone-fit** developability metric, bounding distortion *during* segmentation | meep's direct ancestor; the **cone-fit proxy** (vs pure normal-deviation) would let cylinders/cones grow into single charts → kills the curved-mesh over-fragmentation + stretch outliers. **Lowest-risk, highest-fit.** |
196
- | [Variational Surface Cutting](https://www.cs.cmu.edu/~kmcrane/Projects/VariationalCuts/) | 2018 | Global PDE flow evolves the cut graph to minimize distortion + seam length | The "global, length-regularized cuts" counter-philosophy to greedy grow. Too heavy to port; motivates a boundary-length term + boundary-straightening post-pass. |
197
- | [OptCuts: Joint Cuts + Parameterization](https://www.cs.ubc.ca/labs/imager/tr/2018/OptCuts/) | 2018 | A single **distortion bound** drives the cuts; alternates cut-update ↔ symmetric-Dirichlet flatten; globally bijective, minimal seam length | The strongest argument to make a **distortion threshold the primary segmentation knob** (meep's `stretch` metric already exists). Replace the LSCM-fail→explode fallback with a distortion-bounded re-cut. |
198
- | [AutoCuts](https://dl.acm.org/doi/abs/10.1145/3130800.3130845) | 2017 | One differentiable distortion+seam-length energy; cuts emerge from it | Portable cheap heuristic: add an explicit **boundary-length penalty** to the grow/merge cost (data already in `atlas_build_edge_lengths.js`). |
199
- | [Developability-Driven Piecewise Approximations](https://dl.acm.org/doi/10.1145/3528223.3530117) | 2022 | Deform-then-partition into near-developable patches with regular seams | "Light developability-aware normal smoothing *before* segmentation" lets the existing grower form larger, cleaner charts. |
200
- | [Evolutionary Piecewise Developable Approximations](https://dl.acm.org/doi/10.1145/3592140) | 2023 | Global/evolutionary search for fewer patches | Evidence that iterate-and-merge (the `mergeCharts`/Lloyd backlog) is the right direction; full search is diminishing returns for a real-time lib. |
201
- | [PartUV: Part-Based UV Unwrapping](https://arxiv.org/abs/2511.16659) | 2025 | Top-down recursive split under a distortion bound + learned part priors; ~1/31 Blender's chart count | **Most directly relevant modern paper.** The **recursive-split-only-when-distortion-exceeds-the-bound** skeleton is deterministic and portable even without the learned part decomposition → fewer, larger charts. |
202
- | [SeamGPT / Auto-Regressive Surface Cutting](https://arxiv.org/abs/2506.18017) · [MeshTailor](https://arxiv.org/abs/2603.27309) · [SeamCrafter](https://arxiv.org/abs/2509.20725) | 2025–26 | GPT-style learned seam generation mimicking artist cuts | Not portable (datasets + transformers). Transferable: seams follow **high-dihedral feature edges** (meep has `edge_dihedral`) and want **long coherent chains** → a boundary-chain straightening post-pass. SeamCrafter's **seam-evaluation score** (= f(seam length, fragmentation, distortion)) is a portable objective. |
203
- | [Unsupervised Param w/ Semantic + Visibility](https://arxiv.org/abs/2509.25094) | 2025 | AO-weighted seam term hides cuts in occluded regions | Portable: a cheap per-edge AO/visibility proxy (reuse engine BVH) biasing the cost to **hide seams** — a dimension meep's purely-geometric cost ignores. |
204
- | [Nuvo: Neural UV Mapping](https://pratulsrinivasan.github.io/nuvo/) | ECCV 2024 | Per-asset neural field for *unruly* (NeRF/soup) geometry | Out of scope (meep requires clean welded manifolds). A scope marker for if meep ever ingests scanned/AI soup. |
205
-
206
- ### 4.2 Parameterization / flattening / injectivity
207
-
208
- | Work | Year | One-line | Relevance to meep |
209
- |---|---|---|---|
210
- | [LSCM](https://dl.acm.org/doi/10.1145/566654.566590) | 2002 | The conformal-LS + region-grow pipeline meep/xatlas implement | Validates meep's core as the well-understood baseline; improvement budget is better spent on cuts + isometric relaxation than on this solver. |
211
- | [ARAP/ASAP local–global](https://www.eecs.harvard.edu/~sjg/papers/arap.pdf) | 2008 | Per-triangle rotation fit + one sparse SPD stitch solve, iterated | **Cheapest meaningful upgrade over LSCM.** Each global step is the *same* CG solve meep already runs; minimizes *isometric* (shape) distortion → directly attacks high-stretch charts. No injectivity guarantee (flip gate stays). |
212
- | [SLIM: Scalable Locally Injective Maps](https://igl.ethz.ch/projects/slim/) | 2017 | Local/global for flip-preventing barrier energies (symmetric Dirichlet); reused-Hessian sparse solves | **Strongest candidate to replace the whole cascade.** Guarantees no flips (vs meep's post-hoc reject), minimizes isometric distortion, scales to millions of faces. Needs an injective init + line search; ~20–40 solves/chart, only on charts failing the ortho gate. |
213
- | [Boundary First Flattening (BFF)](https://arxiv.org/abs/1704.06873) | 2017 | Linear conformal flattening with **explicit boundary control**; one Laplacian factorization | Natural drop-in over free-boundary LSCM; reuses the (present-but-unused) `v3_cotangent`. Automatic minimal-area boundary → fewer cuts, fewer self-intersection rejects. Caveat: cot-Laplacian indefinite on obtuse triangles (clamp / intrinsic Delaunay). |
214
- | [Foldover-free maps in 50 lines](https://arxiv.org/abs/2102.03069) + [Practical Lowest Distortion](https://arxiv.org/abs/2201.12112) | 2021–22 | Untangle from an **arbitrary (even folded)** start, then minimize mean then **max** distortion; tiny, deterministic, Newton/L-BFGS | **Most meep-aligned modern optimizer.** Can subsume *both* the flip-reject path *and* the piecewise-explode fallback: feed it the ortho/LSCM output, get a foldover-free low-distortion chart. Optimizes **max distortion last** — exactly meep's accept/reject quantity. |
215
- | [Progressive Parameterizations](https://dl.acm.org/doi/10.1145/3197517.3201331) | 2018 | Foldover-free, low-distortion via a progressive reference; 20k-mesh reliability study | Robustness-engineered alternative/complement to SLIM; composes with meep's CG + an ARAP step. |
216
- | [Isometric Energies (IsoSEA/IsoTLC)](https://duxingyi-charles.github.io/publication/isometric-energies-for-recovering-injectivity-in-constrained-mapping/) | 2022 | Recover injectivity *and* minimize isometric distortion in one energy | A strong default barrier energy if meep builds the optimizer; same solver shape as SLIM/foldover-free. |
217
- | [Progressive Embedding](https://github.com/hankstag/progressive_embedding) | 2019 | Float-robust replacement for Tutte; collapse→re-insert keeping a valid embedding | The robust **injective initializer** any barrier solver needs; overlaps meep's existing half-edge collapse simplifier (`bt_mesh_simplify_by_error`). |
218
- | [Scaffold (2017)](https://cims.nyu.edu/gcl/papers/Scaffold-2017.pdf) + [Efficient Bijective (2020)](https://dl.acm.org/doi/10.1145/3386569.3392435) | 2017–20 | Turn *global* bijectivity into *local* injectivity via a (boundary-band) scaffold | If meep ever wants one guaranteed-overlap-free chart for a whole object; the 2020 boundary-band version scales with boundary length (matches meep's perf culture) and removes the O(b²) self-intersection test. |
219
- | [CETM](https://dl.acm.org/doi/10.1145/1360612.1360676) | 2008 | Discrete conformal via convex log-scale energy (cot-Laplacian Hessian); auto cone singularities | Theoretical anchor for BFF; cone-singularity idea = fewer cuts on high-curvature closed charts. Reference, not a port target. |
220
- | [TinyAD](https://onlinelibrary.wiley.com/doi/full/10.1111/cgf.14607) | 2022 | Per-element AD → free Newton solver; the prototyping pattern | The **design blueprint**: per-triangle local energy + small analytic 2×2/3×3 Hessian → assemble into `SparseMatrixCSR` → `cg_solve`, behind one energy interface, so meep can swap conformal/ARAP/symmetric-Dirichlet/IsoSEA without re-deriving. |
221
-
222
- ### 4.3 Packing
223
-
224
- | Work | Year | One-line | Relevance to meep |
225
- |---|---|---|---|
226
- | [A Thousand Ways to Pack the Bin (Jylänki)](https://github.com/juj/RectangleBinPack) | 2010 | Canonical 2D rect-packing survey: MaxRects > Guillotine > Skyline-BL > Shelf on density; reverse on speed | Locates meep's skyline packer; **best-short-side-fit / min-waste** skyline variants beat plain bottom-left; MaxRects is the density upgrade path meep lacks. Validates the {0°,90°} rotation set. |
227
- | [TABI: Tight & Balanced Interactive Atlas Packing](https://arxiv.org/abs/2602.07782) | 2026 | **Per-axis "local AABB" + OBB proxies**, row-folding, horizontal+vertical compaction; closes ~48 % of the gap to offline xatlas at **~5 ms (~464× faster)** | **Most actionable modern reference.** The local-AABB proxy gives most of the interlocking benefit of meep's bitmap mask at O(slices) cost → lets meep pack tightly **above** its 256² bitmap ceiling, bridging its exact-but-small and loose-but-scalable packers. |
228
- | [FastAtlas: Real-Time Compact Atlases](https://arxiv.org/abs/2502.17712) | 2025 | GPU parallel: bucket by height, parallel scale-search, row-fold, advancing-front push-up; <1.5 ms on 9M-tri | The **"compute the right scale ~once, allow overflow then rescale"** idea is a serial-friendly alternative to meep's 40× elastic-shrink retry loop. |
229
- | [Two-dimensional irregular packing: a review](https://www.frontiersin.org/journals/mechanical-engineering/articles/10.3389/fmech.2022.966691/full) | 2022 | NFP vs raster/pixel vs envelope; metaheuristic sequence optimization | Locates meep's bitmap canBlit precisely as the **raster/pixel** method — cheap overlap test, **poor at *searching* for the best position** (exactly meep's first-fit weakness). NFP = tighter but fragile on concave/holed shapes. |
230
- | [stb_rect_pack / Skyline-BL practitioner study](https://www.david-colson.com/2020/03/10/exploring-rect-packing.html) | 2020 | Skyline-BL + first-fit-decreasing is simple, fast, "good enough" | Validates meep's skyline-as-scalable-default; highest leverage is in **ordering + best-fit metric**, not the data structure. |
231
- | [WebRender atlas allocation](https://mozillagfx.wordpress.com/2021/02/04/improving-texture-atlas-allocation-in-webrender/) | 2021 | Dynamic (online) atlases prefer shelf/slab over guillotine (fragmentation) | Boundary marker: meep's pack is **offline/one-shot**, so high-density guillotine/MaxRects methods are fair game; the fragmentation caveat only applies if meep grows a *streaming* atlas. |
232
- | [Learning Gradient Fields for Irregular Packing](https://arxiv.org/abs/2310.19814) · [Attend2Pack](https://arxiv.org/abs/2107.04333) · [RCQL](https://arxiv.org/abs/2111.06726) | 2021–23 | Learned/RL packing; scales to 1000s of pieces | Gains over strong heuristics are **single-digit %**, and the real lever is **ordering policy**. Watch-items, not adopt-items; the takeaway is "try several deterministic orderings, keep the best." |
233
- | [Ptex / UDIM / Htex](https://www.fxguide.com/fxfeatured/ptex_the_other_side/) | 2008/2002/2022 | Sidestep packing entirely (per-face/per-halfedge) or relax to integer tiles | Bounds the ambition: chasing the last few % of density only matters because meep is atlas-committed. UDIM maps naturally onto meep's existing multi-page support — a possible future output mode. |
234
- | [Robust NFP generation](https://www.mdpi.com/2227-7390/10/16/2941) | 2019–22 | No-fit-polygon = the tight-irregular-nesting primitive | The max-density frontier for meep's concave charts, but expensive/fragile on non-convex+holed shapes — why the port chose bitmap. Held as a documented "if we ever need maximum density" option. |
235
-
236
- ---
237
-
238
- ## 5. Prioritized opportunities (planning backlog — deterministic, dependency-free only)
239
-
240
- Ranked by estimated value ÷ effort. **All are classical/deterministic** — the neural/RL methods are
241
- explicitly *not* adopt-items (non-deterministic, heavy deps, only approximately bijective, against
242
- meep's exact/black-box-tested library semantics); we harvest their *objectives*, not their models.
243
-
244
- ### 5.0 MEASURED OUTCOMES (2026-06-26) — the gating already ran
245
-
246
- The P0 metrics harness was built ([atlas_bench_lib.js](atlas_bench_lib.js) +
247
- [atlas_metrics.bench.spec.js](atlas_metrics.bench.spec.js): chart count + chart-type histogram,
248
- stretch mean/max/p50/p90/p99 + high-distortion tail, seam length, utilization, A/B runner) and used to
249
- gate the three Tier-1 items below. **All three were measured to *not* be free wins on our actual
250
- pipeline** — and the harness surfaced the real lever instead. This is the payoff of measuring first.
251
-
252
- | Tier-1 item | Measured verdict | Evidence |
253
- |---|---|---|
254
- | **mergeCharts** | **Trade-off, not a win** — kept as an off-by-default opt-in (`segment.merge`, `mergeMinDot`). Implemented + 6 unit tests. | Safe threshold (0.9) → −1 % charts (greedy already joins coplanar regions). Effective (0.5) → −20 % charts / −7 % seam but **p99 stretch 4.27→15.21** and piecewise 127→192. No threshold gives fewer-charts-AND-no-stretch-regression. |
255
- | **best-fit packing** | **Rejected** (implemented, measured, reverted). | Δutil **0.00pp** on every fixture in both elastic and growing-page modes — min-waste's few-% gain is masked by pow2 pages + 0.8× elastic-density quantization. |
256
- | **ARAP-for-curvature** | **Premise invalidated** (not built). | Clean curved/developable surfaces (sphere, hemisphere, cylinder, cone, torus) already flatten with **max stretch ≤ 1.5**. LSCM is essentially isometric there. |
257
-
258
- **The real lever the harness found: LSCM boundary self-intersection.** The dominant quality problem is
259
- *not* any of the three above. On the decimated terrain (970 charts, **127 piecewise-explosion
260
- sub-charts**), failure-reason instrumentation of the parameterize cascade showed the explosion comes
261
- from **31 LSCM charts that fail bijectivity, ALL 31 on boundary self-intersection** (zero on
262
- zero-area / degenerate-input / mixed-winding). Free-boundary conformal LSCM has no injectivity
263
- guarantee, so on complex/curved boundaries the UV outline overlaps itself; the piecewise fallback then
264
- (correctly) cuts each into ~4 ortho pieces. *(A sliver/degenerate-input hypothesis was tested first and
265
- disproven — a degenerate-input-tolerant validity tweak was provably inert and reverted. The max-stretch
266
- ~5877 outlier is real but area-negligible: the area-weighted mean stays ~2.5.)*
267
-
268
- **Attempt 1 — Tutte/convex-boundary rescue (built, measured, then REMOVED).** The natural first try is a
269
- guaranteed-injective embedding: pin each self-intersecting disk chart to a circle and solve the interior
270
- (Tutte's theorem ⇒ no flips, no self-intersection). It **works structurally** — on the decimated
271
- terrain it eliminated the explosion (127 piecewise → 0, replaced by 31 whole charts, **−96 charts**,
272
- utilization **71.9 % → 86.3 %**, all guaranteed bijective) — but the **distortion is catastrophic**:
273
- mean stretch **2.55 → 70.9**, p99 **4.27 → 2467**. The self-intersecting charts are *thin/curled* (that
274
- is why LSCM curled them), so forcing them onto a circle ruins them. **Confirmed boundary-dominated:**
275
- upgrading the interior weights uniform → Floater mean-value changed nothing (70.82 → 70.88). So a
276
- convex-boundary embedding is the wrong tool here, and the piecewise explosion (compact low-distortion
277
- pieces) is the *better* quality outcome.
278
-
279
- **Attempt 2 — shape-aware convex boundary (built, measured, reverted).** Map the boundary to an
280
- aspect-matched ellipse instead of a circle (still convex ⇒ still injective). **No improvement** (71.67 vs
281
- 70.9): a curled chart's LSCM layout curls into a roughly *round* blob, so its aspect can't be estimated
282
- without already flattening — a catch-22 that rules out the whole convex-boundary family.
283
-
284
- **Attempt 3 — BFF, intrinsic boundary-first (built, measured, now ALWAYS-ON; the right approach).**
285
- `CHART_TYPE.BFF`: build the flat boundary from the chart's own edge lengths + curvature
286
- (Gauss-Bonnet closure), then a **conformal** pinned-boundary interior (harmonic was tried first and
287
- flipped 26/31; conformal is far less flip-prone). **It clears the gate the convex family failed** —
288
- decimated terrain −4 charts, mean stretch **2.55 → 2.51 (better, not worse)**, every BFF chart bijective,
289
- no clean-fixture regression: a Pareto-safe win, not Tutte's 70×. **But tiny magnitude — only 1 of 31**
290
- self-intersecting charts is rescued; the other 30 fail (diagnosed: 25 flip, 5 self-intersect) because the
291
- v1 **uniform** curvature redistribution leaves the boundary too contorted.
292
-
293
- **Attempt 4 — BFF's optimal Dirichlet-to-Neumann boundary (built, measured; the definitive answer).**
294
- Replaced the uniform curvature with the DtN-optimal distribution (fix boundary scale 0, interior Poisson
295
- `L_II u = Ω_I`, `k̃_b = (π−θ_b) − (L u)_b`). The **DtN boundary fixed the interior** — conformal-interior
296
- flips **25 → 2** — and stayed Pareto-safe (−6 charts, mean 2.55 → 2.51, p99 4.27 → 3.99). **But still only
297
- ~2 of 31 rescued: the flattened *boundary* now self-intersects on ~27/31, and that is FUNDAMENTAL** — true
298
- unclamped cotangents made it *worse* (1 rescue, 30 self-intersections). These high-curvature decimated
299
- charts **cannot be developed to a simple boundary** while preserving edge lengths, so cutting (piecewise)
300
- is the correct injective answer; BFF rescues only the ~2 low-curvature ones.
301
-
302
- **Conclusion (the metrics settle it): the piecewise explosion is largely correct behavior** for
303
- decimated/high-curvature charts — they are intrinsically un-flattenable-whole, and BFF (the right,
304
- fully-built tool) confirms it. BFF is **folded into the single always-on cascade** (ortho → LSCM → BFF →
305
- piecewise, no flags): it is free (compute delta ~−0.3 %, since it runs only on charts that already failed
306
- LSCM) and strictly Pareto-safe (accepts only bijective + near-isometric whole charts). The failed Tutte
307
- convex-boundary path was **removed** (strictly dominated). The only way to
308
- keep these charts whole would be to let the *boundary be cut* during optimization (OptCuts-style joint
309
- cut+flatten) or a scaffolded injective nonlinear map (SLIM) — large, separate builds whose payoff (~29
310
- hard charts, decimated assets only) the metrics say is modest. So: **no further parameterization work is
311
- warranted on the current asset mix; the validated atlas pipeline is in good shape, and the residual
312
- over-segmentation on decimated content is the right answer, not a defect.**
313
-
314
- ### 5.1 Original ranked backlog (pre-measurement — kept for context)
315
-
316
- **P0 — Head-to-head A/B bench.** ✅ **DONE** (the metrics harness above). The remaining gap is an
317
- *xatlas* side-by-side on identical meshes (we have meep-side metrics + xatlas's published numbers).
318
-
319
- **Tier 1 — biggest quality-per-effort, reuse existing infra**
320
-
321
- 1. **`mergeCharts` pass** (xatlas parity + Evolutionary-Developability evidence). Post-segmentation
322
- greedy merge of adjacent charts whose proxy normals agree (dot ≥ ~0.5) and whose merged ortho
323
- projection stays valid. Closes most of the segmentation chart-count gap. *Effort: moderate;
324
- reuses the cost/validity machinery.* → **MEASURED (§5.0): trade-off, shipped off-by-default.**
325
- 2. **Best-fit placement metric in the bitmap packer** (xatlas + Jylänki). Replace `find_first_fit`'s
326
- first-feasible return with a scored scan (`max(extent)² + area`, or contact-perimeter / wasted-gutter).
327
- Highest-leverage single packing-density win. *Effort: low.* → **MEASURED (§5.0): 0.00pp, rejected**
328
- (note: measured for the skyline path; the bitmap-path best-fit is untested but the same pow2/elastic
329
- quantization applies, so it is deprioritized).
330
- 3. **ARAP local/global as the LSCM successor** (Liu 2008 → SLIM). One per-triangle rotation fit +
331
- the *same* sparse-CG global solve, iterated — invoked only on charts that fail the ortho gate.
332
- Directly attacks the 133–359 max-stretch outliers conformal LSCM cannot fix. *Effort: low–moderate;
333
- reuses `cg_solve`.* → **MEASURED (§5.0): premise invalidated for curvature** (clean curved meshes
334
- already flatten ≤1.5; the outliers are sliver-driven). ARAP would only help *if* paired with sliver
335
- cleanup — re-evaluate after the sliver work, not before.
336
-
337
- **Tier 2 — strong, moderate effort**
338
-
339
- 4. **D-Charts cone-fit developability proxy** in the segmentation cost (Julius 2005). Augment the
340
- per-face normal-deviation with a cone-fit angle so curved-but-developable regions (cylinders,
341
- cones, fillets) grow into single charts. Targets the curved-mesh over-fragmentation at its root.
342
- 5. **TABI local-AABB proxy packer above 256²** (TABI 2026). Per-axis interval-AABBs give most of the
343
- silhouette-interlocking benefit at O(slices) cost → tight packing at production sizes without the
344
- bitmap's O(area·mask) blowup. Bridges meep's exact-small / loose-large packer split.
345
- 6. **Distortion-bounded re-cut instead of piecewise explode** (OptCuts/PartUV). When a chart's
346
- stretch exceeds the bound, open the seam along the highest-distortion edge ring (top-down,
347
- recursive) rather than exploding into many ortho sub-charts → fewer, larger charts, shorter seams.
348
- 7. **Multi-ordering best-of-N packing** (RL "sequence" lesson, xatlas "attempts"). Try a few
349
- deterministic orderings (area-desc, max-side-desc, height-desc, perimeter-desc) and keep the
350
- tightest. *Effort: low.*
351
-
352
- **Tier 3 — targeted / opportunistic**
353
-
354
- 8. **Straightness cost term** + **boundary-chain straightening post-pass** (xatlas parity +
355
- AutoCuts/Variational + MeshTailor ChainingSeams). Add the missing 5th cost term and walk each
356
- chart boundary to snap it onto connected high-dihedral chains → boundary regularity.
357
- 9. **`blockAlign` 4×4** (xatlas) — if atlas pages ever feed BC/ETC/ASTC compression.
358
- 10. **Foldover-free / Practical-Lowest-Distortion untangler** (2021–22) — the heavier but
359
- most-meep-aligned option to *replace both* the flip-reject and piecewise-explode paths with one
360
- deterministic untangling solve that minimizes max distortion last. Build behind a TinyAD-style
361
- one-energy-interface so conformal/ARAP/symmetric-Dirichlet/IsoSEA are swappable.
362
- 11. **BFF parameterization backend** behind a `CHART_TYPE` flag — linear, boundary-controlled, fewer
363
- self-intersection rejects; reuses the unused `v3_cotangent`.
364
- 12. **Visibility/AO-weighted seam term** (ICLR-2026) — bias seams into occluded edges using the
365
- engine BVH; for atlases that feed final rendering.
366
- 13. **Largest-area seeding + ≥1 Lloyd relocation** (xatlas parity) — small, completes the
367
- segmentation-parity story.
368
-
369
- ---
370
-
371
- ## 6. Appendix — parameter cross-reference (verified)
372
-
373
- **Segmentation** (meep `ATLAS_SEGMENT_DEFAULTS` vs xatlas `ChartOptions`):
374
- `maxCost 2 / 2.0` ✅ · `normalDeviationWeight 2 / 2.0` ✅ · `normalSeamWeight 4 / 4.0` ✅ ·
375
- `roundnessWeight 0.01 / 0.01` ✅ · `straightnessWeight —/6.0` ❌ · `textureSeamWeight —/0.5`
376
- (dropped, intentional) · hard reject `0.707 / 0.707` ✅ · coplanar eps `1e-4 / 1e-4` ✅ ·
377
- `maxIterations` 1-pass-no-relocate / 1-pass-with-relocate+merge+fill ❌ · seed `ascending-id /
378
- largest-area-region` ❌.
379
-
380
- **Parameterization:** ortho-accept `mean≤1.1, max≤1.25` ✅✅ · LSCM `2 diameter pins` ✅ · LSCM rows
381
- `complex-edge(Lévy) / ABF-angle(+fallback)` ~ · solver `normal-eq CG / OpenNL CG` ~ · LSCM accept
382
- `bijectivity-only` ✅ (shared limitation) · piecewise `greedy ortho grow` ✅.
383
-
384
- **Packing:** util target `0.75 / 0.75` ✅ · `rotateChartsToAxis true/true` ✅ · `rotateCharts(90°)
385
- true/true` ✅ · sort `perimeter-desc / perimeter-desc` ✅ · placement `first-fit / best-fit` ❌ ·
386
- scale packer `skyline-rect(>256²) / bitmap-silhouette(all sizes)` ❌ (deliberate) · small packer
387
- `bitmap-silhouette / bitmap-silhouette` ✅ · `blockAlign —/optional` ❌ · density `elastic-40× /
388
- solved-once` (meep-specific).
389
-
390
- **Source of record:** xatlas web-verified at `source/xatlas/xatlas.{cpp,h}` `master`; meep at
391
- `src/core/geom/3d/atlas/**` (see ATLAS_PORT_PLAN.md for file map). All literature URLs above are
392
- web-verified.