@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,111 @@
1
+ // Rectangular decal cells (1 m each), painted over a backdrop of the cell recipe's own kind:
2
+ // window sash (glazing bars, dark panes the shaders' window glow keys on), four-panel door with
3
+ // raised-and-fielded panels, sign blank with a moulded border and corner screws. Row y grows with
4
+ // world up, so "bottom rail" is low y.
5
+ // params (window_sash): cols 2 · rows 2 (panes per sash) · frame 0.07 · bar 0.022
6
+ // params (door_panel): stile 0.12
7
+
8
+ import { type Canvas, noiseAt, param, smooth } from './canvas.ts';
9
+ import { dome, rect } from './shapes.ts';
10
+ import type { StripRecipe } from './types.ts';
11
+
12
+ /** Pane tone: dark enough that `luma < 0.3` marks glass for window glow. */
13
+ export const PANE_TONE = 0.12;
14
+
15
+ export function paintWindowSash(c: Canvas, r: StripRecipe, seed: number): void {
16
+ const cols = param(r.params, 'cols', 2);
17
+ const rows = param(r.params, 'rows', 2);
18
+ const frame = param(r.params, 'frame', 0.07);
19
+ const bar = param(r.params, 'bar', 0.022);
20
+ const meet = 0.5;
21
+ const pu = c.metresU / c.w;
22
+ const pv = c.metresV / c.h;
23
+ for (let y = 0; y < c.h; y++) {
24
+ const ym = (y + 0.5) * pv;
25
+ const lower = ym < meet;
26
+ const y0 = lower ? frame : meet + bar;
27
+ const y1 = lower ? meet - bar : 1 - frame;
28
+ for (let x = 0; x < c.w; x++) {
29
+ const xm = (x + 0.5) * pu;
30
+ const i = y * c.w + x;
31
+ // Distance into a pane: inside the sash opening, away from every glazing bar.
32
+ const fx = ((xm - frame) / (1 - 2 * frame)) * cols;
33
+ const fy = ((ym - y0) / (y1 - y0)) * rows;
34
+ const inX = Math.min(fx - Math.floor(fx), Math.ceil(fx) - fx) * ((1 - 2 * frame) / cols);
35
+ const inY = Math.min(fy - Math.floor(fy), Math.ceil(fy) - fy) * ((y1 - y0) / rows);
36
+ const open = -rect(xm, ym, frame, y0, 1 - frame, y1);
37
+ const pane = Math.min(open, inX - bar / 2, inY - bar / 2);
38
+ const wood = noiseAt(c, xm, ym, 0.3, 0.02, seed, 3);
39
+ if (pane > 0) {
40
+ const sky = noiseAt(c, xm, ym, 0.6, 0.6, seed + 1, 2);
41
+ c.height[i] = -0.012;
42
+ c.tone[i] = PANE_TONE + 0.05 * (ym - y0) + 0.03 * sky;
43
+ c.rough[i] = 0.05;
44
+ c.metal[i] = 0;
45
+ } else {
46
+ const bevel = smooth(0, 0.01, -pane);
47
+ c.height[i] = -0.012 * (1 - bevel) + 0.0003 * wood;
48
+ c.tone[i] = 0.9 + 0.03 * wood;
49
+ c.rough[i] = r.roughness;
50
+ }
51
+ }
52
+ }
53
+ }
54
+
55
+ export function paintDoorPanel(c: Canvas, r: StripRecipe, seed: number): void {
56
+ const stile = param(r.params, 'stile', 0.12);
57
+ const muntin = stile * 0.7;
58
+ const pu = c.metresU / c.w;
59
+ const pv = c.metresV / c.h;
60
+ // Four panels: two tall above the lock rail, two short below. [x0, y0, x1, y1].
61
+ const midX = 0.5;
62
+ const panels = [
63
+ [stile, 0.2, midX - muntin / 2, 0.42],
64
+ [midX + muntin / 2, 0.2, 1 - stile, 0.42],
65
+ [stile, 0.58, midX - muntin / 2, 1 - stile],
66
+ [midX + muntin / 2, 0.58, 1 - stile, 1 - stile],
67
+ ] as const;
68
+ for (let y = 0; y < c.h; y++) {
69
+ const ym = (y + 0.5) * pv;
70
+ for (let x = 0; x < c.w; x++) {
71
+ const xm = (x + 0.5) * pu;
72
+ const i = y * c.w + x;
73
+ let d = 1;
74
+ for (const [x0, y0, x1, y1] of panels) d = Math.min(d, rect(xm, ym, x0, y0, x1, y1));
75
+ const grain = noiseAt(c, xm, ym, 0.02, 0.4, seed, 3);
76
+ // Recess, then a bevel rising to the raised field 0.04 m in from the panel edge.
77
+ const recess = d < 0 ? 1 : 1 - smooth(0, 0.006, d);
78
+ const field = smooth(0.005, 0.04, -d);
79
+ c.height[i] = -0.012 * recess + 0.008 * field + 0.0003 * grain;
80
+ c.tone[i] = (0.8 + 0.08 * grain) * (d < 0 && d > -0.008 ? 0.65 : d < 0 ? 0.92 : 1);
81
+ c.rough[i] = r.roughness + 0.05 * grain;
82
+ }
83
+ }
84
+ }
85
+
86
+ export function paintSign(c: Canvas, r: StripRecipe, _seed: number): void {
87
+ const border = param(r.params, 'border', 0.05);
88
+ const pu = c.metresU / c.w;
89
+ const pv = c.metresV / c.h;
90
+ const screws = [0.07, 0.93];
91
+ for (let y = 0; y < c.h; y++) {
92
+ const ym = (y + 0.5) * pv;
93
+ for (let x = 0; x < c.w; x++) {
94
+ const xm = (x + 0.5) * pu;
95
+ const i = y * c.w + x;
96
+ const inner = -rect(xm, ym, border, border, 1 - border, 1 - border);
97
+ const edge = Math.min(xm, ym, 1 - xm, 1 - ym);
98
+ const moulding = inner < 0 ? dome(Math.abs(-inner - border / 2), border / 2) : 0;
99
+ let screw = 0;
100
+ for (const sx of screws)
101
+ for (const sy of screws) screw = Math.max(screw, dome(Math.hypot(xm - sx, ym - sy), 0.012));
102
+ c.height[i] = 0.006 * moulding + 0.002 * screw - 0.002 * (1 - smooth(0, 0.004, edge));
103
+ c.tone[i] = inner > 0 ? 0.95 : 0.85 + 0.1 * moulding;
104
+ if (screw > 0) {
105
+ c.tone[i] = 0.6;
106
+ c.metal[i] = 1;
107
+ c.rough[i] = 0.35;
108
+ }
109
+ }
110
+ }
111
+ }
@@ -0,0 +1,53 @@
1
+ // Finish a region canvas (AO, normal, ORM, albedo) and blit it into the sheet. Edge texels are
2
+ // replicated `pad` deep (rows for strips, rows + columns for cells) so the first mip levels never
3
+ // sample a neighbouring region.
4
+
5
+ import type { Canvas } from './canvas.ts';
6
+ import { sobelNormals } from './normal.ts';
7
+ import { cavityOcclusion, packAlbedo, packOrm } from './orm.ts';
8
+ import type { PaintedSheet } from './types.ts';
9
+
10
+ /** An empty sheet: white albedo (vertex colour reads true), flat normal, AO 1, rough 0.8. */
11
+ export function blankSheet(size: number): PaintedSheet {
12
+ const n = size * size * 4;
13
+ const albedo = new Uint8Array(n).fill(255);
14
+ const normal = new Uint8Array(n);
15
+ const orm = new Uint8Array(n);
16
+ const flat = new Uint8Array([128, 128, 255, 255]);
17
+ const base = new Uint8Array([255, 204, 0, 255]);
18
+ for (let i = 0; i < n; i += 4) {
19
+ normal.set(flat, i);
20
+ orm.set(base, i);
21
+ }
22
+ return { size, albedo, normal, orm };
23
+ }
24
+
25
+ export function composeRegion(
26
+ sheet: PaintedSheet,
27
+ c: Canvas,
28
+ x0: number,
29
+ y0: number,
30
+ pad: number,
31
+ ): void {
32
+ const ao = cavityOcclusion(c);
33
+ const maps = [
34
+ [sheet.albedo, packAlbedo(c, ao)],
35
+ [sheet.normal, c.normalRgba ?? sobelNormals(c)],
36
+ [sheet.orm, packOrm(c, ao)],
37
+ ] as const;
38
+ const padX = c.wrapU ? 0 : pad;
39
+ for (let y = 0; y < c.h; y++) {
40
+ const sy = Math.min(c.h - 1 - pad, Math.max(pad, y));
41
+ const dst = ((y0 + y) * sheet.size + x0) * 4;
42
+ const src = sy * c.w;
43
+ const l = (src + padX) * 4;
44
+ const r = (src + c.w - 1 - padX) * 4;
45
+ for (const [to, from] of maps) {
46
+ to.set(from.subarray(l, r + 4), dst + padX * 4);
47
+ for (let x = 0; x < padX; x++) {
48
+ to.set(from.subarray(l, l + 4), dst + x * 4);
49
+ to.set(from.subarray(r, r + 4), dst + (c.w - 1 - x) * 4);
50
+ }
51
+ }
52
+ }
53
+ }
@@ -0,0 +1,62 @@
1
+ // Cast concrete (kind 'concrete'): mottled cement tone, air-void pores, pour-lift lines and
2
+ // formwork tie holes on a grid.
3
+ // params: pores 0.35 (fraction of 8 mm cells holding a void) · ties 0.6 (tie grid, m; 0 = none)
4
+ // lift 0.6 (pour lift spacing, m; 0 = none) · mottle 0.1
5
+
6
+ import { type Canvas, noiseAt, param, periodFor, smooth } from './canvas.ts';
7
+ import { hash2 } from './noise.ts';
8
+ import type { StripRecipe } from './types.ts';
9
+
10
+ const PORE_CELL = 0.008;
11
+
12
+ export function paintConcrete(c: Canvas, r: StripRecipe, seed: number): void {
13
+ const p = r.params;
14
+ const pores = param(p, 'pores', 0.35);
15
+ const ties = param(p, 'ties', 0.6);
16
+ const lift = param(p, 'lift', 0.6);
17
+ const mottle = param(p, 'mottle', 0.1);
18
+ const pu = c.metresU / c.w;
19
+ const pv = c.metresV / c.h;
20
+ const cellM = Math.max(PORE_CELL, 2.5 * Math.max(pu, pv));
21
+ const pPer = periodFor(c, cellM);
22
+ const pCell = c.wrapU ? c.metresU / pPer : cellM;
23
+ const tPer = ties > 0 ? periodFor(c, ties) : 1;
24
+ const tCell = c.wrapU ? c.metresU / tPer : ties;
25
+ for (let y = 0; y < c.h; y++) {
26
+ const ym = (y + 0.5) * pv;
27
+ const liftD = lift > 0 ? Math.abs(ym - Math.round(ym / lift) * lift) : 1;
28
+ const liftGroove = 1 - smooth(0, 0.003, liftD);
29
+ const liftBand = lift > 0 ? hash2(Math.floor(ym / lift), 0, seed + 4) - 0.5 : 0;
30
+ for (let x = 0; x < c.w; x++) {
31
+ const i = y * c.w + x;
32
+ const xm = (x + 0.5) * pu;
33
+ const big = noiseAt(c, xm, ym, 0.25, 0.25, seed, 4);
34
+ const fine = noiseAt(c, xm, ym, 0.004, 0.004, seed + 2, 2);
35
+ const ix = Math.floor(xm / pCell) % pPer;
36
+ const iy = Math.floor(ym / pCell);
37
+ let pit = 0;
38
+ if (hash2(ix, iy, seed + 5) < pores) {
39
+ const cx = (ix + 0.2 + 0.6 * hash2(ix, iy, seed + 6)) * pCell;
40
+ const cy = (iy + 0.2 + 0.6 * hash2(ix, iy, seed + 7)) * pCell;
41
+ const rad = pCell * (0.12 + 0.25 * hash2(ix, iy, seed + 8));
42
+ const d = Math.hypot(xm - cx, ym - cy);
43
+ pit = d < rad ? 1 - d / rad : 0;
44
+ }
45
+ let tie = 0;
46
+ if (ties > 0) {
47
+ const tx = xm - (Math.floor(xm / tCell) + 0.5) * tCell;
48
+ const ty = ym - (Math.floor(ym / ties) + 0.5) * ties;
49
+ const d = Math.hypot(tx, ty);
50
+ tie = d < 0.012 ? 1 : 0;
51
+ }
52
+ c.height[i] =
53
+ 0.0005 * big + 0.00015 * fine - 0.0015 * pit - 0.006 * tie - 0.0012 * liftGroove;
54
+ c.tone[i] =
55
+ (0.78 + mottle * big + 0.05 * liftBand) *
56
+ (1 + 0.04 * fine) *
57
+ (1 - 0.4 * pit) *
58
+ (1 - 0.5 * tie);
59
+ c.rough[i] = r.roughness + 0.05 * fine + 0.05 * big;
60
+ }
61
+ }
62
+ }
@@ -0,0 +1,85 @@
1
+ // Running-bond layout shared by bricks, stone, planks, slates and plates: horizontal courses
2
+ // (rows along V) split into tiles by vertical joints, staggered per course and periodic along U.
3
+ // Per-course column tables are filled once per course, so the per-pixel loop only reads arrays.
4
+
5
+ import { createRng } from '../../core/index.ts';
6
+ import type { Canvas } from './canvas.ts';
7
+
8
+ export interface CourseSpec {
9
+ /** Course height, metres (along V). */
10
+ readonly course: number;
11
+ /** Mean tile length, metres (along U). */
12
+ readonly length: number;
13
+ /** 0 = regular; 0.5 = sizes vary ±25 %. */
14
+ readonly irregular: number;
15
+ /** Fraction of a tile each odd course shifts; random offsets when irregular. */
16
+ readonly stagger: number;
17
+ readonly seed: number;
18
+ }
19
+
20
+ export class Courses {
21
+ /** Tile index within the current course, per column. */
22
+ readonly id: Int32Array;
23
+ /** Distance to the nearest vertical joint, metres, per column. */
24
+ readonly dx: Float32Array;
25
+ /** Distance from the tile's left joint, metres, per column. */
26
+ readonly ux: Float32Array;
27
+ /** The current course: index and its bottom / top in metres. */
28
+ index = -1;
29
+ y0 = 0;
30
+ y1 = 0;
31
+ private readonly bounds: number[] = [0];
32
+ private readonly c: Canvas;
33
+ private readonly spec: CourseSpec;
34
+
35
+ constructor(c: Canvas, spec: CourseSpec) {
36
+ this.c = c;
37
+ this.spec = spec;
38
+ this.id = new Int32Array(c.w);
39
+ this.dx = new Float32Array(c.w);
40
+ this.ux = new Float32Array(c.w);
41
+ const rng = createRng(spec.seed).fork('rows');
42
+ let y = 0;
43
+ while (y < c.metresV) {
44
+ y += spec.course * (1 + spec.irregular * (rng.next() - 0.5));
45
+ this.bounds.push(y);
46
+ }
47
+ }
48
+
49
+ /** Point the tables at the course containing metres `ym`; returns the course index. */
50
+ at(ym: number): number {
51
+ if (this.index >= 0 && ym >= this.y0 && ym < this.y1) return this.index;
52
+ let k = 0;
53
+ while (k < this.bounds.length - 2 && ym >= (this.bounds[k + 1] ?? 0)) k++;
54
+ this.index = k;
55
+ this.y0 = this.bounds[k] ?? 0;
56
+ this.y1 = this.bounds[k + 1] ?? this.c.metresV;
57
+ this.fill(k);
58
+ return k;
59
+ }
60
+
61
+ private fill(k: number): void {
62
+ const { w, metresU } = this.c;
63
+ const s = this.spec;
64
+ const rng = createRng(s.seed).fork(`course${k}`);
65
+ const n = Math.max(1, Math.round(metresU / s.length));
66
+ const lens: number[] = [];
67
+ for (let i = 0; i < n; i++) lens.push(1 + s.irregular * (rng.next() - 0.5));
68
+ const total = lens.reduce((a, b) => a + b, 0);
69
+ const joints = [0];
70
+ for (const l of lens) joints.push((joints[joints.length - 1] ?? 0) + (l / total) * metresU);
71
+ const shift = s.irregular > 0 ? rng.next() * metresU : (k % 2) * s.stagger * (metresU / n);
72
+ const px = metresU / w;
73
+ for (let x = 0; x < w; x++) {
74
+ let u = ((x + 0.5) * px - shift) % metresU;
75
+ if (u < 0) u += metresU;
76
+ let t = 0;
77
+ while (t < n - 1 && u >= (joints[t + 1] ?? metresU)) t++;
78
+ const a = joints[t] ?? 0;
79
+ const b = joints[t + 1] ?? metresU;
80
+ this.id[x] = t;
81
+ this.ux[x] = u - a;
82
+ this.dx[x] = Math.min(u - a, b - u);
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,106 @@
1
+ // Minimal PNG decoder for stamping supplied images into cells and image strips: 8- or 16-bit grey,
2
+ // grey+alpha, RGB, RGBA (16-bit keeps the high byte) and 8-bit palette (with tRNS), non-interlaced. Zero dependencies beyond node:zlib. Anything else
3
+ // throws T3D_RECIPE_INVALID with the conversion to make.
4
+
5
+ import { inflateSync } from 'node:zlib';
6
+ import { Ts23dError } from '../../core/index.ts';
7
+
8
+ export interface Rgba {
9
+ readonly width: number;
10
+ readonly height: number;
11
+ readonly data: Uint8Array;
12
+ }
13
+
14
+ const SIG = [137, 80, 78, 71, 13, 10, 26, 10];
15
+ const CHANNELS: Readonly<Record<number, number>> = { 0: 1, 2: 3, 3: 1, 4: 2, 6: 4 };
16
+
17
+ function bad(cause: string): never {
18
+ throw new Ts23dError('T3D_RECIPE_INVALID', {
19
+ cause: `cell image: ${cause}`,
20
+ fix: 'pass PNG bytes, 8 or 16 bits per channel, non-interlaced (e.g. re-save as RGBA8 PNG)',
21
+ });
22
+ }
23
+
24
+ function paeth(a: number, b: number, c: number): number {
25
+ const p = a + b - c;
26
+ const pa = Math.abs(p - a);
27
+ const pb = Math.abs(p - b);
28
+ const pc = Math.abs(p - c);
29
+ return pa <= pb && pa <= pc ? a : pb <= pc ? b : c;
30
+ }
31
+
32
+ export function decodePng(bytes: Uint8Array): Rgba {
33
+ if (bytes.length < 33 || SIG.some((s, i) => bytes[i] !== s)) bad('not a PNG (bad signature)');
34
+ const dv = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
35
+ let width = 0;
36
+ let height = 0;
37
+ let type = -1;
38
+ let depth = 8;
39
+ let palette: Uint8Array = new Uint8Array();
40
+ let trns: Uint8Array = new Uint8Array();
41
+ const idat: Uint8Array[] = [];
42
+ for (let o = 8; o + 8 <= bytes.length; ) {
43
+ const len = dv.getUint32(o);
44
+ const name = String.fromCharCode(...bytes.subarray(o + 4, o + 8));
45
+ const body = bytes.subarray(o + 8, o + 8 + len);
46
+ if (name === 'IHDR') {
47
+ width = dv.getUint32(o + 8);
48
+ height = dv.getUint32(o + 12);
49
+ type = body[9] ?? -1;
50
+ depth = body[8] ?? 0;
51
+ if (depth !== 8 && !(depth === 16 && type !== 3))
52
+ bad(`bit depth ${depth} (8, or 16 for non-palette images, is supported)`);
53
+ if (body[12] !== 0) bad('interlaced');
54
+ } else if (name === 'PLTE') palette = body;
55
+ else if (name === 'tRNS') trns = body;
56
+ else if (name === 'IDAT') idat.push(body);
57
+ else if (name === 'IEND') break;
58
+ o += 12 + len;
59
+ }
60
+ const ch = CHANNELS[type];
61
+ if (!ch || width === 0 || height === 0) bad(`colour type ${type} or empty image`);
62
+ const raw = new Uint8Array(inflateSync(Buffer.concat(idat)));
63
+ const B = depth / 8;
64
+ const bpp = ch * B;
65
+ const stride = width * bpp;
66
+ if (raw.length < height * (stride + 1)) bad('truncated image data');
67
+ const px = new Uint8Array(height * stride);
68
+ for (let y = 0; y < height; y++) {
69
+ const f = raw[y * (stride + 1)] ?? 0;
70
+ const src = y * (stride + 1) + 1;
71
+ const row = y * stride;
72
+ for (let x = 0; x < stride; x++) {
73
+ const a = x >= bpp ? (px[row + x - bpp] ?? 0) : 0;
74
+ const b = y > 0 ? (px[row - stride + x] ?? 0) : 0;
75
+ const c = x >= bpp && y > 0 ? (px[row - stride + x - bpp] ?? 0) : 0;
76
+ const v = raw[src + x] ?? 0;
77
+ const pred =
78
+ f === 1 ? a : f === 2 ? b : f === 3 ? (a + b) >> 1 : f === 4 ? paeth(a, b, c) : 0;
79
+ px[row + x] = (v + pred) & 255;
80
+ }
81
+ }
82
+ const data = new Uint8Array(width * height * 4);
83
+ for (let i = 0; i < width * height; i++) {
84
+ const s = i * bpp;
85
+ const at = (k: number): number => px[s + k * B] ?? 0;
86
+ const g = at(0);
87
+ const o = i * 4;
88
+ if (type === 3) {
89
+ data[o] = palette[g * 3] ?? 0;
90
+ data[o + 1] = palette[g * 3 + 1] ?? 0;
91
+ data[o + 2] = palette[g * 3 + 2] ?? 0;
92
+ data[o + 3] = trns[g] ?? 255;
93
+ } else if (ch >= 3) {
94
+ data[o] = g;
95
+ data[o + 1] = at(1);
96
+ data[o + 2] = at(2);
97
+ data[o + 3] = ch === 4 ? at(3) : 255;
98
+ } else {
99
+ data[o] = g;
100
+ data[o + 1] = g;
101
+ data[o + 2] = g;
102
+ data[o + 3] = ch === 2 ? at(1) : 255;
103
+ }
104
+ }
105
+ return { width, height, data };
106
+ }
@@ -0,0 +1,73 @@
1
+ // The house sheet: every strip and cell. Classic strips stay near-greyscale and bright (vertex
2
+ // colour carries hue); the material library strips carry measured colour. Each strip reads at its
3
+ // typical face height (`scaleMetres`). `HOUSE_STRIPS` is the one mutable table: defineMaterial()
4
+ // adds project strips to it, so `DEFAULT_SHEET` always paints every strip the layout knows.
5
+
6
+ import { MATERIAL_LIBRARY } from '../library.ts';
7
+ import { toStripRecipe } from '../material-def.ts';
8
+ import type { StripId } from '../trim-sheet.ts';
9
+ import type { SheetRecipe, StripRecipe } from './types.ts';
10
+
11
+ const leaf: StripRecipe = { kind: 'flat', scaleMetres: 1, roughness: 0.6 };
12
+
13
+ const library = Object.fromEntries(
14
+ Object.values(MATERIAL_LIBRARY).map((d) => [d.id, toStripRecipe(d)]),
15
+ );
16
+
17
+ export const HOUSE_STRIPS: Partial<Record<StripId, StripRecipe>> = {
18
+ plain: { kind: 'noise', scaleMetres: 1, roughness: 0.6 },
19
+ brick: { kind: 'bond', scaleMetres: 0.45, roughness: 0.85, params: { grime: 0.2 } },
20
+ stone: {
21
+ kind: 'bond',
22
+ scaleMetres: 0.9,
23
+ roughness: 0.9,
24
+ params: {
25
+ course: 0.22,
26
+ length: 0.4,
27
+ mortar: 0.016,
28
+ depth: 0.012,
29
+ bevel: 0.025,
30
+ irregular: 0.5,
31
+ relief: 0.004,
32
+ variation: 0.3,
33
+ grime: 0.2,
34
+ },
35
+ },
36
+ slate: { kind: 'slate', scaleMetres: 0.66, roughness: 0.7 },
37
+ iron: { kind: 'plates', scaleMetres: 0.5, roughness: 0.55, metalness: 0 },
38
+ wood: { kind: 'planks', scaleMetres: 0.6, roughness: 0.75 },
39
+ glass: { kind: 'glass', scaleMetres: 1, roughness: 0.05 },
40
+ concrete: { kind: 'concrete', scaleMetres: 1, roughness: 0.9, params: { grime: 0.3 } },
41
+ ...library,
42
+ };
43
+
44
+ export const DEFAULT_SHEET: SheetRecipe = {
45
+ seed: 1,
46
+ size: 2048,
47
+ strips: HOUSE_STRIPS,
48
+ cells: {
49
+ window_sash: { kind: 'noise', scaleMetres: 1, roughness: 0.5 },
50
+ door_panel: { kind: 'noise', scaleMetres: 1, roughness: 0.6 },
51
+ clock: { kind: 'noise', scaleMetres: 1, roughness: 0.3 },
52
+ smokebox: {
53
+ kind: 'plates',
54
+ scaleMetres: 1,
55
+ roughness: 0.6,
56
+ metalness: 0.2,
57
+ params: { rust: 0.3 },
58
+ },
59
+ sign: { kind: 'noise', scaleMetres: 1, roughness: 0.5 },
60
+ porthole: { kind: 'plates', scaleMetres: 1, roughness: 0.5 },
61
+ foliage_broadleaf: leaf,
62
+ foliage_maple: leaf,
63
+ foliage_maple_autumn: leaf,
64
+ foliage_birch: leaf,
65
+ foliage_acacia: leaf,
66
+ foliage_palm: leaf,
67
+ foliage_spruce: leaf,
68
+ foliage_spruce_snow: leaf,
69
+ foliage_willow: leaf,
70
+ foliage_reeds: leaf,
71
+ foliage_needles: leaf,
72
+ },
73
+ };
@@ -0,0 +1,63 @@
1
+ // Soft goods. 'weave': canvas / duck cloth — an over-under thread lattice (warp along U, weft
2
+ // along V, never finer than the texel), slubbed threads, soft folds and water stains toward the
3
+ // bottom. 'leather': pebbled grain, creases running across the hide and burnished wear where it
4
+ // is handled (smoother, a little lighter, darker in the creases).
5
+ // params (weave): pitch 0.004 · folds 0.6 · stains 0.3
6
+ // params (leather): pebble 0.004 · creases 0.5 · wear 0.4
7
+
8
+ import { type Canvas, noiseAt, param, smooth } from './canvas.ts';
9
+ import type { StripRecipe } from './types.ts';
10
+
11
+ export function paintWeave(c: Canvas, r: StripRecipe, seed: number): void {
12
+ const p = r.params;
13
+ const pu = c.metresU / c.w;
14
+ const pv = c.metresV / c.h;
15
+ // Threads below ~2 texels alias into moiré: keep the lattice resolvable on both axes.
16
+ const pitchU = Math.max(param(p, 'pitch', 0.004), 2 * pu);
17
+ const pitchV = Math.max(param(p, 'pitch', 0.004), 2 * pv);
18
+ const folds = param(p, 'folds', 0.6);
19
+ const stains = param(p, 'stains', 0.3);
20
+ for (let y = 0; y < c.h; y++) {
21
+ const ym = (y + 0.5) * pv;
22
+ const wy = Math.sin((ym / pitchV) * Math.PI * 2);
23
+ for (let x = 0; x < c.w; x++) {
24
+ const i = y * c.w + x;
25
+ const xm = (x + 0.5) * pu;
26
+ const wx = Math.sin((xm / pitchU) * Math.PI * 2);
27
+ const over = Math.floor(xm / pitchU) + Math.floor(ym / pitchV);
28
+ const thread = over % 2 === 0 ? Math.abs(wy) : Math.abs(wx);
29
+ const slub = noiseAt(c, xm, ym, 0.05, 0.01, seed, 2);
30
+ const fold = noiseAt(c, xm, ym, 0.5, 0.35, seed + 1, 3);
31
+ const stain = stains * smooth(0.1, 0.6, noiseAt(c, xm, ym, 0.2, 0.15, seed + 2, 4));
32
+ c.height[i] = 0.0002 * thread + 0.003 * folds * fold;
33
+ c.tone[i] = (0.9 + 0.06 * thread + 0.05 * slub) * (1 - 0.25 * stain);
34
+ c.rough[i] = Math.min(1, r.roughness + 0.04 * slub - 0.03 * thread);
35
+ c.metal[i] = 0;
36
+ c.mix[i] = stain;
37
+ }
38
+ }
39
+ }
40
+
41
+ export function paintLeather(c: Canvas, r: StripRecipe, seed: number): void {
42
+ const p = r.params;
43
+ const pu = c.metresU / c.w;
44
+ const pv = c.metresV / c.h;
45
+ const pebble = param(p, 'pebble', 0.004);
46
+ const creases = param(p, 'creases', 0.5);
47
+ const wear = param(p, 'wear', 0.4);
48
+ for (let y = 0; y < c.h; y++) {
49
+ const ym = (y + 0.5) * pv;
50
+ for (let x = 0; x < c.w; x++) {
51
+ const i = y * c.w + x;
52
+ const xm = (x + 0.5) * pu;
53
+ const grain = noiseAt(c, xm, ym, pebble, pebble, seed, 3);
54
+ const crease = smooth(0.4, 0.6, noiseAt(c, xm, ym, 0.12, 0.012, seed + 1, 3)) * creases;
55
+ const rub = wear * smooth(0, 0.6, noiseAt(c, xm, ym, 0.3, 0.3, seed + 2, 4));
56
+ c.height[i] = 0.00025 * grain - 0.0008 * crease;
57
+ c.tone[i] = (0.95 + 0.05 * grain) * (1 - 0.45 * crease) * (1 + 0.12 * rub);
58
+ c.rough[i] = Math.min(1, Math.max(0, r.roughness + 0.06 * grain - 0.2 * rub + 0.1 * crease));
59
+ c.metal[i] = 0;
60
+ c.mix[i] = crease;
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,126 @@
1
+ // Broadleaf foliage cells: a twig grows from the bottom-centre anchor toward +V, side twigs
2
+ // alternate off it, leaves sit at the nodes. A darker back layer of leaves fills the crown first
3
+ // for depth. Variants: beech/oak cluster (ovate, fine teeth), palmate maple, autumn maple
4
+ // (red/orange/yellow per leaf), birch (small serrated leaves on thin drooping twigs).
5
+
6
+ import { createRng, type Rng } from '../../core/index.ts';
7
+ import type { Canvas } from './canvas.ts';
8
+ import { AUTUMN, at, curve, dim, drawStem, LEAF, vary } from './foliage-common.ts';
9
+ import { Foliage, type LeafShape, type Rgb } from './foliage-raster.ts';
10
+
11
+ interface ClusterSpec {
12
+ readonly shape: LeafShape;
13
+ readonly len: number;
14
+ readonly wid: number;
15
+ readonly serrate: number;
16
+ readonly twigs: number;
17
+ readonly perTwig: number;
18
+ readonly back: number;
19
+ /** Side-twig droop: 0 = straight out, 1 = bends back down. */
20
+ readonly droop: number;
21
+ readonly colour: (rng: Rng) => Rgb;
22
+ }
23
+
24
+ function cluster(c: Canvas, seed: number, s: ClusterSpec): void {
25
+ const rng = createRng(seed);
26
+ const f = new Foliage(c);
27
+ const leafAt = (x: number, y: number, a: number, k: number, lift: number): void => {
28
+ const len = s.len * rng.range(0.8, 1.15) * k;
29
+ f.leaf(s.shape, x, y, a, len, s.wid * (len / s.len), s.colour(rng), s.serrate, lift);
30
+ };
31
+ // Back layer: darker, unattached leaves filling the crown silhouette.
32
+ for (let i = 0; i < s.back; i++) {
33
+ const x = 0.5 + rng.range(-0.33, 0.33);
34
+ const y = rng.range(0.3, 0.85);
35
+ const col = dim(s.colour(rng), 0.5);
36
+ const len = s.len * rng.range(0.8, 1.1);
37
+ f.leaf(s.shape, x, y, rng.range(-1.4, 1.4), len, s.wid * (len / s.len), col, s.serrate);
38
+ }
39
+ const main = curve(
40
+ 0.5,
41
+ 0.02,
42
+ 0.5 + rng.range(-0.1, 0.1),
43
+ 0.45,
44
+ 0.5 + rng.range(-0.08, 0.08),
45
+ 0.8,
46
+ );
47
+ drawStem(f, main, 0.016, 0.004, LEAF.twig);
48
+ for (let k = 0; k < s.twigs; k++) {
49
+ const t = 0.22 + (k / Math.max(1, s.twigs - 1)) * 0.6;
50
+ const side = k % 2 === 0 ? 1 : -1;
51
+ const i = at(main, t);
52
+ const bx = main.x[i] ?? 0.5;
53
+ const by = main.y[i] ?? 0.5;
54
+ const a = (main.a[i] ?? 0) + side * rng.range(0.7, 1.1);
55
+ const len = 0.3 * (1 - t * 0.45);
56
+ const ex = bx + Math.sin(a) * len;
57
+ const ey = by + Math.cos(a) * len - s.droop * len * 0.4;
58
+ const twig = curve(bx, by, (bx + ex) / 2, (by + ey) / 2 + len * 0.15, ex, ey, 8);
59
+ drawStem(f, twig, 0.007, 0.002, LEAF.twig);
60
+ for (let q = 1; q <= s.perTwig; q++) {
61
+ const j = at(twig, q / s.perTwig);
62
+ const alt = q % 2 === 0 ? 1 : -1;
63
+ const ta = (twig.a[j] ?? 0) + (q === s.perTwig ? 0 : alt * rng.range(0.5, 0.9));
64
+ leafAt(twig.x[j] ?? 0, twig.y[j] ?? 0, ta, 1 - 0.15 * (1 - q / s.perTwig), 0.002);
65
+ }
66
+ }
67
+ const tip = main.x.length - 1;
68
+ leafAt(main.x[tip] ?? 0.5, main.y[tip] ?? 0.8, main.a[tip] ?? 0, 1.1, 0.003);
69
+ f.finish(0.5, 0.35);
70
+ }
71
+
72
+ export function paintBroadleaf(c: Canvas, seed: number): void {
73
+ cluster(c, seed, {
74
+ shape: 'ovate',
75
+ len: 0.15,
76
+ wid: 0.085,
77
+ serrate: 0.03,
78
+ twigs: 6,
79
+ perTwig: 3,
80
+ back: 16,
81
+ droop: 0.1,
82
+ colour: (rng) => vary(rng, LEAF.beech, 0.18),
83
+ });
84
+ }
85
+
86
+ export function paintMaple(c: Canvas, seed: number): void {
87
+ cluster(c, seed, {
88
+ shape: 'palmate',
89
+ len: 0.24,
90
+ wid: 0.24,
91
+ serrate: 0.04,
92
+ twigs: 4,
93
+ perTwig: 2,
94
+ back: 7,
95
+ droop: 0,
96
+ colour: (rng) => vary(rng, LEAF.maple, 0.15),
97
+ });
98
+ }
99
+
100
+ export function paintMapleAutumn(c: Canvas, seed: number): void {
101
+ cluster(c, seed, {
102
+ shape: 'palmate',
103
+ len: 0.24,
104
+ wid: 0.24,
105
+ serrate: 0.04,
106
+ twigs: 4,
107
+ perTwig: 2,
108
+ back: 7,
109
+ droop: 0,
110
+ colour: (rng) => vary(rng, rng.pick(AUTUMN), 0.12),
111
+ });
112
+ }
113
+
114
+ export function paintBirch(c: Canvas, seed: number): void {
115
+ cluster(c, seed, {
116
+ shape: 'ovate',
117
+ len: 0.085,
118
+ wid: 0.06,
119
+ serrate: 0.12,
120
+ twigs: 8,
121
+ perTwig: 5,
122
+ back: 22,
123
+ droop: 0.6,
124
+ colour: (rng) => vary(rng, LEAF.birch, 0.2),
125
+ });
126
+ }