@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,17 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/passes/ray-grid.ts", "../src/passes/bake-ao.ts", "../src/passes/grime.ts", "../src/passes/livery.ts", "../src/passes/optimize-cache.ts", "../src/passes/optimize-weld.ts", "../src/passes/optimize.ts", "../src/passes/weighted-normals.ts"],
4
+ "sourcesContent": [
5
+ "// Ray casting for bakes: triangles bucketed in a uniform 3D grid (CSR, typed arrays), walked\n// with Amanatides–Woo DDA, tested with Möller–Trumbore. Answers \"does this ray hit anything\n// within `tMax`?\" — all an occlusion bake needs. Allocation-free per ray, deterministic.\n\nimport { boundsOf, type Mesh, type Vec3 } from '../core/index.ts';\n\nconst CELL_SCALE = 0.3;\n\nexport class RayGrid {\n private readonly tri: Float64Array;\n /** Per triangle: v0, e1 = v1 − v0, e2 = v2 − v0 (Möller–Trumbore inputs, computed once). */\n private readonly edges: Float64Array;\n /** Per triangle: unnormalised plane normal e1 × e2 and its offset n·v0. */\n private readonly planes: Float64Array;\n private readonly start: Int32Array;\n private readonly list: Int32Array;\n private readonly min: Vec3;\n private readonly res: [number, number, number];\n private readonly cell: number;\n private readonly stamp: Int32Array;\n private ray = 0;\n\n constructor(mesh: Mesh) {\n const n = mesh.indices.length / 3;\n this.tri = new Float64Array(n * 9);\n for (let t = 0; t < n; t++)\n for (let v = 0; v < 3; v++) {\n const i = (mesh.indices[t * 3 + v] ?? 0) * 3;\n for (let k = 0; k < 3; k++) this.tri[t * 9 + v * 3 + k] = mesh.positions[i + k] ?? 0;\n }\n this.edges = new Float64Array(n * 9);\n for (let t = 0; t < n; t++) {\n const o = t * 9;\n for (let k = 0; k < 3; k++) {\n const v0 = this.tri[o + k] ?? 0;\n this.edges[o + k] = v0;\n this.edges[o + 3 + k] = (this.tri[o + 3 + k] ?? 0) - v0;\n this.edges[o + 6 + k] = (this.tri[o + 6 + k] ?? 0) - v0;\n }\n }\n this.planes = new Float64Array(n * 4);\n for (let t = 0; t < n; t++) {\n const E = this.edges;\n const o = t * 9;\n const [ax, ay, az] = [E[o + 3] ?? 0, E[o + 4] ?? 0, E[o + 5] ?? 0];\n const [bx, by, bz] = [E[o + 6] ?? 0, E[o + 7] ?? 0, E[o + 8] ?? 0];\n const nx = ay * bz - az * by;\n const ny = az * bx - ax * bz;\n const nz = ax * by - ay * bx;\n this.planes.set(\n [nx, ny, nz, nx * (E[o] ?? 0) + ny * (E[o + 1] ?? 0) + nz * (E[o + 2] ?? 0)],\n t * 4,\n );\n }\n const b = boundsOf(mesh);\n const span = [0, 1, 2].map((k) => Math.max(1e-6, (b.max[k] ?? 0) - (b.min[k] ?? 0)));\n // Cells ~0.3× the \"two triangles per cell if they filled the volume\" size: triangles live\n // on surfaces, so that size leaves a dozen per occupied cell. Measured on tiger_1 and a\n // sculpted head (0.2–0.5 is flat; larger cells cost 2–4×). Bounded to 256 per axis and\n // ~4M cells overall. Any cell size gives the same answers; only the speed changes.\n const vol = (span[0] ?? 1) * (span[1] ?? 1) * (span[2] ?? 1);\n this.cell = Math.max(\n CELL_SCALE * Math.cbrt(vol / Math.max(1, n / 2)),\n Math.max(...span) / 256,\n Math.cbrt(vol / 4e6),\n 1e-4,\n );\n this.min = [b.min[0] - 1e-6, b.min[1] - 1e-6, b.min[2] - 1e-6];\n this.res = [0, 1, 2].map((k) => Math.max(1, Math.ceil((span[k] ?? 0) / this.cell) + 1)) as [\n number,\n number,\n number,\n ];\n const [rx, ry] = this.res;\n const cells = rx * ry * this.res[2];\n // Each triangle's cell box once, then a counting pass and a fill pass (CSR, t ascending).\n const box = new Int32Array(n * 6);\n const T = this.tri;\n for (let t = 0; t < n; t++)\n for (let k = 0; k < 3; k++) {\n const a = T[t * 9 + k] ?? 0;\n const b2 = T[t * 9 + 3 + k] ?? 0;\n const c = T[t * 9 + 6 + k] ?? 0;\n box[t * 6 + k] = this.coord(Math.min(a, b2, c), k);\n box[t * 6 + 3 + k] = this.coord(Math.max(a, b2, c), k);\n }\n const count = new Int32Array(cells + 1);\n const visit = (t: number, f: (c: number) => void): void => {\n const o = t * 6;\n for (let x = box[o] ?? 0; x <= (box[o + 3] ?? 0); x++)\n for (let y = box[o + 1] ?? 0; y <= (box[o + 4] ?? 0); y++)\n for (let z = box[o + 2] ?? 0; z <= (box[o + 5] ?? 0); z++) f((z * ry + y) * rx + x);\n };\n const bump = (c: number): void => {\n count[c + 1] = (count[c + 1] ?? 0) + 1;\n };\n for (let t = 0; t < n; t++) visit(t, bump);\n for (let c = 0; c < cells; c++) count[c + 1] = (count[c + 1] ?? 0) + (count[c] ?? 0);\n this.start = count;\n const list = new Int32Array(count[cells] ?? 0);\n const fill = new Int32Array(cells);\n for (let t = 0; t < n; t++)\n visit(t, (c) => {\n list[(count[c] ?? 0) + (fill[c] ?? 0)] = t;\n fill[c] = (fill[c] ?? 0) + 1;\n });\n this.list = list;\n this.stamp = new Int32Array(n);\n }\n\n private coord(v: number, k: number): number {\n const r = this.res[k as 0 | 1 | 2];\n return Math.min(\n r - 1,\n Math.max(0, Math.floor((v - (this.min[k as 0 | 1 | 2] ?? 0)) / this.cell)),\n );\n }\n\n /** Any hit of the ray o + t·d (d unit) for 0 < t ≤ tMax. Scalar arguments: no allocation. */\n hit(\n ox: number,\n oy: number,\n oz: number,\n dx: number,\n dy: number,\n dz: number,\n tMax: number,\n ): boolean {\n const q = ++this.ray;\n const start = this.start;\n const list = this.list;\n const stamp = this.stamp;\n const size = this.cell;\n const [rx, ry, rz] = this.res;\n const [mx, my, mz] = this.min;\n let cx = this.coord(ox, 0);\n let cy = this.coord(oy, 1);\n let cz = this.coord(oz, 2);\n const sx = dx > 0 ? 1 : -1;\n const sy = dy > 0 ? 1 : -1;\n const sz = dz > 0 ? 1 : -1;\n let nx = Math.abs(dx) < 1e-12 ? Infinity : (mx + (cx + (dx > 0 ? 1 : 0)) * size - ox) / dx;\n let ny = Math.abs(dy) < 1e-12 ? Infinity : (my + (cy + (dy > 0 ? 1 : 0)) * size - oy) / dy;\n let nz = Math.abs(dz) < 1e-12 ? Infinity : (mz + (cz + (dz > 0 ? 1 : 0)) * size - oz) / dz;\n const ddx = Math.abs(dx) < 1e-12 ? Infinity : size / Math.abs(dx);\n const ddy = Math.abs(dy) < 1e-12 ? Infinity : size / Math.abs(dy);\n const ddz = Math.abs(dz) < 1e-12 ? Infinity : size / Math.abs(dz);\n let t = 0;\n while (t <= tMax) {\n const c = (cz * ry + cy) * rx + cx;\n const end = start[c + 1] ?? 0;\n for (let i = start[c] ?? 0; i < end; i++) {\n const tri = list[i] ?? 0;\n if (stamp[tri] === q) continue;\n stamp[tri] = q;\n if (this.test(tri, ox, oy, oz, dx, dy, dz, tMax)) return true;\n }\n if (nx < ny) {\n if (nx < nz) {\n t = nx;\n cx += sx;\n if (cx < 0 || cx >= rx) return false;\n nx = t + ddx;\n } else {\n t = nz;\n cz += sz;\n if (cz < 0 || cz >= rz) return false;\n nz = t + ddz;\n }\n } else if (ny < nz) {\n t = ny;\n cy += sy;\n if (cy < 0 || cy >= ry) return false;\n ny = t + ddy;\n } else {\n t = nz;\n cz += sz;\n if (cz < 0 || cz >= rz) return false;\n nz = t + ddz;\n }\n }\n return false;\n }\n\n /** Möller–Trumbore on cached v0, e1, e2 (the same arithmetic as deriving them per ray). */\n private test(\n tri: number,\n ox: number,\n oy: number,\n oz: number,\n dx: number,\n dy: number,\n dz: number,\n tMax: number,\n ): boolean {\n // Plane pre-reject: the hit distance along the ray, from two dot products. Only clear misses\n // (behind the origin, or past tMax, with margin) are skipped; Möller–Trumbore decides the rest.\n const P = this.planes;\n const f = tri * 4;\n const nx = P[f] ?? 0;\n const ny = P[f + 1] ?? 0;\n const nz = P[f + 2] ?? 0;\n const th0 = ((P[f + 3] ?? 0) - (nx * ox + ny * oy + nz * oz)) / (nx * dx + ny * dy + nz * dz);\n if (!(th0 > -1e-9 && th0 <= tMax * (1 + 1e-9) + 1e-9)) return false;\n const E = this.edges;\n const b = tri * 9;\n const e1x = E[b + 3] ?? 0;\n const e1y = E[b + 4] ?? 0;\n const e1z = E[b + 5] ?? 0;\n const e2x = E[b + 6] ?? 0;\n const e2y = E[b + 7] ?? 0;\n const e2z = E[b + 8] ?? 0;\n const px = dy * e2z - dz * e2y;\n const py = dz * e2x - dx * e2z;\n const pz = dx * e2y - dy * e2x;\n const det = e1x * px + e1y * py + e1z * pz;\n if (Math.abs(det) < 1e-14) return false;\n const inv = 1 / det;\n const tx = ox - (E[b] ?? 0);\n const ty = oy - (E[b + 1] ?? 0);\n const tz = oz - (E[b + 2] ?? 0);\n const u = (tx * px + ty * py + tz * pz) * inv;\n if (u < 0 || u > 1) return false;\n const qx = ty * e1z - tz * e1y;\n const qy = tz * e1x - tx * e1z;\n const qz = tx * e1y - ty * e1x;\n const v = (dx * qx + dy * qy + dz * qz) * inv;\n if (v < 0 || u + v > 1) return false;\n const th = (e2x * qx + e2y * qy + e2z * qz) * inv;\n return th > 0 && th <= tMax;\n }\n\n /** True if the ray o + t·d (d unit) hits any triangle for 0 < t ≤ tMax. */\n occluded(o: Vec3, d: Vec3, tMax: number): boolean {\n return this.hit(o[0], o[1], o[2], d[0], d[1], d[2], tMax);\n }\n}\n",
6
+ "// Ambient occlusion baked into vertex colour: the cheapest big look upgrade for a vertex-coloured\n// asset — creases, wheel wells and the gap under a turret darken, as a lit render would. Each\n// vertex fires a fixed cosine-weighted hemisphere of rays (Fibonacci spiral, no randomness) at the\n// asset's own triangles (and optionally the ground plane); the hit fraction darkens its colour.\n\nimport { type CompiledAsset, type Mesh, merge, type Vec3, worldMeshes } from '../core/index.ts';\nimport { RayGrid } from './ray-grid.ts';\n\nexport interface AoOptions {\n /** Rays per vertex. Default 24. */\n readonly samples?: number;\n /** Occluders farther than this (metres) don't count. Default 1. */\n readonly radius?: number;\n /** 0 = no change, 1 = fully occluded vertices go black. Default 0.6. */\n readonly strength?: number;\n /** Treat z = 0 as a ground plane (contact shadow under the asset). Default true. */\n readonly ground?: boolean;\n}\n\nconst GOLDEN = Math.PI * (3 - Math.sqrt(5));\n\n/** Fixed cosine-weighted directions around +Z. */\nfunction hemisphere(n: number): Vec3[] {\n return Array.from({ length: n }, (_, i) => {\n const r = Math.sqrt((i + 0.5) / n);\n const phi = i * GOLDEN;\n return [r * Math.cos(phi), r * Math.sin(phi), Math.sqrt(Math.max(0, 1 - r * r))] as Vec3;\n });\n}\n\n/** Orthonormal frame with `n` as its Z (Frisvad / Duff et al. branchless basis). */\nfunction frame(n: Vec3): [Vec3, Vec3] {\n const s = n[2] >= 0 ? 1 : -1;\n const a = -1 / (s + n[2]);\n const b = n[0] * n[1] * a;\n return [\n [1 + s * n[0] * n[0] * a, s * b, -s * n[0]],\n [b, s + n[1] * n[1] * a, -n[1]],\n ];\n}\n\n/**\n * Vertices sharing a position (0.1 mm) and normal (0.001) share one result: welded seams and\n * duplicated soup vertices cost one hemisphere, not many. Open addressing on the six integers.\n */\nclass Memo {\n private readonly keys: Float64Array;\n private readonly vals: Float64Array;\n private readonly used: Uint8Array;\n private readonly mask: number;\n\n constructor(n: number) {\n let cap = 16;\n while (cap < n * 2) cap *= 2;\n this.mask = cap - 1;\n this.keys = new Float64Array(cap * 6);\n this.vals = new Float64Array(cap);\n this.used = new Uint8Array(cap);\n }\n\n /** Slot for the key; `found` tells whether it already holds a value. */\n slot(k: Float64Array): { at: number; found: boolean } {\n let h = 2166136261;\n for (let i = 0; i < 6; i++) h = Math.imul(h ^ ((k[i] ?? 0) | 0), 16777619);\n let at = (h >>> 0) & this.mask;\n for (;;) {\n if (!this.used[at]) return { at, found: false };\n let same = true;\n for (let i = 0; i < 6 && same; i++) same = this.keys[at * 6 + i] === k[i];\n if (same) return { at, found: true };\n at = (at + 1) & this.mask;\n }\n }\n\n get(at: number): number {\n return this.vals[at] ?? 0;\n }\n\n set(at: number, k: Float64Array, v: number): void {\n this.used[at] = 1;\n this.keys.set(k, at * 6);\n this.vals[at] = v;\n }\n}\n\n/** Per-vertex visibility (1 = open sky, 0 = buried) of `mesh` against `grid`. */\nfunction visibility(mesh: Mesh, grid: RayGrid, o: AoOptions): Float32Array {\n const hemi = hemisphere(o.samples ?? 24);\n const D = Float64Array.from(hemi.flat());\n const count = hemi.length;\n const radius = o.radius ?? 1;\n const ground = o.ground ?? true;\n const P = mesh.positions;\n const N = mesh.normals;\n const out = new Float32Array(P.length / 3);\n const memo = new Memo(out.length);\n const key = new Float64Array(6);\n // Lift off the surface so a ray never hits the face it starts on.\n const bias = 2e-3;\n for (let v = 0; v < out.length; v++) {\n const px = P[v * 3] ?? 0;\n const py = P[v * 3 + 1] ?? 0;\n const pz = P[v * 3 + 2] ?? 0;\n const rx = N[v * 3] ?? 0;\n const ry = N[v * 3 + 1] ?? 0;\n const rz = N[v * 3 + 2] ?? 1;\n const len = Math.hypot(rx, ry, rz) || 1;\n const n: Vec3 = [rx / len, ry / len, rz / len];\n key[0] = Math.round(px * 1e4);\n key[1] = Math.round(py * 1e4);\n key[2] = Math.round(pz * 1e4);\n key[3] = Math.round(n[0] * 1e3);\n key[4] = Math.round(n[1] * 1e3);\n key[5] = Math.round(n[2] * 1e3);\n const s = memo.slot(key);\n if (s.found) {\n out[v] = memo.get(s.at);\n continue;\n }\n const [t, b] = frame(n);\n const ox = px + n[0] * bias;\n const oy = py + n[1] * bias;\n const oz = pz + n[2] * bias;\n let blocked = 0;\n for (let i = 0; i < count; i++) {\n const d0 = D[i * 3] ?? 0;\n const d1 = D[i * 3 + 1] ?? 0;\n const d2 = D[i * 3 + 2] ?? 0;\n const wx = t[0] * d0 + b[0] * d1 + n[0] * d2;\n const wy = t[1] * d0 + b[1] * d1 + n[1] * d2;\n const wz = t[2] * d0 + b[2] * d1 + n[2] * d2;\n if (ground && wz < -1e-6 && oz >= 0 && -oz / wz <= radius) blocked++;\n else if (grid.hit(ox, oy, oz, wx, wy, wz, radius)) blocked++;\n }\n const vis = 1 - blocked / count;\n memo.set(s.at, key, vis);\n out[v] = vis;\n }\n return out;\n}\n\nconst darken = (mesh: Mesh, vis: Float32Array, strength: number): Mesh => {\n const colors = new Float32Array(mesh.colors);\n for (let v = 0; v < vis.length; v++) {\n const f = 1 - strength * (1 - (vis[v] ?? 1));\n for (let k = 0; k < 3; k++) colors[v * 3 + k] = (colors[v * 3 + k] ?? 0) * f;\n }\n return { ...mesh, colors };\n};\n\n/** Bake AO of one mesh against itself (or `occluder`, in the same space). */\n// Callers bake several parts against one occluder (a head's skin, jaw and eyes against the\n// whole head): index each occluder once. Meshes are immutable, so the grid stays valid.\nconst grids = new WeakMap<Mesh, RayGrid>();\nconst gridOf = (m: Mesh): RayGrid => {\n const hit = grids.get(m);\n if (hit) return hit;\n const g = new RayGrid(m);\n grids.set(m, g);\n return g;\n};\n\nexport function bakeAo(mesh: Mesh, o: AoOptions = {}, occluder: Mesh = mesh): Mesh {\n return darken(mesh, visibility(mesh, gridOf(occluder), o), o.strength ?? 0.6);\n}\n\n/**\n * Bake AO across a whole compiled asset: every part is occluded by every other (a wheel darkens\n * the hull behind it). Colours only change, so parts keep their local meshes and pivots.\n */\nexport function bakeAoAsset(asset: CompiledAsset, o: AoOptions = {}): CompiledAsset {\n const world = worldMeshes(asset.parts);\n if (world.size === 0) return asset;\n const grid = new RayGrid(merge([...world.values()]));\n const strength = o.strength ?? 0.6;\n return {\n ...asset,\n parts: asset.parts.map((p) => {\n const w = world.get(p.name);\n return p.mesh && w ? { ...p, mesh: darken(p.mesh, visibility(w, grid, o), strength) } : p;\n }),\n };\n}\n",
7
+ "// Grime: darken vertex colour near the ground and in named zones (soot, mud, dust). A pass over a\n// finished mesh, so recipes stay about shape; wear is applied once, the same way everywhere.\n\nimport type { Mesh, Vec3 } from '../core/index.ts';\n\nexport interface GrimeZone {\n readonly at: Vec3;\n readonly radius: number;\n /** 0..1 darkening at the centre. */\n readonly strength: number;\n}\n\nexport interface GrimeOptions {\n /** Height (m) below which mud/dust builds up toward the ground. */\n readonly ground?: number;\n /** Darkening at z = 0. */\n readonly groundStrength?: number;\n readonly zones?: readonly GrimeZone[];\n}\n\nexport function grime(mesh: Mesh, o: GrimeOptions): Mesh {\n const colors = new Float32Array(mesh.colors);\n const g = o.ground ?? 0;\n const gs = o.groundStrength ?? 0.3;\n for (let i = 0; i < mesh.positions.length / 3; i++) {\n const x = mesh.positions[i * 3] ?? 0;\n const y = mesh.positions[i * 3 + 1] ?? 0;\n const z = mesh.positions[i * 3 + 2] ?? 0;\n let f = g > 0 && z < g ? 1 - gs * (1 - Math.max(0, z) / g) : 1;\n for (const zone of o.zones ?? []) {\n const d = Math.hypot(x - zone.at[0], y - zone.at[1], z - zone.at[2]) / zone.radius;\n if (d < 1) f *= 1 - zone.strength * (1 - d);\n }\n for (let k = 0; k < 3; k++) colors[i * 3 + k] = (colors[i * 3 + k] ?? 1) * f;\n }\n return { ...mesh, colors };\n}\n",
8
+ "// Livery: paint a finished mesh by rules instead of by hand. Base colour, then ordered rules —\n// the last matching rule wins — keyed on height bands, an along-length range, a side-elevation\n// polygon (stripes, wings, numbers' backgrounds), and surface orientation (roof, front, back,\n// sides, underside). One call turns a grey loco into \"Daylight\", a tank into its camo scheme.\n\nimport type { Mesh, Vec2, Vec3 } from '../core/index.ts';\n\nexport interface LiveryRule {\n readonly color: Vec3;\n /** Height band [z0, z1] (metres). */\n readonly z?: readonly [number, number];\n /** Along-length band [x0, x1] (metres, +X forward). */\n readonly x?: readonly [number, number];\n /** Polygon in the side elevation (x, z): the region a stripe or panel covers. */\n readonly poly?: readonly Vec2[];\n /** Only faces whose normal points this way (n·axis > 0.5; roof: n.z > 0.55). */\n readonly facing?: 'roof' | 'under' | 'front' | 'back' | 'side';\n /** Multiply into the existing colour instead of replacing it (weathering, shading). */\n readonly multiply?: boolean;\n}\n\nexport interface Livery {\n readonly base?: Vec3;\n readonly rules: readonly LiveryRule[];\n}\n\nfunction inPoly(poly: readonly Vec2[], x: number, z: number): boolean {\n let inside = false;\n for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {\n const [xi, zi] = poly[i] ?? [0, 0];\n const [xj, zj] = poly[j] ?? [0, 0];\n if (zi > z !== zj > z && x < ((xj - xi) * (z - zi)) / (zj - zi) + xi) inside = !inside;\n }\n return inside;\n}\n\nfunction faces(f: NonNullable<LiveryRule['facing']>, n: Vec3): boolean {\n if (f === 'roof') return n[2] > 0.55;\n if (f === 'under') return n[2] < -0.55;\n if (f === 'front') return n[0] > 0.5;\n if (f === 'back') return n[0] < -0.5;\n return Math.abs(n[1]) > 0.5;\n}\n\nexport function livery(mesh: Mesh, l: Livery): Mesh {\n const colors = new Float32Array(mesh.colors);\n for (let i = 0; i < mesh.positions.length / 3; i++) {\n const x = mesh.positions[i * 3] ?? 0;\n const z = mesh.positions[i * 3 + 2] ?? 0;\n const n: Vec3 = [\n mesh.normals[i * 3] ?? 0,\n mesh.normals[i * 3 + 1] ?? 0,\n mesh.normals[i * 3 + 2] ?? 0,\n ];\n let c: Vec3 = l.base ?? [colors[i * 3] ?? 1, colors[i * 3 + 1] ?? 1, colors[i * 3 + 2] ?? 1];\n for (const r of l.rules) {\n if (r.z && (z < r.z[0] || z > r.z[1])) continue;\n if (r.x && (x < r.x[0] || x > r.x[1])) continue;\n if (r.poly && !inPoly(r.poly, x, z)) continue;\n if (r.facing && !faces(r.facing, n)) continue;\n c = r.multiply ? [c[0] * r.color[0], c[1] * r.color[1], c[2] * r.color[2]] : r.color;\n }\n colors.set(c, i * 3);\n }\n return { ...mesh, colors };\n}\n",
9
+ "// Post-transform vertex cache: Tom Forsyth's \"Linear-Speed Vertex Cache Optimisation\" (2006)\n// triangle reorder, the vertex-fetch reorder that follows it, and the ACMR/ATVR analysis that\n// measures both. All integer bookkeeping and fixed tie-breaks (lowest triangle index wins), so\n// the output is byte-deterministic.\n\nconst CACHE = 32;\nconst DECAY = 1.5;\nconst LAST_TRI = 0.75;\nconst VALENCE_SCALE = 2;\nconst VALENCE_POWER = 0.5;\nconst MAX_VALENCE = 64;\n\nconst CACHE_SCORE = Float64Array.from({ length: CACHE }, (_, i) =>\n i < 3 ? LAST_TRI : (1 - (i - 3) / (CACHE - 3)) ** DECAY,\n);\nconst VALENCE_SCORE = Float64Array.from({ length: MAX_VALENCE + 1 }, (_, n) =>\n n === 0 ? 0 : VALENCE_SCALE * n ** -VALENCE_POWER,\n);\n\nconst vertexScore = (pos: number, live: number): number =>\n live === 0\n ? -1\n : (pos >= 0 ? (CACHE_SCORE[pos] ?? 0) : 0) + (VALENCE_SCORE[Math.min(live, MAX_VALENCE)] ?? 0);\n\n/** Reorder triangles for an LRU cache of 32 (Forsyth). Returns a new index buffer. */\nexport function forsyth(indices: Uint32Array, vertexCount: number): Uint32Array {\n const triCount = indices.length / 3;\n if (triCount === 0) return new Uint32Array(0);\n // CSR adjacency: vertex → triangles; `live[v]` counts the not-yet-emitted prefix.\n const live = new Int32Array(vertexCount);\n for (const v of indices) live[v] = (live[v] ?? 0) + 1;\n const offset = new Int32Array(vertexCount + 1);\n for (let v = 0; v < vertexCount; v++) offset[v + 1] = (offset[v] ?? 0) + (live[v] ?? 0);\n const adj = new Int32Array(indices.length);\n const fill = new Int32Array(vertexCount);\n for (let t = 0; t < triCount; t++)\n for (let k = 0; k < 3; k++) {\n const v = indices[t * 3 + k] ?? 0;\n adj[(offset[v] ?? 0) + (fill[v] ?? 0)] = t;\n fill[v] = (fill[v] ?? 0) + 1;\n }\n const cachePos = new Int32Array(vertexCount).fill(-1);\n const score = new Float64Array(vertexCount);\n for (let v = 0; v < vertexCount; v++) score[v] = vertexScore(-1, live[v] ?? 0);\n const emitted = new Uint8Array(triCount);\n const triScoreOf = (t: number): number =>\n (score[indices[t * 3] ?? 0] ?? 0) +\n (score[indices[t * 3 + 1] ?? 0] ?? 0) +\n (score[indices[t * 3 + 2] ?? 0] ?? 0);\n let best = 0;\n let top = triScoreOf(0);\n for (let t = 1; t < triCount; t++) {\n const s = triScoreOf(t);\n if (s > top) {\n top = s;\n best = t;\n }\n }\n const out = new Uint32Array(indices.length);\n let cache = new Int32Array(CACHE + 3);\n let spare = new Int32Array(CACHE + 3);\n let size = 0;\n let cursor = 0;\n for (let n = 0; n < triCount; n++) {\n if (best < 0) {\n while (emitted[cursor]) cursor++;\n best = cursor;\n }\n const t = best;\n emitted[t] = 1;\n const a = indices[t * 3] ?? 0;\n const b = indices[t * 3 + 1] ?? 0;\n const c = indices[t * 3 + 2] ?? 0;\n out[n * 3] = a;\n out[n * 3 + 1] = b;\n out[n * 3 + 2] = c;\n for (const v of [a, b, c]) {\n // Remove t from v's live adjacency (swap with the last live entry).\n const o = offset[v] ?? 0;\n const l = live[v] ?? 0;\n for (let i = o; i < o + l; i++)\n if (adj[i] === t) {\n adj[i] = adj[o + l - 1] ?? 0;\n adj[o + l - 1] = t;\n break;\n }\n live[v] = l - 1;\n }\n // New LRU: the triangle's vertices first, then the old cache minus them.\n spare[0] = a;\n spare[1] = b;\n spare[2] = c;\n let m = 3;\n for (let i = 0; i < size; i++) {\n const v = cache[i] ?? 0;\n if (v !== a && v !== b && v !== c) spare[m++] = v;\n }\n for (let i = CACHE; i < m; i++) {\n const v = spare[i] ?? 0;\n cachePos[v] = -1;\n score[v] = vertexScore(-1, live[v] ?? 0);\n }\n [cache, spare] = [spare, cache];\n size = Math.min(m, CACHE);\n for (let i = 0; i < size; i++) {\n const v = cache[i] ?? 0;\n cachePos[v] = i;\n score[v] = vertexScore(i, live[v] ?? 0);\n }\n best = -1;\n let bestScore = -Infinity;\n for (let j = 0; j < size; j++) {\n const v = cache[j] ?? 0;\n const o = offset[v] ?? 0;\n for (let i = o; i < o + (live[v] ?? 0); i++) {\n const u = adj[i] ?? 0;\n const s = triScoreOf(u);\n if (s > bestScore || (s === bestScore && u < best)) {\n bestScore = s;\n best = u;\n }\n }\n }\n }\n return out;\n}\n\n/** Renumber vertices in order of first use; unreferenced vertices are dropped. */\nexport function fetchOrder(\n indices: Uint32Array,\n vertexCount: number,\n): { indices: Uint32Array; order: Uint32Array } {\n const map = new Int32Array(vertexCount).fill(-1);\n const order: number[] = [];\n const out = new Uint32Array(indices.length);\n for (let i = 0; i < indices.length; i++) {\n const v = indices[i] ?? 0;\n if ((map[v] ?? -1) < 0) {\n map[v] = order.length;\n order.push(v);\n }\n out[i] = map[v] ?? 0;\n }\n return { indices: out, order: Uint32Array.from(order) };\n}\n\nexport interface CacheStats {\n /** Average cache misses per triangle (0.5 ideal on a regular grid, 3 worst). */\n readonly acmr: number;\n /** Misses per unique vertex (1.0 ideal). */\n readonly atvr: number;\n}\n\n/** Simulate a FIFO post-transform cache (16 entries, the meshoptimizer/NVIDIA convention). */\nexport function cacheStats(indices: Uint32Array, vertexCount: number, size = 16): CacheStats {\n const tris = indices.length / 3;\n if (tris === 0) return { acmr: 0, atvr: 0 };\n const stamp = new Int32Array(vertexCount).fill(-1_000_000_000);\n let misses = 0;\n for (const v of indices) {\n // A vertex is cached if it was loaded within the last `size` misses.\n if (misses - (stamp[v] ?? 0) >= size) {\n stamp[v] = misses;\n misses++;\n }\n }\n const seen = new Uint8Array(vertexCount);\n let used = 0;\n for (const v of indices)\n if (!seen[v]) {\n seen[v] = 1;\n used++;\n }\n return { acmr: misses / tris, atvr: used ? misses / used : 0 };\n}\n",
10
+ "// Vertex weld + degenerate/duplicate triangle removal: the \"index\" step of mesh optimisation.\n// Two vertices merge when position, normal, UV and colour all quantise to the same cell, so hard\n// edges (split normals) and UV seams survive. First occurrence wins; output order is the order of\n// first appearance — deterministic, no hashing of floats into iteration order.\n\nimport type { Mesh } from '../core/index.ts';\n\nexport interface WeldTolerance {\n /** Position grid, metres. */\n readonly position: number;\n readonly normal: number;\n readonly uv: number;\n readonly color: number;\n}\n\nexport const DEFAULT_WELD: WeldTolerance = {\n position: 1e-5,\n normal: 1e-3,\n uv: 1e-5,\n // Below the GLB's unorm16 colour step: welding never changes exported colour.\n color: 1 / 131072,\n};\n\nexport interface Welded {\n readonly mesh: Mesh;\n readonly degenerate: number;\n readonly duplicate: number;\n}\n\n/** The quantised attribute tuple of vertex i (12 ints). */\nfunction cellOf(m: Mesh, i: number, t: WeldTolerance, out: Int32Array): void {\n for (let k = 0; k < 3; k++) {\n out[k] = Math.round((m.positions[i * 3 + k] ?? 0) / t.position);\n out[3 + k] = Math.round((m.normals[i * 3 + k] ?? 0) / t.normal);\n out[8 + k] = Math.round((m.colors[i * 3 + k] ?? 0) / t.color);\n }\n out[6] = Math.round((m.uvs[i * 2] ?? 0) / t.uv);\n out[7] = Math.round((m.uvs[i * 2 + 1] ?? 0) / t.uv);\n out[11] = 0;\n}\n\nconst hashCell = (c: Int32Array): number => {\n let h = 2166136261;\n for (let k = 0; k < 11; k++) h = Math.imul(h ^ (c[k] ?? 0), 16777619);\n return h >>> 0;\n};\n\n/** Map each input vertex to its welded representative (open-addressing table, linear probe). */\nfunction weldMap(m: Mesh, t: WeldTolerance): { remap: Uint32Array; keep: number[] } {\n const n = m.positions.length / 3;\n const cells = new Int32Array(n * 12);\n const remap = new Uint32Array(n);\n const keep: number[] = [];\n let cap = 16;\n while (cap < n * 2) cap *= 2;\n const table = new Int32Array(cap).fill(-1);\n const cur = new Int32Array(12);\n for (let i = 0; i < n; i++) {\n cellOf(m, i, t, cur);\n cells.set(cur, i * 12);\n let slot = hashCell(cur) & (cap - 1);\n let found = -1;\n for (;;) {\n const j = table[slot] ?? -1;\n if (j < 0) break;\n const rep = (keep[j] ?? 0) * 12;\n let same = true;\n for (let k = 0; k < 11 && same; k++) same = cells[rep + k] === cur[k];\n if (same) {\n found = j;\n break;\n }\n slot = (slot + 1) & (cap - 1);\n }\n if (found < 0) {\n found = keep.length;\n keep.push(i);\n table[slot] = found;\n }\n remap[i] = found;\n }\n return { remap, keep };\n}\n\n/** Twice the triangle's area, from welded positions. */\nfunction area2(p: Float32Array, a: number, b: number, c: number): number {\n const ax = p[a * 3] ?? 0;\n const ay = p[a * 3 + 1] ?? 0;\n const az = p[a * 3 + 2] ?? 0;\n const ux = (p[b * 3] ?? 0) - ax;\n const uy = (p[b * 3 + 1] ?? 0) - ay;\n const uz = (p[b * 3 + 2] ?? 0) - az;\n const vx = (p[c * 3] ?? 0) - ax;\n const vy = (p[c * 3 + 1] ?? 0) - ay;\n const vz = (p[c * 3 + 2] ?? 0) - az;\n return Math.hypot(uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx);\n}\n\nexport function weld(m: Mesh, t: WeldTolerance = DEFAULT_WELD): Welded {\n const { remap, keep } = weldMap(m, t);\n const pick = (src: Float32Array, w: number): Float32Array => {\n const out = new Float32Array(keep.length * w);\n keep.forEach((i, j) => {\n for (let k = 0; k < w; k++) out[j * w + k] = src[i * w + k] ?? 0;\n });\n return out;\n };\n const positions = pick(m.positions, 3);\n const idx: number[] = [];\n // Duplicate detection: canonical rotation (lowest index first) hashed to a numeric key.\n const seen = new Map<number, number[]>();\n let degenerate = 0;\n let duplicate = 0;\n for (let f = 0; f < m.indices.length; f += 3) {\n const a = remap[m.indices[f] ?? 0] ?? 0;\n const b = remap[m.indices[f + 1] ?? 0] ?? 0;\n const c = remap[m.indices[f + 2] ?? 0] ?? 0;\n // Zero area covers no pixel: dropping it cannot open a crack.\n if (a === b || b === c || a === c || area2(positions, a, b, c) < 1e-12) {\n degenerate++;\n continue;\n }\n // Same triangle, same winding (any rotation) is pure overdraw; the reverse winding is a\n // deliberate double-sided face and stays.\n const [x, y, z] = a < b && a < c ? [a, b, c] : b < c ? [b, c, a] : [c, a, b];\n const h = (Math.imul(x, 73856093) ^ Math.imul(y, 19349663) ^ Math.imul(z, 83492791)) >>> 0;\n const list = seen.get(h);\n if (list?.some((at) => idx[at] === x && idx[at + 1] === y && idx[at + 2] === z)) {\n duplicate++;\n continue;\n }\n if (list) list.push(idx.length);\n else seen.set(h, [idx.length]);\n idx.push(x, y, z);\n }\n return {\n mesh: {\n positions,\n normals: pick(m.normals, 3),\n uvs: pick(m.uvs, 2),\n colors: pick(m.colors, 3),\n indices: new Uint32Array(idx),\n },\n degenerate,\n duplicate,\n };\n}\n",
11
+ "// Game-ready optimisation, run on every LOD before export, in meshoptimizer's order: weld\n// duplicate vertices (index) → reorder triangles for the post-transform vertex cache (Forsyth)\n// → reorder vertices for fetch locality. Same geometry, fewer vertices, fewer cache misses.\n// Zero dependencies, byte-deterministic. Reports ACMR/ATVR before and after.\n\nimport type { Mesh } from '../core/index.ts';\nimport { cacheStats, fetchOrder, forsyth } from './optimize-cache.ts';\nimport { DEFAULT_WELD, type WeldTolerance, weld } from './optimize-weld.ts';\n\nexport interface OptimizeOptions {\n /** Merge vertices closer than this (metres) with matching normal/uv/colour. Default 1e-5. */\n readonly weldEpsilon?: number;\n /** Reorder for the vertex cache (Forsyth). Default true. */\n readonly vertexCache?: boolean;\n}\n\nexport interface OptimizeReport {\n readonly verticesBefore: number;\n readonly verticesAfter: number;\n readonly trianglesBefore: number;\n readonly trianglesAfter: number;\n /** Zero-area / collapsed triangles dropped. */\n readonly degenerate: number;\n /** Exact duplicate triangles (same winding) dropped. */\n readonly duplicate: number;\n /** Average cache miss ratio per triangle before (FIFO 16). */\n readonly acmrBefore: number;\n /** Average cache miss ratio per triangle after reordering (lower is better, ~0.6–0.8 is good). */\n readonly acmr: number;\n /** Cache misses per vertex before / after (1.0 is ideal). */\n readonly atvrBefore: number;\n readonly atvr: number;\n}\n\nfunction reorderVertices(m: Mesh, order: Uint32Array, indices: Uint32Array): Mesh {\n const pick = (src: Float32Array, w: number): Float32Array => {\n const out = new Float32Array(order.length * w);\n for (let j = 0; j < order.length; j++)\n for (let k = 0; k < w; k++) out[j * w + k] = src[(order[j] ?? 0) * w + k] ?? 0;\n return out;\n };\n return {\n positions: pick(m.positions, 3),\n normals: pick(m.normals, 3),\n uvs: pick(m.uvs, 2),\n colors: pick(m.colors, 3),\n indices,\n };\n}\n\nexport function optimize(\n mesh: Mesh,\n o: OptimizeOptions = {},\n): { mesh: Mesh; report: OptimizeReport } {\n const vBefore = mesh.positions.length / 3;\n const before = cacheStats(mesh.indices, vBefore);\n const tol: WeldTolerance = { ...DEFAULT_WELD, position: o.weldEpsilon ?? DEFAULT_WELD.position };\n const w = weld(mesh, tol);\n const vWelded = w.mesh.positions.length / 3;\n // Forsyth targets an LRU-32 cache; on already-good input (flat strips) it can lose a hair on\n // the FIFO-16 measure. Keep whichever order measures better — never make a mesh worse.\n const reordered = o.vertexCache === false ? null : forsyth(w.mesh.indices, vWelded);\n const tris =\n reordered && cacheStats(reordered, vWelded).acmr <= cacheStats(w.mesh.indices, vWelded).acmr\n ? reordered\n : w.mesh.indices;\n const fetched = fetchOrder(tris, vWelded);\n const out = reorderVertices(w.mesh, fetched.order, fetched.indices);\n const after = cacheStats(out.indices, out.positions.length / 3);\n return {\n mesh: out,\n report: {\n verticesBefore: vBefore,\n verticesAfter: out.positions.length / 3,\n trianglesBefore: mesh.indices.length / 3,\n trianglesAfter: out.indices.length / 3,\n degenerate: w.degenerate,\n duplicate: w.duplicate,\n acmrBefore: before.acmr,\n acmr: after.acmr,\n atvrBefore: before.atvr,\n atvr: after.atvr,\n },\n };\n}\n",
12
+ "// Face-weighted vertex normals with a hard-edge split: the mid-poly hard-surface look. Each corner\n// averages the face normals around its position, weighted by face area × corner angle, but only\n// over faces within `hardAngle` of its own face. Big flat faces dominate, so a bevelled box keeps\n// dead-flat sides while its bevels bend the light into soft highlights — no normal map needed.\n\nimport type { Mesh, Vec3 } from '../core/index.ts';\n\nexport interface WeightedNormalsOptions {\n /** Faces meeting at more than this many degrees keep a hard edge. Default 40. */\n readonly hardAngle?: number;\n /** Positions closer than this (metres) count as one point. Default 1e-5. */\n readonly epsilon?: number;\n}\n\ninterface Corner {\n readonly n: Vec3;\n readonly w: number;\n}\n\nfunction faceData(m: Mesh, t: number): { n: Vec3; area: number; angles: Vec3 } {\n const p = (k: number): Vec3 => {\n const i = (m.indices[t * 3 + k] ?? 0) * 3;\n return [m.positions[i] ?? 0, m.positions[i + 1] ?? 0, m.positions[i + 2] ?? 0];\n };\n const v = [p(0), p(1), p(2)] as const;\n const e = (a: Vec3, b: Vec3): Vec3 => [b[0] - a[0], b[1] - a[1], b[2] - a[2]];\n const u = e(v[0], v[1]);\n const w = e(v[0], v[2]);\n const g: Vec3 = [u[1] * w[2] - u[2] * w[1], u[2] * w[0] - u[0] * w[2], u[0] * w[1] - u[1] * w[0]];\n const len = Math.hypot(...g);\n const angle = (k: number): number => {\n const a = e(v[k] ?? v[0], v[(k + 1) % 3] ?? v[0]);\n const b = e(v[k] ?? v[0], v[(k + 2) % 3] ?? v[0]);\n const d = Math.hypot(...a) * Math.hypot(...b);\n return d\n ? Math.acos(Math.max(-1, Math.min(1, (a[0] * b[0] + a[1] * b[1] + a[2] * b[2]) / d)))\n : 0;\n };\n return {\n n: len ? [g[0] / len, g[1] / len, g[2] / len] : [0, 0, 0],\n area: len / 2,\n angles: [angle(0), angle(1), angle(2)],\n };\n}\n\nexport function weightedNormals(m: Mesh, o: WeightedNormalsOptions = {}): Mesh {\n const cosHard = Math.cos(((o.hardAngle ?? 40) * Math.PI) / 180);\n const eps = o.epsilon ?? 1e-5;\n const tris = m.indices.length / 3;\n const corners: Corner[] = [];\n for (let t = 0; t < tris; t++) {\n const f = faceData(m, t);\n for (let k = 0; k < 3; k++) corners.push({ n: f.n, w: f.area * (f.angles[k] ?? 0) });\n }\n // Group corners by quantised position (insertion order — deterministic).\n const groups = new Map<string, number[]>();\n const keyOf = (i: number): string =>\n [0, 1, 2].map((k) => Math.round((m.positions[i * 3 + k] ?? 0) / eps)).join(',');\n for (let c = 0; c < corners.length; c++) {\n const key = keyOf(m.indices[c] ?? 0);\n const g = groups.get(key);\n if (g) g.push(c);\n else groups.set(key, [c]);\n }\n const normal = new Float32Array(corners.length * 3);\n for (const g of groups.values())\n for (const c of g) {\n const me = corners[c];\n if (!me) continue;\n let x = 0;\n let y = 0;\n let z = 0;\n for (const d of g) {\n const o2 = corners[d];\n if (!o2 || me.n[0] * o2.n[0] + me.n[1] * o2.n[1] + me.n[2] * o2.n[2] < cosHard) continue;\n x += o2.n[0] * o2.w;\n y += o2.n[1] * o2.w;\n z += o2.n[2] * o2.w;\n }\n const len = Math.hypot(x, y, z);\n // A degenerate face keeps its original normal.\n const src = (m.indices[c] ?? 0) * 3;\n normal.set(\n len > 1e-12\n ? [x / len, y / len, z / len]\n : [m.normals[src] ?? 0, m.normals[src + 1] ?? 0, m.normals[src + 2] ?? 0],\n c * 3,\n );\n }\n return splitByNormal(m, normal);\n}\n\n/** One output vertex per (input vertex, distinct new normal); first appearance order. */\nfunction splitByNormal(m: Mesh, cornerNormals: Float32Array): Mesh {\n const seen = new Map<string, number>();\n const p: number[] = [];\n const n: number[] = [];\n const uv: number[] = [];\n const col: number[] = [];\n const idx = new Uint32Array(m.indices.length);\n for (let c = 0; c < m.indices.length; c++) {\n const v = m.indices[c] ?? 0;\n const nx = cornerNormals[c * 3] ?? 0;\n const ny = cornerNormals[c * 3 + 1] ?? 0;\n const nz = cornerNormals[c * 3 + 2] ?? 0;\n const key = `${v}:${Math.round(nx * 1e4)},${Math.round(ny * 1e4)},${Math.round(nz * 1e4)}`;\n let out = seen.get(key);\n if (out === undefined) {\n out = p.length / 3;\n seen.set(key, out);\n p.push(m.positions[v * 3] ?? 0, m.positions[v * 3 + 1] ?? 0, m.positions[v * 3 + 2] ?? 0);\n n.push(nx, ny, nz);\n uv.push(m.uvs[v * 2] ?? 0, m.uvs[v * 2 + 1] ?? 0);\n col.push(m.colors[v * 3] ?? 0, m.colors[v * 3 + 1] ?? 0, m.colors[v * 3 + 2] ?? 0);\n }\n idx[c] = out;\n }\n return {\n positions: new Float32Array(p),\n normals: new Float32Array(n),\n uvs: new Float32Array(uv),\n colors: new Float32Array(col),\n indices: idx,\n };\n}\n"
13
+ ],
14
+ "mappings": "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",
15
+ "debugId": "BEEEAE9C1B221C7564756E2164756E21",
16
+ "names": []
17
+ }
@@ -0,0 +1,89 @@
1
+ import {
2
+ Ts23dError2
3
+ } from "./chunk-hg7pf34j.js";
4
+
5
+ // src/grammar/split.ts
6
+ var syntax = (src, why) => new Ts23dError2("T3D_GRAMMAR_SYNTAX", {
7
+ cause: `cannot parse split "${src}": ${why}`,
8
+ fix: "use `sym:<metres>`, `sym:~`, `sym:~<weight>` or `{a:1 | b:2}*`, separated by `|`"
9
+ });
10
+ function parseTerm(raw, src) {
11
+ const t = raw.trim();
12
+ const m = /^([a-z_][a-z0-9_]*):(~(\d*\.?\d+)?|\d*\.?\d+)$/.exec(t);
13
+ if (!m)
14
+ throw syntax(src, `bad term '${t}'`);
15
+ const [, symbol = "", size = ""] = m;
16
+ if (size.startsWith("~"))
17
+ return { kind: "stretch", symbol, weight: m[3] ? Number(m[3]) : 1 };
18
+ return { kind: "fixed", symbol, size: Number(size) };
19
+ }
20
+ function parseSplit2(src) {
21
+ const out = [];
22
+ const re = /\{([^}]*)\}\*|([^|{}]+)/g;
23
+ for (const m of src.matchAll(re)) {
24
+ if (m[1] !== undefined) {
25
+ const body = m[1].split("|").map((s) => parseTerm(s, src));
26
+ if (body.some((b) => b.kind !== "fixed"))
27
+ throw syntax(src, "a repeat body takes fixed sizes");
28
+ out.push({ kind: "repeat", body });
29
+ } else if (m[2] !== undefined && m[2].trim() !== "") {
30
+ out.push(parseTerm(m[2], src));
31
+ }
32
+ }
33
+ if (out.length === 0)
34
+ throw syntax(src, "empty");
35
+ if (out.filter((t) => t.kind === "repeat").length > 1)
36
+ throw syntax(src, "at most one repeat");
37
+ return out;
38
+ }
39
+ var sizeOf = (terms) => terms.reduce((s, t) => s + (t.kind === "fixed" ? t.size : 0), 0);
40
+ function layoutSplit2(terms, length) {
41
+ const fixed = sizeOf(terms);
42
+ const repeat = terms.find((t) => t.kind === "repeat");
43
+ const unit = repeat?.kind === "repeat" ? sizeOf(repeat.body) : 0;
44
+ if (fixed > length + 0.000000001) {
45
+ throw new Ts23dError2("T3D_GRAMMAR_OVERFLOW", {
46
+ cause: `fixed terms need ${fixed} m but the strip is ${length} m`,
47
+ fix: "shrink a fixed term, or turn one into a stretch (`sym:~`)"
48
+ });
49
+ }
50
+ const copies = unit > 0 ? Math.floor((length - fixed) / unit) : 0;
51
+ const weights = terms.reduce((s, t) => s + (t.kind === "stretch" ? t.weight : 0), 0);
52
+ const leftover = length - fixed - copies * unit;
53
+ const grow = weights === 0 && copies > 0 ? (copies * unit + leftover) / (copies * unit) : 1;
54
+ const slots = [];
55
+ let x = 0;
56
+ const push = (symbol, size) => {
57
+ slots.push({ symbol, start: x, size });
58
+ x += size;
59
+ };
60
+ for (const t of terms) {
61
+ if (t.kind === "fixed")
62
+ push(t.symbol, t.size);
63
+ else if (t.kind === "stretch")
64
+ push(t.symbol, weights > 0 ? leftover * t.weight / weights : 0);
65
+ else
66
+ for (let i = 0;i < copies; i++)
67
+ for (const b of t.body)
68
+ if (b.kind === "fixed")
69
+ push(b.symbol, b.size * grow);
70
+ }
71
+ return slots;
72
+ }
73
+ var split2 = (src, length) => layoutSplit2(parseSplit2(src), length);
74
+ // src/grammar/whyte.ts
75
+ function parseWhyte2(arrangement) {
76
+ const parts = arrangement.split("-").map(Number);
77
+ if (parts.length !== 3 || parts.some((n) => !Number.isInteger(n) || n < 0 || n % 2 !== 0)) {
78
+ throw new Ts23dError2("T3D_GRAMMAR_SYNTAX", {
79
+ cause: `'${arrangement}' is not a rigid-frame Whyte arrangement`,
80
+ fix: "use three even numbers: leading-driving-trailing, e.g. '4-4-0' or '2-8-2'"
81
+ });
82
+ }
83
+ const roles = ["leading", "driving", "trailing"];
84
+ return roles.map((role, i) => ({ role, count: parts[i] ?? 0 }));
85
+ }
86
+ export { parseSplit2, layoutSplit2, split2, parseWhyte2 };
87
+
88
+ //# debugId=3FD9805EE52EDB5F64756E2164756E21
89
+ //# sourceMappingURL=chunk-dxvypr7y.js.map
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/grammar/split.ts", "../src/grammar/whyte.ts"],
4
+ "sourcesContent": [
5
+ "// Split grammar (after CGA shape, Müller et al. 2006): one line lays out a facade strip.\n// \"pier:0.9 | {arch:2.5}* | door:3 | pier:~\"\n// x:n fixed width · {a:n | b:m}* repeat to fill · x:~ stretch (shares leftover equally)\n\nimport { Ts23dError } from '../core/index.ts';\n\nexport type SplitTerm =\n | { readonly kind: 'fixed'; readonly symbol: string; readonly size: number }\n | { readonly kind: 'stretch'; readonly symbol: string; readonly weight: number }\n | { readonly kind: 'repeat'; readonly body: readonly SplitTerm[] };\n\nexport interface Slot {\n readonly symbol: string;\n readonly start: number;\n readonly size: number;\n}\n\nconst syntax = (src: string, why: string): Ts23dError =>\n new Ts23dError('T3D_GRAMMAR_SYNTAX', {\n cause: `cannot parse split \"${src}\": ${why}`,\n fix: 'use `sym:<metres>`, `sym:~`, `sym:~<weight>` or `{a:1 | b:2}*`, separated by `|`',\n });\n\nfunction parseTerm(raw: string, src: string): SplitTerm {\n const t = raw.trim();\n const m = /^([a-z_][a-z0-9_]*):(~(\\d*\\.?\\d+)?|\\d*\\.?\\d+)$/.exec(t);\n if (!m) throw syntax(src, `bad term '${t}'`);\n const [, symbol = '', size = ''] = m;\n if (size.startsWith('~')) return { kind: 'stretch', symbol, weight: m[3] ? Number(m[3]) : 1 };\n return { kind: 'fixed', symbol, size: Number(size) };\n}\n\nexport function parseSplit(src: string): SplitTerm[] {\n const out: SplitTerm[] = [];\n const re = /\\{([^}]*)\\}\\*|([^|{}]+)/g;\n for (const m of src.matchAll(re)) {\n if (m[1] !== undefined) {\n const body = m[1].split('|').map((s) => parseTerm(s, src));\n if (body.some((b) => b.kind !== 'fixed'))\n throw syntax(src, 'a repeat body takes fixed sizes');\n out.push({ kind: 'repeat', body });\n } else if (m[2] !== undefined && m[2].trim() !== '') {\n out.push(parseTerm(m[2], src));\n }\n }\n if (out.length === 0) throw syntax(src, 'empty');\n if (out.filter((t) => t.kind === 'repeat').length > 1) throw syntax(src, 'at most one repeat');\n return out;\n}\n\nconst sizeOf = (terms: readonly SplitTerm[]): number =>\n terms.reduce((s, t) => s + (t.kind === 'fixed' ? t.size : 0), 0);\n\n/** Lay a parsed split across `length` metres. Repeats take whole copies; stretches share the rest. */\nexport function layoutSplit(terms: readonly SplitTerm[], length: number): Slot[] {\n const fixed = sizeOf(terms);\n const repeat = terms.find((t) => t.kind === 'repeat');\n const unit = repeat?.kind === 'repeat' ? sizeOf(repeat.body) : 0;\n if (fixed > length + 1e-9) {\n throw new Ts23dError('T3D_GRAMMAR_OVERFLOW', {\n cause: `fixed terms need ${fixed} m but the strip is ${length} m`,\n fix: 'shrink a fixed term, or turn one into a stretch (`sym:~`)',\n });\n }\n const copies = unit > 0 ? Math.floor((length - fixed) / unit) : 0;\n const weights = terms.reduce((s, t) => s + (t.kind === 'stretch' ? t.weight : 0), 0);\n const leftover = length - fixed - copies * unit;\n // No stretch term: the repeat absorbs the leftover by widening each copy evenly.\n const grow = weights === 0 && copies > 0 ? (copies * unit + leftover) / (copies * unit) : 1;\n const slots: Slot[] = [];\n let x = 0;\n const push = (symbol: string, size: number): void => {\n slots.push({ symbol, start: x, size });\n x += size;\n };\n for (const t of terms) {\n if (t.kind === 'fixed') push(t.symbol, t.size);\n else if (t.kind === 'stretch')\n push(t.symbol, weights > 0 ? (leftover * t.weight) / weights : 0);\n else\n for (let i = 0; i < copies; i++)\n for (const b of t.body) if (b.kind === 'fixed') push(b.symbol, b.size * grow);\n }\n return slots;\n}\n\nexport const split = (src: string, length: number): Slot[] => layoutSplit(parseSplit(src), length);\n",
6
+ "// Whyte notation (\"4-4-0\", \"2-6-2\") → wheel groups. Domain-native params: the loco kind reads it.\n\nimport { Ts23dError } from '../core/index.ts';\n\nexport interface WheelGroup {\n readonly role: 'leading' | 'driving' | 'trailing';\n readonly count: number;\n}\n\nexport function parseWhyte(arrangement: string): WheelGroup[] {\n const parts = arrangement.split('-').map(Number);\n if (parts.length !== 3 || parts.some((n) => !Number.isInteger(n) || n < 0 || n % 2 !== 0)) {\n throw new Ts23dError('T3D_GRAMMAR_SYNTAX', {\n cause: `'${arrangement}' is not a rigid-frame Whyte arrangement`,\n fix: \"use three even numbers: leading-driving-trailing, e.g. '4-4-0' or '2-8-2'\",\n });\n }\n const roles = ['leading', 'driving', 'trailing'] as const;\n return roles.map((role, i) => ({ role, count: parts[i] ?? 0 }));\n}\n"
7
+ ],
8
+ "mappings": "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",
9
+ "debugId": "3FD9805EE52EDB5F64756E2164756E21",
10
+ "names": []
11
+ }