@developerz.ai/ts23d 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (567) hide show
  1. package/.claude/agents/bug-hunter.md +21 -0
  2. package/.claude/agents/docs-author.md +13 -0
  3. package/.claude/agents/dx-auditor.md +14 -0
  4. package/.claude/agents/primitive-author.md +22 -0
  5. package/.claude/agents/recipe-author.md +36 -0
  6. package/.claude/agents/visual-reviewer.md +23 -0
  7. package/.claude/commands/feature.md +28 -0
  8. package/.claude/commands/new-recipe.md +19 -0
  9. package/.claude/commands/release.md +14 -0
  10. package/.claude/commands/verify.md +9 -0
  11. package/.claude/skills/author-recipe/SKILL.md +93 -0
  12. package/CHANGELOG.md +90 -0
  13. package/CLAUDE.md +85 -0
  14. package/LICENSE +21 -0
  15. package/README.md +385 -2
  16. package/dist/chunk-6b05mnmx.js +19 -0
  17. package/dist/chunk-6b05mnmx.js.map +11 -0
  18. package/dist/chunk-7rtfjh9f.js +45 -0
  19. package/dist/chunk-7rtfjh9f.js.map +10 -0
  20. package/dist/chunk-8j4c28jt.js +4085 -0
  21. package/dist/chunk-8j4c28jt.js.map +46 -0
  22. package/dist/chunk-d1fv6hrm.js +2532 -0
  23. package/dist/chunk-d1fv6hrm.js.map +43 -0
  24. package/dist/chunk-dbq4qf52.js +902 -0
  25. package/dist/chunk-dbq4qf52.js.map +25 -0
  26. package/dist/chunk-drna2rny.js +836 -0
  27. package/dist/chunk-drna2rny.js.map +17 -0
  28. package/dist/chunk-dxvypr7y.js +89 -0
  29. package/dist/chunk-dxvypr7y.js.map +11 -0
  30. package/dist/chunk-f6yme003.js +1589 -0
  31. package/dist/chunk-f6yme003.js.map +30 -0
  32. package/dist/chunk-hg7pf34j.js +465 -0
  33. package/dist/chunk-hg7pf34j.js.map +19 -0
  34. package/dist/chunk-jq4e17tj.js +1031 -0
  35. package/dist/chunk-jq4e17tj.js.map +21 -0
  36. package/dist/chunk-y63c6zcv.js +2668 -0
  37. package/dist/chunk-y63c6zcv.js.map +53 -0
  38. package/dist/cli/args.d.ts +30 -0
  39. package/dist/cli/bin.d.ts +2 -0
  40. package/dist/cli/bin.js +348 -0
  41. package/dist/cli/bin.js.map +15 -0
  42. package/dist/cli/load.d.ts +2 -0
  43. package/dist/cli/manifest.d.ts +53 -0
  44. package/dist/cli/render-cmds.d.ts +12 -0
  45. package/dist/cli/run.d.ts +1 -0
  46. package/dist/cli/texture-cache.d.ts +4 -0
  47. package/dist/core/asset.d.ts +10 -0
  48. package/dist/core/definition.d.ts +155 -0
  49. package/dist/core/errors.d.ts +17 -0
  50. package/dist/core/family.d.ts +23 -0
  51. package/dist/core/index.d.ts +9 -0
  52. package/dist/core/index.js +69 -0
  53. package/dist/core/index.js.map +9 -0
  54. package/dist/core/mesh.d.ts +35 -0
  55. package/dist/core/part.d.ts +114 -0
  56. package/dist/core/png.d.ts +1 -0
  57. package/dist/core/rng.d.ts +12 -0
  58. package/dist/core/transform.d.ts +20 -0
  59. package/dist/core/vec.d.ts +11 -0
  60. package/dist/core/world.d.ts +16 -0
  61. package/dist/export/bin-writer.d.ts +16 -0
  62. package/dist/export/container.d.ts +3 -0
  63. package/dist/export/credits.d.ts +4 -0
  64. package/dist/export/glb-options.d.ts +48 -0
  65. package/dist/export/glb.d.ts +8 -0
  66. package/dist/export/hierarchy.d.ts +23 -0
  67. package/dist/export/index.d.ts +5 -0
  68. package/dist/export/index.js +40 -0
  69. package/dist/export/index.js.map +9 -0
  70. package/dist/export/lights.d.ts +8 -0
  71. package/dist/export/lod-coverage.d.ts +12 -0
  72. package/dist/export/materials.d.ts +23 -0
  73. package/dist/export/merge-pivots.d.ts +6 -0
  74. package/dist/export/metadata.d.ts +21 -0
  75. package/dist/export/motion.d.ts +9 -0
  76. package/dist/export/optimize-parts.d.ts +26 -0
  77. package/dist/export/primitive.d.ts +3 -0
  78. package/dist/export/tangents.d.ts +2 -0
  79. package/dist/export/textures.d.ts +22 -0
  80. package/dist/export/version.d.ts +2 -0
  81. package/dist/grammar/index.d.ts +2 -0
  82. package/dist/grammar/index.js +16 -0
  83. package/dist/grammar/index.js.map +9 -0
  84. package/dist/grammar/split.d.ts +21 -0
  85. package/dist/grammar/whyte.d.ts +5 -0
  86. package/dist/index.d.ts +11 -0
  87. package/dist/index.js +457 -0
  88. package/dist/index.js.map +9 -0
  89. package/dist/kinds/building.d.ts +44 -0
  90. package/dist/kinds/faces.d.ts +27 -0
  91. package/dist/kinds/head-armour.d.ts +5 -0
  92. package/dist/kinds/head-beard.d.ts +6 -0
  93. package/dist/kinds/head-bust.d.ts +5 -0
  94. package/dist/kinds/head-extras.d.ts +15 -0
  95. package/dist/kinds/head-face.d.ts +8 -0
  96. package/dist/kinds/head-garb.d.ts +4 -0
  97. package/dist/kinds/head-geom.d.ts +7 -0
  98. package/dist/kinds/head-hair.d.ts +4 -0
  99. package/dist/kinds/head-layout.d.ts +29 -0
  100. package/dist/kinds/head-mesh.d.ts +31 -0
  101. package/dist/kinds/head-mouth.d.ts +4 -0
  102. package/dist/kinds/head-params.d.ts +116 -0
  103. package/dist/kinds/head-presets.d.ts +19 -0
  104. package/dist/kinds/head-rim.d.ts +10 -0
  105. package/dist/kinds/head-tone.d.ts +10 -0
  106. package/dist/kinds/head-torso.d.ts +35 -0
  107. package/dist/kinds/head.d.ts +39 -0
  108. package/dist/kinds/hull-lines.d.ts +65 -0
  109. package/dist/kinds/hull-skin.d.ts +6 -0
  110. package/dist/kinds/hull.d.ts +14 -0
  111. package/dist/kinds/index.d.ts +16 -0
  112. package/dist/kinds/index.js +78 -0
  113. package/dist/kinds/index.js.map +9 -0
  114. package/dist/kinds/mass.d.ts +15 -0
  115. package/dist/kinds/openings.d.ts +30 -0
  116. package/dist/kinds/planned.d.ts +6 -0
  117. package/dist/kinds/roof-chimney.d.ts +16 -0
  118. package/dist/kinds/roof-shape.d.ts +64 -0
  119. package/dist/kinds/roof.d.ts +31 -0
  120. package/dist/kinds/vegetation-fronds.d.ts +15 -0
  121. package/dist/kinds/vegetation-impostor.d.ts +9 -0
  122. package/dist/kinds/vegetation-leaves.d.ts +15 -0
  123. package/dist/kinds/vegetation-mesh.d.ts +21 -0
  124. package/dist/kinds/vegetation-params.d.ts +90 -0
  125. package/dist/kinds/vegetation-presets.d.ts +20 -0
  126. package/dist/kinds/vegetation-skeleton.d.ts +20 -0
  127. package/dist/kinds/vegetation.d.ts +42 -0
  128. package/dist/kinds/vehicle.d.ts +42 -0
  129. package/dist/material/cc0.d.ts +4 -0
  130. package/dist/material/define.d.ts +34 -0
  131. package/dist/material/generator.d.ts +4 -0
  132. package/dist/material/index.d.ts +9 -0
  133. package/dist/material/index.js +70 -0
  134. package/dist/material/index.js.map +9 -0
  135. package/dist/material/library.d.ts +7 -0
  136. package/dist/material/material-def.d.ts +30 -0
  137. package/dist/material/paint/bond.d.ts +3 -0
  138. package/dist/material/paint/canvas.d.ts +39 -0
  139. package/dist/material/paint/cell.d.ts +4 -0
  140. package/dist/material/paint/cells-round.d.ts +5 -0
  141. package/dist/material/paint/cells.d.ts +7 -0
  142. package/dist/material/paint/compose.d.ts +5 -0
  143. package/dist/material/paint/concrete.d.ts +3 -0
  144. package/dist/material/paint/courses.d.ts +31 -0
  145. package/dist/material/paint/decode-png.d.ts +6 -0
  146. package/dist/material/paint/default-sheet.d.ts +4 -0
  147. package/dist/material/paint/fabric.d.ts +4 -0
  148. package/dist/material/paint/foliage-broad.d.ts +5 -0
  149. package/dist/material/paint/foliage-common.d.ts +35 -0
  150. package/dist/material/paint/foliage-compound.d.ts +4 -0
  151. package/dist/material/paint/foliage-conifer.d.ts +5 -0
  152. package/dist/material/paint/foliage-raster.d.ts +26 -0
  153. package/dist/material/paint/foliage.d.ts +3 -0
  154. package/dist/material/paint/image-strip.d.ts +4 -0
  155. package/dist/material/paint/kit.d.ts +5 -0
  156. package/dist/material/paint/masks.d.ts +3 -0
  157. package/dist/material/paint/metal.d.ts +3 -0
  158. package/dist/material/paint/noise.d.ts +9 -0
  159. package/dist/material/paint/normal.d.ts +8 -0
  160. package/dist/material/paint/orm.d.ts +8 -0
  161. package/dist/material/paint/planks.d.ts +3 -0
  162. package/dist/material/paint/plates.d.ts +3 -0
  163. package/dist/material/paint/shapes.d.ts +8 -0
  164. package/dist/material/paint/slate.d.ts +3 -0
  165. package/dist/material/paint/stamp.d.ts +3 -0
  166. package/dist/material/paint/strip.d.ts +3 -0
  167. package/dist/material/paint/surface.d.ts +5 -0
  168. package/dist/material/paint/types.d.ts +65 -0
  169. package/dist/material/paint/validate.d.ts +3 -0
  170. package/dist/material/palette.d.ts +14 -0
  171. package/dist/material/shader-godot.d.ts +2 -0
  172. package/dist/material/shader-three.d.ts +2 -0
  173. package/dist/material/shader.d.ts +46 -0
  174. package/dist/material/slots.d.ts +5 -0
  175. package/dist/material/texture-source.d.ts +34 -0
  176. package/dist/material/trim-sheet.d.ts +38 -0
  177. package/dist/neural/generator.d.ts +25 -0
  178. package/dist/neural/images.d.ts +17 -0
  179. package/dist/neural/index.d.ts +2 -0
  180. package/dist/neural/index.js +14 -0
  181. package/dist/neural/index.js.map +9 -0
  182. package/dist/passes/bake-ao.d.ts +17 -0
  183. package/dist/passes/grime.d.ts +15 -0
  184. package/dist/passes/index.d.ts +6 -0
  185. package/dist/passes/index.js +22 -0
  186. package/dist/passes/index.js.map +9 -0
  187. package/dist/passes/livery.d.ts +19 -0
  188. package/dist/passes/optimize-cache.d.ts +15 -0
  189. package/dist/passes/optimize-weld.d.ts +15 -0
  190. package/dist/passes/optimize.d.ts +28 -0
  191. package/dist/passes/ray-grid.d.ts +23 -0
  192. package/dist/passes/weighted-normals.d.ts +8 -0
  193. package/dist/primitives/beam.d.ts +17 -0
  194. package/dist/primitives/bevel-box.d.ts +13 -0
  195. package/dist/primitives/box.d.ts +16 -0
  196. package/dist/primitives/cell.d.ts +20 -0
  197. package/dist/primitives/check.d.ts +12 -0
  198. package/dist/primitives/closed.d.ts +11 -0
  199. package/dist/primitives/erosion.d.ts +22 -0
  200. package/dist/primitives/font-5x7.d.ts +3 -0
  201. package/dist/primitives/heightfield.d.ts +16 -0
  202. package/dist/primitives/index.d.ts +23 -0
  203. package/dist/primitives/index.js +81 -0
  204. package/dist/primitives/index.js.map +9 -0
  205. package/dist/primitives/lathe-facets.d.ts +8 -0
  206. package/dist/primitives/lathe.d.ts +26 -0
  207. package/dist/primitives/lattice.d.ts +30 -0
  208. package/dist/primitives/loft.d.ts +15 -0
  209. package/dist/primitives/mc-table.d.ts +2 -0
  210. package/dist/primitives/member.d.ts +19 -0
  211. package/dist/primitives/noise.d.ts +34 -0
  212. package/dist/primitives/planar.d.ts +10 -0
  213. package/dist/primitives/prism.d.ts +13 -0
  214. package/dist/primitives/sculpt-edit.d.ts +56 -0
  215. package/dist/primitives/sculpt-tree.d.ts +23 -0
  216. package/dist/primitives/sculpt.d.ts +27 -0
  217. package/dist/primitives/sdf-grid.d.ts +17 -0
  218. package/dist/primitives/sdf-ops.d.ts +37 -0
  219. package/dist/primitives/sdf.d.ts +21 -0
  220. package/dist/primitives/strip-uv.d.ts +11 -0
  221. package/dist/primitives/surface-nets.d.ts +7 -0
  222. package/dist/primitives/sweep.d.ts +19 -0
  223. package/dist/primitives/terrain-color.d.ts +30 -0
  224. package/dist/primitives/terrain-grid.d.ts +36 -0
  225. package/dist/primitives/text-layout.d.ts +22 -0
  226. package/dist/primitives/text.d.ts +27 -0
  227. package/dist/primitives/tiled.d.ts +22 -0
  228. package/dist/primitives/transport.d.ts +17 -0
  229. package/dist/primitives/triangulate.d.ts +2 -0
  230. package/dist/primitives/value-noise.d.ts +10 -0
  231. package/dist/qa/checks.d.ts +11 -0
  232. package/dist/qa/clash.d.ts +2 -0
  233. package/dist/qa/floating.d.ts +5 -0
  234. package/dist/qa/gates.d.ts +12 -0
  235. package/dist/qa/geometry.d.ts +21 -0
  236. package/dist/qa/index.d.ts +12 -0
  237. package/dist/qa/index.js +78 -0
  238. package/dist/qa/index.js.map +9 -0
  239. package/dist/qa/inside.d.ts +12 -0
  240. package/dist/qa/inspect.d.ts +18 -0
  241. package/dist/qa/lods.d.ts +12 -0
  242. package/dist/qa/measures.d.ts +4 -0
  243. package/dist/qa/occlusion.d.ts +3 -0
  244. package/dist/qa/sanity.d.ts +7 -0
  245. package/dist/qa/types.d.ts +12 -0
  246. package/dist/render/beauty.d.ts +40 -0
  247. package/dist/render/camera.d.ts +33 -0
  248. package/dist/render/depth-map.d.ts +38 -0
  249. package/dist/render/font.d.ts +1 -0
  250. package/dist/render/ground.d.ts +13 -0
  251. package/dist/render/index.d.ts +10 -0
  252. package/dist/render/index.js +47 -0
  253. package/dist/render/index.js.map +9 -0
  254. package/dist/render/lighting.d.ts +27 -0
  255. package/dist/render/lod-strip.d.ts +5 -0
  256. package/dist/render/metrics.d.ts +37 -0
  257. package/dist/render/options.d.ts +28 -0
  258. package/dist/render/photo-match.d.ts +19 -0
  259. package/dist/render/raster.d.ts +25 -0
  260. package/dist/render/resolve.d.ts +11 -0
  261. package/dist/render/review-prompt.d.ts +2 -0
  262. package/dist/render/review-warnings.d.ts +34 -0
  263. package/dist/render/review.d.ts +24 -0
  264. package/dist/render/scene.d.ts +18 -0
  265. package/dist/render/shade.d.ts +22 -0
  266. package/dist/render/sheet.d.ts +15 -0
  267. package/dist/render/texture.d.ts +15 -0
  268. package/dist/render/thumbnail.d.ts +8 -0
  269. package/dist/render/vis-buffer.d.ts +18 -0
  270. package/dist/testing/assert.d.ts +21 -0
  271. package/dist/testing/compiled.d.ts +15 -0
  272. package/dist/testing/hash.d.ts +1 -0
  273. package/dist/testing/index.d.ts +4 -0
  274. package/dist/testing/index.js +134 -0
  275. package/dist/testing/index.js.map +13 -0
  276. package/dist/testing/snapshot.d.ts +13 -0
  277. package/docs/README.md +56 -0
  278. package/docs/architecture/README.md +68 -0
  279. package/docs/architecture/adding-a-kind.md +44 -0
  280. package/docs/architecture/adding-a-primitive.md +49 -0
  281. package/docs/architecture/errors.md +47 -0
  282. package/docs/architecture/glb-production.md +214 -0
  283. package/docs/architecture/gltf-capabilities.md +117 -0
  284. package/docs/architecture/materials.md +151 -0
  285. package/docs/decisions/001-recipe-compiler-over-ai-meshes.md +27 -0
  286. package/docs/decisions/002-typescript-not-json.md +22 -0
  287. package/docs/decisions/003-shared-trim-sheet.md +21 -0
  288. package/docs/decisions/004-z-up-metres.md +21 -0
  289. package/docs/decisions/005-zero-runtime-deps.md +21 -0
  290. package/docs/decisions/006-single-package-subpath-exports.md +20 -0
  291. package/docs/decisions/007-cpu-contact-sheets.md +21 -0
  292. package/docs/decisions/008-surface-materials.md +21 -0
  293. package/docs/decisions/009-gltf-front-axis.md +21 -0
  294. package/docs/decisions/README.md +15 -0
  295. package/docs/idea/01-vision.md +117 -0
  296. package/docs/idea/02-dsl.md +343 -0
  297. package/docs/idea/03-ir.md +97 -0
  298. package/docs/idea/04-materials.md +114 -0
  299. package/docs/idea/05-agent-loop.md +141 -0
  300. package/docs/idea/06-qa.md +101 -0
  301. package/docs/idea/07-what-fits.md +45 -0
  302. package/docs/idea/08-neural-adapters.md +78 -0
  303. package/docs/idea/09-kinds.md +105 -0
  304. package/docs/idea/10-sculpting.md +166 -0
  305. package/docs/idea/11-materials-authoring.md +132 -0
  306. package/docs/idea/12-blender-bridge.md +136 -0
  307. package/docs/idea/13-asset-pipeline-research.md +89 -0
  308. package/docs/landscape.md +49 -0
  309. package/docs/plans/roadmap.md +139 -0
  310. package/examples/build-with-bun.ts +41 -0
  311. package/llms.txt +47 -0
  312. package/package.json +100 -4
  313. package/recipes/README.md +38 -0
  314. package/recipes/asteroid/README.md +46 -0
  315. package/recipes/asteroid/asteroid.ts +336 -0
  316. package/recipes/boulders/README.md +28 -0
  317. package/recipes/boulders/boulders.ts +117 -0
  318. package/recipes/boxcar/README.md +53 -0
  319. package/recipes/boxcar/boxcar.ts +1000 -0
  320. package/recipes/cargo_container_scifi/README.md +52 -0
  321. package/recipes/cargo_container_scifi/cargo_container_scifi.ts +461 -0
  322. package/recipes/dropship/README.md +84 -0
  323. package/recipes/dropship/dropship.ts +1144 -0
  324. package/recipes/eiffel_tower/README.md +110 -0
  325. package/recipes/eiffel_tower/eiffel_tower.ts +781 -0
  326. package/recipes/goblin_head/README.md +75 -0
  327. package/recipes/goblin_head/goblin_head.ts +38 -0
  328. package/recipes/human_head/README.md +68 -0
  329. package/recipes/human_head/human_head.ts +38 -0
  330. package/recipes/loco_440/README.md +32 -0
  331. package/recipes/loco_440/loco_440.ts +1404 -0
  332. package/recipes/material_swatches/README.md +21 -0
  333. package/recipes/material_swatches/material_swatches.ts +189 -0
  334. package/recipes/mountain_range/README.md +45 -0
  335. package/recipes/mountain_range/mountain_range.ts +128 -0
  336. package/recipes/oak/README.md +30 -0
  337. package/recipes/oak/oak.ts +19 -0
  338. package/recipes/orc_head/README.md +78 -0
  339. package/recipes/orc_head/orc_head.ts +41 -0
  340. package/recipes/palm/README.md +30 -0
  341. package/recipes/palm/palm.ts +19 -0
  342. package/recipes/pine/README.md +29 -0
  343. package/recipes/pine/pine.ts +19 -0
  344. package/recipes/signal_gantry/README.md +36 -0
  345. package/recipes/signal_gantry/signal_gantry.ts +522 -0
  346. package/recipes/station_halt/README.md +39 -0
  347. package/recipes/station_halt/station_halt.ts +722 -0
  348. package/recipes/t34/README.md +44 -0
  349. package/recipes/t34/t34.ts +1068 -0
  350. package/recipes/tiger_1/README.md +75 -0
  351. package/recipes/tiger_1/tiger_1.ts +1370 -0
  352. package/recipes/water_tower/README.md +40 -0
  353. package/recipes/water_tower/water_tower.ts +542 -0
  354. package/src/cli/args.ts +125 -0
  355. package/src/cli/bin.ts +7 -0
  356. package/src/cli/load.ts +17 -0
  357. package/src/cli/manifest.ts +95 -0
  358. package/src/cli/render-cmds.ts +66 -0
  359. package/src/cli/run.ts +192 -0
  360. package/src/cli/texture-cache.ts +24 -0
  361. package/src/core/asset.ts +129 -0
  362. package/src/core/definition.ts +156 -0
  363. package/src/core/errors.ts +50 -0
  364. package/src/core/family.ts +50 -0
  365. package/src/core/index.ts +66 -0
  366. package/src/core/mesh.ts +114 -0
  367. package/src/core/part.ts +130 -0
  368. package/src/core/png.ts +49 -0
  369. package/src/core/rng.ts +49 -0
  370. package/src/core/transform.ts +90 -0
  371. package/src/core/vec.ts +26 -0
  372. package/src/core/world.ts +80 -0
  373. package/src/export/bin-writer.ts +79 -0
  374. package/src/export/container.ts +35 -0
  375. package/src/export/credits.ts +25 -0
  376. package/src/export/glb-options.ts +53 -0
  377. package/src/export/glb.ts +187 -0
  378. package/src/export/hierarchy.ts +122 -0
  379. package/src/export/index.ts +34 -0
  380. package/src/export/lights.ts +49 -0
  381. package/src/export/lod-coverage.ts +71 -0
  382. package/src/export/materials.ts +126 -0
  383. package/src/export/merge-pivots.ts +146 -0
  384. package/src/export/metadata.ts +62 -0
  385. package/src/export/motion.ts +70 -0
  386. package/src/export/optimize-parts.ts +80 -0
  387. package/src/export/primitive.ts +35 -0
  388. package/src/export/tangents.ts +75 -0
  389. package/src/export/textures.ts +88 -0
  390. package/src/export/version.ts +6 -0
  391. package/src/grammar/index.ts +4 -0
  392. package/src/grammar/split.ts +87 -0
  393. package/src/grammar/whyte.ts +20 -0
  394. package/src/index.ts +14 -0
  395. package/src/kinds/building.ts +153 -0
  396. package/src/kinds/faces.ts +138 -0
  397. package/src/kinds/head-armour.ts +181 -0
  398. package/src/kinds/head-beard.ts +133 -0
  399. package/src/kinds/head-bust.ts +184 -0
  400. package/src/kinds/head-extras.ts +150 -0
  401. package/src/kinds/head-face.ts +242 -0
  402. package/src/kinds/head-garb.ts +181 -0
  403. package/src/kinds/head-geom.ts +31 -0
  404. package/src/kinds/head-hair.ts +193 -0
  405. package/src/kinds/head-layout.ts +63 -0
  406. package/src/kinds/head-mesh.ts +195 -0
  407. package/src/kinds/head-mouth.ts +111 -0
  408. package/src/kinds/head-params.ts +162 -0
  409. package/src/kinds/head-presets.ts +155 -0
  410. package/src/kinds/head-rim.ts +128 -0
  411. package/src/kinds/head-tone.ts +52 -0
  412. package/src/kinds/head-torso.ts +230 -0
  413. package/src/kinds/head.ts +176 -0
  414. package/src/kinds/hull-lines.ts +160 -0
  415. package/src/kinds/hull-skin.ts +83 -0
  416. package/src/kinds/hull.ts +209 -0
  417. package/src/kinds/index.ts +63 -0
  418. package/src/kinds/mass.ts +110 -0
  419. package/src/kinds/openings.ts +141 -0
  420. package/src/kinds/planned.ts +12 -0
  421. package/src/kinds/roof-chimney.ts +100 -0
  422. package/src/kinds/roof-shape.ts +230 -0
  423. package/src/kinds/roof.ts +250 -0
  424. package/src/kinds/vegetation-fronds.ts +126 -0
  425. package/src/kinds/vegetation-impostor.ts +118 -0
  426. package/src/kinds/vegetation-leaves.ts +168 -0
  427. package/src/kinds/vegetation-mesh.ts +174 -0
  428. package/src/kinds/vegetation-params.ts +147 -0
  429. package/src/kinds/vegetation-presets.ts +184 -0
  430. package/src/kinds/vegetation-skeleton.ts +168 -0
  431. package/src/kinds/vegetation.ts +199 -0
  432. package/src/kinds/vehicle.ts +144 -0
  433. package/src/material/cc0.ts +41 -0
  434. package/src/material/define.ts +130 -0
  435. package/src/material/generator.ts +63 -0
  436. package/src/material/index.ts +60 -0
  437. package/src/material/library.ts +196 -0
  438. package/src/material/material-def.ts +84 -0
  439. package/src/material/paint/bond.ts +60 -0
  440. package/src/material/paint/canvas.ts +101 -0
  441. package/src/material/paint/cell.ts +39 -0
  442. package/src/material/paint/cells-round.ts +119 -0
  443. package/src/material/paint/cells.ts +111 -0
  444. package/src/material/paint/compose.ts +53 -0
  445. package/src/material/paint/concrete.ts +62 -0
  446. package/src/material/paint/courses.ts +85 -0
  447. package/src/material/paint/decode-png.ts +106 -0
  448. package/src/material/paint/default-sheet.ts +73 -0
  449. package/src/material/paint/fabric.ts +63 -0
  450. package/src/material/paint/foliage-broad.ts +126 -0
  451. package/src/material/paint/foliage-common.ts +93 -0
  452. package/src/material/paint/foliage-compound.ts +135 -0
  453. package/src/material/paint/foliage-conifer.ts +143 -0
  454. package/src/material/paint/foliage-raster.ts +196 -0
  455. package/src/material/paint/foliage.ts +23 -0
  456. package/src/material/paint/image-strip.ts +88 -0
  457. package/src/material/paint/kit.ts +37 -0
  458. package/src/material/paint/masks.ts +46 -0
  459. package/src/material/paint/metal.ts +109 -0
  460. package/src/material/paint/noise.ts +52 -0
  461. package/src/material/paint/normal.ts +52 -0
  462. package/src/material/paint/orm.ts +108 -0
  463. package/src/material/paint/planks.ts +101 -0
  464. package/src/material/paint/plates.ts +72 -0
  465. package/src/material/paint/shapes.ts +28 -0
  466. package/src/material/paint/slate.ts +52 -0
  467. package/src/material/paint/stamp.ts +40 -0
  468. package/src/material/paint/strip.ts +48 -0
  469. package/src/material/paint/surface.ts +60 -0
  470. package/src/material/paint/types.ts +94 -0
  471. package/src/material/paint/validate.ts +74 -0
  472. package/src/material/palette.ts +46 -0
  473. package/src/material/shader-godot.ts +77 -0
  474. package/src/material/shader-three.ts +103 -0
  475. package/src/material/shader.ts +100 -0
  476. package/src/material/slots.ts +18 -0
  477. package/src/material/texture-source.ts +86 -0
  478. package/src/material/trim-sheet.ts +166 -0
  479. package/src/neural/generator.ts +37 -0
  480. package/src/neural/images.ts +27 -0
  481. package/src/neural/index.ts +10 -0
  482. package/src/passes/bake-ao.ts +183 -0
  483. package/src/passes/grime.ts +37 -0
  484. package/src/passes/index.ts +8 -0
  485. package/src/passes/livery.ts +66 -0
  486. package/src/passes/optimize-cache.ts +175 -0
  487. package/src/passes/optimize-weld.ts +147 -0
  488. package/src/passes/optimize.ts +85 -0
  489. package/src/passes/ray-grid.ts +237 -0
  490. package/src/passes/weighted-normals.ts +125 -0
  491. package/src/primitives/beam.ts +60 -0
  492. package/src/primitives/bevel-box.ts +140 -0
  493. package/src/primitives/box.ts +90 -0
  494. package/src/primitives/cell.ts +115 -0
  495. package/src/primitives/check.ts +49 -0
  496. package/src/primitives/closed.ts +74 -0
  497. package/src/primitives/erosion.ts +183 -0
  498. package/src/primitives/font-5x7.ts +117 -0
  499. package/src/primitives/heightfield.ts +101 -0
  500. package/src/primitives/index.ts +56 -0
  501. package/src/primitives/lathe-facets.ts +45 -0
  502. package/src/primitives/lathe.ts +174 -0
  503. package/src/primitives/lattice.ts +131 -0
  504. package/src/primitives/loft.ts +174 -0
  505. package/src/primitives/mc-table.ts +41 -0
  506. package/src/primitives/member.ts +130 -0
  507. package/src/primitives/noise.ts +157 -0
  508. package/src/primitives/planar.ts +55 -0
  509. package/src/primitives/prism.ts +85 -0
  510. package/src/primitives/sculpt-edit.ts +212 -0
  511. package/src/primitives/sculpt-tree.ts +226 -0
  512. package/src/primitives/sculpt.ts +80 -0
  513. package/src/primitives/sdf-grid.ts +131 -0
  514. package/src/primitives/sdf-ops.ts +145 -0
  515. package/src/primitives/sdf.ts +83 -0
  516. package/src/primitives/strip-uv.ts +26 -0
  517. package/src/primitives/surface-nets.ts +161 -0
  518. package/src/primitives/sweep.ts +162 -0
  519. package/src/primitives/terrain-color.ts +85 -0
  520. package/src/primitives/terrain-grid.ts +137 -0
  521. package/src/primitives/text-layout.ts +85 -0
  522. package/src/primitives/text.ts +197 -0
  523. package/src/primitives/tiled.ts +93 -0
  524. package/src/primitives/transport.ts +85 -0
  525. package/src/primitives/triangulate.ts +42 -0
  526. package/src/primitives/value-noise.ts +62 -0
  527. package/src/qa/checks.ts +110 -0
  528. package/src/qa/clash.ts +177 -0
  529. package/src/qa/floating.ts +63 -0
  530. package/src/qa/gates.ts +126 -0
  531. package/src/qa/geometry.ts +187 -0
  532. package/src/qa/index.ts +28 -0
  533. package/src/qa/inside.ts +114 -0
  534. package/src/qa/inspect.ts +107 -0
  535. package/src/qa/lods.ts +97 -0
  536. package/src/qa/measures.ts +67 -0
  537. package/src/qa/occlusion.ts +166 -0
  538. package/src/qa/sanity.ts +137 -0
  539. package/src/qa/types.ts +17 -0
  540. package/src/render/beauty.ts +115 -0
  541. package/src/render/camera.ts +142 -0
  542. package/src/render/depth-map.ts +191 -0
  543. package/src/render/font.ts +76 -0
  544. package/src/render/ground.ts +87 -0
  545. package/src/render/index.ts +34 -0
  546. package/src/render/lighting.ts +121 -0
  547. package/src/render/lod-strip.ts +34 -0
  548. package/src/render/metrics.ts +147 -0
  549. package/src/render/options.ts +81 -0
  550. package/src/render/photo-match.ts +28 -0
  551. package/src/render/raster.ts +143 -0
  552. package/src/render/resolve.ts +109 -0
  553. package/src/render/review-prompt.ts +59 -0
  554. package/src/render/review-warnings.ts +92 -0
  555. package/src/render/review.ts +103 -0
  556. package/src/render/scene.ts +119 -0
  557. package/src/render/shade.ts +204 -0
  558. package/src/render/sheet.ts +88 -0
  559. package/src/render/texture.ts +97 -0
  560. package/src/render/thumbnail.ts +75 -0
  561. package/src/render/vis-buffer.ts +119 -0
  562. package/src/testing/assert.ts +115 -0
  563. package/src/testing/compiled.ts +31 -0
  564. package/src/testing/hash.ts +14 -0
  565. package/src/testing/index.ts +14 -0
  566. package/src/testing/snapshot.ts +37 -0
  567. package/src/types/gltf-validator.d.ts +13 -0
