@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,36 @@
1
+ # Semaphore signal bridge — US lattice type, c. 1905–1915 (`signal_gantry`, `signal_gantry_4`)
2
+
3
+ ## Identity
4
+ A riveted lattice signal bridge spanning the main tracks, carrying one pipe mast per track with
5
+ lower-quadrant semaphore arms (Union Switch & Signal Style B era, from c. 1905). `signal_gantry`
6
+ spans two tracks; `signal_gantry_4` spans four, as in the 1909 photo below. Signature features:
7
+ box-lattice posts on concrete footings, a lattice girder with knee braces at the corners, a plank
8
+ walkway with a hand rail, slender masts with ball finials, red blades pointing right, spectacles
9
+ with red/green roundels in front of oil lamps.
10
+
11
+ ## Specs
12
+ | Dimension | Value | Source |
13
+ |---|---|---|
14
+ | vertical clearance under the bridge | 22 ft (6.706 m) min. over top of rail | Pennsylvania Code §33.41 and other state codes, https://regulations.justia.com/states/pennsylvania/title-52/part-i/subpart-b/chapter-33/subchapter-b/safety-bridges-tunnels-trestles-and-switches/section-33-41 |
15
+ | track centres | 13 ft (3.962 m), the common US double-track spacing | https://en.wikipedia.org/wiki/Track_spacing |
16
+ | post to adjacent track centre | ≥ 8 ft 6 in (2.591 m) for signal posts | Illinois Admin. Code 92 §1500 (side clearance of semaphore posts), search summary; ilga.gov blocks fetchers |
17
+ | blade length | 4–5 ft; 5 ft (1.524 m) used | https://www.railroadsignals.us/signals/sem/ ; GWR 5 ft arms, https://en.wikipedia.org/wiki/Railway_semaphore_signal |
18
+ | lower-quadrant positions | 0° stop, 30° approach, 60° clear (down) | https://www.railroadsignals.us/signals/sem/ |
19
+ | mast base below first arm on a bridge | ≈ 3 ft | same (Picture 57) |
20
+ | girder depth, post section, walkway | 1.5 m, 0.6 × 0.45 m, 1.0 m | ESTIMATE, scaled from the 1909 photo against the 13 ft track centres |
21
+
22
+ ## Photos (by view)
23
+ | View | URL | Notes |
24
+ |---|---|---|
25
+ | front (driver's view), 4 tracks | https://commons.wikimedia.org/wiki/File:Signal_bridge_-_Discs_%26_semaphores_1909.jpg | lattice posts, knee braces, masts with blades right of the mast |
26
+ | US&S Style B (museum) | https://www.irm.org/?p=19319 | lower-quadrant arm and spectacle |
27
+ | detail, semaphore anatomy | https://www.railroadsignals.us/signals/sem/ | blade, roundels, spectacle, lamp, mechanism |
28
+
29
+ ## Parts the engine needs
30
+ `arm_<track>_home`, `arm_<track>_distant` (pivots, one-way `sway` about −X: the blade drops 0–60° and returns) ·
31
+ `lamp_*_lens` (glow) · sockets `lamp_*_light` (light) · `post_l`, `post_r`, `girder`, `mast_*`.
32
+
33
+ ## Open questions
34
+ - Arms rest horizontal (stop) and drop one way to 60° (clear) with `oneWay` sway; the 30° approach
35
+ position of three-position signals is passed through, not held.
36
+ - Girder depth and post section are photo estimates; no measured drawing was found online.
@@ -0,0 +1,522 @@
1
+ // Semaphore signal bridge, US lattice type (c. 1905–1915): box-lattice posts on concrete footings,
2
+ // a lattice girder 22 ft over the rails with knee braces, a plank walkway, and one pipe mast per
3
+ // track carrying lower-quadrant arms (home + distant) on spectacles in front of oil lamps. Tracks
4
+ // run along X, the bridge spans Y, signals face +X (the approaching driver). Rail top z = 0.
5
+ // A family over the number of tracks. Dossier: ./README.md.
6
+
7
+ import {
8
+ beam,
9
+ box,
10
+ type Check,
11
+ type CheckFinding,
12
+ cylinder,
13
+ defineFamily,
14
+ grime,
15
+ hex,
16
+ type Lod,
17
+ lathe,
18
+ lattice,
19
+ type Mesh,
20
+ merge,
21
+ place,
22
+ prism,
23
+ type Vec2,
24
+ worldMeshes,
25
+ } from '@developerz.ai/ts23d';
26
+
27
+ const FT = 0.3048;
28
+ const TRACK_CENTRES = 13 * FT; // 3.962
29
+ const POST_CLEAR = 8.5 * FT; // post centre ↔ outer track centre, 2.591
30
+ const CLEARANCE = 22 * FT; // 6.706 under the girder
31
+ const GIRDER_D = 1.5;
32
+ const GIRDER_W = 1.0;
33
+ const CHORD = 0.12;
34
+ const ZB = CLEARANCE + CHORD / 2; // girder base chord centreline
35
+ const DECK_Z = ZB + GIRDER_D + CHORD / 2 + 0.05; // walkway top
36
+ const FOOT_H = 0.4;
37
+ const BLADE_L = 5 * FT; // 1.524
38
+ const BLADE_0 = 0.15; // blade starts this far right of the pivot
39
+ const ARM_X = 0.1; // front face of the mast + clearance: arms live in x ∈ [0.1, 0.14]
40
+ const LOW_ARM = 1.75; // pivot over the deck: the swept blade (r ≈ 1.67) clears the walkway
41
+ const ARM_GAP = 2.35; // the upper spectacle clears the lower blade's sweep
42
+ const MAST_H = LOW_ARM + ARM_GAP + 0.45;
43
+
44
+ const steel = hex('#2d3033');
45
+ const steelDark = hex('#1f2123');
46
+ const concrete = hex('#b5afa3');
47
+ const plank = hex('#6d5a45');
48
+ const red = hex('#b0261c');
49
+ const white = hex('#ece9e0');
50
+ const lens = hex('#ffcf7a');
51
+
52
+ const halfSpan = (tracks: number): number => ((tracks - 1) / 2) * TRACK_CENTRES + POST_CLEAR;
53
+ const trackYs = (tracks: number): number[] =>
54
+ Array.from({ length: tracks }, (_, i) => (i - (tracks - 1) / 2) * TRACK_CENTRES);
55
+
56
+ /** Holds the 22 ft × 10 ft 8 in clearance envelope over every track: nothing may sag into it. */
57
+ const clearanceEnvelope =
58
+ (tracks: number): Check =>
59
+ (asset) => {
60
+ const out: CheckFinding[] = [];
61
+ for (const [name, m] of worldMeshes(asset.parts)) {
62
+ for (let i = 0; i < m.positions.length; i += 3) {
63
+ const y = m.positions[i + 1] ?? 0;
64
+ const z = m.positions[i + 2] ?? 0;
65
+ if (
66
+ z > 0.05 &&
67
+ z < CLEARANCE - 0.005 &&
68
+ trackYs(tracks).some((t) => Math.abs(y - t) < 1.63)
69
+ ) {
70
+ out.push({
71
+ message: `'${name}' enters the clearance envelope at z ${z.toFixed(2)} m`,
72
+ fix: 'keep everything 22 ft over the rail and 5 ft 4 in either side of each track centre',
73
+ part: name,
74
+ });
75
+ break;
76
+ }
77
+ }
78
+ }
79
+ return out;
80
+ };
81
+
82
+ /** One semaphore arm in its pivot's space (pivot at the origin, swings about +X): blade to +Y,
83
+ * spectacle with red / green roundels below-left, hub to the mast. Modelled at stop (horizontal). */
84
+ function arm(kind: 'home' | 'distant', lod: Lod): { blade: Mesh; spectacle: Mesh } {
85
+ const end = BLADE_0 + BLADE_L;
86
+ const profile: Vec2[] =
87
+ kind === 'home'
88
+ ? [
89
+ [BLADE_0, -0.11],
90
+ [end, -0.1],
91
+ [end, 0.1],
92
+ [BLADE_0, 0.11],
93
+ ]
94
+ : [
95
+ [BLADE_0, -0.11],
96
+ [end, -0.12],
97
+ [end - 0.18, 0],
98
+ [end, 0.12],
99
+ [BLADE_0, 0.11],
100
+ ];
101
+ const blade: Mesh[] = [
102
+ place(prism({ profile, depth: 0.02, plane: 'yz', color: red, strip: 'iron' }), {
103
+ at: [ARM_X + 0.03, 0, 0],
104
+ }),
105
+ ];
106
+ if (lod < 2) {
107
+ // White band 0.25 m from the end (front face only), black-and-white back.
108
+ const b0 = end - (kind === 'home' ? 0.42 : 0.55);
109
+ blade.push(box({ size: [0.004, 0.12, 0.2], at: [ARM_X + 0.042, b0, -0.1], color: white }));
110
+ blade.push(
111
+ box({
112
+ size: [0.004, BLADE_L, 0.2],
113
+ at: [ARM_X + 0.018, BLADE_0 + BLADE_L / 2, -0.1],
114
+ color: white,
115
+ }),
116
+ );
117
+ }
118
+ const rg: Mesh[] = [
119
+ // Hub on the spindle (touches the mast face) and the cast spectacle plate.
120
+ cylinder({
121
+ radius: 0.06,
122
+ length: ARM_X + 0.05 - 0.075,
123
+ segments: lod === 2 ? 4 : 8,
124
+ axis: 'x',
125
+ at: [(0.075 + ARM_X + 0.05) / 2, 0, 0],
126
+ color: steelDark,
127
+ }),
128
+ place(
129
+ prism({
130
+ profile: [
131
+ [-0.42, -0.12],
132
+ [0.22, -0.48],
133
+ [0.3, -0.36],
134
+ [0.12, 0.08],
135
+ [-0.06, 0.08],
136
+ [-0.42, 0.04],
137
+ ],
138
+ depth: 0.025,
139
+ plane: 'yz',
140
+ color: steelDark,
141
+ strip: 'iron',
142
+ }),
143
+ { at: [ARM_X + 0.0125, 0, 0] },
144
+ ),
145
+ ];
146
+ if (lod < 2) {
147
+ const red0: Vec2 = [-0.25, -0.25];
148
+ const a = Math.PI / 3; // green comes in front of the lamp when the blade drops 60°
149
+ const green0: Vec2 = [
150
+ red0[0] * Math.cos(a) - red0[1] * Math.sin(a),
151
+ red0[0] * Math.sin(a) + red0[1] * Math.cos(a),
152
+ ];
153
+ for (const [[y, z], c] of [
154
+ [red0, hex('#c4231b')],
155
+ [green0, hex('#1f8f5a')],
156
+ ] as const)
157
+ rg.push(
158
+ cylinder({
159
+ radius: 0.105,
160
+ length: 0.015,
161
+ segments: lod === 0 ? 12 : 6,
162
+ axis: 'x',
163
+ at: [ARM_X + 0.032, y, z],
164
+ color: c,
165
+ }),
166
+ );
167
+ }
168
+ return { blade: merge(blade), spectacle: merge(rg) };
169
+ }
170
+
171
+ interface Params {
172
+ readonly tracks: number;
173
+ }
174
+
175
+ const bridge = defineFamily({
176
+ kind: 'prop',
177
+ tags: ['railroad', 'signal', 'semaphore', 'lineside', 'usa', '1910s'],
178
+ license: 'CC0-1.0',
179
+ sources: [
180
+ 'https://commons.wikimedia.org/wiki/File:Signal_bridge_-_Discs_%26_semaphores_1909.jpg',
181
+ 'https://regulations.justia.com/states/pennsylvania/title-52/part-i/subpart-b/chapter-33/subchapter-b/safety-bridges-tunnels-trestles-and-switches/section-33-41',
182
+ 'https://en.wikipedia.org/wiki/Track_spacing',
183
+ 'https://www.railroadsignals.us/signals/sem/',
184
+ 'https://en.wikipedia.org/wiki/Railway_semaphore_signal',
185
+ 'https://www.irm.org/?p=19319',
186
+ ],
187
+ real: {
188
+ length: GIRDER_W + 0.12, // walkway + hand rail
189
+ width: 2 * halfSpan(2) + 0.9,
190
+ height: DECK_Z + MAST_H + 0.2,
191
+ measures: [
192
+ {
193
+ label: 'track centres (13 ft)',
194
+ value: TRACK_CENTRES,
195
+ axis: 'y',
196
+ between: ['mast_0', 'mast_1'],
197
+ source: 'Track spacing',
198
+ },
199
+ {
200
+ label: 'post to track centre (8 ft 6 in)',
201
+ value: POST_CLEAR,
202
+ axis: 'y',
203
+ between: ['post_r', 'mast_0'],
204
+ source: 'Illinois 92 §1500',
205
+ },
206
+ {
207
+ label: 'blade length (5 ft)',
208
+ value: BLADE_L,
209
+ axis: 'y',
210
+ parts: ['arm_0_home_blade'],
211
+ source: 'railroadsignals.us',
212
+ },
213
+ ],
214
+ },
215
+ budget: { triangles: [10000, 4400, 830] },
216
+ glow: [{ parts: ['lamp_*_lens'], color: [1, 0.78, 0.45], strength: 4 }],
217
+ defaults: { tracks: 2 } as Params,
218
+ build(ctx, p) {
219
+ const lod = ctx.lod;
220
+ const hs = halfSpan(p.tracks);
221
+ const dirt = (m: Mesh): Mesh => grime(m, { ground: 1.2, groundStrength: 0.35 });
222
+ const section = lod === 0 ? 'angle' : 'square';
223
+
224
+ // ---- posts on footings: box lattice (LOD0/1), plain columns far away.
225
+ for (const [side, s] of [
226
+ ['l', 1],
227
+ ['r', -1],
228
+ ] as const) {
229
+ const y = s * hs;
230
+ ctx.part(
231
+ `footing_${side}`,
232
+ box({
233
+ size: [0.95, 0.8, FOOT_H],
234
+ at: [0, y, 0],
235
+ color: concrete,
236
+ strip: 'concrete',
237
+ omit: ['bottom'],
238
+ }),
239
+ );
240
+ const top = ZB + GIRDER_D;
241
+ const post =
242
+ lod === 2
243
+ ? box({
244
+ size: [0.6, 0.45, top - FOOT_H],
245
+ at: [0, y, FOOT_H],
246
+ color: steel,
247
+ strip: 'iron',
248
+ })
249
+ : lattice({
250
+ from: [0, y, FOOT_H],
251
+ to: [0, y, top],
252
+ depth: 0.6,
253
+ width: 0.45,
254
+ centred: true,
255
+ chord: 0.09,
256
+ web: 0.05,
257
+ pattern: 'x',
258
+ bays: ctx.pick([16, 9, 4]),
259
+ section,
260
+ color: steel,
261
+ strip: 'iron',
262
+ });
263
+ const plate = box({ size: [0.75, 0.6, 0.04], at: [0, y, FOOT_H], color: steelDark });
264
+ ctx.part(`post_${side}`, dirt(merge([post, plate])));
265
+ // Knee braces from the post into the girder soffit, front and back faces.
266
+ const knees = (lod === 2 ? [0] : [-GIRDER_W / 2 + 0.05, GIRDER_W / 2 - 0.05]).map((x) =>
267
+ beam({
268
+ from: [x, y - s * 0.22, ZB - 0.9],
269
+ to: [x, y - s * 1.0, ZB],
270
+ width: 0.1,
271
+ height: 0.1,
272
+ color: steel,
273
+ strip: 'iron',
274
+ }),
275
+ );
276
+ ctx.part(`knee_${side}`, merge(knees));
277
+ }
278
+
279
+ // ---- girder: box lattice (warren), plank walkway on top, hand rail on the back edge.
280
+ const girder =
281
+ lod === 2
282
+ ? lattice({
283
+ from: [0, -hs, ZB],
284
+ to: [0, hs, ZB],
285
+ up: [0, 0, 1],
286
+ depth: GIRDER_D,
287
+ chord: CHORD,
288
+ pattern: 'x',
289
+ bays: Math.round(hs * 0.8),
290
+ color: steel,
291
+ })
292
+ : lattice({
293
+ from: [0, -hs, ZB],
294
+ to: [0, hs, ZB],
295
+ up: [0, 0, 1],
296
+ depth: GIRDER_D,
297
+ width: GIRDER_W,
298
+ chord: CHORD,
299
+ web: 0.07,
300
+ pattern: lod === 0 ? 'x' : 'warren', // the 1909 bridge is a dense X lattice
301
+ bays: ctx.pick([Math.round(hs * 1.4), Math.round(hs * 0.8), 4]),
302
+ section,
303
+ color: steel,
304
+ strip: 'iron',
305
+ });
306
+ ctx.part('girder', girder);
307
+ const deck: Mesh[] = [
308
+ box({
309
+ size: [GIRDER_W + 0.1, 2 * hs + 0.45, 0.05],
310
+ at: [0, 0, DECK_Z - 0.05],
311
+ color: plank,
312
+ strip: 'wood',
313
+ }),
314
+ ];
315
+ if (lod === 2)
316
+ for (const y of [-hs, hs])
317
+ deck.push(
318
+ box({ size: [0.05, 0.05, 1.02], at: [-GIRDER_W / 2 - 0.02, y, DECK_Z], color: steel }),
319
+ );
320
+ if (lod === 2)
321
+ deck.push(
322
+ box({
323
+ size: [0.05, 2 * hs, 0.05],
324
+ at: [-GIRDER_W / 2 - 0.02, 0, DECK_Z + 0.97],
325
+ color: steel,
326
+ }),
327
+ );
328
+ if (lod < 2) {
329
+ const railX = -GIRDER_W / 2 - 0.02;
330
+ deck.push(
331
+ beam({
332
+ from: [railX, -hs, DECK_Z + 1.0],
333
+ to: [railX, hs, DECK_Z + 1.0],
334
+ width: 0.045,
335
+ segments: lod === 0 ? 6 : 0,
336
+ color: steel,
337
+ }),
338
+ );
339
+ deck.push(
340
+ beam({
341
+ from: [railX, -hs, DECK_Z + 0.5],
342
+ to: [railX, hs, DECK_Z + 0.5],
343
+ width: 0.035,
344
+ color: steel,
345
+ }),
346
+ );
347
+ const n = Math.round((2 * hs) / 1.5);
348
+ for (let i = 0; i <= n; i++) {
349
+ const y = -hs + (2 * hs * i) / n;
350
+ deck.push(box({ size: [0.05, 0.05, 1.02], at: [railX, y, DECK_Z], color: steel }));
351
+ }
352
+ }
353
+ ctx.part('walkway', merge(deck));
354
+
355
+ // ---- ladder up the right post to the walkway.
356
+ if (lod < 2) {
357
+ const ly = -hs - 0.32;
358
+ const lad: Mesh[] = [];
359
+ for (const x of [-0.2, 0.2])
360
+ lad.push(box({ size: [0.05, 0.04, DECK_Z - FOOT_H], at: [x, ly, FOOT_H], color: steel }));
361
+ for (let z = FOOT_H + 0.3; z < DECK_Z - 0.05; z += lod === 0 ? 0.3 : 0.6)
362
+ lad.push(
363
+ cylinder({
364
+ radius: 0.012,
365
+ length: 0.4,
366
+ segments: lod === 0 ? 6 : 4,
367
+ axis: 'x',
368
+ at: [0, ly, z],
369
+ color: steel,
370
+ }),
371
+ );
372
+ for (const z of [FOOT_H + 1.5, ZB - 1, ZB + 0.6])
373
+ for (const x of [-0.2, 0.2])
374
+ lad.push(box({ size: [0.04, 0.12, 0.04], at: [x, ly + 0.08, z], color: steel })); // stand-off brackets
375
+ ctx.part('ladder', merge(lad));
376
+ }
377
+
378
+ // ---- masts, arms, spectacles and lamps: one mast per track.
379
+ const segs = ctx.pick([10, 8, 5]);
380
+ trackYs(p.tracks).forEach((y, t) => {
381
+ const mast: Mesh[] = [
382
+ box({ size: [0.36, 0.36, 0.06], at: [0, y, DECK_Z], color: steelDark }),
383
+ lathe({
384
+ profile: [
385
+ [0.09, DECK_Z],
386
+ [0.075, DECK_Z + 0.4],
387
+ [0.065, DECK_Z + MAST_H],
388
+ ],
389
+ segments: segs,
390
+ color: steel,
391
+ at: [0, y, 0],
392
+ }),
393
+ lathe({
394
+ profile: [
395
+ [0, DECK_Z + MAST_H - 0.02],
396
+ [0.08, DECK_Z + MAST_H + 0.06],
397
+ [0.06, DECK_Z + MAST_H + 0.15],
398
+ [0, DECK_Z + MAST_H + 0.18],
399
+ ],
400
+ segments: segs,
401
+ color: steelDark,
402
+ at: [0, y, 0],
403
+ }), // ball finial
404
+ ];
405
+ if (lod === 0) {
406
+ // Step bolts up the back of the mast; mechanism cases behind each arm.
407
+ for (let z = DECK_Z + 0.4; z < DECK_Z + MAST_H - 0.4; z += 0.38)
408
+ mast.push(
409
+ box({
410
+ size: [0.2, 0.025, 0.025],
411
+ at: [-0.13, y + (Math.round(z * 10) % 2 ? 0.03 : -0.03), z],
412
+ color: steel,
413
+ }),
414
+ );
415
+ }
416
+ for (const [k, kind] of [
417
+ [0, 'home'],
418
+ [1, 'distant'],
419
+ ] as const) {
420
+ const pz = DECK_Z + LOW_ARM + (kind === 'home' ? ARM_GAP : 0);
421
+ if (lod < 2)
422
+ mast.push(box({ size: [0.2, 0.22, 0.32], at: [-0.17, y, pz - 0.2], color: steelDark })); // mechanism case
423
+ // Lamp behind the red roundel's stop position, on a bracket from the mast.
424
+ const ly = y - 0.25;
425
+ const lz = pz - 0.25;
426
+ ctx.part(
427
+ `lamp_${t}_${kind}`,
428
+ merge([
429
+ box({ size: [0.2, 0.24, 0.3], at: [-0.02, ly, lz - 0.15], color: steelDark }),
430
+ lathe({
431
+ profile: [
432
+ [0.07, lz + 0.15],
433
+ [0.05, lz + 0.26],
434
+ [0, lz + 0.29],
435
+ ],
436
+ segments: lod === 2 ? 3 : 6,
437
+ color: steelDark,
438
+ at: [-0.02, ly, 0],
439
+ }), // chimney
440
+ box({ size: [0.05, 0.12, 0.05], at: [-0.02, y - 0.09, lz - 0.05], color: steelDark }), // bracket to the mast
441
+ ]),
442
+ );
443
+ ctx.part(
444
+ `lamp_${t}_${kind}_lens`,
445
+ cylinder({
446
+ radius: 0.06,
447
+ length: 0.01,
448
+ segments: lod === 2 ? 4 : 8,
449
+ axis: 'x',
450
+ at: [0.085, ly, lz],
451
+ color: lens,
452
+ }),
453
+ );
454
+ ctx.socket(`lamp_${t}_${kind}_light`, {
455
+ kind: 'light',
456
+ at: [0.1, ly, lz],
457
+ dir: [1, 0, 0],
458
+ data: { aspect: kind },
459
+ });
460
+ const a = arm(kind, lod);
461
+ const name = `arm_${t}_${kind}`;
462
+ ctx.group(name, {
463
+ at: [0, y, pz],
464
+ // Lower quadrant: about −X the blade (+Y) drops; stop → 60° clear → stop.
465
+ motion: {
466
+ kind: 'sway',
467
+ axis: [-1, 0, 0],
468
+ degrees: 60,
469
+ hz: 0.08 + 0.02 * k,
470
+ oneWay: true,
471
+ },
472
+ });
473
+ ctx.part(`${name}_spectacle`, a.spectacle, { parent: name });
474
+ ctx.part(`${name}_blade`, a.blade, { parent: name });
475
+ }
476
+ ctx.part(`mast_${t}`, merge(mast));
477
+ });
478
+ },
479
+ });
480
+
481
+ export const signal_gantry = bridge.variant({
482
+ name: 'signal_gantry',
483
+ description:
484
+ 'US lattice semaphore signal bridge over two tracks (c. 1910): lattice posts and girder, walkway, a mast per track with lower-quadrant home and distant arms, spectacles and lamps.',
485
+ checks: [clearanceEnvelope(2)],
486
+ });
487
+
488
+ export const signal_gantry_4 = bridge.variant({
489
+ name: 'signal_gantry_4',
490
+ description: 'The same signal bridge over four tracks, as in the 1909 photograph.',
491
+ params: { tracks: 4 },
492
+ real: {
493
+ length: GIRDER_W + 0.12, // walkway + hand rail
494
+ width: 2 * halfSpan(4) + 0.9,
495
+ height: DECK_Z + MAST_H + 0.2,
496
+ measures: [
497
+ {
498
+ label: 'track centres (13 ft)',
499
+ value: TRACK_CENTRES,
500
+ axis: 'y',
501
+ between: ['mast_0', 'mast_1'],
502
+ source: 'Track spacing',
503
+ },
504
+ {
505
+ label: 'post to track centre (8 ft 6 in)',
506
+ value: POST_CLEAR,
507
+ axis: 'y',
508
+ between: ['post_r', 'mast_0'],
509
+ source: 'Illinois 92 §1500',
510
+ },
511
+ {
512
+ label: 'blade length (5 ft)',
513
+ value: BLADE_L,
514
+ axis: 'y',
515
+ parts: ['arm_0_home_blade'],
516
+ source: 'railroadsignals.us',
517
+ },
518
+ ],
519
+ },
520
+ budget: { triangles: [13000, 5900, 1460] },
521
+ checks: [clearanceEnvelope(4)],
522
+ });
@@ -0,0 +1,39 @@
1
+ # Country station — GWR standard brick building, Toddington (1904) (`station_halt`)
2
+
3
+ ## Identity
4
+ The Great Western Railway's standard small brick station of c. 1900, as at Toddington
5
+ (Honeybourne line, opened 1 Dec 1904; restored by the Gloucestershire Warwickshire Railway and the
6
+ basis of the Bachmann/Scenecraft "GWR standard station"). Chosen because it is the archetypal
7
+ British country station and is photographed from every side. Signature features: one-storey red
8
+ brick building with a blue-brick plinth, segment-headed sash windows and panelled doors all opening
9
+ onto the platform, a steep slate gable roof with tall brick stacks, a deep platform canopy with a
10
+ fretted timber valance in GWR chocolate & cream, a brick-faced platform with a pale stone coping,
11
+ benches against the wall, oil/gas lamps and a black running-in name board.
12
+
13
+ ## Specs
14
+ | Dimension | Value (m) | Source |
15
+ |---|---|---|
16
+ | platform height over rail | 0.915 (3 ft, UK standard) | https://en.wikipedia.org/wiki/Railway_platform_height |
17
+ | platform length (real) | 120 (400 ft); a 30 m section is modelled | https://en.wikipedia.org/wiki/Toddington_railway_station |
18
+ | building footprint | ≈ 20.0 × 6.4 | ESTIMATE: scaled from the photos (doors 2.1 m, people 1.75 m) |
19
+ | wall height (platform → eaves) | ≈ 3.9 | ESTIMATE, same photos |
20
+ | roof pitch | ≈ 33° | ESTIMATE, gable end in the photo |
21
+ | canopy depth / valance | ≈ 3.4 / 0.5 | ESTIMATE, platform photo |
22
+ | brick course | 0.075 (UK brick 65 mm + 10 mm joint) | trim-sheet `brick` strip (true scale) |
23
+
24
+ ## Photos (by view)
25
+ | View | URL | Notes |
26
+ |---|---|---|
27
+ | 3/4 from the opposite platform | https://commons.wikimedia.org/wiki/File:Toddington_Railway_Station_GWSR_001.jpg | gable end, canopy + valance, stacks, name board, platform coping |
28
+ | along the platform | https://commons.wikimedia.org/wiki/File:Toddington_railway_station_1.jpg | canopy underside, clock, benches with cast "GWR" ends, sign boards |
29
+ | road side | https://commons.wikimedia.org/wiki/File:Toddington_railway_station9.4.05.jpg | back elevation |
30
+ | model of the type | https://www.bachmann.co.uk/product/gwr-standard-station---chocolate-and-cream/44-1019 | the standard design, based on Toddington |
31
+
32
+ ## Parts the engine needs
33
+ `platform`, `building`, `roof`, `canopy` (static) · `lamp_*` (glow) · sockets `bench_*` (seat),
34
+ `door_*` (interact) · emitters `chimney_*` (smoke).
35
+
36
+ ## Open questions
37
+ - Toddington's canopy is cantilevered from the wall on brackets; this model carries its front edge on
38
+ cast-iron columns (the other common GWR arrangement and the brief's ask). Flagged deviation.
39
+ - No measured drawing was found online; building and canopy dimensions are photo estimates.