@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,183 @@
1
+ // Hydraulic droplet erosion (Beyer 2015, "Implementation of a method for hydraulic erosion"; the
2
+ // Lague variant): thousands of droplets start at random points (from the Rng), roll downhill with
3
+ // inertia, pick up sediment while fast and on steep ground, drop it where they slow or climb, and
4
+ // evaporate. Gullies, carved valleys, alluvial fans and sharp ridges appear: the look of World
5
+ // Machine / Gaea terrain. Heights are normalised to 0..1 while simulating, so the defaults behave
6
+ // the same on any relief; the result is rescaled to metres. Also records flow and deposit maps.
7
+
8
+ import type { Rng } from '../core/index.ts';
9
+ import { count } from './check.ts';
10
+ import type { TerrainGrid } from './terrain-grid.ts';
11
+
12
+ export interface ErosionOptions {
13
+ /** Droplets simulated. ~1 per grid point is mild, 2–3 is strongly carved. Default 70 000. */
14
+ readonly droplets?: number;
15
+ /** Steps a droplet lives. Default 30. */
16
+ readonly lifetime?: number;
17
+ /** 0 = droplets follow the gradient exactly, 1 = they never turn. Default 0.05. */
18
+ readonly inertia?: number;
19
+ /** Sediment a droplet can carry per unit of speed × water × drop. Default 4. */
20
+ readonly capacity?: number;
21
+ readonly minCapacity?: number;
22
+ /** Share of spare capacity eroded per step. Default 0.3. */
23
+ readonly erode?: number;
24
+ /** Share of surplus sediment deposited per step. Default 0.3. */
25
+ readonly deposit?: number;
26
+ readonly evaporate?: number;
27
+ readonly gravity?: number;
28
+ /** Erosion brush radius in grid cells (wider = smoother gullies). Default 3. */
29
+ readonly radius?: number;
30
+ }
31
+
32
+ const put = (h: Float64Array, dep: Float64Array, k: number, a: number): void => {
33
+ h[k] = (h[k] ?? 0) + a;
34
+ dep[k] = (dep[k] ?? 0) + a;
35
+ };
36
+
37
+ interface Sim {
38
+ readonly h: Float64Array;
39
+ readonly flow: Float64Array;
40
+ readonly dep: Float64Array;
41
+ readonly nx: number;
42
+ readonly ny: number;
43
+ readonly inertia: number;
44
+ readonly capK: number;
45
+ readonly minCap: number;
46
+ readonly erodeK: number;
47
+ readonly depositK: number;
48
+ readonly evap: number;
49
+ readonly gravity: number;
50
+ readonly life: number;
51
+ }
52
+
53
+ interface Brush {
54
+ readonly dx: Int32Array;
55
+ readonly dy: Int32Array;
56
+ readonly w: Float64Array;
57
+ }
58
+
59
+ /** Cell offsets within the radius, weights falling off linearly, summing to 1. */
60
+ function makeBrush(radius: number): Brush {
61
+ const dx: number[] = [];
62
+ const dy: number[] = [];
63
+ const w: number[] = [];
64
+ for (let y = -radius; y <= radius; y++)
65
+ for (let x = -radius; x <= radius; x++) {
66
+ const d = Math.sqrt(x * x + y * y);
67
+ if (d < radius) {
68
+ dx.push(x);
69
+ dy.push(y);
70
+ w.push(radius - d);
71
+ }
72
+ }
73
+ const sum = w.reduce((s, v) => s + v, 0);
74
+ return {
75
+ dx: Int32Array.from(dx),
76
+ dy: Int32Array.from(dy),
77
+ w: Float64Array.from(w, (v) => v / sum),
78
+ };
79
+ }
80
+
81
+ /** One droplet's life. Module-level with scalar locals: no closures for the JIT to trip on. */
82
+ function droplet(s: Sim, b: Brush, x0: number, y0: number): void {
83
+ const { h, nx, ny } = s;
84
+ let x = x0;
85
+ let y = y0;
86
+ let dx = 0;
87
+ let dy = 0;
88
+ let speed = 1;
89
+ let water = 1;
90
+ let sediment = 0;
91
+ for (let step = 0; step < s.life; step++) {
92
+ const i = Math.floor(x);
93
+ const j = Math.floor(y);
94
+ const u = x - i;
95
+ const v = y - j;
96
+ const k = j * nx + i;
97
+ const a = h[k] ?? 0;
98
+ const bb = h[k + 1] ?? 0;
99
+ const c = h[k + nx] ?? 0;
100
+ const d = h[k + nx + 1] ?? 0;
101
+ const height = a * (1 - u) * (1 - v) + bb * u * (1 - v) + c * (1 - u) * v + d * u * v;
102
+ const gx = (bb - a) * (1 - v) + (d - c) * v;
103
+ const gy = (c - a) * (1 - u) + (d - bb) * u;
104
+ dx = dx * s.inertia - gx * (1 - s.inertia);
105
+ dy = dy * s.inertia - gy * (1 - s.inertia);
106
+ const len = Math.sqrt(dx * dx + dy * dy);
107
+ if (len === 0) return;
108
+ dx /= len;
109
+ dy /= len;
110
+ x += dx;
111
+ y += dy;
112
+ s.flow[k] = (s.flow[k] ?? 0) + water;
113
+ if (x < 0 || y < 0 || x >= nx - 1 || y >= ny - 1) return;
114
+ const dh = bilinear(h, nx, x, y) - height;
115
+ const cap = Math.max(-dh * speed * water * s.capK, s.minCap);
116
+ if (sediment > cap || dh > 0) {
117
+ // Fill the pit we climbed out of, or drop the surplus: split over the 4 corners.
118
+ const amount = dh > 0 ? Math.min(dh, sediment) : (sediment - cap) * s.depositK;
119
+ sediment -= amount;
120
+ put(h, s.dep, k, amount * (1 - u) * (1 - v));
121
+ put(h, s.dep, k + 1, amount * u * (1 - v));
122
+ put(h, s.dep, k + nx, amount * (1 - u) * v);
123
+ put(h, s.dep, k + nx + 1, amount * u * v);
124
+ } else {
125
+ const amount = Math.min((cap - sediment) * s.erodeK, -dh);
126
+ for (let n = 0; n < b.w.length; n++) {
127
+ const ci = i + (b.dx[n] ?? 0);
128
+ const cj = j + (b.dy[n] ?? 0);
129
+ if (ci < 0 || cj < 0 || ci >= nx || cj >= ny) continue;
130
+ const cell = cj * nx + ci;
131
+ const take = Math.min(h[cell] ?? 0, amount * (b.w[n] ?? 0));
132
+ h[cell] = (h[cell] ?? 0) - take;
133
+ sediment += take;
134
+ }
135
+ }
136
+ speed = Math.sqrt(Math.max(0, speed * speed - dh * s.gravity));
137
+ water *= 1 - s.evap;
138
+ }
139
+ }
140
+
141
+ function bilinear(h: Float64Array, nx: number, x: number, y: number): number {
142
+ const i = Math.floor(x);
143
+ const j = Math.floor(y);
144
+ const u = x - i;
145
+ const v = y - j;
146
+ const k = j * nx + i;
147
+ const a = h[k] ?? 0;
148
+ const b = h[k + 1] ?? 0;
149
+ const c = h[k + nx] ?? 0;
150
+ const d = h[k + nx + 1] ?? 0;
151
+ return a * (1 - u) * (1 - v) + b * u * (1 - v) + c * (1 - u) * v + d * u * v;
152
+ }
153
+
154
+ export function hydraulicErosion(g: TerrainGrid, rng: Rng, o: ErosionOptions = {}): TerrainGrid {
155
+ const drops = count('erosion droplets', o.droplets ?? 70000, 0, 10_000_000);
156
+ const life = count('erosion lifetime', o.lifetime ?? 30, 1, 1000);
157
+ const radius = count('erosion radius', o.radius ?? 3, 1, 32);
158
+ const { nx, ny } = g;
159
+ let lo = Number.POSITIVE_INFINITY;
160
+ let hi = Number.NEGATIVE_INFINITY;
161
+ for (const v of g.z) {
162
+ lo = Math.min(lo, v);
163
+ hi = Math.max(hi, v);
164
+ }
165
+ const relief = hi - lo || 1;
166
+ const h = Float64Array.from(g.z, (v) => (v - lo) / relief);
167
+ const flow = new Float64Array(h.length);
168
+ const dep = new Float64Array(h.length);
169
+ const sim: Sim = {
170
+ ...{ h, flow, dep, nx, ny, life, inertia: o.inertia ?? 0.05, capK: o.capacity ?? 4 },
171
+ ...{ minCap: o.minCapacity ?? 0.01, erodeK: o.erode ?? 0.3, depositK: o.deposit ?? 0.3 },
172
+ ...{ evap: o.evaporate ?? 0.01, gravity: o.gravity ?? 4 },
173
+ };
174
+ const brush = makeBrush(radius);
175
+ for (let n = 0; n < drops; n++) droplet(sim, brush, rng.next() * (nx - 2), rng.next() * (ny - 2));
176
+ const norm = (m: Float64Array): Float64Array => {
177
+ let top = 0;
178
+ for (const v of m) top = Math.max(top, v);
179
+ // Square-root compresses the long tail: a few rivers carry most water.
180
+ return top > 0 ? m.map((v) => Math.sqrt(v / top)) : m;
181
+ };
182
+ return { ...g, z: h.map((v) => lo + v * relief), flow: norm(flow), deposit: norm(dep) };
183
+ }
@@ -0,0 +1,117 @@
1
+ // The built-in 5 × 7 glyph table for `text`: Latin A–Z, digits, common punctuation and Cyrillic
2
+ // А–Я + Ё (lower case maps to upper). One entry = 7 rows top → bottom, each a 5-bit number,
3
+ // bit 4 = left column — the classic LCD character-generator shapes, legible down to a few pixels.
4
+ // Primitives (tier 2) cannot import render/font.ts (tier 3), hence this own copy.
5
+
6
+ const A = [14, 17, 17, 17, 31, 17, 17];
7
+ const B = [30, 17, 17, 30, 17, 17, 30];
8
+ const C = [14, 17, 16, 16, 16, 17, 14];
9
+ const E = [31, 16, 16, 30, 16, 16, 31];
10
+ const H = [17, 17, 17, 31, 17, 17, 17];
11
+ const K = [17, 18, 20, 24, 20, 18, 17];
12
+ const M = [17, 27, 21, 21, 17, 17, 17];
13
+ const O = [14, 17, 17, 17, 17, 17, 14];
14
+ const P = [30, 17, 17, 30, 16, 16, 16];
15
+ const T = [31, 4, 4, 4, 4, 4, 4];
16
+ const X = [17, 17, 10, 4, 10, 17, 17];
17
+
18
+ export const GLYPHS: Readonly<Record<string, readonly number[]>> = {
19
+ ' ': [0, 0, 0, 0, 0, 0, 0],
20
+ A,
21
+ B,
22
+ C,
23
+ D: [28, 18, 17, 17, 17, 18, 28],
24
+ E,
25
+ F: [31, 16, 16, 30, 16, 16, 16],
26
+ G: [14, 17, 16, 23, 17, 17, 15],
27
+ H,
28
+ I: [14, 4, 4, 4, 4, 4, 14],
29
+ J: [7, 2, 2, 2, 2, 18, 12],
30
+ K,
31
+ L: [16, 16, 16, 16, 16, 16, 31],
32
+ M,
33
+ N: [17, 17, 25, 21, 19, 17, 17],
34
+ O,
35
+ P,
36
+ Q: [14, 17, 17, 17, 21, 18, 13],
37
+ R: [30, 17, 17, 30, 20, 18, 17],
38
+ S: [15, 16, 16, 14, 1, 1, 30],
39
+ T,
40
+ U: [17, 17, 17, 17, 17, 17, 14],
41
+ V: [17, 17, 17, 17, 17, 10, 4],
42
+ W: [17, 17, 17, 21, 21, 21, 10],
43
+ X,
44
+ Y: [17, 17, 10, 4, 4, 4, 4],
45
+ Z: [31, 1, 2, 4, 8, 16, 31],
46
+ '0': [14, 17, 19, 21, 25, 17, 14],
47
+ '1': [4, 12, 4, 4, 4, 4, 14],
48
+ '2': [14, 17, 1, 2, 4, 8, 31],
49
+ '3': [31, 2, 4, 2, 1, 17, 14],
50
+ '4': [2, 6, 10, 18, 31, 2, 2],
51
+ '5': [31, 16, 30, 1, 1, 17, 14],
52
+ '6': [6, 8, 16, 30, 17, 17, 14],
53
+ '7': [31, 1, 2, 4, 8, 8, 8],
54
+ '8': [14, 17, 17, 14, 17, 17, 14],
55
+ '9': [14, 17, 17, 15, 1, 2, 12],
56
+ '.': [0, 0, 0, 0, 0, 12, 12],
57
+ ',': [0, 0, 0, 0, 12, 4, 8],
58
+ '-': [0, 0, 0, 31, 0, 0, 0],
59
+ '/': [0, 1, 2, 4, 8, 16, 0],
60
+ ':': [0, 12, 12, 0, 12, 12, 0],
61
+ "'": [12, 4, 8, 0, 0, 0, 0],
62
+ '"': [10, 10, 10, 0, 0, 0, 0],
63
+ '&': [12, 18, 20, 8, 21, 18, 13],
64
+ '!': [4, 4, 4, 4, 4, 0, 4],
65
+ '?': [14, 17, 1, 2, 4, 0, 4],
66
+ '#': [10, 10, 31, 10, 31, 10, 10],
67
+ '+': [0, 4, 4, 31, 4, 4, 0],
68
+ '=': [0, 0, 31, 0, 31, 0, 0],
69
+ '*': [0, 4, 21, 14, 21, 4, 0],
70
+ '(': [2, 4, 8, 8, 8, 4, 2],
71
+ ')': [8, 4, 2, 2, 2, 4, 8],
72
+ '%': [24, 25, 2, 4, 8, 19, 3],
73
+ '°': [12, 18, 18, 12, 0, 0, 0],
74
+ '№': [18, 26, 26, 22, 22, 18, 21],
75
+ А: A,
76
+ Б: [31, 16, 16, 30, 17, 17, 30],
77
+ В: B,
78
+ Г: [31, 16, 16, 16, 16, 16, 16],
79
+ Д: [6, 10, 10, 10, 10, 31, 17],
80
+ Е: E,
81
+ Ё: [10, 0, 31, 16, 30, 16, 31],
82
+ Ж: [21, 21, 21, 14, 21, 21, 21],
83
+ З: [14, 17, 1, 6, 1, 17, 14],
84
+ И: [17, 17, 19, 21, 25, 17, 17],
85
+ Й: [10, 4, 17, 19, 21, 25, 17],
86
+ К: K,
87
+ Л: [7, 9, 9, 9, 9, 9, 17],
88
+ М: M,
89
+ Н: H,
90
+ О: O,
91
+ П: [31, 17, 17, 17, 17, 17, 17],
92
+ Р: P,
93
+ С: C,
94
+ Т: T,
95
+ У: [17, 17, 17, 15, 1, 17, 14],
96
+ Ф: [4, 14, 21, 21, 21, 14, 4],
97
+ Х: X,
98
+ Ц: [18, 18, 18, 18, 18, 31, 1],
99
+ Ч: [17, 17, 17, 15, 1, 1, 1],
100
+ Ш: [21, 21, 21, 21, 21, 21, 31],
101
+ Щ: [21, 21, 21, 21, 21, 31, 1],
102
+ Ъ: [24, 8, 8, 14, 9, 9, 14],
103
+ Ы: [17, 17, 17, 29, 19, 19, 29],
104
+ Ь: [16, 16, 16, 30, 17, 17, 30],
105
+ Э: [14, 17, 1, 7, 1, 17, 14],
106
+ Ю: [18, 21, 21, 29, 21, 21, 18],
107
+ Я: [15, 17, 17, 15, 5, 9, 17],
108
+ };
109
+
110
+ const group = (c: string): number =>
111
+ /[A-Z]/.test(c) ? 0 : /[0-9]/.test(c) ? 1 : /[А-ЯЁ]/.test(c) ? 3 : 2;
112
+ /** Every character `text` can set (lower case is accepted and set as upper case). */
113
+ export const SUPPORTED_CHARS = Object.keys(GLYPHS)
114
+ .filter((c) => c !== ' ')
115
+ .sort((a, b) => group(a) - group(b) || (a < b ? -1 : a > b ? 1 : 0))
116
+ .join('')
117
+ .concat(' and space');
@@ -0,0 +1,101 @@
1
+ // Terrain from a height function over a rectangle: hills, embankments, spoil heaps, battlefield
2
+ // ground for presentation scenes. Smooth normals by central differences; UVs tile in metres.
3
+ // `cells` is the LOD knob — a recipe passes fewer cells at LOD 1/2. `skirt` drops walls from
4
+ // the edges to a base height: a solid map tile / diorama block that stands on z = 0.
5
+ // triangles = 2 · cx · cy + (skirt ? 4 · (cx + cy) : 0)
6
+
7
+ import { type Mesh, MeshBuilder, normalize, type Vec3 } from '../core/index.ts';
8
+ import { type StripId, stripRect } from '../material/index.ts';
9
+ import { mirroredV, stripVMetres } from './strip-uv.ts';
10
+
11
+ export interface HeightfieldOptions {
12
+ /** [minX, minY, maxX, maxY] in metres. */
13
+ readonly rect: readonly [number, number, number, number];
14
+ readonly cells: readonly [number, number];
15
+ readonly height: (x: number, y: number) => number;
16
+ /** Vertex colour per point (e.g. darker in ruts, greener on slopes). */
17
+ readonly color: Vec3 | ((x: number, y: number, z: number) => Vec3);
18
+ readonly strip?: StripId;
19
+ /** Close the sides down to this z (e.g. 0): flat-shaded walls, outward normals. */
20
+ readonly skirt?: number;
21
+ /** Wall colour; default: the terrain colour at the top edge. */
22
+ readonly skirtColor?: Vec3;
23
+ }
24
+
25
+ export function heightfield(o: HeightfieldOptions): Mesh {
26
+ const [x0, y0, x1, y1] = o.rect;
27
+ const [nx, ny] = o.cells;
28
+ const dx = (x1 - x0) / nx;
29
+ const dy = (y1 - y0) / ny;
30
+ const rect = stripRect(o.strip ?? 'plain');
31
+ const vm = stripVMetres(o.strip ?? 'plain');
32
+ const b = new MeshBuilder();
33
+ const ids: number[] = [];
34
+ for (let j = 0; j <= ny; j++) {
35
+ for (let i = 0; i <= nx; i++) {
36
+ const x = x0 + i * dx;
37
+ const y = y0 + j * dy;
38
+ const z = o.height(x, y);
39
+ const n = normalize([
40
+ o.height(x - dx, y) - o.height(x + dx, y),
41
+ o.height(x, y - dy) - o.height(x, y + dy),
42
+ 2 * Math.min(dx, dy),
43
+ ]);
44
+ const color = typeof o.color === 'function' ? o.color(x, y, z) : o.color;
45
+ const u = (x - x0) / rect.metres;
46
+ ids.push(
47
+ b.vertex({
48
+ p: [x, y, z],
49
+ n,
50
+ // V mirrors every band: continuous, so no triangle straddles a wrap and smears the strip.
51
+ uv: [rect.u0 + u * (rect.u1 - rect.u0), mirroredV(rect, y - y0, vm)],
52
+ color,
53
+ }),
54
+ );
55
+ }
56
+ }
57
+ const at = (i: number, j: number): number => ids[j * (nx + 1) + i] ?? 0;
58
+ for (let j = 0; j < ny; j++)
59
+ for (let i = 0; i < nx; i++) b.quad(at(i, j), at(i + 1, j), at(i + 1, j + 1), at(i, j + 1));
60
+ if (o.skirt !== undefined) skirt(b, o, rect);
61
+ return b.build();
62
+ }
63
+
64
+ /** Four walls from the edge vertices down to `o.skirt`, each quad CCW seen from outside. */
65
+ function skirt(b: MeshBuilder, o: HeightfieldOptions, rect: ReturnType<typeof stripRect>): void {
66
+ const [x0, y0, x1, y1] = o.rect;
67
+ const [nx, ny] = o.cells;
68
+ const base = o.skirt ?? 0;
69
+ // Edge: start corner, step per cell, cell count, outward normal. Walking CCW seen from above,
70
+ // outside is on the right, so (top a, top b, base b, base a) reversed is CCW from outside.
71
+ const edges: [number, number, number, number, number, Vec3][] = [
72
+ [x0, y0, (x1 - x0) / nx, 0, nx, [0, -1, 0]],
73
+ [x1, y0, 0, (y1 - y0) / ny, ny, [1, 0, 0]],
74
+ [x1, y1, -(x1 - x0) / nx, 0, nx, [0, 1, 0]],
75
+ [x0, y1, 0, -(y1 - y0) / ny, ny, [-1, 0, 0]],
76
+ ];
77
+ const col = (x: number, y: number, z: number): Vec3 =>
78
+ o.skirtColor ?? (typeof o.color === 'function' ? o.color(x, y, z) : o.color);
79
+ const v = (x: number, y: number, z: number, n: Vec3, u: number, color: Vec3): number =>
80
+ b.vertex({
81
+ p: [x, y, z],
82
+ n,
83
+ uv: [rect.u0 + (u / rect.metres) * (rect.u1 - rect.u0), z > base ? rect.v1 : rect.v0],
84
+ color,
85
+ });
86
+ let run = 0;
87
+ for (const [sx, sy, dx, dy, n, nrm] of edges) {
88
+ const step = Math.hypot(dx, dy);
89
+ for (let k = 0; k < n; k++) {
90
+ const [ax, ay, bx, by] = [sx + dx * k, sy + dy * k, sx + dx * (k + 1), sy + dy * (k + 1)];
91
+ const az = o.height(ax, ay);
92
+ const bz = o.height(bx, by);
93
+ const ca = col(ax, ay, az);
94
+ const cb = col(bx, by, bz);
95
+ const ta = v(ax, ay, az, nrm, run, ca);
96
+ const tb = v(bx, by, bz, nrm, run + step, cb);
97
+ b.quad(v(ax, ay, base, nrm, run, ca), v(bx, by, base, nrm, run + step, cb), tb, ta);
98
+ run += step;
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,56 @@
1
+ // Public API of /primitives: geometry builders, each emitting the core Mesh IR.
2
+
3
+ export { type BeamOptions, beam } from './beam.ts';
4
+ export { type BoxOptions, box } from './box.ts';
5
+ export { type CellOptions, cell } from './cell.ts';
6
+ export { type ErosionOptions, hydraulicErosion } from './erosion.ts';
7
+ export { type HeightfieldOptions, heightfield } from './heightfield.ts';
8
+ export { cylinder, type LatheOptions, lathe } from './lathe.ts';
9
+ export { type LatticeOptions, lattice, type TrussPattern } from './lattice.ts';
10
+ export { type LoftColor, type LoftOptions, loft, ringXY } from './loft.ts';
11
+ export type { SectionKind } from './member.ts';
12
+ export {
13
+ billow,
14
+ type FractalOptions,
15
+ fbm,
16
+ gradientNoise2,
17
+ type Noise2,
18
+ ridged,
19
+ terrace,
20
+ valueNoise2,
21
+ warp,
22
+ } from './noise.ts';
23
+ export { type PlanarOptions, planar } from './planar.ts';
24
+ export { type PrismOptions, prism } from './prism.ts';
25
+ export {
26
+ type SculptEdit,
27
+ type SculptField,
28
+ type SculptOptions,
29
+ type SculptShape,
30
+ sculpt,
31
+ sculptField,
32
+ } from './sculpt.ts';
33
+ export { type SdfColor, type SdfOptions, sdf } from './sdf.ts';
34
+ export { type Field, sd } from './sdf-ops.ts';
35
+ export { type SweepOptions, sweep } from './sweep.ts';
36
+ export { type TerrainColorOptions, type TerrainPalette, terrainColor } from './terrain-color.ts';
37
+ export {
38
+ sampler,
39
+ slopeMap,
40
+ type TerrainGrid,
41
+ type TerrainGridOptions,
42
+ type ThermalOptions,
43
+ terrainGrid,
44
+ thermalErosion,
45
+ } from './terrain-grid.ts';
46
+ export {
47
+ type MeasureOptions,
48
+ measureText,
49
+ type TextFont,
50
+ type TextOptions,
51
+ text,
52
+ } from './text.ts';
53
+ export { type TiledOptions, tiled } from './tiled.ts';
54
+ export { arcLengths, type SweepFrame, transportFrames } from './transport.ts';
55
+ export { triangulate } from './triangulate.ts';
56
+ export { valueNoise } from './value-noise.ts';
@@ -0,0 +1,45 @@
1
+ // Faceted bands for `lathe({ faceted: true })`: every segment quad gets four vertices of its own
2
+ // and the exact normal of its facet plane, so an n-sided tank, tower or roof shades flat.
3
+
4
+ import type { Vec2, Vec3 } from '../core/index.ts';
5
+
6
+ /** The profile and segment count lathe was given. */
7
+ interface Facetable {
8
+ readonly profile: readonly Vec2[];
9
+ readonly segments: number;
10
+ }
11
+
12
+ export /** Flat-shaded bands: four own vertices per segment quad, normal of the facet plane. */
13
+ function facets(
14
+ o: Facetable,
15
+ put: (p: Vec3, n: Vec3, uv: Vec2) => number,
16
+ tri: (a: number, b: number, c: number) => void,
17
+ sideUv: (s: number, i: number, r: number) => Vec2,
18
+ ): void {
19
+ const half = Math.PI / o.segments;
20
+ const corner = (s: number): [number, number] => {
21
+ const t = (s / o.segments) * Math.PI * 2 - Math.PI / 2;
22
+ return [Math.cos(t), Math.sin(t)];
23
+ };
24
+ for (let i = 0; i + 1 < o.profile.length; i++) {
25
+ const [r0 = 0, z0 = 0] = o.profile[i] ?? [];
26
+ const [r1 = 0, z1 = 0] = o.profile[i + 1] ?? [];
27
+ for (let s = 0; s < o.segments; s++) {
28
+ const tm = ((s + 0.5) / o.segments) * Math.PI * 2 - Math.PI / 2;
29
+ // The facet's chord sits cos(half) inside the ring, which tilts its normal by that much.
30
+ const nx = (z1 - z0) * Math.cos(tm);
31
+ const ny = (z1 - z0) * Math.sin(tm);
32
+ const nz = -(r1 - r0) * Math.cos(half);
33
+ const l = Math.hypot(nx, ny, nz) || 1;
34
+ const n: Vec3 = [nx / l, ny / l, nz / l];
35
+ const [c0, s0] = corner(s);
36
+ const [c1, s1] = corner(s + 1);
37
+ const a = put([r0 * c0, r0 * s0, z0], n, sideUv(s, i, r0));
38
+ const bb = put([r0 * c1, r0 * s1, z0], n, sideUv(s + 1, i, r0));
39
+ const c = put([r1 * c1, r1 * s1, z1], n, sideUv(s + 1, i + 1, r1));
40
+ const d = put([r1 * c0, r1 * s0, z1], n, sideUv(s, i + 1, r1));
41
+ tri(a, bb, c);
42
+ tri(a, c, d);
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,174 @@
1
+ // Surface of revolution around local Z: boilers, wheels, domes, spires, chimneys, tanks.
2
+ // `segments` is the knob LOD turns down; profiles are (radius, z) pairs bottom→top.
3
+ // Rings start at -90° so a vertex always sits at the contact point: a coarse LOD2 wheel still
4
+ // touches its track (the floating-parts gate caught exactly that).
5
+ // Normals: smooth around the axis, split at profile creases; `faceted` gives every segment its own
6
+ // flat normal (n-sided tanks, towers, roofs). UVs: `uv: 'metres'` maps the strip at true scale
7
+ // (arc length × profile length, staves and shingles at real size); default stretches one strip
8
+ // width around and one strip height along the profile.
9
+
10
+ import { type Mesh, MeshBuilder, type Vec2, type Vec3 } from '../core/index.ts';
11
+ import { type StripId, stripRect } from '../material/index.ts';
12
+ import { facets } from './lathe-facets.ts';
13
+ import { mirroredV, stripU, stripVMetres } from './strip-uv.ts';
14
+
15
+ export interface LatheOptions {
16
+ readonly profile: readonly Vec2[];
17
+ readonly segments: number;
18
+ readonly color: Vec3;
19
+ readonly strip?: StripId;
20
+ /** Rotate the lathe axis from Z onto X or Y (wheels spin about Y). */
21
+ readonly axis?: 'x' | 'y' | 'z';
22
+ readonly at?: Vec3;
23
+ /** Close the ends with fans (solid cylinders/wheels). */
24
+ readonly caps?: boolean;
25
+ /** Profile turns sharper than this (degrees) get split normals: a hard rim, not a smear
26
+ * whose averaged normal opposes one band. Default 50. */
27
+ readonly creaseDeg?: number;
28
+ /** 'metres': true-scale strip mapping. Default 'stretch'. */
29
+ readonly uv?: 'stretch' | 'metres';
30
+ /** Flat facets: one normal per segment (an n-sided prism of revolution). */
31
+ readonly faceted?: boolean;
32
+ }
33
+
34
+ // Swapping two coordinates is a reflection (det −1): normals are swapped with the points so they
35
+ // still point out, but triangle winding flips, so 'x'/'y' lathes emit their indices reversed.
36
+ const orient = (p: Vec3, axis: 'x' | 'y' | 'z'): Vec3 =>
37
+ axis === 'z' ? p : axis === 'y' ? [p[0], p[2], p[1]] : [p[2], p[1], p[0]];
38
+
39
+ export function lathe(o: LatheOptions): Mesh {
40
+ const axis = o.axis ?? 'z';
41
+ const [ox, oy, oz] = o.at ?? [0, 0, 0];
42
+ const rect = stripRect(o.strip ?? 'plain');
43
+ const b = new MeshBuilder();
44
+ const mirrored = axis !== 'z';
45
+ const tri = (x: number, y: number, z: number): void => {
46
+ if (mirrored) b.tri(x, z, y);
47
+ else b.tri(x, y, z);
48
+ };
49
+ const ring: number[][] = [];
50
+ const put = (p: Vec3, n: Vec3, uv: Vec2): number => {
51
+ const q = orient(p, axis);
52
+ return b.vertex({
53
+ p: [q[0] + ox, q[1] + oy, q[2] + oz],
54
+ n: orient(n, axis),
55
+ uv,
56
+ color: o.color,
57
+ });
58
+ };
59
+ const metres = o.uv === 'metres';
60
+ const vm = stripVMetres(o.strip ?? 'plain');
61
+ const run: number[] = [0];
62
+ for (let i = 1; i < o.profile.length; i++) {
63
+ const [r0 = 0, z0 = 0] = o.profile[i - 1] ?? [];
64
+ const [r1 = 0, z1 = 0] = o.profile[i] ?? [];
65
+ run.push((run[i - 1] ?? 0) + Math.hypot(r1 - r0, z1 - z0));
66
+ }
67
+ /** Side UV at segment s of profile point i (radius r). */
68
+ const sideUv = (s: number, i: number, r: number): Vec2 =>
69
+ metres
70
+ ? [stripU(rect, (Math.PI * 2 * r * s) / o.segments), mirroredV(rect, run[i] ?? 0, vm)]
71
+ : [
72
+ rect.u0 + (s / o.segments) * (rect.u1 - rect.u0),
73
+ rect.v0 + (i / Math.max(1, o.profile.length - 1)) * (rect.v1 - rect.v0),
74
+ ];
75
+ /** Cap UV at direction (cos, sin) · r on a disc (0, 0 = centre). */
76
+ const capUv = (c: number, sn: number, r: number): Vec2 =>
77
+ metres
78
+ ? [stripU(rect, c * r), mirroredV(rect, (sn + 1) * r, vm)]
79
+ : [
80
+ rect.u0 + (0.5 + c / 2) * (rect.u1 - rect.u0),
81
+ rect.v0 + (0.5 + sn / 2) * (rect.v1 - rect.v0),
82
+ ];
83
+ const creaseCos = Math.cos(((o.creaseDeg ?? 50) * Math.PI) / 180);
84
+ /** One ring of segments + 1 vertices at profile point i with normal along chord (dr, dz). */
85
+ const emitRing = (i: number, dr: number, dz: number): number[] => {
86
+ const [r, z] = o.profile[i] ?? [0, 0];
87
+ const len = Math.hypot(dr, dz) || 1;
88
+ const row: number[] = [];
89
+ for (let s = 0; s <= o.segments; s++) {
90
+ const t = (s / o.segments) * Math.PI * 2 - Math.PI / 2;
91
+ const c = Math.cos(t);
92
+ const sn = Math.sin(t);
93
+ row.push(
94
+ put([r * c, r * sn, z], [(dz / len) * c, (dz / len) * sn, -dr / len], sideUv(s, i, r)),
95
+ );
96
+ }
97
+ return row;
98
+ };
99
+ // Each profile point gives the ring that ends the band below (`top`) and the one that starts
100
+ // the band above (`ring`); they are the same ring unless the profile creases there.
101
+ const top: number[][] = [];
102
+ if (o.faceted) facets(o, put, tri, sideUv);
103
+ else
104
+ o.profile.forEach(([r, z], i) => {
105
+ const prev = o.profile[i - 1] ?? o.profile[i] ?? [r, z];
106
+ const next = o.profile[i + 1] ?? o.profile[i] ?? [r, z];
107
+ const ir = r - prev[0];
108
+ const iz = z - prev[1];
109
+ const or = next[0] - r;
110
+ const oz = next[1] - z;
111
+ const li = Math.hypot(ir, iz);
112
+ const lo = Math.hypot(or, oz);
113
+ if (li > 1e-12 && lo > 1e-12 && (ir * or + iz * oz) / (li * lo) < creaseCos) {
114
+ top.push(emitRing(i, ir, iz));
115
+ ring.push(emitRing(i, or, oz));
116
+ return;
117
+ }
118
+ // Profile-tangent normal: perpendicular to the neighbour chord in (r, z).
119
+ const row = emitRing(i, next[0] - prev[0], next[1] - prev[1]);
120
+ top.push(row);
121
+ ring.push(row);
122
+ });
123
+ for (let i = 0; i + 1 < ring.length; i++) {
124
+ for (let s = 0; s < o.segments; s++) {
125
+ const a = ring[i]?.[s] ?? 0;
126
+ const bb = ring[i]?.[s + 1] ?? 0;
127
+ const c = top[i + 1]?.[s + 1] ?? 0;
128
+ const d = top[i + 1]?.[s] ?? 0;
129
+ tri(a, bb, c);
130
+ tri(a, c, d);
131
+ }
132
+ }
133
+ if (o.caps) {
134
+ const ends = [
135
+ { pt: o.profile[0], n: -1 },
136
+ { pt: o.profile[o.profile.length - 1], n: 1 },
137
+ ];
138
+ for (const { pt, n } of ends) {
139
+ if (!pt) continue;
140
+ const centre = put([0, 0, pt[1]], [0, 0, n], capUv(0, 0, pt[0]));
141
+ const rim: number[] = [];
142
+ for (let s = 0; s <= o.segments; s++) {
143
+ const t = (s / o.segments) * Math.PI * 2 - Math.PI / 2;
144
+ rim.push(
145
+ put(
146
+ [pt[0] * Math.cos(t), pt[0] * Math.sin(t), pt[1]],
147
+ [0, 0, n],
148
+ capUv(Math.cos(t), Math.sin(t), pt[0]),
149
+ ),
150
+ );
151
+ }
152
+ for (let s = 0; s < o.segments; s++) {
153
+ const r0 = rim[s] ?? 0;
154
+ const r1 = rim[s + 1] ?? 0;
155
+ if (n > 0) tri(centre, r0, r1);
156
+ else tri(centre, r1, r0);
157
+ }
158
+ }
159
+ }
160
+ return b.build();
161
+ }
162
+
163
+ /** Convenience: a capped cylinder, the most common lathe. */
164
+ export const cylinder = (
165
+ o: Omit<LatheOptions, 'profile' | 'caps'> & { radius: number; length: number },
166
+ ): Mesh =>
167
+ lathe({
168
+ ...o,
169
+ profile: [
170
+ [o.radius, -o.length / 2],
171
+ [o.radius, o.length / 2],
172
+ ],
173
+ caps: true,
174
+ });