@@ -0,0 +1,2532 @@
1
+ import {
2
+ Ts23dError2,
3
+ MeshBuilder2,
4
+ frame2,
5
+ applyAffine2,
6
+ sub2,
7
+ dot2,
8
+ cross2,
9
+ length2,
10
+ normalize2
11
+ } from "./chunk-hg7pf34j.js";
12
+ import {
13
+ DEFAULT_SHEET2,
14
+ TRIM_SHEET_SIZE2,
15
+ stripRect2,
16
+ cellRect2
17
+ } from "./chunk-y63c6zcv.js";
18
+
19
+ // src/primitives/bevel-box.ts
20
+ var FACES = [
21
+ { name: "front", u: [0, 1, 0], v: [0, 0, 1] },
22
+ { name: "back", u: [0, -1, 0], v: [0, 0, 1] },
23
+ { name: "left", u: [-1, 0, 0], v: [0, 0, 1] },
24
+ { name: "right", u: [1, 0, 0], v: [0, 0, 1] },
25
+ { name: "top", u: [1, 0, 0], v: [0, 1, 0] },
26
+ { name: "bottom", u: [1, 0, 0], v: [0, -1, 0] }
27
+ ];
28
+ var SIGNS = [-1, 1];
29
+ function bevelBox(o) {
30
+ const { half, centre, bevel: bv } = o;
31
+ const rect = stripRect2(o.strip);
32
+ const b = new MeshBuilder2;
33
+ const dot3 = (a, c) => a[0] * c[0] + a[1] * c[1] + a[2] * c[2];
34
+ const ext = (a) => Math.abs(a[0]) * half[0] + Math.abs(a[1]) * half[1] + Math.abs(a[2]) * half[2];
35
+ const point = (s, k) => [
36
+ centre[0] + (s[0] ?? 1) * (half[0] - (k === 0 ? 0 : bv)),
37
+ centre[1] + (s[1] ?? 1) * (half[1] - (k === 1 ? 0 : bv)),
38
+ centre[2] + (s[2] ?? 1) * (half[2] - (k === 2 ? 0 : bv))
39
+ ];
40
+ const put = (s, k, n) => {
41
+ const f = FACES[k * 2 + ((s[k] ?? 1) > 0 ? 0 : 1)] ?? { u: n, v: n };
42
+ const p = point(s, k);
43
+ const rel = [p[0] - centre[0], p[1] - centre[1], p[2] - centre[2]];
44
+ const eu = ext(f.u);
45
+ const ev = ext(f.v);
46
+ return b.vertex({
47
+ p,
48
+ n,
49
+ uv: [
50
+ rect.u0 + (dot3(rel, f.u) + eu) / rect.metres * (rect.u1 - rect.u0),
51
+ rect.v0 + (dot3(rel, f.v) + ev) / (2 * ev) * (rect.v1 - rect.v0)
52
+ ],
53
+ color: o.color
54
+ });
55
+ };
56
+ const poly = (corners, n) => {
57
+ const pts = corners.map(([s, k]) => point(s, k));
58
+ const [a = n, c = n, d = n] = pts;
59
+ const e1 = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
60
+ const e2 = [d[0] - a[0], d[1] - a[1], d[2] - a[2]];
61
+ const g = [
62
+ e1[1] * e2[2] - e1[2] * e2[1],
63
+ e1[2] * e2[0] - e1[0] * e2[2],
64
+ e1[0] * e2[1] - e1[1] * e2[0]
65
+ ];
66
+ const ids = corners.map(([s, k]) => put(s, k, n));
67
+ if (dot3(g, n) < 0)
68
+ ids.reverse();
69
+ const [i0 = 0, i1 = 0, i2 = 0, i3] = ids;
70
+ if (i3 === undefined)
71
+ b.tri(i0, i1, i2);
72
+ else
73
+ b.quad(i0, i1, i2, i3);
74
+ };
75
+ const unit = (k, s) => [k === 0 ? s : 0, k === 1 ? s : 0, k === 2 ? s : 0];
76
+ const corner = (k, sk, l, sl, m, sm) => {
77
+ const s = [1, 1, 1];
78
+ s[k] = sk;
79
+ s[l] = sl;
80
+ s[m] = sm;
81
+ return s;
82
+ };
83
+ for (let k = 0;k < 3; k++) {
84
+ const [l, m] = [(k + 1) % 3, (k + 2) % 3];
85
+ for (const sk of SIGNS) {
86
+ if (o.omit.includes((FACES[k * 2 + (sk > 0 ? 0 : 1)] ?? { name: "top" }).name))
87
+ continue;
88
+ const ring = [
89
+ [-1, -1],
90
+ [1, -1],
91
+ [1, 1],
92
+ [-1, 1]
93
+ ].map(([a, c]) => [corner(k, sk, l, a, m, c), k]);
94
+ poly(ring, unit(k, sk));
95
+ }
96
+ }
97
+ for (let m = 0;m < 3; m++) {
98
+ const [k, l] = [(m + 1) % 3, (m + 2) % 3];
99
+ for (const sk of SIGNS)
100
+ for (const sl of SIGNS) {
101
+ const lo = corner(k, sk, l, sl, m, -1);
102
+ const hi = corner(k, sk, l, sl, m, 1);
103
+ const n = normalize2([0, 1, 2].map((j) => j === k ? sk : j === l ? sl : 0));
104
+ poly([
105
+ [lo, k],
106
+ [hi, k],
107
+ [hi, l],
108
+ [lo, l]
109
+ ], n);
110
+ }
111
+ }
112
+ for (const sx of SIGNS)
113
+ for (const sy of SIGNS)
114
+ for (const sz of SIGNS) {
115
+ const s = [sx, sy, sz];
116
+ poly([
117
+ [s, 0],
118
+ [s, 1],
119
+ [s, 2]
120
+ ], normalize2([sx, sy, sz]));
121
+ }
122
+ return b.build();
123
+ }
124
+
125
+ // src/primitives/check.ts
126
+ function invalid(cause, fix) {
127
+ throw new Ts23dError2("T3D_RECIPE_INVALID", { cause, fix });
128
+ }
129
+ var finite = (v) => v.every(Number.isFinite);
130
+ function spanOf(what, origin, u, v) {
131
+ if (!finite(origin) || !finite(u) || !finite(v))
132
+ invalid(`${what}: origin/u/v has a NaN or Infinity`, "pass finite metre vectors");
133
+ const lu = length2(u);
134
+ const lv = length2(v);
135
+ if (lu < 0.000000001 || lv < 0.000000001)
136
+ invalid(`${what}: edge u (${lu} m) or v (${lv} m) has zero length`, "give u and v the face edges in metres, both non-zero (e.g. u: [4, 0, 0], v: [0, 0, 3])");
137
+ const c = cross2(u, v);
138
+ const lc = length2(c);
139
+ if (lc < 0.000001 * lu * lv)
140
+ invalid(`${what}: u and v are parallel, so the face has no area`, "make v perpendicular to u (u along the face, v up it)");
141
+ return { lu, lv, n: [c[0] / lc, c[1] / lc, c[2] / lc] };
142
+ }
143
+ function count(what, n, min, max) {
144
+ if (!Number.isInteger(n) || n < min || n > max)
145
+ invalid(`${what} is ${n}`, `use a whole number from ${min} to ${max}`);
146
+ return n;
147
+ }
148
+ function positive(what, n, example) {
149
+ if (!Number.isFinite(n) || n <= 0)
150
+ invalid(`${what} is ${n}`, `use a length > 0 m (${example})`);
151
+ return n;
152
+ }
153
+
154
+ // src/primitives/box.ts
155
+ var FACES2 = [
156
+ { name: "front", n: [1, 0, 0], u: [0, 1, 0], v: [0, 0, 1] },
157
+ { name: "back", n: [-1, 0, 0], u: [0, -1, 0], v: [0, 0, 1] },
158
+ { name: "right", n: [0, -1, 0], u: [1, 0, 0], v: [0, 0, 1] },
159
+ { name: "left", n: [0, 1, 0], u: [-1, 0, 0], v: [0, 0, 1] },
160
+ { name: "top", n: [0, 0, 1], u: [1, 0, 0], v: [0, 1, 0] },
161
+ { name: "bottom", n: [0, 0, -1], u: [1, 0, 0], v: [0, -1, 0] }
162
+ ];
163
+ function box2(o) {
164
+ const [w, d, h] = o.size;
165
+ const [cx, cy, cz] = o.at ?? [0, 0, 0];
166
+ const half = [w / 2, d / 2, h / 2];
167
+ const centre = [cx, cy, cz + h / 2];
168
+ const bevel = o.bevel ?? 0;
169
+ if (bevel !== 0) {
170
+ const limit = Math.min(w, d, h) / 2;
171
+ if (!(bevel > 0 && bevel < limit))
172
+ invalid(`box bevel ${bevel} m does not fit a ${w} × ${d} × ${h} m box`, `use 0 < bevel < ${limit} m (half the smallest size), e.g. ${Math.min(0.02, limit / 4)}`);
173
+ return bevelBox({
174
+ half,
175
+ centre,
176
+ bevel,
177
+ color: o.color,
178
+ strip: o.strip ?? "plain",
179
+ omit: o.omit ?? []
180
+ });
181
+ }
182
+ const rect = stripRect2(o.strip ?? "plain");
183
+ const b = new MeshBuilder2;
184
+ for (const f of FACES2) {
185
+ if (o.omit?.includes(f.name))
186
+ continue;
187
+ const extent = (axis) => Math.abs(axis[0]) * half[0] + Math.abs(axis[1]) * half[1] + Math.abs(axis[2]) * half[2];
188
+ const eu = extent(f.u);
189
+ const ev = extent(f.v);
190
+ const en = extent(f.n);
191
+ const ids = [
192
+ [-1, -1],
193
+ [1, -1],
194
+ [1, 1],
195
+ [-1, 1]
196
+ ].map(([su = 0, sv = 0]) => {
197
+ const p = [0, 1, 2].map((k) => (centre[k] ?? 0) + (f.n[k] ?? 0) * en + (f.u[k] ?? 0) * eu * su + (f.v[k] ?? 0) * ev * sv);
198
+ const uMetres = (su + 1) / 2 * eu * 2;
199
+ const vFrac = (sv + 1) / 2;
200
+ return b.vertex({
201
+ p,
202
+ n: f.n,
203
+ uv: [
204
+ rect.u0 + uMetres / rect.metres * (rect.u1 - rect.u0),
205
+ rect.v0 + vFrac * (rect.v1 - rect.v0)
206
+ ],
207
+ color: o.color
208
+ });
209
+ });
210
+ const [a = 0, c = 0, e = 0, g = 0] = ids;
211
+ b.quad(a, c, e, g);
212
+ }
213
+ return b.build();
214
+ }
215
+
216
+ // src/primitives/lathe-facets.ts
217
+ function facets(o, put, tri, sideUv) {
218
+ const half = Math.PI / o.segments;
219
+ const corner = (s) => {
220
+ const t = s / o.segments * Math.PI * 2 - Math.PI / 2;
221
+ return [Math.cos(t), Math.sin(t)];
222
+ };
223
+ for (let i = 0;i + 1 < o.profile.length; i++) {
224
+ const [r0 = 0, z0 = 0] = o.profile[i] ?? [];
225
+ const [r1 = 0, z1 = 0] = o.profile[i + 1] ?? [];
226
+ for (let s = 0;s < o.segments; s++) {
227
+ const tm = (s + 0.5) / o.segments * Math.PI * 2 - Math.PI / 2;
228
+ const nx = (z1 - z0) * Math.cos(tm);
229
+ const ny = (z1 - z0) * Math.sin(tm);
230
+ const nz = -(r1 - r0) * Math.cos(half);
231
+ const l = Math.hypot(nx, ny, nz) || 1;
232
+ const n = [nx / l, ny / l, nz / l];
233
+ const [c0, s0] = corner(s);
234
+ const [c1, s1] = corner(s + 1);
235
+ const a = put([r0 * c0, r0 * s0, z0], n, sideUv(s, i, r0));
236
+ const bb = put([r0 * c1, r0 * s1, z0], n, sideUv(s + 1, i, r0));
237
+ const c = put([r1 * c1, r1 * s1, z1], n, sideUv(s + 1, i + 1, r1));
238
+ const d = put([r1 * c0, r1 * s0, z1], n, sideUv(s, i + 1, r1));
239
+ tri(a, bb, c);
240
+ tri(a, c, d);
241
+ }
242
+ }
243
+ }
244
+
245
+ // src/primitives/strip-uv.ts
246
+ var HALF_TEXEL = 0.5 / TRIM_SHEET_SIZE2;
247
+ var stripVMetres = (id) => DEFAULT_SHEET2.strips[id]?.scaleMetres ?? 1;
248
+ var stripU = (rect, metres) => rect.u0 + metres / rect.metres * (rect.u1 - rect.u0);
249
+ var stripV = (rect, frac) => rect.v0 + HALF_TEXEL + frac * (rect.v1 - rect.v0 - 2 * HALF_TEXEL);
250
+ function mirroredV(rect, metres, vMetres) {
251
+ const t = metres / vMetres;
252
+ const m = t - 2 * Math.floor(t / 2);
253
+ return stripV(rect, m <= 1 ? m : 2 - m);
254
+ }
255
+
256
+ // src/primitives/lathe.ts
257
+ var orient = (p, axis) => axis === "z" ? p : axis === "y" ? [p[0], p[2], p[1]] : [p[2], p[1], p[0]];
258
+ function lathe2(o) {
259
+ const axis = o.axis ?? "z";
260
+ const [ox, oy, oz] = o.at ?? [0, 0, 0];
261
+ const rect = stripRect2(o.strip ?? "plain");
262
+ const b = new MeshBuilder2;
263
+ const mirrored = axis !== "z";
264
+ const tri = (x, y, z) => {
265
+ if (mirrored)
266
+ b.tri(x, z, y);
267
+ else
268
+ b.tri(x, y, z);
269
+ };
270
+ const ring = [];
271
+ const put = (p, n, uv) => {
272
+ const q = orient(p, axis);
273
+ return b.vertex({
274
+ p: [q[0] + ox, q[1] + oy, q[2] + oz],
275
+ n: orient(n, axis),
276
+ uv,
277
+ color: o.color
278
+ });
279
+ };
280
+ const metres = o.uv === "metres";
281
+ const vm = stripVMetres(o.strip ?? "plain");
282
+ const run = [0];
283
+ for (let i = 1;i < o.profile.length; i++) {
284
+ const [r0 = 0, z0 = 0] = o.profile[i - 1] ?? [];
285
+ const [r1 = 0, z1 = 0] = o.profile[i] ?? [];
286
+ run.push((run[i - 1] ?? 0) + Math.hypot(r1 - r0, z1 - z0));
287
+ }
288
+ const sideUv = (s, i, r) => metres ? [stripU(rect, Math.PI * 2 * r * s / o.segments), mirroredV(rect, run[i] ?? 0, vm)] : [
289
+ rect.u0 + s / o.segments * (rect.u1 - rect.u0),
290
+ rect.v0 + i / Math.max(1, o.profile.length - 1) * (rect.v1 - rect.v0)
291
+ ];
292
+ const capUv = (c, sn, r) => metres ? [stripU(rect, c * r), mirroredV(rect, (sn + 1) * r, vm)] : [
293
+ rect.u0 + (0.5 + c / 2) * (rect.u1 - rect.u0),
294
+ rect.v0 + (0.5 + sn / 2) * (rect.v1 - rect.v0)
295
+ ];
296
+ const creaseCos = Math.cos((o.creaseDeg ?? 50) * Math.PI / 180);
297
+ const emitRing = (i, dr, dz) => {
298
+ const [r, z] = o.profile[i] ?? [0, 0];
299
+ const len = Math.hypot(dr, dz) || 1;
300
+ const row = [];
301
+ for (let s = 0;s <= o.segments; s++) {
302
+ const t = s / o.segments * Math.PI * 2 - Math.PI / 2;
303
+ const c = Math.cos(t);
304
+ const sn = Math.sin(t);
305
+ row.push(put([r * c, r * sn, z], [dz / len * c, dz / len * sn, -dr / len], sideUv(s, i, r)));
306
+ }
307
+ return row;
308
+ };
309
+ const top = [];
310
+ if (o.faceted)
311
+ facets(o, put, tri, sideUv);
312
+ else
313
+ o.profile.forEach(([r, z], i) => {
314
+ const prev = o.profile[i - 1] ?? o.profile[i] ?? [r, z];
315
+ const next = o.profile[i + 1] ?? o.profile[i] ?? [r, z];
316
+ const ir = r - prev[0];
317
+ const iz = z - prev[1];
318
+ const or = next[0] - r;
319
+ const oz = next[1] - z;
320
+ const li = Math.hypot(ir, iz);
321
+ const lo = Math.hypot(or, oz);
322
+ if (li > 0.000000000001 && lo > 0.000000000001 && (ir * or + iz * oz) / (li * lo) < creaseCos) {
323
+ top.push(emitRing(i, ir, iz));
324
+ ring.push(emitRing(i, or, oz));
325
+ return;
326
+ }
327
+ const row = emitRing(i, next[0] - prev[0], next[1] - prev[1]);
328
+ top.push(row);
329
+ ring.push(row);
330
+ });
331
+ for (let i = 0;i + 1 < ring.length; i++) {
332
+ for (let s = 0;s < o.segments; s++) {
333
+ const a = ring[i]?.[s] ?? 0;
334
+ const bb = ring[i]?.[s + 1] ?? 0;
335
+ const c = top[i + 1]?.[s + 1] ?? 0;
336
+ const d = top[i + 1]?.[s] ?? 0;
337
+ tri(a, bb, c);
338
+ tri(a, c, d);
339
+ }
340
+ }
341
+ if (o.caps) {
342
+ const ends = [
343
+ { pt: o.profile[0], n: -1 },
344
+ { pt: o.profile[o.profile.length - 1], n: 1 }
345
+ ];
346
+ for (const { pt, n } of ends) {
347
+ if (!pt)
348
+ continue;
349
+ const centre = put([0, 0, pt[1]], [0, 0, n], capUv(0, 0, pt[0]));
350
+ const rim = [];
351
+ for (let s = 0;s <= o.segments; s++) {
352
+ const t = s / o.segments * Math.PI * 2 - Math.PI / 2;
353
+ rim.push(put([pt[0] * Math.cos(t), pt[0] * Math.sin(t), pt[1]], [0, 0, n], capUv(Math.cos(t), Math.sin(t), pt[0])));
354
+ }
355
+ for (let s = 0;s < o.segments; s++) {
356
+ const r0 = rim[s] ?? 0;
357
+ const r1 = rim[s + 1] ?? 0;
358
+ if (n > 0)
359
+ tri(centre, r0, r1);
360
+ else
361
+ tri(centre, r1, r0);
362
+ }
363
+ }
364
+ }
365
+ return b.build();
366
+ }
367
+ var cylinder2 = (o) => lathe2({
368
+ ...o,
369
+ profile: [
370
+ [o.radius, -o.length / 2],
371
+ [o.radius, o.length / 2]
372
+ ],
373
+ caps: true
374
+ });
375
+
376
+ // src/primitives/beam.ts
377
+ function beam2(o) {
378
+ const dir = sub2(o.to, o.from);
379
+ const len = length2(dir);
380
+ const w = normalize2(dir);
381
+ const ref = o.up ?? (Math.abs(w[2]) > 0.95 ? [1, 0, 0] : [0, 0, 1]);
382
+ const u = normalize2(cross2(ref, w));
383
+ const v = cross2(w, u);
384
+ const local = o.segments && o.segments >= 3 ? lathe2({
385
+ profile: [
386
+ [o.width / 2, 0],
387
+ [o.width / 2, len]
388
+ ],
389
+ segments: o.segments,
390
+ color: o.color,
391
+ caps: o.caps ?? true,
392
+ ...o.strip ? { strip: o.strip } : {}
393
+ }) : box2({
394
+ size: [o.width, o.height ?? o.width, len],
395
+ ...o.caps === false ? { omit: ["top", "bottom"] } : {},
396
+ color: o.color,
397
+ ...o.strip ? { strip: o.strip } : {}
398
+ });
399
+ return applyAffine2(local, frame2(u, v, w, o.from));
400
+ }
401
+ // src/primitives/cell.ts
402
+ var add3 = (a, b, s) => [
403
+ a[0] + b[0] * s,
404
+ a[1] + b[1] * s,
405
+ a[2] + b[2] * s
406
+ ];
407
+ function cell2(o) {
408
+ const { lu, lv, n } = spanOf("cell", o.origin, o.u, o.v);
409
+ const d = o.inset ?? 0;
410
+ if (!Number.isFinite(d))
411
+ invalid(`cell inset is ${d}`, "use a finite depth in metres (0.1 = a 10 cm recess)");
412
+ if (d !== 0 && o.doubleSided)
413
+ invalid("cell: inset with doubleSided", "drop doubleSided for a recessed/raised panel, or set inset: 0");
414
+ const r = cellRect2(o.cell);
415
+ const e = HALF_TEXEL;
416
+ const rim = [
417
+ o.origin,
418
+ add3(o.origin, o.u, 1),
419
+ add3(add3(o.origin, o.u, 1), o.v, 1),
420
+ add3(o.origin, o.v, 1)
421
+ ];
422
+ const face = rim.map((p) => add3(p, n, -d));
423
+ const uvs = [
424
+ [r.u0 + e, r.v0 + e],
425
+ [r.u1 - e, r.v0 + e],
426
+ [r.u1 - e, r.v1 - e],
427
+ [r.u0 + e, r.v1 - e]
428
+ ];
429
+ const b = new MeshBuilder2;
430
+ for (const side of o.doubleSided ? [1, -1] : [1]) {
431
+ const nn = [n[0] * side, n[1] * side, n[2] * side];
432
+ const [i0 = 0, i1 = 0, i2 = 0, i3 = 0] = face.map((p, k) => b.vertex({ p, n: nn, uv: uvs[k] ?? [0, 0], color: o.color }));
433
+ if (side > 0)
434
+ b.quad(i0, i1, i2, i3);
435
+ else
436
+ b.quad(i0, i3, i2, i1);
437
+ }
438
+ if (d !== 0)
439
+ reveals(b, o, rim, face, n, d, [lu, lv, lu, lv]);
440
+ return b.build();
441
+ }
442
+ function reveals(b, o, rim, face, n, d, lens) {
443
+ const strip = o.reveal ?? "plain";
444
+ const rect = stripRect2(strip);
445
+ const fv = Math.min(1, Math.abs(d) / stripVMetres(strip));
446
+ const color = o.revealColor ?? o.color;
447
+ for (let i = 0;i < 4; i++) {
448
+ const a = rim[i] ?? n;
449
+ const c = rim[(i + 1) % 4] ?? n;
450
+ const ed = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
451
+ const s = Math.sign(d);
452
+ const nn = normalize2([
453
+ (n[1] * ed[2] - n[2] * ed[1]) * s,
454
+ (n[2] * ed[0] - n[0] * ed[2]) * s,
455
+ (n[0] * ed[1] - n[1] * ed[0]) * s
456
+ ]);
457
+ const len = lens[i] ?? 0;
458
+ const q = [a, c, face[(i + 1) % 4] ?? c, face[i] ?? a];
459
+ const uv = [
460
+ [stripU(rect, 0), stripV(rect, 0)],
461
+ [stripU(rect, len), stripV(rect, 0)],
462
+ [stripU(rect, len), stripV(rect, fv)],
463
+ [stripU(rect, 0), stripV(rect, fv)]
464
+ ];
465
+ const [j0 = 0, j1 = 0, j2 = 0, j3 = 0] = q.map((p, k) => b.vertex({ p, n: nn, uv: uv[k] ?? [0, 0], color }));
466
+ b.quad(j0, j1, j2, j3);
467
+ }
468
+ }
469
+ // src/primitives/erosion.ts
470
+ var put = (h, dep, k, a) => {
471
+ h[k] = (h[k] ?? 0) + a;
472
+ dep[k] = (dep[k] ?? 0) + a;
473
+ };
474
+ function makeBrush(radius) {
475
+ const dx = [];
476
+ const dy = [];
477
+ const w = [];
478
+ for (let y = -radius;y <= radius; y++)
479
+ for (let x = -radius;x <= radius; x++) {
480
+ const d = Math.sqrt(x * x + y * y);
481
+ if (d < radius) {
482
+ dx.push(x);
483
+ dy.push(y);
484
+ w.push(radius - d);
485
+ }
486
+ }
487
+ const sum = w.reduce((s, v) => s + v, 0);
488
+ return {
489
+ dx: Int32Array.from(dx),
490
+ dy: Int32Array.from(dy),
491
+ w: Float64Array.from(w, (v) => v / sum)
492
+ };
493
+ }
494
+ function droplet(s, b, x0, y0) {
495
+ const { h, nx, ny } = s;
496
+ let x = x0;
497
+ let y = y0;
498
+ let dx = 0;
499
+ let dy = 0;
500
+ let speed = 1;
501
+ let water = 1;
502
+ let sediment = 0;
503
+ for (let step = 0;step < s.life; step++) {
504
+ const i = Math.floor(x);
505
+ const j = Math.floor(y);
506
+ const u = x - i;
507
+ const v = y - j;
508
+ const k = j * nx + i;
509
+ const a = h[k] ?? 0;
510
+ const bb = h[k + 1] ?? 0;
511
+ const c = h[k + nx] ?? 0;
512
+ const d = h[k + nx + 1] ?? 0;
513
+ const height = a * (1 - u) * (1 - v) + bb * u * (1 - v) + c * (1 - u) * v + d * u * v;
514
+ const gx = (bb - a) * (1 - v) + (d - c) * v;
515
+ const gy = (c - a) * (1 - u) + (d - bb) * u;
516
+ dx = dx * s.inertia - gx * (1 - s.inertia);
517
+ dy = dy * s.inertia - gy * (1 - s.inertia);
518
+ const len = Math.sqrt(dx * dx + dy * dy);
519
+ if (len === 0)
520
+ return;
521
+ dx /= len;
522
+ dy /= len;
523
+ x += dx;
524
+ y += dy;
525
+ s.flow[k] = (s.flow[k] ?? 0) + water;
526
+ if (x < 0 || y < 0 || x >= nx - 1 || y >= ny - 1)
527
+ return;
528
+ const dh = bilinear(h, nx, x, y) - height;
529
+ const cap = Math.max(-dh * speed * water * s.capK, s.minCap);
530
+ if (sediment > cap || dh > 0) {
531
+ const amount = dh > 0 ? Math.min(dh, sediment) : (sediment - cap) * s.depositK;
532
+ sediment -= amount;
533
+ put(h, s.dep, k, amount * (1 - u) * (1 - v));
534
+ put(h, s.dep, k + 1, amount * u * (1 - v));
535
+ put(h, s.dep, k + nx, amount * (1 - u) * v);
536
+ put(h, s.dep, k + nx + 1, amount * u * v);
537
+ } else {
538
+ const amount = Math.min((cap - sediment) * s.erodeK, -dh);
539
+ for (let n = 0;n < b.w.length; n++) {
540
+ const ci = i + (b.dx[n] ?? 0);
541
+ const cj = j + (b.dy[n] ?? 0);
542
+ if (ci < 0 || cj < 0 || ci >= nx || cj >= ny)
543
+ continue;
544
+ const cell = cj * nx + ci;
545
+ const take = Math.min(h[cell] ?? 0, amount * (b.w[n] ?? 0));
546
+ h[cell] = (h[cell] ?? 0) - take;
547
+ sediment += take;
548
+ }
549
+ }
550
+ speed = Math.sqrt(Math.max(0, speed * speed - dh * s.gravity));
551
+ water *= 1 - s.evap;
552
+ }
553
+ }
554
+ function bilinear(h, nx, x, y) {
555
+ const i = Math.floor(x);
556
+ const j = Math.floor(y);
557
+ const u = x - i;
558
+ const v = y - j;
559
+ const k = j * nx + i;
560
+ const a = h[k] ?? 0;
561
+ const b = h[k + 1] ?? 0;
562
+ const c = h[k + nx] ?? 0;
563
+ const d = h[k + nx + 1] ?? 0;
564
+ return a * (1 - u) * (1 - v) + b * u * (1 - v) + c * (1 - u) * v + d * u * v;
565
+ }
566
+ function hydraulicErosion2(g, rng, o = {}) {
567
+ const drops = count("erosion droplets", o.droplets ?? 70000, 0, 1e7);
568
+ const life = count("erosion lifetime", o.lifetime ?? 30, 1, 1000);
569
+ const radius = count("erosion radius", o.radius ?? 3, 1, 32);
570
+ const { nx, ny } = g;
571
+ let lo = Number.POSITIVE_INFINITY;
572
+ let hi = Number.NEGATIVE_INFINITY;
573
+ for (const v of g.z) {
574
+ lo = Math.min(lo, v);
575
+ hi = Math.max(hi, v);
576
+ }
577
+ const relief = hi - lo || 1;
578
+ const h = Float64Array.from(g.z, (v) => (v - lo) / relief);
579
+ const flow = new Float64Array(h.length);
580
+ const dep = new Float64Array(h.length);
581
+ const sim = {
582
+ ...{ h, flow, dep, nx, ny, life, inertia: o.inertia ?? 0.05, capK: o.capacity ?? 4 },
583
+ ...{ minCap: o.minCapacity ?? 0.01, erodeK: o.erode ?? 0.3, depositK: o.deposit ?? 0.3 },
584
+ ...{ evap: o.evaporate ?? 0.01, gravity: o.gravity ?? 4 }
585
+ };
586
+ const brush = makeBrush(radius);
587
+ for (let n = 0;n < drops; n++)
588
+ droplet(sim, brush, rng.next() * (nx - 2), rng.next() * (ny - 2));
589
+ const norm = (m) => {
590
+ let top = 0;
591
+ for (const v of m)
592
+ top = Math.max(top, v);
593
+ return top > 0 ? m.map((v) => Math.sqrt(v / top)) : m;
594
+ };
595
+ return { ...g, z: h.map((v) => lo + v * relief), flow: norm(flow), deposit: norm(dep) };
596
+ }
597
+ // src/primitives/heightfield.ts
598
+ function heightfield2(o) {
599
+ const [x0, y0, x1, y1] = o.rect;
600
+ const [nx, ny] = o.cells;
601
+ const dx = (x1 - x0) / nx;
602
+ const dy = (y1 - y0) / ny;
603
+ const rect = stripRect2(o.strip ?? "plain");
604
+ const vm = stripVMetres(o.strip ?? "plain");
605
+ const b = new MeshBuilder2;
606
+ const ids = [];
607
+ for (let j = 0;j <= ny; j++) {
608
+ for (let i = 0;i <= nx; i++) {
609
+ const x = x0 + i * dx;
610
+ const y = y0 + j * dy;
611
+ const z = o.height(x, y);
612
+ const n = normalize2([
613
+ o.height(x - dx, y) - o.height(x + dx, y),
614
+ o.height(x, y - dy) - o.height(x, y + dy),
615
+ 2 * Math.min(dx, dy)
616
+ ]);
617
+ const color = typeof o.color === "function" ? o.color(x, y, z) : o.color;
618
+ const u = (x - x0) / rect.metres;
619
+ ids.push(b.vertex({
620
+ p: [x, y, z],
621
+ n,
622
+ uv: [rect.u0 + u * (rect.u1 - rect.u0), mirroredV(rect, y - y0, vm)],
623
+ color
624
+ }));
625
+ }
626
+ }
627
+ const at = (i, j) => ids[j * (nx + 1) + i] ?? 0;
628
+ for (let j = 0;j < ny; j++)
629
+ for (let i = 0;i < nx; i++)
630
+ b.quad(at(i, j), at(i + 1, j), at(i + 1, j + 1), at(i, j + 1));
631
+ if (o.skirt !== undefined)
632
+ skirt(b, o, rect);
633
+ return b.build();
634
+ }
635
+ function skirt(b, o, rect) {
636
+ const [x0, y0, x1, y1] = o.rect;
637
+ const [nx, ny] = o.cells;
638
+ const base = o.skirt ?? 0;
639
+ const edges = [
640
+ [x0, y0, (x1 - x0) / nx, 0, nx, [0, -1, 0]],
641
+ [x1, y0, 0, (y1 - y0) / ny, ny, [1, 0, 0]],
642
+ [x1, y1, -(x1 - x0) / nx, 0, nx, [0, 1, 0]],
643
+ [x0, y1, 0, -(y1 - y0) / ny, ny, [-1, 0, 0]]
644
+ ];
645
+ const col = (x, y, z) => o.skirtColor ?? (typeof o.color === "function" ? o.color(x, y, z) : o.color);
646
+ const v = (x, y, z, n, u, color) => b.vertex({
647
+ p: [x, y, z],
648
+ n,
649
+ uv: [rect.u0 + u / rect.metres * (rect.u1 - rect.u0), z > base ? rect.v1 : rect.v0],
650
+ color
651
+ });
652
+ let run = 0;
653
+ for (const [sx, sy, dx, dy, n, nrm] of edges) {
654
+ const step = Math.hypot(dx, dy);
655
+ for (let k = 0;k < n; k++) {
656
+ const [ax, ay, bx, by] = [sx + dx * k, sy + dy * k, sx + dx * (k + 1), sy + dy * (k + 1)];
657
+ const az = o.height(ax, ay);
658
+ const bz = o.height(bx, by);
659
+ const ca = col(ax, ay, az);
660
+ const cb = col(bx, by, bz);
661
+ const ta = v(ax, ay, az, nrm, run, ca);
662
+ const tb = v(bx, by, bz, nrm, run + step, cb);
663
+ b.quad(v(ax, ay, base, nrm, run, ca), v(bx, by, base, nrm, run + step, cb), tb, ta);
664
+ run += step;
665
+ }
666
+ }
667
+ }
668
+ // src/primitives/triangulate.ts
669
+ var area = (p) => p.reduce((s, a, i) => {
670
+ const b = p[(i + 1) % p.length] ?? a;
671
+ return s + a[0] * b[1] - b[0] * a[1];
672
+ }, 0) / 2;
673
+ var cross = (a, b, c) => (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
674
+ function inside(p, a, b, c) {
675
+ return cross(a, b, p) >= 0 && cross(b, c, p) >= 0 && cross(c, a, p) >= 0;
676
+ }
677
+ function triangulate2(poly) {
678
+ const idx = poly.map((_, i) => i);
679
+ if (area(poly) < 0)
680
+ idx.reverse();
681
+ const out = [];
682
+ let guard = idx.length * idx.length;
683
+ while (idx.length > 3 && guard-- > 0) {
684
+ for (let i = 0;i < idx.length; i++) {
685
+ const ia = idx[(i + idx.length - 1) % idx.length] ?? 0;
686
+ const ib = idx[i] ?? 0;
687
+ const ic = idx[(i + 1) % idx.length] ?? 0;
688
+ const a = poly[ia] ?? [0, 0];
689
+ const b = poly[ib] ?? [0, 0];
690
+ const c = poly[ic] ?? [0, 0];
691
+ if (cross(a, b, c) <= 0)
692
+ continue;
693
+ if (idx.some((j) => j !== ia && j !== ib && j !== ic && inside(poly[j] ?? [0, 0], a, b, c)))
694
+ continue;
695
+ out.push([ia, ib, ic]);
696
+ idx.splice(i, 1);
697
+ break;
698
+ }
699
+ }
700
+ if (idx.length === 3)
701
+ out.push([idx[0] ?? 0, idx[1] ?? 0, idx[2] ?? 0]);
702
+ return out;
703
+ }
704
+
705
+ // src/primitives/member.ts
706
+ function section(kind, w) {
707
+ const h = w / 2;
708
+ const t = w * 0.15;
709
+ const ring = kind === "square" ? [
710
+ [-h, -h],
711
+ [h, -h],
712
+ [h, h],
713
+ [-h, h]
714
+ ] : [
715
+ [-h, -h],
716
+ [h, -h],
717
+ [h, -h + t],
718
+ [-h + t, -h + t],
719
+ [-h + t, h],
720
+ [-h, h]
721
+ ];
722
+ const lens = ring.map((a, i) => {
723
+ const b = ring[(i + 1) % ring.length] ?? a;
724
+ return Math.hypot(b[0] - a[0], b[1] - a[1]);
725
+ });
726
+ const total = lens.reduce((s, l) => s + l, 0);
727
+ let acc = 0;
728
+ const run = lens.map((l) => {
729
+ const r = acc / total;
730
+ acc += l;
731
+ return r;
732
+ });
733
+ return { ring, caps: triangulate2(ring), run, sideTris: ring.length * 2 };
734
+ }
735
+ function emitMember(mb, s, a, b, y, caps, color, rect) {
736
+ const d = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
737
+ const len = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
738
+ const w = [d[0] / len, d[1] / len, d[2] / len];
739
+ const k = y[0] * w[0] + y[1] * w[1] + y[2] * w[2];
740
+ const yr = [y[0] - w[0] * k, y[1] - w[1] * k, y[2] - w[2] * k];
741
+ const yl = Math.sqrt(yr[0] * yr[0] + yr[1] * yr[1] + yr[2] * yr[2]);
742
+ const yy = [yr[0] / yl, yr[1] / yl, yr[2] / yl];
743
+ const x = [
744
+ yy[1] * w[2] - yy[2] * w[1],
745
+ yy[2] * w[0] - yy[0] * w[2],
746
+ yy[0] * w[1] - yy[1] * w[0]
747
+ ];
748
+ const at = (p, end) => [
749
+ end[0] + x[0] * p[0] + yy[0] * p[1],
750
+ end[1] + x[1] * p[0] + yy[1] * p[1],
751
+ end[2] + x[2] * p[0] + yy[2] * p[1]
752
+ ];
753
+ const n = s.ring.length;
754
+ const u1 = stripU(rect, len);
755
+ const u0 = stripU(rect, 0);
756
+ for (let i = 0;i < n; i++) {
757
+ const p = s.ring[i] ?? [0, 0];
758
+ const q = s.ring[(i + 1) % n] ?? p;
759
+ const ex = q[0] - p[0];
760
+ const ey = q[1] - p[1];
761
+ const el = Math.hypot(ex, ey);
762
+ const nx = ey / el;
763
+ const ny = -ex / el;
764
+ const nrm = [x[0] * nx + yy[0] * ny, x[1] * nx + yy[1] * ny, x[2] * nx + yy[2] * ny];
765
+ const v0 = stripV(rect, s.run[i] ?? 0);
766
+ const v1 = stripV(rect, i + 1 < n ? s.run[i + 1] ?? 1 : 1);
767
+ const i0 = mb.vertex({ p: at(p, a), n: nrm, uv: [u0, v0], color });
768
+ const i1 = mb.vertex({ p: at(q, a), n: nrm, uv: [u0, v1], color });
769
+ const i2 = mb.vertex({ p: at(q, b), n: nrm, uv: [u1, v1], color });
770
+ const i3 = mb.vertex({ p: at(p, b), n: nrm, uv: [u1, v0], color });
771
+ mb.quad(i0, i1, i2, i3);
772
+ }
773
+ if (!caps)
774
+ return;
775
+ for (const [end, sign] of [
776
+ [a, -1],
777
+ [b, 1]
778
+ ]) {
779
+ const nrm = [w[0] * sign, w[1] * sign, w[2] * sign];
780
+ const first = mb.vertex({
781
+ p: at(s.ring[0] ?? [0, 0], end),
782
+ n: nrm,
783
+ uv: [u0, stripV(rect, 0)],
784
+ color
785
+ });
786
+ for (let i = 1;i < n; i++) {
787
+ const p = s.ring[i] ?? [0, 0];
788
+ mb.vertex({ p: at(p, end), n: nrm, uv: [u0, stripV(rect, s.run[i] ?? 0)], color });
789
+ }
790
+ for (const [i, j, l] of s.caps) {
791
+ if (sign > 0)
792
+ mb.tri(first + i, first + j, first + l);
793
+ else
794
+ mb.tri(first + i, first + l, first + j);
795
+ }
796
+ }
797
+ }
798
+
799
+ // src/primitives/lattice.ts
800
+ function lattice2(o) {
801
+ const d = [o.to[0] - o.from[0], o.to[1] - o.from[1], o.to[2] - o.from[2]];
802
+ const len = Math.hypot(d[0], d[1], d[2]);
803
+ if (!(len > 0.000001))
804
+ invalid("lattice: from and to coincide", "give the truss two distinct end points in metres");
805
+ const depth = positive("lattice depth", o.depth, "e.g. 2 for a 2 m deep girder");
806
+ const chord = positive("lattice chord", o.chord, "e.g. 0.2");
807
+ if (chord >= depth)
808
+ invalid(`lattice chord ${chord} m ≥ depth ${depth} m`, "make the chord member thinner than the depth");
809
+ const web = positive("lattice web", o.web ?? chord * 0.6, "e.g. 0.6 · chord");
810
+ const k = count("lattice bays", o.bays ?? Math.max(1, Math.round(len / depth)), 1, 2000);
811
+ const w = normalize2(d);
812
+ const upHint = o.up ?? (Math.abs(w[2]) > 0.95 ? [1, 0, 0] : [0, 0, 1]);
813
+ const dotU = upHint[0] * w[0] + upHint[1] * w[1] + upHint[2] * w[2];
814
+ const upR = [upHint[0] - w[0] * dotU, upHint[1] - w[1] * dotU, upHint[2] - w[2] * dotU];
815
+ if (Math.hypot(upR[0], upR[1], upR[2]) < 0.000001)
816
+ invalid("lattice: up is parallel to from → to", "pass an `up` perpendicular to the truss axis");
817
+ const up = normalize2(upR);
818
+ const side = [
819
+ w[1] * up[2] - w[2] * up[1],
820
+ w[2] * up[0] - w[0] * up[2],
821
+ w[0] * up[1] - w[1] * up[0]
822
+ ];
823
+ const dEnd = positive("lattice depthEnd", o.depthEnd ?? depth, "e.g. 1");
824
+ const wid = o.width === undefined ? 0 : positive("lattice width", o.width, "e.g. 2");
825
+ const wEnd = o.width === undefined ? 0 : positive("lattice widthEnd", o.widthEnd ?? wid, "e.g. 1");
826
+ const c0 = o.centred ? -0.5 : 0;
827
+ const line = (a, c) => (t) => {
828
+ const along = len * t;
829
+ const lat = a * (wid + (wEnd - wid) * t) / 2;
830
+ const h = (c0 + c) * (depth + (dEnd - depth) * t);
831
+ return [
832
+ o.from[0] + w[0] * along + side[0] * lat + up[0] * h,
833
+ o.from[1] + w[1] * along + side[1] * lat + up[1] * h,
834
+ o.from[2] + w[2] * along + side[2] * lat + up[2] * h
835
+ ];
836
+ };
837
+ const neg = (v) => [-v[0], -v[1], -v[2]];
838
+ const faces = o.width === undefined ? [[line(0, 0), line(0, 1), side]] : [
839
+ [line(-1, 0), line(-1, 1), neg(side)],
840
+ [line(1, 0), line(1, 1), side],
841
+ [line(-1, 1), line(1, 1), up],
842
+ [line(-1, 0), line(1, 0), neg(up)]
843
+ ];
844
+ const chords = o.width === undefined ? [line(0, 0), line(0, 1)] : [line(-1, 0), line(1, 0), line(-1, 1), line(1, 1)];
845
+ const rect = stripRect2(o.strip ?? "iron");
846
+ const sc = section(o.section ?? "square", chord);
847
+ const sw = section(o.section ?? "square", web);
848
+ const mb = new MeshBuilder2;
849
+ for (const c of chords)
850
+ emitMember(mb, sc, c(0), c(1), up, true, o.color, rect);
851
+ for (const [lo, hi, n] of faces)
852
+ for (const [ta, la, tb, lb] of webMembers(o.pattern ?? "warren", k))
853
+ emitMember(mb, sw, (la ? hi : lo)(ta), (lb ? hi : lo)(tb), n, false, o.color, rect);
854
+ return mb.build();
855
+ }
856
+ function webMembers(pattern, k) {
857
+ const out = [];
858
+ const t = (i) => i / k;
859
+ if (pattern !== "warren")
860
+ for (let i = 0;i <= k; i++)
861
+ out.push([t(i), false, t(i), true]);
862
+ for (let i = 0;i < k; i++) {
863
+ const down = [t(i), true, t(i + 1), false];
864
+ const rise = [t(i), false, t(i + 1), true];
865
+ const middle = k % 2 === 1 && i === (k - 1) / 2;
866
+ const left = i < k / 2;
867
+ if (pattern === "warren")
868
+ out.push(i % 2 === 0 ? rise : down);
869
+ else if (pattern === "x" || middle)
870
+ out.push(rise, down);
871
+ else if (pattern === "pratt")
872
+ out.push(left ? down : rise);
873
+ else
874
+ out.push(left ? rise : down);
875
+ }
876
+ return out;
877
+ }
878
+ // src/primitives/loft.ts
879
+ function ringXY2(centre, rx, ry, segments, wobble, phase = 0) {
880
+ const out = [];
881
+ for (let k = 0;k < segments; k++) {
882
+ const a = phase + k / segments * Math.PI * 2;
883
+ const w = wobble ? wobble(a) : 1;
884
+ out.push([centre[0] + rx * Math.cos(a) * w, centre[1] + ry * Math.sin(a) * w, centre[2]]);
885
+ }
886
+ return out;
887
+ }
888
+ var invalid2 = (cause, fix) => new Ts23dError2("T3D_RECIPE_INVALID", { cause, fix });
889
+ var centroid = (r) => {
890
+ let x = 0;
891
+ let y = 0;
892
+ let z = 0;
893
+ for (const p of r) {
894
+ x += p[0];
895
+ y += p[1];
896
+ z += p[2];
897
+ }
898
+ return [x / r.length, y / r.length, z / r.length];
899
+ };
900
+ function loft2(o) {
901
+ const R = o.rings.length;
902
+ if (R < 2)
903
+ throw invalid2(`loft has ${R} ring(s)`, "pass at least 2 rings (bottom → top)");
904
+ const N = o.rings[0]?.length ?? 0;
905
+ if (N < 3)
906
+ throw invalid2(`loft rings have ${N} vertices`, "give every ring at least 3 vertices");
907
+ for (const [i, r] of o.rings.entries()) {
908
+ if (r.length !== N) {
909
+ throw invalid2(`loft ring ${i} has ${r.length} vertices, ring 0 has ${N}`, "build every ring with the same vertex count (same `segments` in ringXY)");
910
+ }
911
+ }
912
+ const at = (i, k) => o.rings[i]?.[(k % N + N) % N] ?? [0, 0, 0];
913
+ const cents = o.rings.map(centroid);
914
+ const along = [0];
915
+ for (let i = 1;i < R; i++) {
916
+ const a = cents[i - 1] ?? [0, 0, 0];
917
+ const b = cents[i] ?? a;
918
+ along.push((along[i - 1] ?? 0) + Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]));
919
+ }
920
+ const total = along[R - 1] || 1;
921
+ const raw = [];
922
+ let facing = 0;
923
+ for (let i = 0;i < R; i++) {
924
+ const c = cents[i] ?? [0, 0, 0];
925
+ const ax = cents[Math.min(R - 1, i + 1)] ?? c;
926
+ const bx = cents[Math.max(0, i - 1)] ?? c;
927
+ const axis = [ax[0] - bx[0], ax[1] - bx[1], ax[2] - bx[2]];
928
+ for (let k = 0;k < N; k++) {
929
+ const p = at(i, k);
930
+ const u0 = at(i, k - 1);
931
+ const u1 = at(i, k + 1);
932
+ const v0 = at(Math.max(0, i - 1), k);
933
+ const v1 = at(Math.min(R - 1, i + 1), k);
934
+ const tu = [u1[0] - u0[0], u1[1] - u0[1], u1[2] - u0[2]];
935
+ const tv = [v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2]];
936
+ let n = [
937
+ tu[1] * tv[2] - tu[2] * tv[1],
938
+ tu[2] * tv[0] - tu[0] * tv[2],
939
+ tu[0] * tv[1] - tu[1] * tv[0]
940
+ ];
941
+ if (Math.hypot(n[0], n[1], n[2]) < 0.000000000001)
942
+ n = i === 0 ? [-axis[0], -axis[1], -axis[2]] : axis;
943
+ facing += n[0] * (p[0] - c[0]) + n[1] * (p[1] - c[1]) + n[2] * (p[2] - c[2]);
944
+ raw.push(n);
945
+ }
946
+ }
947
+ const flip = facing < 0 ? -1 : 1;
948
+ const rect = stripRect2(o.strip ?? "plain");
949
+ const du = rect.u1 - rect.u0;
950
+ const dv = rect.v1 - rect.v0;
951
+ const mode = o.uv ?? "length";
952
+ const color = (i, p) => typeof o.color === "function" ? o.color(o.rings[i] ?? [], i, p) : o.color;
953
+ const b = new MeshBuilder2;
954
+ for (let i = 0;i < R; i++) {
955
+ let around = 0;
956
+ for (let k = 0;k <= N; k++) {
957
+ const p = at(i, k);
958
+ if (k > 0) {
959
+ const q = at(i, k - 1);
960
+ around += Math.hypot(p[0] - q[0], p[1] - q[1], p[2] - q[2]);
961
+ }
962
+ const n = raw[i * N + k % N] ?? [0, 0, 1];
963
+ const l = (Math.hypot(n[0], n[1], n[2]) || 1) * flip;
964
+ const s = (along[i] ?? 0) / rect.metres;
965
+ const uv = mode === "row" ? [rect.u0 + around / rect.metres * du, rect.v0 + (along[i] ?? 0) / total * dv] : mode === "swap" ? [rect.u0 + k / N * du, rect.v0 + (along[i] ?? 0) / total * dv] : [rect.u0 + s * du, rect.v0 + k / N * dv];
966
+ b.vertex({ p, n: [n[0] / l, n[1] / l, n[2] / l], uv, color: color(i, p) });
967
+ }
968
+ }
969
+ for (let i = 0;i + 1 < R; i++) {
970
+ const r0 = i * (N + 1);
971
+ const r1 = r0 + N + 1;
972
+ for (let k = 0;k < N; k++) {
973
+ if (flip > 0)
974
+ b.quad(r0 + k, r0 + k + 1, r1 + k + 1, r1 + k);
975
+ else
976
+ b.quad(r0 + k, r1 + k, r1 + k + 1, r0 + k + 1);
977
+ }
978
+ }
979
+ const ends = [
980
+ [0, o.capStart === true],
981
+ [R - 1, o.capEnd === true]
982
+ ];
983
+ for (const [i, on] of ends) {
984
+ if (!on)
985
+ continue;
986
+ const c = cents[i] ?? [0, 0, 0];
987
+ const other = cents[i === 0 ? 1 : R - 2] ?? c;
988
+ const d = [c[0] - other[0], c[1] - other[1], c[2] - other[2]];
989
+ const l = Math.hypot(d[0], d[1], d[2]) || 1;
990
+ const nn = [d[0] / l, d[1] / l, d[2] / l];
991
+ const mid = b.vertex({ p: c, n: nn, uv: [rect.u0, rect.v0], color: color(i, c) });
992
+ for (let k = 0;k < N; k++) {
993
+ const p = at(i, k);
994
+ b.vertex({ p, n: nn, uv: [rect.u0, rect.v1], color: color(i, p) });
995
+ }
996
+ const e1 = at(i, 0);
997
+ const e2 = at(i, 1);
998
+ const cr = [
999
+ (e1[1] - c[1]) * (e2[2] - c[2]) - (e1[2] - c[2]) * (e2[1] - c[1]),
1000
+ (e1[2] - c[2]) * (e2[0] - c[0]) - (e1[0] - c[0]) * (e2[2] - c[2]),
1001
+ (e1[0] - c[0]) * (e2[1] - c[1]) - (e1[1] - c[1]) * (e2[0] - c[0])
1002
+ ];
1003
+ const ccw = cr[0] * nn[0] + cr[1] * nn[1] + cr[2] * nn[2] >= 0;
1004
+ for (let k = 0;k < N; k++) {
1005
+ const a = mid + 1 + k;
1006
+ const z = mid + 1 + (k + 1) % N;
1007
+ if (ccw)
1008
+ b.tri(mid, a, z);
1009
+ else
1010
+ b.tri(mid, z, a);
1011
+ }
1012
+ }
1013
+ return b.build();
1014
+ }
1015
+ // src/primitives/noise.ts
1016
+ var R = Math.SQRT1_2;
1017
+ var GX = [1, -1, 0, 0, R, -R, R, -R];
1018
+ var GY = [0, 0, 1, -1, R, R, -R, -R];
1019
+ function permutation(rng) {
1020
+ const p = new Uint8Array(512);
1021
+ for (let i = 0;i < 256; i++)
1022
+ p[i] = i;
1023
+ for (let i = 255;i > 0; i--) {
1024
+ const j = rng.int(0, i);
1025
+ const t = p[i] ?? 0;
1026
+ p[i] = p[j] ?? 0;
1027
+ p[j] = t;
1028
+ }
1029
+ for (let i = 0;i < 256; i++)
1030
+ p[i + 256] = p[i] ?? 0;
1031
+ return p;
1032
+ }
1033
+ var fade = (t) => t * t * t * (t * (t * 6 - 15) + 10);
1034
+ function gradientNoise22(rng) {
1035
+ const p = permutation(rng);
1036
+ const grad = (ix, iy, dx, dy) => {
1037
+ const g = (p[(p[ix & 255] ?? 0) + (iy & 255)] ?? 0) & 7;
1038
+ return (GX[g] ?? 0) * dx + (GY[g] ?? 0) * dy;
1039
+ };
1040
+ return (x, y) => {
1041
+ const ix = Math.floor(x);
1042
+ const iy = Math.floor(y);
1043
+ const fx = x - ix;
1044
+ const fy = y - iy;
1045
+ const u = fade(fx);
1046
+ const v = fade(fy);
1047
+ const a = grad(ix, iy, fx, fy);
1048
+ const b = grad(ix + 1, iy, fx - 1, fy);
1049
+ const c = grad(ix, iy + 1, fx, fy - 1);
1050
+ const d = grad(ix + 1, iy + 1, fx - 1, fy - 1);
1051
+ const top = a + (b - a) * u;
1052
+ return (top + (c + (d - c) * u - top) * v) * Math.SQRT2;
1053
+ };
1054
+ }
1055
+ function valueNoise22(rng) {
1056
+ const p = permutation(rng);
1057
+ const vals = new Float64Array(256);
1058
+ for (let i = 0;i < 256; i++)
1059
+ vals[i] = rng.next() * 2 - 1;
1060
+ const at = (ix, iy) => vals[p[(p[ix & 255] ?? 0) + (iy & 255)] ?? 0] ?? 0;
1061
+ return (x, y) => {
1062
+ const ix = Math.floor(x);
1063
+ const iy = Math.floor(y);
1064
+ const u = fade(x - ix);
1065
+ const v = fade(y - iy);
1066
+ const top = at(ix, iy) + (at(ix + 1, iy) - at(ix, iy)) * u;
1067
+ const bot = at(ix, iy + 1) + (at(ix + 1, iy + 1) - at(ix, iy + 1)) * u;
1068
+ return top + (bot - top) * v;
1069
+ };
1070
+ }
1071
+ function fractal(n, o, shape) {
1072
+ const s = 1 / (o.scale ?? 1);
1073
+ const octaves = o.octaves ?? 5;
1074
+ const lac = o.lacunarity ?? 2;
1075
+ const gain = o.gain ?? 0.5;
1076
+ return (x, y) => {
1077
+ let sum = 0;
1078
+ let amp = 1;
1079
+ let norm = 0;
1080
+ let f = s;
1081
+ for (let i = 0;i < octaves; i++) {
1082
+ sum += amp * shape(n(x * f + i * 17.31, y * f - i * 9.73));
1083
+ norm += amp;
1084
+ amp *= gain;
1085
+ f *= lac;
1086
+ }
1087
+ return sum / norm;
1088
+ };
1089
+ }
1090
+ var fbm2 = (n, o = {}) => fractal(n, o, (v) => v);
1091
+ var billow2 = (n, o = {}) => fractal(n, o, (v) => 2 * Math.abs(v) - 1);
1092
+ function ridged2(n, o = {}) {
1093
+ const s = 1 / (o.scale ?? 1);
1094
+ const octaves = o.octaves ?? 6;
1095
+ const lac = o.lacunarity ?? 2;
1096
+ const gain = o.gain ?? 0.5;
1097
+ const offset = o.offset ?? 1;
1098
+ return (x, y) => {
1099
+ let sum = 0;
1100
+ let norm = 0;
1101
+ let amp = 1;
1102
+ let weight = 1;
1103
+ let f = s;
1104
+ for (let i = 0;i < octaves; i++) {
1105
+ const crest = offset - Math.abs(n(x * f + i * 17.31, y * f - i * 9.73));
1106
+ const signal = crest * crest * weight;
1107
+ weight = Math.min(1, Math.max(0, signal * 2));
1108
+ sum += signal * amp;
1109
+ norm += amp * offset * offset;
1110
+ amp *= gain;
1111
+ f *= lac;
1112
+ }
1113
+ return sum / norm;
1114
+ };
1115
+ }
1116
+ var warp2 = (n, wx, wy, amount) => (x, y) => n(x + amount * wx(x, y), y + amount * wy(x, y));
1117
+ function terrace2(h, step, sharpness = 0.5) {
1118
+ const k = Math.floor(h / step);
1119
+ const t = h / step - k;
1120
+ const s = Math.min(1, Math.max(0, sharpness));
1121
+ const u = s >= 1 ? 0 : Math.min(1, Math.max(0, (t - s) / (1 - s)));
1122
+ const riser = u * u * (3 - 2 * u);
1123
+ return (k + t + (riser - t) * s) * step;
1124
+ }
1125
+ // src/primitives/planar.ts
1126
+ function planar2(o) {
1127
+ const [a = [0, 0, 0], b = [1, 0, 0], c = [0, 1, 0]] = o.points;
1128
+ const n = normalize2(cross2(sub2(b, a), sub2(c, a)));
1129
+ const u = normalize2(sub2(b, a));
1130
+ const v = cross2(n, u);
1131
+ const flat = o.points.map((p) => [dot2(sub2(p, a), u), dot2(sub2(p, a), v)]);
1132
+ const rect = stripRect2(o.strip ?? "plain");
1133
+ const tris = triangulate2(flat);
1134
+ const mb = new MeshBuilder2;
1135
+ for (const side of o.doubleSided ? [1, -1] : [1]) {
1136
+ const nn = [n[0] * side, n[1] * side, n[2] * side];
1137
+ const ids = o.points.map((p, i) => {
1138
+ const f = flat[i] ?? [0, 0];
1139
+ return mb.vertex({
1140
+ p,
1141
+ n: nn,
1142
+ uv: [
1143
+ rect.u0 + f[0] / rect.metres * (rect.u1 - rect.u0),
1144
+ rect.v0 + (f[1] / rect.metres % 1 + 1) % 1 * (rect.v1 - rect.v0)
1145
+ ],
1146
+ color: o.color
1147
+ });
1148
+ });
1149
+ for (const [x, y, z] of tris) {
1150
+ const [i0 = 0, i1 = 0, i2 = 0] = [ids[x], ids[y], ids[z]];
1151
+ if (side > 0)
1152
+ mb.tri(i0, i1, i2);
1153
+ else
1154
+ mb.tri(i0, i2, i1);
1155
+ }
1156
+ }
1157
+ return mb.build();
1158
+ }
1159
+ // src/primitives/prism.ts
1160
+ var lift = (plane, p, d) => plane === "xz" ? [p[0], d, p[1]] : plane === "xy" ? [p[0], p[1], d] : [d, p[0], p[1]];
1161
+ function prism2(o) {
1162
+ const plane = o.plane ?? "xy";
1163
+ const d0 = o.centred === false ? 0 : -o.depth / 2;
1164
+ const d1 = d0 + o.depth;
1165
+ const rect = stripRect2(o.strip ?? "plain");
1166
+ const uv = (u, v) => [
1167
+ rect.u0 + u / rect.metres * (rect.u1 - rect.u0),
1168
+ rect.v0 + (v % 1 + 1) % 1 * (rect.v1 - rect.v0)
1169
+ ];
1170
+ const b = new MeshBuilder2;
1171
+ const n = o.profile.length;
1172
+ const sign = o.profile.reduce((s, a, i) => {
1173
+ const c = o.profile[(i + 1) % n] ?? a;
1174
+ return s + a[0] * c[1] - c[0] * a[1];
1175
+ }, 0) > 0 ? 1 : -1;
1176
+ const hand = plane === "xz" ? -1 : 1;
1177
+ let run = 0;
1178
+ for (let i = 0;i < n; i++) {
1179
+ const a = o.profile[i] ?? [0, 0];
1180
+ const c = o.profile[(i + 1) % n] ?? a;
1181
+ const e = [c[0] - a[0], c[1] - a[1]];
1182
+ const len = Math.hypot(e[0], e[1]);
1183
+ if (len < 0.000000001)
1184
+ continue;
1185
+ const n2 = [e[1] / len * sign, -e[0] / len * sign];
1186
+ const nrm = normalize2(lift(plane, n2, 0));
1187
+ const p = [lift(plane, a, d0), lift(plane, c, d0), lift(plane, c, d1), lift(plane, a, d1)];
1188
+ const ids = p.map((q, k) => b.vertex({
1189
+ p: q,
1190
+ n: nrm,
1191
+ uv: uv(run + (k === 1 || k === 2 ? len : 0), k >= 2 ? o.depth : 0),
1192
+ color: o.color
1193
+ }));
1194
+ const [i0 = 0, i1 = 0, i2 = 0, i3 = 0] = ids;
1195
+ if (sign * hand > 0)
1196
+ b.quad(i0, i1, i2, i3);
1197
+ else
1198
+ b.quad(i0, i3, i2, i1);
1199
+ run += len;
1200
+ }
1201
+ if (o.caps !== false) {
1202
+ const tris = triangulate2(o.profile);
1203
+ for (const [d, s] of [
1204
+ [d0, -1],
1205
+ [d1, 1]
1206
+ ]) {
1207
+ const nrm = normalize2(lift(plane, [0, 0], s));
1208
+ const ids = o.profile.map((q) => b.vertex({ p: lift(plane, q, d), n: nrm, uv: uv(q[0], q[1]), color: o.color }));
1209
+ for (const [x, y, z] of tris) {
1210
+ const [a = 0, c = 0, e = 0] = [ids[x], ids[y], ids[z]];
1211
+ if (s * hand > 0)
1212
+ b.tri(a, c, e);
1213
+ else
1214
+ b.tri(a, e, c);
1215
+ }
1216
+ }
1217
+ }
1218
+ return b.build();
1219
+ }
1220
+ // src/primitives/sdf-ops.ts
1221
+ var clamp01 = (x) => x < 0 ? 0 : Math.min(x, 1);
1222
+ var shapes = {
1223
+ sphere: (x, y, z, r) => Math.sqrt(x * x + y * y + z * z) - r,
1224
+ ellipsoid(x, y, z, rx, ry, rz) {
1225
+ const k0 = Math.sqrt((x / rx) ** 2 + (y / ry) ** 2 + (z / rz) ** 2);
1226
+ const k1 = Math.sqrt((x / (rx * rx)) ** 2 + (y / (ry * ry)) ** 2 + (z / (rz * rz)) ** 2);
1227
+ return k1 === 0 ? -Math.min(rx, ry, rz) : k0 * (k0 - 1) / k1;
1228
+ },
1229
+ roundBox(x, y, z, hx, hy, hz, r) {
1230
+ const qx = Math.abs(x) - hx + r;
1231
+ const qy = Math.abs(y) - hy + r;
1232
+ const qz = Math.abs(z) - hz + r;
1233
+ const ox = Math.max(qx, 0);
1234
+ const oy = Math.max(qy, 0);
1235
+ const oz = Math.max(qz, 0);
1236
+ return Math.sqrt(ox * ox + oy * oy + oz * oz) + Math.min(Math.max(qx, qy, qz), 0) - r;
1237
+ },
1238
+ capsule(x, y, z, len, r) {
1239
+ const t = len > 0 ? Math.min(Math.max(z, 0), len) : 0;
1240
+ return Math.sqrt(x * x + y * y + (z - t) * (z - t)) - r;
1241
+ },
1242
+ cone(x, y, z, r1, r2, h) {
1243
+ const hh = h / 2;
1244
+ const qx = Math.sqrt(x * x + y * y);
1245
+ const qy = z - hh;
1246
+ const cax = qx - Math.min(qx, qy < 0 ? r1 : r2);
1247
+ const cay = Math.abs(qy) - hh;
1248
+ const k2x = r2 - r1;
1249
+ const k2y = 2 * hh;
1250
+ const t = clamp01(((r2 - qx) * k2x + (hh - qy) * k2y) / (k2x * k2x + k2y * k2y));
1251
+ const cbx = qx - r2 + k2x * t;
1252
+ const cby = qy - hh + k2y * t;
1253
+ const s = cbx < 0 && cay < 0 ? -1 : 1;
1254
+ return s * Math.sqrt(Math.min(cax * cax + cay * cay, cbx * cbx + cby * cby));
1255
+ },
1256
+ torus(x, y, z, R, r) {
1257
+ const q = Math.sqrt(x * x + y * y) - R;
1258
+ return Math.sqrt(q * q + z * z) - r;
1259
+ }
1260
+ };
1261
+ var smoothWeight = (a, b, k) => k > 0 ? clamp01(0.5 + 0.5 * (b - a) / k) : a < b ? 1 : 0;
1262
+ var sd2 = {
1263
+ sphere: (at, r) => (p) => shapes.sphere(p[0] - at[0], p[1] - at[1], p[2] - at[2], r),
1264
+ ellipsoid: (at, radii) => (p) => shapes.ellipsoid(p[0] - at[0], p[1] - at[1], p[2] - at[2], radii[0], radii[1], radii[2]),
1265
+ box: (at, size, round = 0) => (p) => shapes.roundBox(p[0] - at[0], p[1] - at[1], p[2] - at[2], size[0] / 2, size[1] / 2, size[2] / 2, round),
1266
+ capsule(a, b, r) {
1267
+ const bx = b[0] - a[0];
1268
+ const by = b[1] - a[1];
1269
+ const bz = b[2] - a[2];
1270
+ const bb = bx * bx + by * by + bz * bz;
1271
+ return (p) => {
1272
+ const px = p[0] - a[0];
1273
+ const py = p[1] - a[1];
1274
+ const pz = p[2] - a[2];
1275
+ const h = bb > 0 ? clamp01((px * bx + py * by + pz * bz) / bb) : 0;
1276
+ return Math.sqrt((px - bx * h) ** 2 + (py - by * h) ** 2 + (pz - bz * h) ** 2) - r;
1277
+ };
1278
+ },
1279
+ cone: (at, r1, r2, h) => (p) => shapes.cone(p[0] - at[0], p[1] - at[1], p[2] - at[2], r1, r2, h),
1280
+ torus: (at, R, r) => (p) => shapes.torus(p[0] - at[0], p[1] - at[1], p[2] - at[2], R, r),
1281
+ union: (...fs) => (p) => {
1282
+ let d = Number.POSITIVE_INFINITY;
1283
+ for (const f of fs)
1284
+ d = Math.min(d, f(p));
1285
+ return d;
1286
+ },
1287
+ intersect: (a, b) => (p) => Math.max(a(p), b(p)),
1288
+ subtract: (a, b) => (p) => Math.max(a(p), -b(p)),
1289
+ smoothUnion: (k, a, b) => (p) => {
1290
+ const da = a(p);
1291
+ const db = b(p);
1292
+ const h = smoothWeight(da, db, k);
1293
+ return db + (da - db) * h - k * h * (1 - h);
1294
+ },
1295
+ smoothSubtract: (k, a, b) => (p) => {
1296
+ const da = a(p);
1297
+ const db = -b(p);
1298
+ const h = smoothWeight(-da, -db, k);
1299
+ return da + (db - da) * (1 - h) + k * h * (1 - h);
1300
+ },
1301
+ displace: (f, noise, amount) => (p) => f(p) + amount * noise(p)
1302
+ };
1303
+
1304
+ // src/primitives/sculpt-edit.ts
1305
+ var dims = (e) => {
1306
+ if (typeof e.size === "number")
1307
+ return [e.size, e.size, e.size];
1308
+ const [a, b, c] = e.size;
1309
+ return [a, b, c ?? b];
1310
+ };
1311
+ function sculptShape(e, i, mirrorAll) {
1312
+ const [a, b, c] = dims(e);
1313
+ const where = `sculpt edit ${i} (${e.shape})`;
1314
+ if (![a, b, c].every((x) => Number.isFinite(x) && x > 0))
1315
+ invalid(`${where}: size has a value ≤ 0`, "give every size component in metres, > 0");
1316
+ if ((e.blend ?? 0) < 0 || !Number.isFinite(e.blend ?? 0))
1317
+ invalid(`${where}: blend is ${e.blend}`, "use a blend radius ≥ 0 m (0.01 = 1 cm fillet)");
1318
+ if (e.shape === "capsule" && !e.to)
1319
+ invalid(`${where}: capsule needs \`to\``, "add to: [x, y, z], the far end");
1320
+ const [rx, ry, rz] = (e.rotate ?? [0, 0, 0]).map((d) => d * Math.PI / 180);
1321
+ const [cx, sx, cy, sy, cz, sz] = [
1322
+ Math.cos(rx ?? 0),
1323
+ Math.sin(rx ?? 0),
1324
+ Math.cos(ry ?? 0),
1325
+ Math.sin(ry ?? 0),
1326
+ Math.cos(rz ?? 0),
1327
+ Math.sin(rz ?? 0)
1328
+ ];
1329
+ const m = [
1330
+ cz * cy,
1331
+ cz * sy * sx - sz * cx,
1332
+ cz * sy * cx + sz * sx,
1333
+ sz * cy,
1334
+ sz * sy * sx + cz * cx,
1335
+ sz * sy * cx - cz * sx,
1336
+ -sy,
1337
+ cy * sx,
1338
+ cy * cx
1339
+ ];
1340
+ const [m0 = 1, m1 = 0, m2 = 0, m3 = 0, m4 = 1, m5 = 0, m6 = 0, m7 = 0, m8 = 1] = m;
1341
+ const [ox, oy, oz] = e.at;
1342
+ const to = e.to ?? e.at;
1343
+ const [dx, dy, dz] = [to[0] - ox, to[1] - oy, to[2] - oz];
1344
+ const len = Math.sqrt(dx * dx + dy * dy + dz * dz);
1345
+ const round = Math.min(e.round ?? 0, a / 2, b / 2, c / 2);
1346
+ const kernel = e.shape === "sphere" ? (x, y, z) => shapes.sphere(x, y, z, a) : e.shape === "ellipsoid" ? (x, y, z) => shapes.ellipsoid(x, y, z, a, b, c) : e.shape === "roundBox" ? (x, y, z) => shapes.roundBox(x, y, z, a / 2, b / 2, c / 2, round) : e.shape === "cone" ? (x, y, z) => shapes.cone(x, y, z, a, b, c) : (x, y, z) => shapes.torus(x, y, z, a, b);
1347
+ const rotated = e.rotate?.some((d) => d !== 0) ?? false;
1348
+ const one = e.shape === "capsule" ? (px, py, pz) => {
1349
+ const wx = px - ox;
1350
+ const wy = py - oy;
1351
+ const wz = pz - oz;
1352
+ const t = len > 0 ? Math.min(1, Math.max(0, (wx * dx + wy * dy + wz * dz) / (len * len))) : 0;
1353
+ return Math.sqrt((wx - dx * t) ** 2 + (wy - dy * t) ** 2 + (wz - dz * t) ** 2) - a;
1354
+ } : rotated ? (px, py, pz) => {
1355
+ const wx = px - ox;
1356
+ const wy = py - oy;
1357
+ const wz = pz - oz;
1358
+ return kernel(m0 * wx + m3 * wy + m6 * wz, m1 * wx + m4 * wy + m7 * wz, m2 * wx + m5 * wy + m8 * wz);
1359
+ } : (px, py, pz) => kernel(px - ox, py - oy, pz - oz);
1360
+ if (!(e.mirror ?? mirrorAll))
1361
+ return (p) => one(p[0], p[1], p[2]);
1362
+ const { c: sc, r: sr, scale, inside } = shapeSphere(e);
1363
+ const bound = (dist) => {
1364
+ const out = dist - sr;
1365
+ return out > 0 ? scale * out : inside ? out : Number.NEGATIVE_INFINITY;
1366
+ };
1367
+ return (p) => {
1368
+ const dx0 = p[0] - sc[0];
1369
+ const dz0 = p[2] - sc[2];
1370
+ const near = Math.sqrt(dx0 * dx0 + (p[1] - sc[1]) ** 2 + dz0 * dz0);
1371
+ const far = Math.sqrt(dx0 * dx0 + (p[1] + sc[1]) ** 2 + dz0 * dz0);
1372
+ const [first, second, lb] = near <= far ? [p[1], -p[1], bound(far)] : [-p[1], p[1], bound(near)];
1373
+ const v = one(p[0], first, p[2]);
1374
+ return lb >= v ? v : Math.min(v, one(p[0], second, p[2]));
1375
+ };
1376
+ }
1377
+ function shapeSphere(e) {
1378
+ const [a, b, c] = dims(e);
1379
+ const to = e.to ?? e.at;
1380
+ const centre = e.shape === "capsule" ? [(e.at[0] + to[0]) / 2, (e.at[1] + to[1]) / 2, (e.at[2] + to[2]) / 2] : e.at;
1381
+ const r = e.shape === "sphere" ? a : e.shape === "ellipsoid" ? Math.max(a, b, c) : e.shape === "roundBox" ? Math.hypot(a, b, c) / 2 : e.shape === "cone" ? c + Math.max(a, b) : e.shape === "torus" ? a + b : a + Math.hypot(to[0] - e.at[0], to[1] - e.at[1], to[2] - e.at[2]) / 2;
1382
+ const ell = e.shape === "ellipsoid";
1383
+ const lo = Math.min(a, b, c);
1384
+ return { c: centre, r, scale: ell ? (lo / r) ** 2 : 1, inside: !ell };
1385
+ }
1386
+ function editBounds(e, mirrorAll) {
1387
+ if ("group" in e)
1388
+ return groupBounds(e, mirrorAll);
1389
+ const { c: centre, r } = shapeSphere(e);
1390
+ const g = r + (e.blend ?? 0);
1391
+ const lo = [centre[0] - g, centre[1] - g, centre[2] - g];
1392
+ const hi = [centre[0] + g, centre[1] + g, centre[2] + g];
1393
+ if (e.mirror ?? mirrorAll) {
1394
+ const [l, h] = [lo[1], hi[1]];
1395
+ lo[1] = Math.min(l, -h);
1396
+ hi[1] = Math.max(h, -l);
1397
+ }
1398
+ return [lo, hi];
1399
+ }
1400
+ function groupBounds(g, mirrorAll) {
1401
+ const lo = [Infinity, Infinity, Infinity];
1402
+ const hi = [-Infinity, -Infinity, -Infinity];
1403
+ const k = g.blend ?? 0;
1404
+ for (const e of g.group) {
1405
+ if ((e.op ?? "add") !== "add")
1406
+ continue;
1407
+ const [a, b] = editBounds(e, g.mirror ?? mirrorAll);
1408
+ for (let i = 0;i < 3; i++) {
1409
+ lo[i] = Math.min(lo[i] ?? 0, (a[i] ?? 0) - k);
1410
+ hi[i] = Math.max(hi[i] ?? 0, (b[i] ?? 0) + k);
1411
+ }
1412
+ }
1413
+ return [lo, hi];
1414
+ }
1415
+
1416
+ // src/primitives/sculpt-tree.ts
1417
+ var ADD = 0;
1418
+ var SUB = 1;
1419
+ var INTER = 2;
1420
+ var PAINT = 3;
1421
+ var OPS = { add: ADD, subtract: SUB, intersect: INTER, paint: PAINT };
1422
+ function compile(edits, base, mirror, path = "sculpt") {
1423
+ if (!edits.some((e) => (e.op ?? "add") === "add"))
1424
+ invalid(`${path} has no add edits, so nothing to carve from`, "make the first edit op: 'add'");
1425
+ return edits.map((e, i) => {
1426
+ const op = OPS[e.op ?? "add"];
1427
+ const k = e.blend ?? 0;
1428
+ const m = e.mirror ?? mirror;
1429
+ if ("group" in e) {
1430
+ const kids = compile(e.group, e.color ?? base, m, `${path} group ${i}`);
1431
+ const b = enclose(kids);
1432
+ return node(op, k, e.color ?? null, null, kids, e.color ?? base, 3, b.c, b.r, b.scale, b.inside, false, b.under);
1433
+ }
1434
+ const s = shapeSphere(e);
1435
+ return node(op, k, e.color ?? null, sculptShape(e, i, m), null, base, 0, s.c, s.r, s.scale, s.inside, m, 0);
1436
+ });
1437
+ }
1438
+ function node(op, k, color, shape, kids, base, rgb, c, r, scale, inside, mirror, under) {
1439
+ return {
1440
+ op,
1441
+ k,
1442
+ color,
1443
+ shape,
1444
+ kids,
1445
+ base,
1446
+ rgb: new Float64Array(rgb),
1447
+ c,
1448
+ r,
1449
+ scale,
1450
+ inside,
1451
+ mirror,
1452
+ under
1453
+ };
1454
+ }
1455
+ function enclose(kids) {
1456
+ const adds = kids.filter((n) => n.op === ADD);
1457
+ const spheres = adds.flatMap((n) => n.mirror ? [n, { ...n, c: [n.c[0], -n.c[1], n.c[2]] }] : [n]);
1458
+ const lo = [0, 1, 2].map((a) => Math.min(...spheres.map((n) => (n.c[a] ?? 0) - n.r)));
1459
+ const hi = [0, 1, 2].map((a) => Math.max(...spheres.map((n) => (n.c[a] ?? 0) + n.r)));
1460
+ const c = [
1461
+ ((lo[0] ?? 0) + (hi[0] ?? 0)) / 2,
1462
+ ((lo[1] ?? 0) + (hi[1] ?? 0)) / 2,
1463
+ ((lo[2] ?? 0) + (hi[2] ?? 0)) / 2
1464
+ ];
1465
+ const r = Math.max(...spheres.map((n) => Math.hypot(n.c[0] - c[0], n.c[1] - c[1], n.c[2] - c[2]) + n.r));
1466
+ return {
1467
+ c,
1468
+ r,
1469
+ scale: Math.min(...adds.map((n) => n.scale)),
1470
+ inside: adds.every((n) => n.inside),
1471
+ mirror: false,
1472
+ under: adds.reduce((u, n) => u + n.k / 4 + n.under, 0)
1473
+ };
1474
+ }
1475
+ function lowerBound(n, p) {
1476
+ const dx = p[0] - n.c[0];
1477
+ const dz = p[2] - n.c[2];
1478
+ let dy = p[1] - n.c[1];
1479
+ let q = dx * dx + dy * dy + dz * dz;
1480
+ if (n.mirror) {
1481
+ dy = p[1] + n.c[1];
1482
+ q = Math.min(q, dx * dx + dy * dy + dz * dz);
1483
+ }
1484
+ const out = Math.sqrt(q) - n.r;
1485
+ if (out > 0)
1486
+ return n.scale * out - n.under;
1487
+ return n.inside ? out - n.under : Number.NEGATIVE_INFINITY;
1488
+ }
1489
+ var clamp012 = (x) => x < 0 ? 0 : Math.min(x, 1);
1490
+ var weight = (a, b, k) => k > 0 ? clamp012(0.5 + 0.5 * (b - a) / k) : a < b ? 1 : 0;
1491
+ var slack = (d) => 0.000000001 * (1 + Math.abs(d));
1492
+ function fold(nodes, p, rgb, base, sparse = true) {
1493
+ let d = Number.POSITIVE_INFINITY;
1494
+ if (rgb)
1495
+ rgb.set(base);
1496
+ for (const n of nodes) {
1497
+ const k = n.k;
1498
+ if (n.op === PAINT) {
1499
+ if (!rgb || !n.color || !n.shape)
1500
+ continue;
1501
+ const kk = Math.max(k, 0.000000001);
1502
+ if (sparse && lowerBound(n, p) > kk / 2 + slack(kk))
1503
+ continue;
1504
+ const w = 1 - clamp012(0.5 - n.shape(p) / kk);
1505
+ if (w < 1)
1506
+ mix(rgb, n.color, w);
1507
+ continue;
1508
+ }
1509
+ const empty = d === Number.POSITIVE_INFINITY;
1510
+ if (empty && n.op !== ADD)
1511
+ continue;
1512
+ if (sparse && !empty) {
1513
+ if (n.op === ADD && lowerBound(n, p) > d + k + slack(d))
1514
+ continue;
1515
+ if (n.op === SUB && lowerBound(n, p) > k - d + slack(d))
1516
+ continue;
1517
+ }
1518
+ const v = n.kids ? fold(n.kids, p, rgb ? n.rgb : null, n.base, sparse) : n.shape ? n.shape(p) : 0;
1519
+ let w = 0;
1520
+ if (empty)
1521
+ d = v;
1522
+ else if (n.op === ADD) {
1523
+ w = weight(d, v, k);
1524
+ if (w !== 1)
1525
+ d = v + (d - v) * w - k * w * (1 - w);
1526
+ } else {
1527
+ const b = n.op === SUB ? -v : v;
1528
+ w = weight(-d, -b, k);
1529
+ if (w !== 1)
1530
+ d = -(-b + (-d + b) * w - k * w * (1 - w));
1531
+ }
1532
+ if (!rgb || w >= 1)
1533
+ continue;
1534
+ if (n.kids) {
1535
+ if (n.color || n.op === ADD)
1536
+ mixArr(rgb, n.rgb, w);
1537
+ } else if (n.color || n.op === ADD)
1538
+ mix(rgb, n.color ?? base, w);
1539
+ }
1540
+ return d;
1541
+ }
1542
+ var mix = (rgb, c, w) => {
1543
+ for (let j = 0;j < 3; j++)
1544
+ rgb[j] = (c[j] ?? 0) + ((rgb[j] ?? 0) - (c[j] ?? 0)) * w;
1545
+ };
1546
+ var mixArr = (rgb, c, w) => {
1547
+ for (let j = 0;j < 3; j++)
1548
+ rgb[j] = (c[j] ?? 0) + ((rgb[j] ?? 0) - (c[j] ?? 0)) * w;
1549
+ };
1550
+
1551
+ // src/primitives/sdf-grid.ts
1552
+ var MAX_POINTS = 1 << 24;
1553
+ var BLOCK = 4;
1554
+ function sampleGrid(raw, bounds, h, lipschitz, symmetricY = false) {
1555
+ const [lo0, hi0] = bounds;
1556
+ if (!Number.isFinite(h) || h <= 0)
1557
+ invalid(`sdf resolution is ${h}`, "pass the cell edge in metres, e.g. ctx.pick([0.004, 0.012, 0.03])");
1558
+ if (![0, 1, 2].every((k) => Number.isFinite(lo0[k] ?? Number.NaN) && (hi0[k] ?? 0) > (lo0[k] ?? 0)))
1559
+ invalid(`sdf bounds [${lo0.join(", ")}] → [${hi0.join(", ")}] are empty or inverted`, "give bounds as [min, max] corners with max > min on every axis, in metres");
1560
+ const m = Math.ceil(Math.max(Math.abs(lo0[1]), Math.abs(hi0[1])) / h);
1561
+ const lo = symmetricY ? [lo0[0], -m * h, lo0[2]] : lo0;
1562
+ const hi = symmetricY ? [hi0[0], m * h, hi0[2]] : hi0;
1563
+ const size = (k) => Math.ceil(((hi[k] ?? 0) - (lo[k] ?? 0)) / h) + 3;
1564
+ const [nx, ny, nz] = [size(0), symmetricY ? 2 * m + 3 : size(1), size(2)];
1565
+ const yAt = (j) => symmetricY ? (j - m - 1) * h : lo[1] - h + j * h;
1566
+ if (nx * ny * nz > MAX_POINTS) {
1567
+ const vol = [0, 1, 2].reduce((v, k) => v * ((hi[k] ?? 0) - (lo[k] ?? 0)), 1);
1568
+ invalid(`sdf grid ${nx}×${ny}×${nz} exceeds ${MAX_POINTS} points at ${h} m cells`, `use cells ≥ ${Math.cbrt(vol / MAX_POINTS).toPrecision(2)} m, or tighten the bounds`);
1569
+ }
1570
+ const cx = (lo[0] + hi[0]) / 2;
1571
+ const cy = (lo[1] + hi[1]) / 2;
1572
+ const cz = (lo[2] + hi[2]) / 2;
1573
+ const [bx, by, bz] = [(hi[0] - lo[0]) / 2, (hi[1] - lo[1]) / 2, (hi[2] - lo[2]) / 2];
1574
+ const field = (p) => {
1575
+ const qx = Math.abs(p[0] - cx) - bx;
1576
+ const qy = Math.abs(p[1] - cy) - by;
1577
+ const qz = Math.abs(p[2] - cz) - bz;
1578
+ const box = Math.hypot(Math.max(qx, 0), Math.max(qy, 0), Math.max(qz, 0)) + Math.min(Math.max(qx, qy, qz), 0);
1579
+ const f = raw(p);
1580
+ if (Number.isNaN(f))
1581
+ invalid(`sdf field returned NaN at [${p.join(", ")}]`, "make the field return a finite distance everywhere in bounds");
1582
+ return Math.max(f, box);
1583
+ };
1584
+ const origin = [lo[0] - h, symmetricY ? -(m + 1) * h : lo[1] - h, lo[2] - h];
1585
+ const values = new Float32Array(nx * ny * nz);
1586
+ const exact = new Uint8Array(nx * ny * nz);
1587
+ const [kx, ky, kz] = [
1588
+ Math.ceil((nx - 1) / BLOCK),
1589
+ Math.ceil((ny - 1) / BLOCK),
1590
+ Math.ceil((nz - 1) / BLOCK)
1591
+ ];
1592
+ const coarse = new Float32Array(kx * ky * kz);
1593
+ const p = [0, 0, 0];
1594
+ const floor = h * 0.01;
1595
+ const reach = lipschitz * BLOCK * h * Math.sqrt(3) * 0.5 + h;
1596
+ for (let k = 0;k < kz; k++)
1597
+ for (let j = 0;j < ky; j++)
1598
+ for (let i = 0;i < kx; i++) {
1599
+ p[0] = origin[0] + (i + 0.5) * BLOCK * h;
1600
+ p[1] = origin[1] + (j + 0.5) * BLOCK * h;
1601
+ p[2] = origin[2] + (k + 0.5) * BLOCK * h;
1602
+ const v = field(p);
1603
+ coarse[i + kx * (j + ky * k)] = v;
1604
+ if (Math.abs(v) > reach)
1605
+ continue;
1606
+ for (let z = k * BLOCK;z <= Math.min(nz - 1, (k + 1) * BLOCK); z++)
1607
+ for (let y = j * BLOCK;y <= Math.min(ny - 1, (j + 1) * BLOCK); y++)
1608
+ for (let x = i * BLOCK;x <= Math.min(nx - 1, (i + 1) * BLOCK); x++)
1609
+ exact[x + nx * (y + ny * z)] = 1;
1610
+ }
1611
+ for (let z = 0;z < nz; z++)
1612
+ for (let y = 0;y < ny; y++)
1613
+ for (let x = 0;x < nx; x++) {
1614
+ const id = x + nx * (y + ny * z);
1615
+ if (exact[id]) {
1616
+ p[0] = origin[0] + x * h;
1617
+ p[1] = yAt(y);
1618
+ p[2] = origin[2] + z * h;
1619
+ const f = field(p);
1620
+ values[id] = Math.abs(f) >= floor ? f : f < 0 ? -floor : floor;
1621
+ } else {
1622
+ const b = Math.min(kx - 1, Math.floor(x / BLOCK)) + kx * (Math.min(ky - 1, Math.floor(y / BLOCK)) + ky * Math.min(kz - 1, Math.floor(z / BLOCK)));
1623
+ values[id] = coarse[b] ?? 1;
1624
+ }
1625
+ }
1626
+ return { nx, ny, nz, origin, h, values, field };
1627
+ }
1628
+
1629
+ // src/primitives/mc-table.ts
1630
+ var PACKED = ".083.019.183981.12a.08312a.92a029.2832a8a98.3b2.0b28b0.19023b.1b219b98b.3a1ba3.0a108a8ba.3" + "903b9ba9.98aa8b.478.430734.019847.419471731.12a847.34730412a.92a902847.2a9297273794.8473b2" + ".b47b24204.90184723b.47b94b9b2921.3a13ba784.1ba14b1047b4.47890b9bab03.47b4b99ba.954.954083" + ".054150.854835315.12a954.30812a495.52a542402.2a5325354348.95423b.0b208b495.05401523b.21525" + "828b485.a3ba13954.4950818a18ba.54050b5bab03.54858aa8b.978579.930953573.078017157.153357.97" + "8957a12.a12950530573.802825857a52.2a5253357.7957893b2.95797292027b.23b018178157.b21b17715." + "958857a13a3b.5705097b010aba0.ba0b03a50807570.ba57b5.a65.0835a6.9015a6.1831985a6.165261.165" + "126308.965906026.598582526328.23ba65.b08b20a65.01923b5a6.5a61929b298b.63b653513.08b0b50515" + "b6.3b6036065059.65969bb98.5a6478.43047365a.1905a6847.a65197173794.612651478.125526304347.8" + "47905065026.739794329596269.3b2784a65.5a647242027b.01947823b5a6.9219b294b7b45a6.8473b53515" + "b6.51b5b610b7b404b.059065036b63847.65969b4797b9.a4964a.4a649a083.a01a60640.83181686461a.14" + "9124264.308129249264.024426.832824426.a49a64b23.08228b49a4a6.3b201606461a.64161a48121b8b1." + "964936913b63.8b1810b61914641.3b6360064.648b68.7a678a89a.0730a709a67a.a671a7178180.a67a7117" + "3.126168189867.269291679093739.780706602.732672.23ba68a89867.20727b09767a9a7.1801781a767a2" + "3b.b21b17a61671.896867916b63136.091b67.7807063b0b60.7b6.76b.308b76.019b76.819831b76.a126b7" + ".12a3086b7.2902a96b7.6b72a3a83a98.723627.708760620.276237019.162186198876.a76a17137.a7617a" + "187108.03707a0a96a7.76a7a88a9.684b86.36b306046.86b846901.946963931b36.6846b82a1.12a30b06b0" + "46.4b846b0292a9.a93a32943b36463.823842462.042462.190234246438.194142246.8138618466a1.a10a0" + "6604.4634386a3039a93.a946a4.49576b.083495b76.50154076b.b76834354315.954a1276b.6b712a083495" + ".76b54a42a402.348354325a52b76.723762549.954086062687.362376150540.628687218485158.954a1617" + "6137.16a176107870954.40a4a503a6a737a.76a7a854a48a.6956b9b89.36b063056095.0b805b01556b.6b36" + "35531.12a95b9b8b56.0b306b09656912a.b85b56805a52025.6b36352a3a53.589528562382.956960062.158" + "180568382628.156216.13616a386569896.a10a06950560.03856a.a56.b5a75b.b5ab75830.5b75ab190.a75" + "ab7981831.b12b71751.08312717572b.9759279022b7.75272b592328982.25a235375.820852875a25.9015a" + "35373a2.982921872a25752.135375.087071175.903935537.987597.5845a8ab8.5045b05abb30.01984a8ab" + "a45.ab4a45b34941314.2512852b8458.04b0b345b2b151b.0250592b5458b85.9452b3.25a352345384.5a252" + "4420.3a235a385458019.5a2524192942.845853351.045105.845853905035.945.4b749b9ab.0834979b79ab" + ".1ab1b414074b.3143481a474bab4.4b79b492b912.9749b791b2b1083.b74b42240.b74b42834324.29a27923" + "7749.9a7974a27870207.37a3a274a1a040a.1a2874.491417713.491417081871.403743.487.9a8ab8.30939" + "bb9a.01a0a88ab.31ab3a.12b1b99b8.30939b1292b9.02b80b.32b.23828aa89.9a2092.23828a0181a8.1a2." + "138918.091.038.";
1631
+ var TRI = PACKED.split(".").map((c) => [...c].map((h) => Number.parseInt(h, 16)));
1632
+
1633
+ // src/primitives/surface-nets.ts
1634
+ var CORNER = [0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1];
1635
+ var EDGE = [0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7];
1636
+ function surfaceNets(g) {
1637
+ const { nx, ny, nz, values: v, h, origin: o } = g;
1638
+ const cells = new Int32Array((nx - 1) * (ny - 1) * (nz - 1)).fill(-1);
1639
+ const pos = [];
1640
+ const c = new Float64Array(8);
1641
+ for (let z = 0;z < nz - 1; z++)
1642
+ for (let y = 0;y < ny - 1; y++)
1643
+ for (let x = 0;x < nx - 1; x++) {
1644
+ let mask = 0;
1645
+ for (let k = 0;k < 8; k++) {
1646
+ const val = v[x + (CORNER[k * 3] ?? 0) + nx * (y + (CORNER[k * 3 + 1] ?? 0) + ny * (z + (CORNER[k * 3 + 2] ?? 0)))] ?? 1;
1647
+ c[k] = val;
1648
+ if (val < 0)
1649
+ mask |= 1 << k;
1650
+ }
1651
+ if (mask === 0 || mask === 255)
1652
+ continue;
1653
+ let sx = 0;
1654
+ let sy = 0;
1655
+ let sz = 0;
1656
+ let n = 0;
1657
+ for (let e = 0;e < 12; e++) {
1658
+ const a = EDGE[e * 2] ?? 0;
1659
+ const b = EDGE[e * 2 + 1] ?? 0;
1660
+ const va = c[a] ?? 0;
1661
+ const vb = c[b] ?? 0;
1662
+ if (va < 0 === vb < 0)
1663
+ continue;
1664
+ const t = va / (va - vb);
1665
+ sx += (CORNER[a * 3] ?? 0) + t * ((CORNER[b * 3] ?? 0) - (CORNER[a * 3] ?? 0));
1666
+ sy += (CORNER[a * 3 + 1] ?? 0) + t * ((CORNER[b * 3 + 1] ?? 0) - (CORNER[a * 3 + 1] ?? 0));
1667
+ sz += (CORNER[a * 3 + 2] ?? 0) + t * ((CORNER[b * 3 + 2] ?? 0) - (CORNER[a * 3 + 2] ?? 0));
1668
+ n++;
1669
+ }
1670
+ cells[x + (nx - 1) * (y + (ny - 1) * z)] = pos.length / 3;
1671
+ pos.push(o[0] + (x + sx / n) * h, o[1] + (y + sy / n) * h, o[2] + (z + sz / n) * h);
1672
+ }
1673
+ const tris = [];
1674
+ const cell = (x, y, z) => cells[x + (nx - 1) * (y + (ny - 1) * z)] ?? 0;
1675
+ const P = (i, k) => pos[i * 3 + k] ?? 0;
1676
+ const n1 = new Float64Array(3);
1677
+ const n2 = new Float64Array(3);
1678
+ const normal = (a, b, c, n) => {
1679
+ const ex = P(b, 0) - P(a, 0);
1680
+ const ey = P(b, 1) - P(a, 1);
1681
+ const ez = P(b, 2) - P(a, 2);
1682
+ const fx = P(c, 0) - P(a, 0);
1683
+ const fy = P(c, 1) - P(a, 1);
1684
+ const fz = P(c, 2) - P(a, 2);
1685
+ const x = ey * fz - ez * fy;
1686
+ const y = ez * fx - ex * fz;
1687
+ const z = ex * fy - ey * fx;
1688
+ const l = Math.sqrt(x * x + y * y + z * z) || 1;
1689
+ n[0] = x / l;
1690
+ n[1] = y / l;
1691
+ n[2] = z / l;
1692
+ };
1693
+ const flatness = () => (n1[0] ?? 0) * (n2[0] ?? 0) + (n1[1] ?? 0) * (n2[1] ?? 0) + (n1[2] ?? 0) * (n2[2] ?? 0);
1694
+ const quad = (a, b, cc, d, out) => {
1695
+ const [q0, q1, q2, q3] = out ? [a, b, cc, d] : [a, d, cc, b];
1696
+ normal(q0, q1, q2, n1);
1697
+ normal(q0, q2, q3, n2);
1698
+ const along02 = flatness();
1699
+ normal(q0, q1, q3, n1);
1700
+ normal(q1, q2, q3, n2);
1701
+ if (along02 >= flatness())
1702
+ tris.push(q0, q1, q2, q0, q2, q3);
1703
+ else
1704
+ tris.push(q0, q1, q3, q1, q2, q3);
1705
+ };
1706
+ for (let z = 1;z < nz - 1; z++)
1707
+ for (let y = 1;y < ny - 1; y++)
1708
+ for (let x = 1;x < nx - 1; x++) {
1709
+ const inside = (v[x + nx * (y + ny * z)] ?? 1) < 0;
1710
+ if (x < nx - 1 && inside !== (v[x + 1 + nx * (y + ny * z)] ?? 1) < 0)
1711
+ quad(cell(x, y - 1, z - 1), cell(x, y, z - 1), cell(x, y, z), cell(x, y - 1, z), inside);
1712
+ if (y < ny - 1 && inside !== (v[x + nx * (y + 1 + ny * z)] ?? 1) < 0)
1713
+ quad(cell(x - 1, y, z - 1), cell(x - 1, y, z), cell(x, y, z), cell(x, y, z - 1), inside);
1714
+ if (z < nz - 1 && inside !== (v[x + nx * (y + ny * (z + 1))] ?? 1) < 0)
1715
+ quad(cell(x - 1, y - 1, z), cell(x, y - 1, z), cell(x, y, z), cell(x - 1, y, z), inside);
1716
+ }
1717
+ return { pos, tris };
1718
+ }
1719
+ function marchingCubes(g) {
1720
+ const { nx, ny, nz, values: v, h, origin: o } = g;
1721
+ const shared = new Map;
1722
+ const pos = [];
1723
+ const tris = [];
1724
+ for (let z = 0;z < nz - 1; z++)
1725
+ for (let y = 0;y < ny - 1; y++)
1726
+ for (let x = 0;x < nx - 1; x++) {
1727
+ let mask = 0;
1728
+ for (let k = 0;k < 8; k++)
1729
+ if ((v[x + (CORNER[k * 3] ?? 0) + nx * (y + (CORNER[k * 3 + 1] ?? 0) + ny * (z + (CORNER[k * 3 + 2] ?? 0)))] ?? 1) < 0)
1730
+ mask |= 1 << k;
1731
+ const list = TRI[mask] ?? [];
1732
+ for (let t = 0;t < list.length; t += 3)
1733
+ for (const j of [0, 2, 1]) {
1734
+ const e = list[t + j] ?? 0;
1735
+ const a = EDGE[e * 2] ?? 0;
1736
+ const b = EDGE[e * 2 + 1] ?? 0;
1737
+ const ax = x + (CORNER[a * 3] ?? 0);
1738
+ const ay = y + (CORNER[a * 3 + 1] ?? 0);
1739
+ const az = z + (CORNER[a * 3 + 2] ?? 0);
1740
+ const bx = x + (CORNER[b * 3] ?? 0);
1741
+ const by = y + (CORNER[b * 3 + 1] ?? 0);
1742
+ const bz = z + (CORNER[b * 3 + 2] ?? 0);
1743
+ const ia = ax + nx * (ay + ny * az);
1744
+ const ib = bx + nx * (by + ny * bz);
1745
+ const lowId = Math.min(ia, ib);
1746
+ const key = lowId * 3 + (ax !== bx ? 0 : ay !== by ? 1 : 2);
1747
+ let id = shared.get(key);
1748
+ if (id === undefined) {
1749
+ const va = v[ia] ?? 0;
1750
+ const s = va / (va - (v[ib] ?? 0));
1751
+ id = pos.length / 3;
1752
+ pos.push(o[0] + (ax + s * (bx - ax)) * h, o[1] + (ay + s * (by - ay)) * h, o[2] + (az + s * (bz - az)) * h);
1753
+ shared.set(key, id);
1754
+ }
1755
+ tris.push(id);
1756
+ }
1757
+ }
1758
+ return { pos, tris };
1759
+ }
1760
+
1761
+ // src/primitives/sdf.ts
1762
+ function sdf2(o) {
1763
+ const lip = o.lipschitz ?? 1.25;
1764
+ if (!(lip >= 1))
1765
+ invalid(`sdf lipschitz is ${lip}`, "use ≥ 1 (1 = exact distance field)");
1766
+ const g = sampleGrid(o.field, o.bounds, o.resolution, lip, o.symmetry === "y");
1767
+ const raw = o.mesher === "cubes" ? marchingCubes(g) : surfaceNets(g);
1768
+ if (raw.tris.length === 0)
1769
+ invalid("sdf field has no surface inside its bounds (never crosses zero)", "return negative distances inside the shape, positive outside, and make bounds contain it");
1770
+ const strip = o.strip ?? "plain";
1771
+ const rect = stripRect2(strip);
1772
+ const vm = stripVMetres(strip);
1773
+ const e = g.h * 0.5;
1774
+ const q = [0, 0, 0];
1775
+ const at = (x, y, z) => {
1776
+ q[0] = x;
1777
+ q[1] = y;
1778
+ q[2] = z;
1779
+ return g.field(q);
1780
+ };
1781
+ const b = new MeshBuilder2;
1782
+ for (let i = 0;i < raw.pos.length; i += 3) {
1783
+ const x = raw.pos[i] ?? 0;
1784
+ const y = raw.pos[i + 1] ?? 0;
1785
+ const z = raw.pos[i + 2] ?? 0;
1786
+ const gx = at(x + e, y, z) - at(x - e, y, z);
1787
+ const gy = at(x, y + e, z) - at(x, y - e, z);
1788
+ const gz = at(x, y, z + e) - at(x, y, z - e);
1789
+ const gl = Math.sqrt(gx * gx + gy * gy + gz * gz);
1790
+ const n = gl > 0 ? [gx / gl, gy / gl, gz / gl] : [0, 0, 1];
1791
+ const ax = Math.abs(n[0]);
1792
+ const ay = Math.abs(n[1]);
1793
+ const az = Math.abs(n[2]);
1794
+ const [s, t] = az >= ax && az >= ay ? [x, y] : ax >= ay ? [y, z] : [x, z];
1795
+ const p = [x, y, z];
1796
+ b.vertex({
1797
+ p,
1798
+ n,
1799
+ uv: [stripU(rect, s), mirroredV(rect, t, vm)],
1800
+ color: typeof o.color === "function" ? o.color(p, n) : o.color
1801
+ });
1802
+ }
1803
+ for (let i = 0;i < raw.tris.length; i += 3)
1804
+ b.tri(raw.tris[i] ?? 0, raw.tris[i + 1] ?? 0, raw.tris[i + 2] ?? 0);
1805
+ return b.build();
1806
+ }
1807
+
1808
+ // src/primitives/sculpt.ts
1809
+ function sculptField2(edits, o) {
1810
+ if (edits.length === 0)
1811
+ invalid("sculpt has no edits", "start with an { shape: 'sphere', op: 'add', ... } edit");
1812
+ const nodes = compile(edits, o.color, o.mirror === "y");
1813
+ const rgb = new Float64Array(3);
1814
+ const adds = edits.filter((e) => (e.op ?? "add") === "add");
1815
+ const lo = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY];
1816
+ const hi = [Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY];
1817
+ for (const e of adds) {
1818
+ const [a, b] = editBounds(e, o.mirror === "y");
1819
+ for (let k = 0;k < 3; k++) {
1820
+ lo[k] = Math.min(lo[k] ?? 0, a[k] ?? 0);
1821
+ hi[k] = Math.max(hi[k] ?? 0, b[k] ?? 0);
1822
+ }
1823
+ }
1824
+ return {
1825
+ field: (p) => fold(nodes, p, null, o.color),
1826
+ colorAt: (p) => {
1827
+ fold(nodes, p, rgb, o.color);
1828
+ return [rgb[0] ?? 0, rgb[1] ?? 0, rgb[2] ?? 0];
1829
+ },
1830
+ bounds: [
1831
+ [lo[0] ?? 0, lo[1] ?? 0, lo[2] ?? 0],
1832
+ [hi[0] ?? 0, hi[1] ?? 0, hi[2] ?? 0]
1833
+ ]
1834
+ };
1835
+ }
1836
+ function sculpt2(o) {
1837
+ const s = sculptField2(o.edits, { color: o.color, ...o.mirror ? { mirror: o.mirror } : {} });
1838
+ return sdf2({
1839
+ field: s.field,
1840
+ bounds: s.bounds,
1841
+ resolution: o.resolution,
1842
+ color: (p) => s.colorAt(p),
1843
+ ...o.mesher ? { mesher: o.mesher } : {},
1844
+ ...o.mirror === "y" ? { symmetry: "y" } : {},
1845
+ ...o.strip ? { strip: o.strip } : {}
1846
+ });
1847
+ }
1848
+ // src/primitives/transport.ts
1849
+ var sub = (a, b) => [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
1850
+ var dot = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
1851
+ var unit = (a) => {
1852
+ const l = Math.hypot(a[0], a[1], a[2]) || 1;
1853
+ return [a[0] / l, a[1] / l, a[2] / l];
1854
+ };
1855
+ var cross3 = (a, b) => [
1856
+ a[1] * b[2] - a[2] * b[1],
1857
+ a[2] * b[0] - a[0] * b[2],
1858
+ a[0] * b[1] - a[1] * b[0]
1859
+ ];
1860
+ var reflect = (v, axis, c) => {
1861
+ const k = 2 / c * dot(axis, v);
1862
+ return [v[0] - k * axis[0], v[1] - k * axis[1], v[2] - k * axis[2]];
1863
+ };
1864
+ function arcLengths2(path) {
1865
+ if (path.length < 2) {
1866
+ throw new Ts23dError2("T3D_RECIPE_INVALID", {
1867
+ cause: `sweep path has ${path.length} point(s)`,
1868
+ fix: "pass at least 2 path points (from → to); a single point has no direction to sweep along"
1869
+ });
1870
+ }
1871
+ const s = [0];
1872
+ for (let i = 1;i < path.length; i++) {
1873
+ const d = Math.hypot(...sub(path[i] ?? [0, 0, 0], path[i - 1] ?? [0, 0, 0]));
1874
+ if (d < 0.000000001) {
1875
+ throw new Ts23dError2("T3D_RECIPE_INVALID", {
1876
+ cause: `sweep path points ${i - 1} and ${i} coincide (zero-length segment)`,
1877
+ fix: "make consecutive path points distinct — drop duplicates before sweeping"
1878
+ });
1879
+ }
1880
+ s.push((s[i - 1] ?? 0) + d);
1881
+ }
1882
+ return s;
1883
+ }
1884
+ function transportFrames2(path) {
1885
+ arcLengths2(path);
1886
+ const last = path.length - 1;
1887
+ const tangents = path.map((_, i) => unit(sub(path[Math.min(last, i + 1)] ?? [0, 0, 0], path[Math.max(0, i - 1)] ?? [0, 0, 0])));
1888
+ const t0 = tangents[0] ?? [0, 0, 1];
1889
+ const ref = Math.abs(t0[2]) > 0.9 ? [1, 0, 0] : [0, 0, 1];
1890
+ const k = dot(ref, t0);
1891
+ let n = unit([ref[0] - k * t0[0], ref[1] - k * t0[1], ref[2] - k * t0[2]]);
1892
+ const out = [{ t: t0, n, b: cross3(t0, n) }];
1893
+ for (let i = 1;i <= last; i++) {
1894
+ const p0 = path[i - 1] ?? [0, 0, 0];
1895
+ const p1 = path[i] ?? [0, 0, 0];
1896
+ const ti = tangents[i - 1] ?? t0;
1897
+ const tj = tangents[i] ?? t0;
1898
+ const v1 = sub(p1, p0);
1899
+ const c1 = dot(v1, v1);
1900
+ const nL = reflect(n, v1, c1);
1901
+ const tL = reflect(ti, v1, c1);
1902
+ const v2 = sub(tj, tL);
1903
+ const c2 = dot(v2, v2);
1904
+ n = unit(c2 < 0.000000000001 ? nL : reflect(nL, v2, c2));
1905
+ out.push({ t: tj, n, b: cross3(tj, n) });
1906
+ }
1907
+ return out;
1908
+ }
1909
+
1910
+ // src/primitives/sweep.ts
1911
+ function section2(s) {
1912
+ if (!Array.isArray(s)) {
1913
+ const c = s;
1914
+ if (c.segments < 3 || !(c.radius > 0)) {
1915
+ throw new Ts23dError2("T3D_RECIPE_INVALID", {
1916
+ cause: `sweep circle section has radius ${c.radius} and ${c.segments} segments`,
1917
+ fix: "use radius > 0 and segments >= 3 (pick segments from ctx.lod: e.g. 8 / 5 / 3)"
1918
+ });
1919
+ }
1920
+ const nrm = [];
1921
+ for (let k = 0;k < c.segments; k++) {
1922
+ const a = k / c.segments * Math.PI * 2;
1923
+ nrm.push([Math.cos(a), Math.sin(a)]);
1924
+ }
1925
+ return { pts: nrm.map(([x, y]) => [x * c.radius, y * c.radius]), nrm };
1926
+ }
1927
+ const poly = s;
1928
+ if (poly.length < 3) {
1929
+ throw new Ts23dError2("T3D_RECIPE_INVALID", {
1930
+ cause: `sweep section has ${poly.length} point(s)`,
1931
+ fix: "pass a closed polygon of at least 3 points, or { radius, segments }"
1932
+ });
1933
+ }
1934
+ const area = poly.reduce((a, p, i) => {
1935
+ const q = poly[(i + 1) % poly.length] ?? p;
1936
+ return a + p[0] * q[1] - q[0] * p[1];
1937
+ }, 0);
1938
+ const pts = area < 0 ? [...poly].reverse() : poly;
1939
+ const nrm = pts.map((p, i) => {
1940
+ const a = pts[(i + pts.length - 1) % pts.length] ?? p;
1941
+ const b = pts[(i + 1) % pts.length] ?? p;
1942
+ const e1 = Math.hypot(p[0] - a[0], p[1] - a[1]) || 1;
1943
+ const e2 = Math.hypot(b[0] - p[0], b[1] - p[1]) || 1;
1944
+ const x = (p[1] - a[1]) / e1 + (b[1] - p[1]) / e2;
1945
+ const y = -(p[0] - a[0]) / e1 - (b[0] - p[0]) / e2;
1946
+ const l = Math.hypot(x, y) || 1;
1947
+ return [x / l, y / l];
1948
+ });
1949
+ return { pts, nrm };
1950
+ }
1951
+ function sweep2(o) {
1952
+ const arc = arcLengths2(o.path);
1953
+ const frames = transportFrames2(o.path);
1954
+ const P = o.path.length;
1955
+ if (o.scale && o.scale.length !== P) {
1956
+ throw new Ts23dError2("T3D_RECIPE_INVALID", {
1957
+ cause: `sweep has ${P} path points but ${o.scale.length} scales`,
1958
+ fix: "pass exactly one scale per path point (or omit scale for a constant section)"
1959
+ });
1960
+ }
1961
+ const sec = section2(o.section);
1962
+ const S = sec.pts.length;
1963
+ const total = arc[P - 1] ?? 1;
1964
+ const rect = stripRect2(o.strip ?? "plain");
1965
+ const du = (rect.u1 - rect.u0) / rect.metres;
1966
+ const twist = (o.twist ?? 0) * Math.PI / 180;
1967
+ const b = new MeshBuilder2;
1968
+ const rim = new Float64Array(P * S * 3);
1969
+ for (let i = 0;i < P; i++) {
1970
+ const c = o.path[i] ?? [0, 0, 0];
1971
+ const { t, n, b: bn } = frames[i] ?? { t: [0, 0, 1], n: [1, 0, 0], b: [0, 1, 0] };
1972
+ const k = o.scale?.[i] ?? 1;
1973
+ const i0 = Math.max(0, i - 1);
1974
+ const i1 = Math.min(P - 1, i + 1);
1975
+ const slope = ((o.scale?.[i1] ?? 1) - (o.scale?.[i0] ?? 1)) / ((arc[i1] ?? 0) - (arc[i0] ?? 0) || 1);
1976
+ const rot = twist * (arc[i] ?? 0) / total;
1977
+ const cr = Math.cos(rot);
1978
+ const sr = Math.sin(rot);
1979
+ const u = rect.u0 + (arc[i] ?? 0) * du;
1980
+ for (let j = 0;j <= S; j++) {
1981
+ const [px, py] = sec.pts[j % S] ?? [0, 0];
1982
+ const [nx, ny] = sec.nrm[j % S] ?? [1, 0];
1983
+ const x = (px * cr - py * sr) * k;
1984
+ const y = (px * sr + py * cr) * k;
1985
+ const mx = nx * cr - ny * sr;
1986
+ const my = nx * sr + ny * cr;
1987
+ const back = -slope * (px * nx + py * ny);
1988
+ const qx = mx * n[0] + my * bn[0] + back * t[0];
1989
+ const qy = mx * n[1] + my * bn[1] + back * t[1];
1990
+ const qz = mx * n[2] + my * bn[2] + back * t[2];
1991
+ const ql = Math.hypot(qx, qy, qz) || 1;
1992
+ const p = [
1993
+ c[0] + x * n[0] + y * bn[0],
1994
+ c[1] + x * n[1] + y * bn[1],
1995
+ c[2] + x * n[2] + y * bn[2]
1996
+ ];
1997
+ if (j < S)
1998
+ rim.set(p, (i * S + j) * 3);
1999
+ b.vertex({
2000
+ p,
2001
+ n: [qx / ql, qy / ql, qz / ql],
2002
+ uv: [u, rect.v0 + j / S * (rect.v1 - rect.v0)],
2003
+ color: o.color
2004
+ });
2005
+ }
2006
+ }
2007
+ for (let i = 0;i + 1 < P; i++) {
2008
+ const r0 = i * (S + 1);
2009
+ const r1 = r0 + S + 1;
2010
+ for (let j = 0;j < S; j++)
2011
+ b.quad(r0 + j, r0 + j + 1, r1 + j + 1, r1 + j);
2012
+ }
2013
+ const caps = o.caps === true ? ["start", "end"] : o.caps ? [o.caps] : [];
2014
+ for (const end of caps) {
2015
+ const i = end === "start" ? 0 : P - 1;
2016
+ const f = frames[i]?.t ?? [0, 0, 1];
2017
+ const sign = end === "start" ? -1 : 1;
2018
+ const nn = [f[0] * sign, f[1] * sign, f[2] * sign];
2019
+ const centre = b.vertex({
2020
+ p: o.path[i] ?? [0, 0, 0],
2021
+ n: nn,
2022
+ uv: [rect.u0, rect.v0],
2023
+ color: o.color
2024
+ });
2025
+ const first = centre + 1;
2026
+ for (let j = 0;j < S; j++) {
2027
+ const q = (i * S + j) * 3;
2028
+ const p = [rim[q] ?? 0, rim[q + 1] ?? 0, rim[q + 2] ?? 0];
2029
+ b.vertex({ p, n: nn, uv: [rect.u0, rect.v1], color: o.color });
2030
+ }
2031
+ for (let j = 0;j < S; j++) {
2032
+ const a = first + j;
2033
+ const c = first + (j + 1) % S;
2034
+ if (sign > 0)
2035
+ b.tri(centre, a, c);
2036
+ else
2037
+ b.tri(centre, c, a);
2038
+ }
2039
+ }
2040
+ return b.build();
2041
+ }
2042
+ // src/primitives/terrain-grid.ts
2043
+ function terrainGrid2(o) {
2044
+ const [x0, y0, x1, y1] = o.rect;
2045
+ if (!(x1 > x0 && y1 > y0))
2046
+ invalid(`terrain rect [${o.rect.join(", ")}] is empty`, "pass [minX, minY, maxX, maxY] with max > min");
2047
+ const n = count("terrain cells", o.cells, 2, 4096);
2048
+ const z = new Float64Array((n + 1) * (n + 1));
2049
+ for (let j = 0;j <= n; j++)
2050
+ for (let i = 0;i <= n; i++) {
2051
+ const h = o.height(x0 + (x1 - x0) * i / n, y0 + (y1 - y0) * j / n);
2052
+ if (!Number.isFinite(h))
2053
+ invalid(`terrain height is ${h} at point (${i}, ${j})`, "return a finite height in metres");
2054
+ z[j * (n + 1) + i] = h;
2055
+ }
2056
+ return { nx: n + 1, ny: n + 1, rect: o.rect, z };
2057
+ }
2058
+ function sampler2(g, map = g.z) {
2059
+ const [x0, y0, x1, y1] = g.rect;
2060
+ const sx = (g.nx - 1) / (x1 - x0);
2061
+ const sy = (g.ny - 1) / (y1 - y0);
2062
+ return (x, y) => {
2063
+ const fx = Math.min(g.nx - 1, Math.max(0, (x - x0) * sx));
2064
+ const fy = Math.min(g.ny - 1, Math.max(0, (y - y0) * sy));
2065
+ const i = Math.min(g.nx - 2, Math.floor(fx));
2066
+ const j = Math.min(g.ny - 2, Math.floor(fy));
2067
+ const u = fx - i;
2068
+ const v = fy - j;
2069
+ const k = j * g.nx + i;
2070
+ const a = map[k] ?? 0;
2071
+ const b = map[k + 1] ?? 0;
2072
+ const c = map[k + g.nx] ?? 0;
2073
+ const d = map[k + g.nx + 1] ?? 0;
2074
+ return a + (b - a) * u + (c + (d - c) * u - (a + (b - a) * u)) * v;
2075
+ };
2076
+ }
2077
+ function slopeMap2(g) {
2078
+ const [x0, y0, x1, y1] = g.rect;
2079
+ const dx = (x1 - x0) / (g.nx - 1);
2080
+ const dy = (y1 - y0) / (g.ny - 1);
2081
+ const out = new Float64Array(g.z.length);
2082
+ for (let j = 0;j < g.ny; j++)
2083
+ for (let i = 0;i < g.nx; i++) {
2084
+ const l = g.z[j * g.nx + Math.max(0, i - 1)] ?? 0;
2085
+ const r = g.z[j * g.nx + Math.min(g.nx - 1, i + 1)] ?? 0;
2086
+ const b = g.z[Math.max(0, j - 1) * g.nx + i] ?? 0;
2087
+ const t = g.z[Math.min(g.ny - 1, j + 1) * g.nx + i] ?? 0;
2088
+ const sx = (r - l) / (dx * (Math.min(g.nx - 1, i + 1) - Math.max(0, i - 1)));
2089
+ const sy = (t - b) / (dy * (Math.min(g.ny - 1, j + 1) - Math.max(0, j - 1)));
2090
+ out[j * g.nx + i] = Math.sqrt(sx * sx + sy * sy);
2091
+ }
2092
+ return out;
2093
+ }
2094
+ function thermalErosion2(g, o = {}) {
2095
+ const talus = o.talus ?? 0.7;
2096
+ const rate = Math.min(0.5, Math.max(0, o.rate ?? 0.4));
2097
+ const iterations = count("thermal iterations", o.iterations ?? 30, 0, 1e4);
2098
+ const [x0, , x1] = g.rect;
2099
+ const cell = (x1 - x0) / (g.nx - 1);
2100
+ const D = [-1, 0, 1, 0, 0, -1, 0, 1, -1, -1, 1, -1, -1, 1, 1, 1];
2101
+ const limit = D.map((_, k) => k < 8 ? talus * cell : talus * cell * Math.SQRT2);
2102
+ let z = Float64Array.from(g.z);
2103
+ for (let it = 0;it < iterations; it++) {
2104
+ const next = Float64Array.from(z);
2105
+ for (let j = 1;j < g.ny - 1; j++)
2106
+ for (let i = 1;i < g.nx - 1; i++) {
2107
+ const k = j * g.nx + i;
2108
+ const h = z[k] ?? 0;
2109
+ let total = 0;
2110
+ let most = 0;
2111
+ for (let d = 0;d < 16; d += 2) {
2112
+ const ex = h - (z[k + (D[d] ?? 0) + (D[d + 1] ?? 0) * g.nx] ?? 0) - (limit[d] ?? 0);
2113
+ if (ex > 0) {
2114
+ total += ex;
2115
+ if (ex > most)
2116
+ most = ex;
2117
+ }
2118
+ }
2119
+ if (total <= 0)
2120
+ continue;
2121
+ const move = rate * most;
2122
+ next[k] = (next[k] ?? 0) - move;
2123
+ for (let d = 0;d < 16; d += 2) {
2124
+ const n = k + (D[d] ?? 0) + (D[d + 1] ?? 0) * g.nx;
2125
+ const ex = h - (z[n] ?? 0) - (limit[d] ?? 0);
2126
+ if (ex > 0)
2127
+ next[n] = (next[n] ?? 0) + move * ex / total;
2128
+ }
2129
+ }
2130
+ z = next;
2131
+ }
2132
+ return { ...g, z };
2133
+ }
2134
+
2135
+ // src/primitives/terrain-color.ts
2136
+ var ramp = (a, b, x) => {
2137
+ const t = Math.min(1, Math.max(0, (x - a) / (b - a)));
2138
+ return t * t * (3 - 2 * t);
2139
+ };
2140
+ function terrainColor2(g, o) {
2141
+ const slope = sampler2(g, slopeMap2(g));
2142
+ const flow = g.flow ? sampler2(g, g.flow) : () => 0;
2143
+ const dep = g.deposit ? sampler2(g, g.deposit) : () => 0;
2144
+ const P = o.palette;
2145
+ const datum = o.datum ?? 0;
2146
+ const rockS = o.rockSlope ?? 0.8;
2147
+ const snowS = o.snowSlope ?? 1;
2148
+ const jit = o.jitter ?? 60;
2149
+ const c = [0, 0, 0];
2150
+ const mix = (to, w) => {
2151
+ for (let k = 0;k < 3; k++)
2152
+ c[k] = (c[k] ?? 0) + ((to[k] ?? 0) - (c[k] ?? 0)) * w;
2153
+ };
2154
+ return (x, y, z) => {
2155
+ const n = o.noise ? o.noise(x, y) : 0;
2156
+ const alt = z + datum + n * jit;
2157
+ const s = slope(x, y) * (1 + 0.15 * n);
2158
+ c[0] = P.forest[0];
2159
+ c[1] = P.forest[1];
2160
+ c[2] = P.forest[2];
2161
+ mix(P.grass, ramp(o.treeline - 80, o.treeline + 80, alt));
2162
+ mix(P.scree, 0.85 * ramp(o.treeline + 350, o.treeline + 800, alt));
2163
+ mix(P.grass, ramp(0.55, 0.8, s) * (1 - ramp(o.treeline - 80, o.treeline + 80, alt)) * 0.6);
2164
+ mix(P.scree, ramp(0.4, 0.8, dep(x, y)) * ramp(0.2, 0.45, s) * (1 - ramp(rockS, rockS + 0.3, s)));
2165
+ mix(P.wet, 0.7 * ramp(0.35, 0.8, flow(x, y)) * (1 - ramp(o.snowline - 100, o.snowline, alt)));
2166
+ mix(P.rock, ramp(rockS - 0.15, rockS + 0.15, s));
2167
+ mix(P.snow, ramp(o.snowline - 60, o.snowline + 120, alt) * (1 - ramp(snowS - 0.3, snowS + 0.2, s)));
2168
+ return [c[0] ?? 0, c[1] ?? 0, c[2] ?? 0];
2169
+ };
2170
+ }
2171
+ // src/primitives/font-5x7.ts
2172
+ var A = [14, 17, 17, 17, 31, 17, 17];
2173
+ var B = [30, 17, 17, 30, 17, 17, 30];
2174
+ var C = [14, 17, 16, 16, 16, 17, 14];
2175
+ var E = [31, 16, 16, 30, 16, 16, 31];
2176
+ var H = [17, 17, 17, 31, 17, 17, 17];
2177
+ var K = [17, 18, 20, 24, 20, 18, 17];
2178
+ var M = [17, 27, 21, 21, 17, 17, 17];
2179
+ var O = [14, 17, 17, 17, 17, 17, 14];
2180
+ var P = [30, 17, 17, 30, 16, 16, 16];
2181
+ var T = [31, 4, 4, 4, 4, 4, 4];
2182
+ var X = [17, 17, 10, 4, 10, 17, 17];
2183
+ var GLYPHS = {
2184
+ " ": [0, 0, 0, 0, 0, 0, 0],
2185
+ A,
2186
+ B,
2187
+ C,
2188
+ D: [28, 18, 17, 17, 17, 18, 28],
2189
+ E,
2190
+ F: [31, 16, 16, 30, 16, 16, 16],
2191
+ G: [14, 17, 16, 23, 17, 17, 15],
2192
+ H,
2193
+ I: [14, 4, 4, 4, 4, 4, 14],
2194
+ J: [7, 2, 2, 2, 2, 18, 12],
2195
+ K,
2196
+ L: [16, 16, 16, 16, 16, 16, 31],
2197
+ M,
2198
+ N: [17, 17, 25, 21, 19, 17, 17],
2199
+ O,
2200
+ P,
2201
+ Q: [14, 17, 17, 17, 21, 18, 13],
2202
+ R: [30, 17, 17, 30, 20, 18, 17],
2203
+ S: [15, 16, 16, 14, 1, 1, 30],
2204
+ T,
2205
+ U: [17, 17, 17, 17, 17, 17, 14],
2206
+ V: [17, 17, 17, 17, 17, 10, 4],
2207
+ W: [17, 17, 17, 21, 21, 21, 10],
2208
+ X,
2209
+ Y: [17, 17, 10, 4, 4, 4, 4],
2210
+ Z: [31, 1, 2, 4, 8, 16, 31],
2211
+ "0": [14, 17, 19, 21, 25, 17, 14],
2212
+ "1": [4, 12, 4, 4, 4, 4, 14],
2213
+ "2": [14, 17, 1, 2, 4, 8, 31],
2214
+ "3": [31, 2, 4, 2, 1, 17, 14],
2215
+ "4": [2, 6, 10, 18, 31, 2, 2],
2216
+ "5": [31, 16, 30, 1, 1, 17, 14],
2217
+ "6": [6, 8, 16, 30, 17, 17, 14],
2218
+ "7": [31, 1, 2, 4, 8, 8, 8],
2219
+ "8": [14, 17, 17, 14, 17, 17, 14],
2220
+ "9": [14, 17, 17, 15, 1, 2, 12],
2221
+ ".": [0, 0, 0, 0, 0, 12, 12],
2222
+ ",": [0, 0, 0, 0, 12, 4, 8],
2223
+ "-": [0, 0, 0, 31, 0, 0, 0],
2224
+ "/": [0, 1, 2, 4, 8, 16, 0],
2225
+ ":": [0, 12, 12, 0, 12, 12, 0],
2226
+ "'": [12, 4, 8, 0, 0, 0, 0],
2227
+ '"': [10, 10, 10, 0, 0, 0, 0],
2228
+ "&": [12, 18, 20, 8, 21, 18, 13],
2229
+ "!": [4, 4, 4, 4, 4, 0, 4],
2230
+ "?": [14, 17, 1, 2, 4, 0, 4],
2231
+ "#": [10, 10, 31, 10, 31, 10, 10],
2232
+ "+": [0, 4, 4, 31, 4, 4, 0],
2233
+ "=": [0, 0, 31, 0, 31, 0, 0],
2234
+ "*": [0, 4, 21, 14, 21, 4, 0],
2235
+ "(": [2, 4, 8, 8, 8, 4, 2],
2236
+ ")": [8, 4, 2, 2, 2, 4, 8],
2237
+ "%": [24, 25, 2, 4, 8, 19, 3],
2238
+ "°": [12, 18, 18, 12, 0, 0, 0],
2239
+ "№": [18, 26, 26, 22, 22, 18, 21],
2240
+ А: A,
2241
+ Б: [31, 16, 16, 30, 17, 17, 30],
2242
+ В: B,
2243
+ Г: [31, 16, 16, 16, 16, 16, 16],
2244
+ Д: [6, 10, 10, 10, 10, 31, 17],
2245
+ Е: E,
2246
+ Ё: [10, 0, 31, 16, 30, 16, 31],
2247
+ Ж: [21, 21, 21, 14, 21, 21, 21],
2248
+ З: [14, 17, 1, 6, 1, 17, 14],
2249
+ И: [17, 17, 19, 21, 25, 17, 17],
2250
+ Й: [10, 4, 17, 19, 21, 25, 17],
2251
+ К: K,
2252
+ Л: [7, 9, 9, 9, 9, 9, 17],
2253
+ М: M,
2254
+ Н: H,
2255
+ О: O,
2256
+ П: [31, 17, 17, 17, 17, 17, 17],
2257
+ Р: P,
2258
+ С: C,
2259
+ Т: T,
2260
+ У: [17, 17, 17, 15, 1, 17, 14],
2261
+ Ф: [4, 14, 21, 21, 21, 14, 4],
2262
+ Х: X,
2263
+ Ц: [18, 18, 18, 18, 18, 31, 1],
2264
+ Ч: [17, 17, 17, 15, 1, 1, 1],
2265
+ Ш: [21, 21, 21, 21, 21, 21, 31],
2266
+ Щ: [21, 21, 21, 21, 21, 31, 1],
2267
+ Ъ: [24, 8, 8, 14, 9, 9, 14],
2268
+ Ы: [17, 17, 17, 29, 19, 19, 29],
2269
+ Ь: [16, 16, 16, 30, 17, 17, 30],
2270
+ Э: [14, 17, 1, 7, 1, 17, 14],
2271
+ Ю: [18, 21, 21, 29, 21, 21, 18],
2272
+ Я: [15, 17, 17, 15, 5, 9, 17]
2273
+ };
2274
+ var group = (c) => /[A-Z]/.test(c) ? 0 : /[0-9]/.test(c) ? 1 : /[А-ЯЁ]/.test(c) ? 3 : 2;
2275
+ var SUPPORTED_CHARS = Object.keys(GLYPHS).filter((c) => c !== " ").sort((a, b) => group(a) - group(b) || (a < b ? -1 : a > b ? 1 : 0)).join("").concat(" and space");
2276
+
2277
+ // src/primitives/text-layout.ts
2278
+ var SPACE = 3;
2279
+ function rows(ch, font) {
2280
+ const g = GLYPHS[ch] ?? GLYPHS[ch.toUpperCase()];
2281
+ if (!g)
2282
+ invalid(`text: no glyph for ${JSON.stringify(ch)} (U+${(ch.codePointAt(0) ?? 0).toString(16).toUpperCase().padStart(4, "0")})`, `use only these characters (lower case is set as upper case): ${SUPPORTED_CHARS}`);
2283
+ if (ch === " ")
2284
+ return { rows: g, width: SPACE };
2285
+ return font === "block" ? { rows: g.map((r) => r << 1 | r), width: 6 } : { rows: g, width: 5 };
2286
+ }
2287
+ function widthPx(str, font, tracking) {
2288
+ const chars = [...str];
2289
+ return chars.reduce((w, ch) => w + rows(ch, font).width, 0) + Math.max(0, chars.length - 1) * tracking;
2290
+ }
2291
+ function measureText2(str, o) {
2292
+ return widthPx(str, o.font ?? "5x7", o.tracking ?? 1) * o.height / 7;
2293
+ }
2294
+ function layout(str, font, tracking) {
2295
+ const rects = [];
2296
+ let pen = 0;
2297
+ for (const ch of str) {
2298
+ const g = rows(ch, font);
2299
+ let open = new Map;
2300
+ for (let r = 0;r <= 7; r++) {
2301
+ const bits = g.rows[r] ?? 0;
2302
+ const next = new Map;
2303
+ let c = 0;
2304
+ while (c < g.width) {
2305
+ if (!(bits >> g.width - 1 - c & 1)) {
2306
+ c++;
2307
+ continue;
2308
+ }
2309
+ const start = c;
2310
+ while (c < g.width && bits >> g.width - 1 - c & 1)
2311
+ c++;
2312
+ const key = `${start},${c}`;
2313
+ next.set(key, open.get(key) ?? { c0: start, c1: c, r0: r });
2314
+ }
2315
+ for (const [key, run] of open)
2316
+ if (!next.has(key))
2317
+ rects.push({ c0: pen + run.c0, c1: pen + run.c1, r0: run.r0, r1: r });
2318
+ open = next;
2319
+ }
2320
+ pen += g.width + tracking;
2321
+ }
2322
+ return { rects, width: Math.max(0, pen - tracking) };
2323
+ }
2324
+
2325
+ // src/primitives/text.ts
2326
+ var LIFT = 0.002;
2327
+ function text2(str, o) {
2328
+ if (!(Number.isFinite(o.height) && o.height > 0 && o.height < 1000))
2329
+ invalid(`text height is ${o.height}`, "give the cap height in metres, > 0 (e.g. 0.3 for wagon lettering)");
2330
+ const depth = o.depth ?? 0;
2331
+ if (!(Number.isFinite(depth) && depth >= 0))
2332
+ invalid(`text depth is ${depth}`, "use 0 (flush) or a raised thickness > 0 m");
2333
+ const font = o.font ?? "5x7";
2334
+ const tracking = o.tracking ?? 1;
2335
+ let height = o.height;
2336
+ if (o.maxWidth !== undefined) {
2337
+ if (!(o.maxWidth > 0))
2338
+ invalid(`text maxWidth is ${o.maxWidth}`, "give the panel width in metres, > 0");
2339
+ const w = measureText2(str, { height, font, tracking });
2340
+ if (w > o.maxWidth)
2341
+ height *= o.maxWidth / w;
2342
+ }
2343
+ const along = normalize2(o.along ?? [0, 1, 0]);
2344
+ const up0 = o.up ?? [0, 0, 1];
2345
+ const k = up0[0] * along[0] + up0[1] * along[1] + up0[2] * along[2];
2346
+ const upR = [up0[0] - along[0] * k, up0[1] - along[1] * k, up0[2] - along[2] * k];
2347
+ if (Math.hypot(upR[0], upR[1], upR[2]) < 0.000000001)
2348
+ invalid("text: up is parallel to along", "pass an `up` perpendicular to the reading direction");
2349
+ const up = normalize2(upR);
2350
+ const n = [
2351
+ along[1] * up[2] - along[2] * up[1],
2352
+ along[2] * up[0] - along[0] * up[2],
2353
+ along[0] * up[1] - along[1] * up[0]
2354
+ ];
2355
+ const px = height / 7;
2356
+ const { rects, width } = layout(str, font, tracking);
2357
+ const start = o.align === "centre" ? -width * px / 2 : o.align === "right" ? -width * px : 0;
2358
+ const rect = stripRect2(o.strip ?? "plain");
2359
+ const b = new MeshBuilder2;
2360
+ const at = (u, v, w) => [
2361
+ o.origin[0] + along[0] * u + up[0] * v + n[0] * w,
2362
+ o.origin[1] + along[1] * u + up[1] * v + n[1] * w,
2363
+ o.origin[2] + along[2] * u + up[2] * v + n[2] * w
2364
+ ];
2365
+ const quad = (c, nrm, us, vs) => {
2366
+ const ids = c.map((p, i) => b.vertex({
2367
+ p,
2368
+ n: nrm,
2369
+ uv: [
2370
+ stripU(rect, us[i] ?? 0),
2371
+ stripV(rect, Math.min(1, Math.max(0, (vs[i] ?? 0) / height)))
2372
+ ],
2373
+ color: o.color
2374
+ }));
2375
+ const [a = n, e = n, f = n] = c;
2376
+ const g = [0, 1, 2].map((j) => {
2377
+ const [x, y] = [(j + 1) % 3, (j + 2) % 3];
2378
+ return ((e[x] ?? 0) - (a[x] ?? 0)) * ((f[y] ?? 0) - (a[y] ?? 0)) - ((e[y] ?? 0) - (a[y] ?? 0)) * ((f[x] ?? 0) - (a[x] ?? 0));
2379
+ });
2380
+ const [i0 = 0, i1 = 0, i2 = 0, i3 = 0] = ids;
2381
+ if ((g[0] ?? 0) * nrm[0] + (g[1] ?? 0) * nrm[1] + (g[2] ?? 0) * nrm[2] >= 0)
2382
+ b.quad(i0, i1, i2, i3);
2383
+ else
2384
+ b.quad(i0, i3, i2, i1);
2385
+ };
2386
+ const neg = (v) => [-v[0], -v[1], -v[2]];
2387
+ for (const piece of pieces(rects, px, start, o.surface)) {
2388
+ const { u0, u1, v0, v1, s } = piece;
2389
+ const lo = depth > 0 ? s : s + LIFT;
2390
+ const hi = depth > 0 ? s + depth : lo;
2391
+ quad([at(u0, v0, hi), at(u1, v0, hi), at(u1, v1, hi), at(u0, v1, hi)], n, [u0, u1, u1, u0], [v0, v0, v1, v1]);
2392
+ if (depth <= 0)
2393
+ continue;
2394
+ quad([at(u0, v0, lo), at(u1, v0, lo), at(u1, v0, hi), at(u0, v0, hi)], neg(up), [u0, u1, u1, u0], [0, 0, depth, depth]);
2395
+ quad([at(u1, v0, lo), at(u1, v1, lo), at(u1, v1, hi), at(u1, v0, hi)], along, [v0, v1, v1, v0], [0, 0, depth, depth]);
2396
+ quad([at(u1, v1, lo), at(u0, v1, lo), at(u0, v1, hi), at(u1, v1, hi)], up, [u1, u0, u0, u1], [0, 0, depth, depth]);
2397
+ quad([at(u0, v1, lo), at(u0, v0, lo), at(u0, v0, hi), at(u0, v1, hi)], neg(along), [v1, v0, v0, v1], [0, 0, depth, depth]);
2398
+ }
2399
+ return b.build();
2400
+ }
2401
+ function pieces(rects, px, start, surface) {
2402
+ const out = [];
2403
+ for (const r of rects) {
2404
+ const v0 = (7 - r.r1) * px;
2405
+ const v1 = (7 - r.r0) * px;
2406
+ if (!surface) {
2407
+ out.push({ u0: start + r.c0 * px, u1: start + r.c1 * px, v0, v1, s: 0 });
2408
+ continue;
2409
+ }
2410
+ const lift = (c) => {
2411
+ let top = Number.NEGATIVE_INFINITY;
2412
+ for (const fu of [0.02, 0.5, 0.98])
2413
+ for (const v of [v0 + 0.02 * px, (v0 + v1) / 2, v1 - 0.02 * px])
2414
+ top = Math.max(top, surface(start + (c + fu) * px, v));
2415
+ return top;
2416
+ };
2417
+ let c = r.c0;
2418
+ while (c < r.c1) {
2419
+ const s = lift(c);
2420
+ let e = c + 1;
2421
+ while (e < r.c1 && Math.abs(lift(e) - s) < 0.000001)
2422
+ e++;
2423
+ out.push({ u0: start + c * px, u1: start + e * px, v0, v1, s });
2424
+ c = e;
2425
+ }
2426
+ }
2427
+ return out;
2428
+ }
2429
+ // src/primitives/tiled.ts
2430
+ function tiled2(o) {
2431
+ const { lu, lv, n } = spanOf("tiled", o.origin, o.u, o.v);
2432
+ const strip = o.strip ?? "plain";
2433
+ const segs = count("tiled segments", o.segments ?? 1, 1, 4096);
2434
+ const vm = positive("tiled vMetres", o.vMetres ?? stripVMetres(strip), "e.g. 0.45 for brick");
2435
+ const rect = stripRect2(strip);
2436
+ const uOff = o.uOffset ?? 0;
2437
+ const b = new MeshBuilder2;
2438
+ const sides = o.doubleSided ? [1, -1] : [1];
2439
+ let t = 0;
2440
+ while (t < lv - 0.000000001) {
2441
+ let local = (o.vOffset ?? 0) + t;
2442
+ local -= Math.floor(local / vm) * vm;
2443
+ if (vm - local < 0.000000001)
2444
+ local = 0;
2445
+ const step = Math.min(lv - t, vm - local);
2446
+ const fv0 = local / vm;
2447
+ const fv1 = (local + step) / vm;
2448
+ for (const side of sides) {
2449
+ const nn = [n[0] * side, n[1] * side, n[2] * side];
2450
+ const first = row(b, o, nn, rect, uOff, lu, segs, t / lv, stripV(rect, fv0));
2451
+ row(b, o, nn, rect, uOff, lu, segs, (t + step) / lv, stripV(rect, fv1));
2452
+ for (let j = 0;j < segs; j++) {
2453
+ const a = first + j;
2454
+ const c = first + segs + 1 + j;
2455
+ if (side > 0)
2456
+ b.quad(a, a + 1, c + 1, c);
2457
+ else
2458
+ b.quad(a, c, c + 1, a + 1);
2459
+ }
2460
+ }
2461
+ t += step;
2462
+ }
2463
+ return b.build();
2464
+ }
2465
+ function row(b, o, n, rect, uOff, lu, segs, fv, v) {
2466
+ let first = -1;
2467
+ for (let j = 0;j <= segs; j++) {
2468
+ const fu = j / segs;
2469
+ const id = b.vertex({
2470
+ p: [
2471
+ o.origin[0] + o.u[0] * fu + o.v[0] * fv,
2472
+ o.origin[1] + o.u[1] * fu + o.v[1] * fv,
2473
+ o.origin[2] + o.u[2] * fu + o.v[2] * fv
2474
+ ],
2475
+ n,
2476
+ uv: [stripU(rect, uOff + lu * fu), v],
2477
+ color: o.color
2478
+ });
2479
+ if (first < 0)
2480
+ first = id;
2481
+ }
2482
+ return first;
2483
+ }
2484
+ // src/primitives/value-noise.ts
2485
+ function valueNoise3(rng, o = {}) {
2486
+ const perm = new Uint8Array(512);
2487
+ const vals = new Float64Array(256);
2488
+ for (let i = 0;i < 256; i++) {
2489
+ perm[i] = i;
2490
+ vals[i] = rng.next() * 2 - 1;
2491
+ }
2492
+ for (let i = 255;i > 0; i--) {
2493
+ const j = rng.int(0, i);
2494
+ const t = perm[i] ?? 0;
2495
+ perm[i] = perm[j] ?? 0;
2496
+ perm[j] = t;
2497
+ }
2498
+ for (let i = 0;i < 256; i++)
2499
+ perm[i + 256] = perm[i] ?? 0;
2500
+ const at = (x, y, z) => vals[perm[(perm[(perm[x & 255] ?? 0) + (y & 255)] ?? 0) + (z & 255)] ?? 0] ?? 0;
2501
+ const fade = (t) => t * t * t * (t * (t * 6 - 15) + 10);
2502
+ const lerp = (a, b, t) => a + (b - a) * t;
2503
+ const one = (x, y, z) => {
2504
+ const xi = Math.floor(x);
2505
+ const yi = Math.floor(y);
2506
+ const zi = Math.floor(z);
2507
+ const u = fade(x - xi);
2508
+ const v = fade(y - yi);
2509
+ const w = fade(z - zi);
2510
+ const plane = (k) => lerp(lerp(at(xi, yi, k), at(xi + 1, yi, k), u), lerp(at(xi, yi + 1, k), at(xi + 1, yi + 1, k), u), v);
2511
+ return lerp(plane(zi), plane(zi + 1), w);
2512
+ };
2513
+ const s = 1 / (o.scale ?? 1);
2514
+ const octaves = o.octaves ?? 3;
2515
+ return (p) => {
2516
+ let sum = 0;
2517
+ let amp = 1;
2518
+ let norm = 0;
2519
+ let f = s;
2520
+ for (let i = 0;i < octaves; i++) {
2521
+ sum += amp * one(p[0] * f, p[1] * f, p[2] * f);
2522
+ norm += amp;
2523
+ amp *= 0.5;
2524
+ f *= 2;
2525
+ }
2526
+ return sum / norm;
2527
+ };
2528
+ }
2529
+ export { box2, lathe2, cylinder2, beam2, cell2, hydraulicErosion2, heightfield2, triangulate2, lattice2, ringXY2, loft2, gradientNoise22, valueNoise22, fbm2, billow2, ridged2, warp2, terrace2, planar2, prism2, sd2, sdf2, sculptField2, sculpt2, arcLengths2, transportFrames2, sweep2, terrainGrid2, sampler2, slopeMap2, thermalErosion2, terrainColor2, measureText2, text2, tiled2, valueNoise3 };
2530
+
2531
+ //# debugId=1A8BAFD57A1802CD64756E2164756E21
2532
+ //# sourceMappingURL=chunk-d1fv6hrm.js.map