@developerz.ai/ts23d 0.0.0-stage → 0.1.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.
- package/.claude/agents/bug-hunter.md +21 -0
- package/.claude/agents/docs-author.md +13 -0
- package/.claude/agents/dx-auditor.md +14 -0
- package/.claude/agents/primitive-author.md +22 -0
- package/.claude/agents/recipe-author.md +36 -0
- package/.claude/agents/visual-reviewer.md +23 -0
- package/.claude/commands/feature.md +28 -0
- package/.claude/commands/new-recipe.md +19 -0
- package/.claude/commands/release.md +14 -0
- package/.claude/commands/verify.md +9 -0
- package/.claude/skills/author-recipe/SKILL.md +93 -0
- package/CHANGELOG.md +79 -0
- package/CLAUDE.md +85 -0
- package/LICENSE +21 -0
- package/README.md +380 -2
- package/dist/chunk-11v28977.js +1575 -0
- package/dist/chunk-11v28977.js.map +30 -0
- package/dist/chunk-1ypfs7ga.js +3571 -0
- package/dist/chunk-1ypfs7ga.js.map +42 -0
- package/dist/chunk-4ddzsqtc.js +464 -0
- package/dist/chunk-4ddzsqtc.js.map +19 -0
- package/dist/chunk-a8fxakcj.js +19 -0
- package/dist/chunk-a8fxakcj.js.map +11 -0
- package/dist/chunk-gcyp9b4d.js +755 -0
- package/dist/chunk-gcyp9b4d.js.map +22 -0
- package/dist/chunk-kgvbpqqw.js +44 -0
- package/dist/chunk-kgvbpqqw.js.map +10 -0
- package/dist/chunk-kvcep7ft.js +1919 -0
- package/dist/chunk-kvcep7ft.js.map +43 -0
- package/dist/chunk-ravbb06q.js +89 -0
- package/dist/chunk-ravbb06q.js.map +11 -0
- package/dist/chunk-w1zyhj40.js +1031 -0
- package/dist/chunk-w1zyhj40.js.map +21 -0
- package/dist/chunk-wtqhq529.js +2532 -0
- package/dist/chunk-wtqhq529.js.map +43 -0
- package/dist/chunk-xnt2sdhf.js +836 -0
- package/dist/chunk-xnt2sdhf.js.map +17 -0
- package/dist/cli/args.d.ts +24 -0
- package/dist/cli/bin.d.ts +2 -0
- package/dist/cli/bin.js +307 -0
- package/dist/cli/bin.js.map +14 -0
- package/dist/cli/load.d.ts +2 -0
- package/dist/cli/manifest.d.ts +49 -0
- package/dist/cli/render-cmds.d.ts +12 -0
- package/dist/cli/run.d.ts +1 -0
- package/dist/core/asset.d.ts +10 -0
- package/dist/core/definition.d.ts +148 -0
- package/dist/core/errors.d.ts +17 -0
- package/dist/core/family.d.ts +23 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.js +69 -0
- package/dist/core/index.js.map +9 -0
- package/dist/core/mesh.d.ts +35 -0
- package/dist/core/part.d.ts +114 -0
- package/dist/core/png.d.ts +1 -0
- package/dist/core/rng.d.ts +12 -0
- package/dist/core/transform.d.ts +20 -0
- package/dist/core/vec.d.ts +11 -0
- package/dist/core/world.d.ts +16 -0
- package/dist/export/bin-writer.d.ts +16 -0
- package/dist/export/container.d.ts +3 -0
- package/dist/export/glb.d.ts +38 -0
- package/dist/export/index.d.ts +4 -0
- package/dist/export/index.js +26 -0
- package/dist/export/index.js.map +9 -0
- package/dist/export/lights.d.ts +8 -0
- package/dist/export/materials.d.ts +23 -0
- package/dist/export/merge-pivots.d.ts +6 -0
- package/dist/export/metadata.d.ts +19 -0
- package/dist/export/motion.d.ts +9 -0
- package/dist/export/optimize-parts.d.ts +26 -0
- package/dist/export/primitive.d.ts +3 -0
- package/dist/export/tangents.d.ts +2 -0
- package/dist/export/textures.d.ts +22 -0
- package/dist/export/version.d.ts +2 -0
- package/dist/grammar/index.d.ts +2 -0
- package/dist/grammar/index.js +16 -0
- package/dist/grammar/index.js.map +9 -0
- package/dist/grammar/split.d.ts +21 -0
- package/dist/grammar/whyte.d.ts +5 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +411 -0
- package/dist/index.js.map +9 -0
- package/dist/kinds/building.d.ts +44 -0
- package/dist/kinds/faces.d.ts +27 -0
- package/dist/kinds/head-armour.d.ts +9 -0
- package/dist/kinds/head-beard.d.ts +6 -0
- package/dist/kinds/head-bust.d.ts +4 -0
- package/dist/kinds/head-extras.d.ts +15 -0
- package/dist/kinds/head-face.d.ts +6 -0
- package/dist/kinds/head-geom.d.ts +7 -0
- package/dist/kinds/head-hair.d.ts +4 -0
- package/dist/kinds/head-layout.d.ts +29 -0
- package/dist/kinds/head-mesh.d.ts +27 -0
- package/dist/kinds/head-params.d.ts +108 -0
- package/dist/kinds/head-presets.d.ts +19 -0
- package/dist/kinds/head-rim.d.ts +10 -0
- package/dist/kinds/head.d.ts +39 -0
- package/dist/kinds/hull-lines.d.ts +65 -0
- package/dist/kinds/hull-skin.d.ts +6 -0
- package/dist/kinds/hull.d.ts +14 -0
- package/dist/kinds/index.d.ts +16 -0
- package/dist/kinds/index.js +78 -0
- package/dist/kinds/index.js.map +9 -0
- package/dist/kinds/mass.d.ts +15 -0
- package/dist/kinds/openings.d.ts +30 -0
- package/dist/kinds/planned.d.ts +6 -0
- package/dist/kinds/roof-chimney.d.ts +16 -0
- package/dist/kinds/roof-shape.d.ts +64 -0
- package/dist/kinds/roof.d.ts +31 -0
- package/dist/kinds/vegetation-fronds.d.ts +15 -0
- package/dist/kinds/vegetation-impostor.d.ts +9 -0
- package/dist/kinds/vegetation-leaves.d.ts +15 -0
- package/dist/kinds/vegetation-mesh.d.ts +21 -0
- package/dist/kinds/vegetation-params.d.ts +90 -0
- package/dist/kinds/vegetation-presets.d.ts +20 -0
- package/dist/kinds/vegetation-skeleton.d.ts +20 -0
- package/dist/kinds/vegetation.d.ts +42 -0
- package/dist/kinds/vehicle.d.ts +42 -0
- package/dist/material/generator.d.ts +4 -0
- package/dist/material/index.d.ts +4 -0
- package/dist/material/index.js +38 -0
- package/dist/material/index.js.map +9 -0
- package/dist/material/paint/bond.d.ts +3 -0
- package/dist/material/paint/canvas.d.ts +32 -0
- package/dist/material/paint/cell.d.ts +4 -0
- package/dist/material/paint/cells-round.d.ts +5 -0
- package/dist/material/paint/cells.d.ts +7 -0
- package/dist/material/paint/compose.d.ts +5 -0
- package/dist/material/paint/concrete.d.ts +3 -0
- package/dist/material/paint/courses.d.ts +31 -0
- package/dist/material/paint/decode-png.d.ts +6 -0
- package/dist/material/paint/default-sheet.d.ts +2 -0
- package/dist/material/paint/foliage-broad.d.ts +5 -0
- package/dist/material/paint/foliage-common.d.ts +35 -0
- package/dist/material/paint/foliage-compound.d.ts +4 -0
- package/dist/material/paint/foliage-conifer.d.ts +5 -0
- package/dist/material/paint/foliage-raster.d.ts +26 -0
- package/dist/material/paint/foliage.d.ts +3 -0
- package/dist/material/paint/masks.d.ts +3 -0
- package/dist/material/paint/noise.d.ts +9 -0
- package/dist/material/paint/normal.d.ts +8 -0
- package/dist/material/paint/orm.d.ts +8 -0
- package/dist/material/paint/planks.d.ts +3 -0
- package/dist/material/paint/plates.d.ts +3 -0
- package/dist/material/paint/shapes.d.ts +8 -0
- package/dist/material/paint/slate.d.ts +3 -0
- package/dist/material/paint/stamp.d.ts +3 -0
- package/dist/material/paint/strip.d.ts +3 -0
- package/dist/material/paint/surface.d.ts +5 -0
- package/dist/material/paint/types.d.ts +35 -0
- package/dist/material/paint/validate.d.ts +3 -0
- package/dist/material/palette.d.ts +12 -0
- package/dist/material/shader-godot.d.ts +2 -0
- package/dist/material/shader-three.d.ts +2 -0
- package/dist/material/shader.d.ts +46 -0
- package/dist/material/trim-sheet.d.ts +22 -0
- package/dist/neural/generator.d.ts +25 -0
- package/dist/neural/images.d.ts +17 -0
- package/dist/neural/index.d.ts +2 -0
- package/dist/neural/index.js +14 -0
- package/dist/neural/index.js.map +9 -0
- package/dist/passes/bake-ao.d.ts +17 -0
- package/dist/passes/grime.d.ts +15 -0
- package/dist/passes/index.d.ts +6 -0
- package/dist/passes/index.js +22 -0
- package/dist/passes/index.js.map +9 -0
- package/dist/passes/livery.d.ts +19 -0
- package/dist/passes/optimize-cache.d.ts +15 -0
- package/dist/passes/optimize-weld.d.ts +15 -0
- package/dist/passes/optimize.d.ts +28 -0
- package/dist/passes/ray-grid.d.ts +23 -0
- package/dist/passes/weighted-normals.d.ts +8 -0
- package/dist/primitives/beam.d.ts +17 -0
- package/dist/primitives/bevel-box.d.ts +13 -0
- package/dist/primitives/box.d.ts +16 -0
- package/dist/primitives/cell.d.ts +20 -0
- package/dist/primitives/check.d.ts +12 -0
- package/dist/primitives/closed.d.ts +11 -0
- package/dist/primitives/erosion.d.ts +22 -0
- package/dist/primitives/font-5x7.d.ts +3 -0
- package/dist/primitives/heightfield.d.ts +16 -0
- package/dist/primitives/index.d.ts +23 -0
- package/dist/primitives/index.js +81 -0
- package/dist/primitives/index.js.map +9 -0
- package/dist/primitives/lathe-facets.d.ts +8 -0
- package/dist/primitives/lathe.d.ts +26 -0
- package/dist/primitives/lattice.d.ts +30 -0
- package/dist/primitives/loft.d.ts +15 -0
- package/dist/primitives/mc-table.d.ts +2 -0
- package/dist/primitives/member.d.ts +19 -0
- package/dist/primitives/noise.d.ts +34 -0
- package/dist/primitives/planar.d.ts +10 -0
- package/dist/primitives/prism.d.ts +13 -0
- package/dist/primitives/sculpt-edit.d.ts +56 -0
- package/dist/primitives/sculpt-tree.d.ts +23 -0
- package/dist/primitives/sculpt.d.ts +27 -0
- package/dist/primitives/sdf-grid.d.ts +17 -0
- package/dist/primitives/sdf-ops.d.ts +37 -0
- package/dist/primitives/sdf.d.ts +21 -0
- package/dist/primitives/strip-uv.d.ts +11 -0
- package/dist/primitives/surface-nets.d.ts +7 -0
- package/dist/primitives/sweep.d.ts +19 -0
- package/dist/primitives/terrain-color.d.ts +30 -0
- package/dist/primitives/terrain-grid.d.ts +36 -0
- package/dist/primitives/text-layout.d.ts +22 -0
- package/dist/primitives/text.d.ts +27 -0
- package/dist/primitives/tiled.d.ts +22 -0
- package/dist/primitives/transport.d.ts +17 -0
- package/dist/primitives/triangulate.d.ts +2 -0
- package/dist/primitives/value-noise.d.ts +10 -0
- package/dist/qa/checks.d.ts +11 -0
- package/dist/qa/clash.d.ts +2 -0
- package/dist/qa/floating.d.ts +5 -0
- package/dist/qa/gates.d.ts +12 -0
- package/dist/qa/geometry.d.ts +21 -0
- package/dist/qa/index.d.ts +12 -0
- package/dist/qa/index.js +78 -0
- package/dist/qa/index.js.map +9 -0
- package/dist/qa/inside.d.ts +12 -0
- package/dist/qa/inspect.d.ts +18 -0
- package/dist/qa/lods.d.ts +12 -0
- package/dist/qa/measures.d.ts +4 -0
- package/dist/qa/occlusion.d.ts +3 -0
- package/dist/qa/sanity.d.ts +7 -0
- package/dist/qa/types.d.ts +12 -0
- package/dist/render/beauty.d.ts +40 -0
- package/dist/render/camera.d.ts +33 -0
- package/dist/render/depth-map.d.ts +38 -0
- package/dist/render/font.d.ts +1 -0
- package/dist/render/ground.d.ts +13 -0
- package/dist/render/index.d.ts +10 -0
- package/dist/render/index.js +47 -0
- package/dist/render/index.js.map +9 -0
- package/dist/render/lighting.d.ts +20 -0
- package/dist/render/lod-strip.d.ts +5 -0
- package/dist/render/metrics.d.ts +37 -0
- package/dist/render/options.d.ts +28 -0
- package/dist/render/photo-match.d.ts +19 -0
- package/dist/render/raster.d.ts +25 -0
- package/dist/render/resolve.d.ts +11 -0
- package/dist/render/review-prompt.d.ts +2 -0
- package/dist/render/review-warnings.d.ts +34 -0
- package/dist/render/review.d.ts +24 -0
- package/dist/render/scene.d.ts +18 -0
- package/dist/render/shade.d.ts +22 -0
- package/dist/render/sheet.d.ts +15 -0
- package/dist/render/texture.d.ts +15 -0
- package/dist/render/thumbnail.d.ts +8 -0
- package/dist/render/vis-buffer.d.ts +18 -0
- package/dist/testing/assert.d.ts +21 -0
- package/dist/testing/compiled.d.ts +15 -0
- package/dist/testing/hash.d.ts +1 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.js +134 -0
- package/dist/testing/index.js.map +13 -0
- package/dist/testing/snapshot.d.ts +13 -0
- package/docs/README.md +52 -0
- package/docs/architecture/README.md +68 -0
- package/docs/architecture/adding-a-kind.md +44 -0
- package/docs/architecture/adding-a-primitive.md +49 -0
- package/docs/architecture/errors.md +47 -0
- package/docs/architecture/glb-production.md +214 -0
- package/docs/architecture/gltf-capabilities.md +80 -0
- package/docs/decisions/001-recipe-compiler-over-ai-meshes.md +27 -0
- package/docs/decisions/002-typescript-not-json.md +22 -0
- package/docs/decisions/003-shared-trim-sheet.md +21 -0
- package/docs/decisions/004-z-up-metres.md +21 -0
- package/docs/decisions/005-zero-runtime-deps.md +21 -0
- package/docs/decisions/006-single-package-subpath-exports.md +20 -0
- package/docs/decisions/007-cpu-contact-sheets.md +21 -0
- package/docs/decisions/008-surface-materials.md +21 -0
- package/docs/decisions/009-gltf-front-axis.md +21 -0
- package/docs/decisions/README.md +15 -0
- package/docs/idea/01-vision.md +117 -0
- package/docs/idea/02-dsl.md +343 -0
- package/docs/idea/03-ir.md +97 -0
- package/docs/idea/04-materials.md +114 -0
- package/docs/idea/05-agent-loop.md +141 -0
- package/docs/idea/06-qa.md +101 -0
- package/docs/idea/07-what-fits.md +45 -0
- package/docs/idea/08-neural-adapters.md +78 -0
- package/docs/idea/09-kinds.md +105 -0
- package/docs/landscape.md +49 -0
- package/docs/plans/roadmap.md +127 -0
- package/examples/build-with-bun.ts +41 -0
- package/llms.txt +47 -0
- package/package.json +99 -4
- package/recipes/README.md +38 -0
- package/recipes/asteroid/README.md +46 -0
- package/recipes/asteroid/asteroid.ts +336 -0
- package/recipes/boulders/README.md +28 -0
- package/recipes/boulders/boulders.ts +117 -0
- package/recipes/boxcar/README.md +46 -0
- package/recipes/boxcar/boxcar.ts +916 -0
- package/recipes/cargo_container_scifi/README.md +52 -0
- package/recipes/cargo_container_scifi/cargo_container_scifi.ts +461 -0
- package/recipes/dropship/README.md +84 -0
- package/recipes/dropship/dropship.ts +1144 -0
- package/recipes/eiffel_tower/README.md +110 -0
- package/recipes/eiffel_tower/eiffel_tower.ts +781 -0
- package/recipes/goblin_head/README.md +62 -0
- package/recipes/goblin_head/goblin_head.ts +36 -0
- package/recipes/human_head/README.md +64 -0
- package/recipes/human_head/human_head.ts +37 -0
- package/recipes/loco_440/README.md +32 -0
- package/recipes/loco_440/loco_440.ts +1404 -0
- package/recipes/material_swatches/README.md +21 -0
- package/recipes/material_swatches/material_swatches.ts +183 -0
- package/recipes/mountain_range/README.md +45 -0
- package/recipes/mountain_range/mountain_range.ts +128 -0
- package/recipes/oak/README.md +30 -0
- package/recipes/oak/oak.ts +19 -0
- package/recipes/orc_head/README.md +66 -0
- package/recipes/orc_head/orc_head.ts +39 -0
- package/recipes/palm/README.md +30 -0
- package/recipes/palm/palm.ts +19 -0
- package/recipes/pine/README.md +29 -0
- package/recipes/pine/pine.ts +19 -0
- package/recipes/signal_gantry/README.md +36 -0
- package/recipes/signal_gantry/signal_gantry.ts +522 -0
- package/recipes/station_halt/README.md +39 -0
- package/recipes/station_halt/station_halt.ts +722 -0
- package/recipes/t34/README.md +44 -0
- package/recipes/t34/t34.ts +1068 -0
- package/recipes/tiger_1/README.md +75 -0
- package/recipes/tiger_1/tiger_1.ts +1370 -0
- package/recipes/water_tower/README.md +40 -0
- package/recipes/water_tower/water_tower.ts +542 -0
- package/src/cli/args.ts +112 -0
- package/src/cli/bin.ts +7 -0
- package/src/cli/load.ts +17 -0
- package/src/cli/manifest.ts +89 -0
- package/src/cli/render-cmds.ts +66 -0
- package/src/cli/run.ts +168 -0
- package/src/core/asset.ts +128 -0
- package/src/core/definition.ts +149 -0
- package/src/core/errors.ts +45 -0
- package/src/core/family.ts +50 -0
- package/src/core/index.ts +66 -0
- package/src/core/mesh.ts +114 -0
- package/src/core/part.ts +130 -0
- package/src/core/png.ts +49 -0
- package/src/core/rng.ts +49 -0
- package/src/core/transform.ts +90 -0
- package/src/core/vec.ts +26 -0
- package/src/core/world.ts +80 -0
- package/src/export/bin-writer.ts +79 -0
- package/src/export/container.ts +35 -0
- package/src/export/glb.ts +200 -0
- package/src/export/index.ts +18 -0
- package/src/export/lights.ts +49 -0
- package/src/export/materials.ts +126 -0
- package/src/export/merge-pivots.ts +146 -0
- package/src/export/metadata.ts +59 -0
- package/src/export/motion.ts +70 -0
- package/src/export/optimize-parts.ts +80 -0
- package/src/export/primitive.ts +35 -0
- package/src/export/tangents.ts +75 -0
- package/src/export/textures.ts +88 -0
- package/src/export/version.ts +6 -0
- package/src/grammar/index.ts +4 -0
- package/src/grammar/split.ts +87 -0
- package/src/grammar/whyte.ts +20 -0
- package/src/index.ts +14 -0
- package/src/kinds/building.ts +153 -0
- package/src/kinds/faces.ts +138 -0
- package/src/kinds/head-armour.ts +151 -0
- package/src/kinds/head-beard.ts +133 -0
- package/src/kinds/head-bust.ts +221 -0
- package/src/kinds/head-extras.ts +150 -0
- package/src/kinds/head-face.ts +222 -0
- package/src/kinds/head-geom.ts +31 -0
- package/src/kinds/head-hair.ts +152 -0
- package/src/kinds/head-layout.ts +63 -0
- package/src/kinds/head-mesh.ts +157 -0
- package/src/kinds/head-params.ts +153 -0
- package/src/kinds/head-presets.ts +152 -0
- package/src/kinds/head-rim.ts +128 -0
- package/src/kinds/head.ts +171 -0
- package/src/kinds/hull-lines.ts +160 -0
- package/src/kinds/hull-skin.ts +83 -0
- package/src/kinds/hull.ts +209 -0
- package/src/kinds/index.ts +63 -0
- package/src/kinds/mass.ts +110 -0
- package/src/kinds/openings.ts +141 -0
- package/src/kinds/planned.ts +12 -0
- package/src/kinds/roof-chimney.ts +100 -0
- package/src/kinds/roof-shape.ts +230 -0
- package/src/kinds/roof.ts +250 -0
- package/src/kinds/vegetation-fronds.ts +126 -0
- package/src/kinds/vegetation-impostor.ts +118 -0
- package/src/kinds/vegetation-leaves.ts +168 -0
- package/src/kinds/vegetation-mesh.ts +174 -0
- package/src/kinds/vegetation-params.ts +147 -0
- package/src/kinds/vegetation-presets.ts +184 -0
- package/src/kinds/vegetation-skeleton.ts +168 -0
- package/src/kinds/vegetation.ts +199 -0
- package/src/kinds/vehicle.ts +144 -0
- package/src/material/generator.ts +56 -0
- package/src/material/index.ts +29 -0
- package/src/material/paint/bond.ts +60 -0
- package/src/material/paint/canvas.ts +91 -0
- package/src/material/paint/cell.ts +39 -0
- package/src/material/paint/cells-round.ts +119 -0
- package/src/material/paint/cells.ts +111 -0
- package/src/material/paint/compose.ts +53 -0
- package/src/material/paint/concrete.ts +62 -0
- package/src/material/paint/courses.ts +85 -0
- package/src/material/paint/decode-png.ts +100 -0
- package/src/material/paint/default-sheet.ts +61 -0
- package/src/material/paint/foliage-broad.ts +126 -0
- package/src/material/paint/foliage-common.ts +93 -0
- package/src/material/paint/foliage-compound.ts +135 -0
- package/src/material/paint/foliage-conifer.ts +143 -0
- package/src/material/paint/foliage-raster.ts +196 -0
- package/src/material/paint/foliage.ts +23 -0
- package/src/material/paint/masks.ts +44 -0
- package/src/material/paint/noise.ts +52 -0
- package/src/material/paint/normal.ts +52 -0
- package/src/material/paint/orm.ts +95 -0
- package/src/material/paint/planks.ts +56 -0
- package/src/material/paint/plates.ts +72 -0
- package/src/material/paint/shapes.ts +28 -0
- package/src/material/paint/slate.ts +52 -0
- package/src/material/paint/stamp.ts +40 -0
- package/src/material/paint/strip.ts +42 -0
- package/src/material/paint/surface.ts +60 -0
- package/src/material/paint/types.ts +51 -0
- package/src/material/paint/validate.ts +58 -0
- package/src/material/palette.ts +43 -0
- package/src/material/shader-godot.ts +77 -0
- package/src/material/shader-three.ts +103 -0
- package/src/material/shader.ts +100 -0
- package/src/material/trim-sheet.ts +100 -0
- package/src/neural/generator.ts +37 -0
- package/src/neural/images.ts +27 -0
- package/src/neural/index.ts +10 -0
- package/src/passes/bake-ao.ts +183 -0
- package/src/passes/grime.ts +37 -0
- package/src/passes/index.ts +8 -0
- package/src/passes/livery.ts +66 -0
- package/src/passes/optimize-cache.ts +175 -0
- package/src/passes/optimize-weld.ts +147 -0
- package/src/passes/optimize.ts +85 -0
- package/src/passes/ray-grid.ts +237 -0
- package/src/passes/weighted-normals.ts +125 -0
- package/src/primitives/beam.ts +60 -0
- package/src/primitives/bevel-box.ts +140 -0
- package/src/primitives/box.ts +90 -0
- package/src/primitives/cell.ts +115 -0
- package/src/primitives/check.ts +49 -0
- package/src/primitives/closed.ts +74 -0
- package/src/primitives/erosion.ts +183 -0
- package/src/primitives/font-5x7.ts +117 -0
- package/src/primitives/heightfield.ts +101 -0
- package/src/primitives/index.ts +56 -0
- package/src/primitives/lathe-facets.ts +45 -0
- package/src/primitives/lathe.ts +174 -0
- package/src/primitives/lattice.ts +131 -0
- package/src/primitives/loft.ts +174 -0
- package/src/primitives/mc-table.ts +41 -0
- package/src/primitives/member.ts +130 -0
- package/src/primitives/noise.ts +157 -0
- package/src/primitives/planar.ts +55 -0
- package/src/primitives/prism.ts +85 -0
- package/src/primitives/sculpt-edit.ts +212 -0
- package/src/primitives/sculpt-tree.ts +226 -0
- package/src/primitives/sculpt.ts +80 -0
- package/src/primitives/sdf-grid.ts +131 -0
- package/src/primitives/sdf-ops.ts +145 -0
- package/src/primitives/sdf.ts +83 -0
- package/src/primitives/strip-uv.ts +26 -0
- package/src/primitives/surface-nets.ts +161 -0
- package/src/primitives/sweep.ts +162 -0
- package/src/primitives/terrain-color.ts +85 -0
- package/src/primitives/terrain-grid.ts +137 -0
- package/src/primitives/text-layout.ts +85 -0
- package/src/primitives/text.ts +197 -0
- package/src/primitives/tiled.ts +93 -0
- package/src/primitives/transport.ts +85 -0
- package/src/primitives/triangulate.ts +42 -0
- package/src/primitives/value-noise.ts +62 -0
- package/src/qa/checks.ts +110 -0
- package/src/qa/clash.ts +177 -0
- package/src/qa/floating.ts +63 -0
- package/src/qa/gates.ts +126 -0
- package/src/qa/geometry.ts +187 -0
- package/src/qa/index.ts +28 -0
- package/src/qa/inside.ts +114 -0
- package/src/qa/inspect.ts +107 -0
- package/src/qa/lods.ts +97 -0
- package/src/qa/measures.ts +67 -0
- package/src/qa/occlusion.ts +166 -0
- package/src/qa/sanity.ts +137 -0
- package/src/qa/types.ts +17 -0
- package/src/render/beauty.ts +115 -0
- package/src/render/camera.ts +142 -0
- package/src/render/depth-map.ts +191 -0
- package/src/render/font.ts +76 -0
- package/src/render/ground.ts +87 -0
- package/src/render/index.ts +34 -0
- package/src/render/lighting.ts +95 -0
- package/src/render/lod-strip.ts +34 -0
- package/src/render/metrics.ts +147 -0
- package/src/render/options.ts +81 -0
- package/src/render/photo-match.ts +28 -0
- package/src/render/raster.ts +143 -0
- package/src/render/resolve.ts +109 -0
- package/src/render/review-prompt.ts +59 -0
- package/src/render/review-warnings.ts +92 -0
- package/src/render/review.ts +103 -0
- package/src/render/scene.ts +119 -0
- package/src/render/shade.ts +199 -0
- package/src/render/sheet.ts +88 -0
- package/src/render/texture.ts +97 -0
- package/src/render/thumbnail.ts +75 -0
- package/src/render/vis-buffer.ts +119 -0
- package/src/testing/assert.ts +115 -0
- package/src/testing/compiled.ts +31 -0
- package/src/testing/hash.ts +14 -0
- package/src/testing/index.ts +14 -0
- package/src/testing/snapshot.ts +37 -0
- package/src/types/gltf-validator.d.ts +13 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// Vessel hulls from the lines plan (hull-lines.ts): a smooth-shaded shell skinned over stations
|
|
2
|
+
// (denser toward bow and stern), split at the waterline and boot-top so the paint bands are crisp,
|
|
3
|
+
// optional bulwarks with a cap rail, a cambered plank deck laid in true-scale bands fore and aft,
|
|
4
|
+
// and a flat transom. Waterline at `at` z, bow +X. LOD = stations × section points, nothing else.
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
type BuildContext,
|
|
8
|
+
type Lod,
|
|
9
|
+
type Mesh,
|
|
10
|
+
MeshBuilder,
|
|
11
|
+
merge,
|
|
12
|
+
translate,
|
|
13
|
+
type Vec3,
|
|
14
|
+
} from '../core/index.ts';
|
|
15
|
+
import { stripRect } from '../material/index.ts';
|
|
16
|
+
import { sweep, triangulate } from '../primitives/index.ts';
|
|
17
|
+
import { dedupe, stripScale } from './faces.ts';
|
|
18
|
+
import { type HullLines, type HullOptions, hullLines, thetaAt } from './hull-lines.ts';
|
|
19
|
+
import { emitBand, type Grid, normalsOf } from './hull-skin.ts';
|
|
20
|
+
|
|
21
|
+
export type { HullColors, HullLines, HullOptions } from './hull-lines.ts';
|
|
22
|
+
|
|
23
|
+
/** Width of one deck band (one V of the wood strip); LOD2 squeezes the whole beam into one. */
|
|
24
|
+
const deckBand = (o: HullOptions, lod: Lod): number => (lod === 2 ? o.beam : stripScale('wood'));
|
|
25
|
+
|
|
26
|
+
/** Plank deck between the bulwarks: bands `wood` scale wide, planks running fore and aft. */
|
|
27
|
+
function deckMesh(o: HullOptions, ln: HullLines, xs: readonly number[], inset: number, lod: Lod) {
|
|
28
|
+
const b = new MeshBuilder();
|
|
29
|
+
const rect = stripRect('wood');
|
|
30
|
+
const w = deckBand(o, lod);
|
|
31
|
+
const camber = o.camber ?? o.beam / 50;
|
|
32
|
+
const yd = (x: number): number => Math.max(0, ln.halfBreadth(x) - inset);
|
|
33
|
+
for (let y0 = -Math.ceil(o.beam / 2 / w) * w; y0 < o.beam / 2; y0 += w) {
|
|
34
|
+
const at = (x: number, y: number): Vec3 => {
|
|
35
|
+
const h = yd(x);
|
|
36
|
+
const c = Math.max(-h, Math.min(h, y));
|
|
37
|
+
return [x, c, ln.deck(x) + (h > 0 ? camber * (1 - (c / h) ** 2) : 0)];
|
|
38
|
+
};
|
|
39
|
+
for (let i = 0; i + 1 < xs.length; i++) {
|
|
40
|
+
const x0 = xs[i] ?? 0;
|
|
41
|
+
const x1 = xs[i + 1] ?? 0;
|
|
42
|
+
const q = [at(x0, y0), at(x0, y0 + w), at(x1, y0 + w), at(x1, y0)];
|
|
43
|
+
if (
|
|
44
|
+
Math.abs((q[1]?.[1] ?? 0) - (q[0]?.[1] ?? 0)) +
|
|
45
|
+
Math.abs((q[2]?.[1] ?? 0) - (q[3]?.[1] ?? 0)) <
|
|
46
|
+
1e-6
|
|
47
|
+
)
|
|
48
|
+
continue;
|
|
49
|
+
const ids = q.map((p) =>
|
|
50
|
+
b.vertex({
|
|
51
|
+
p,
|
|
52
|
+
n: [0, 0, 1],
|
|
53
|
+
uv: [rect.u0 + p[0] / rect.metres, rect.v0 + ((p[1] - y0) / w) * (rect.v1 - rect.v0)],
|
|
54
|
+
color: o.colors.deck,
|
|
55
|
+
}),
|
|
56
|
+
);
|
|
57
|
+
b.quad(ids[0] ?? 0, ids[3] ?? 0, ids[2] ?? 0, ids[1] ?? 0);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return b.build();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface HullMesh {
|
|
64
|
+
/** Shell (+ bulwarks + transom). */
|
|
65
|
+
readonly shell: Mesh;
|
|
66
|
+
readonly deck: Mesh;
|
|
67
|
+
readonly lines: HullLines;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function hullMesh(o: HullOptions, lod: Lod = 0): HullMesh {
|
|
71
|
+
const ln = hullLines(o);
|
|
72
|
+
const half = o.length / 2;
|
|
73
|
+
const stations = [36, 18, 8][lod] ?? 8;
|
|
74
|
+
const na = [6, 3, 2][lod] ?? 2;
|
|
75
|
+
const nc = [4, 2, 1][lod] ?? 1;
|
|
76
|
+
// Cosine spacing: stations crowd the bow and stern where the shape turns.
|
|
77
|
+
const xs = Array.from(
|
|
78
|
+
{ length: stations + 1 },
|
|
79
|
+
(_, i) => -half + (o.length * (1 - Math.cos((Math.PI * i) / stations))) / 2,
|
|
80
|
+
);
|
|
81
|
+
const boot = o.bootTop ?? 0.3;
|
|
82
|
+
const hb = o.bulwark ?? 0;
|
|
83
|
+
const tb = 0.12;
|
|
84
|
+
const grid: Grid = xs.map((x) => {
|
|
85
|
+
const tw = thetaAt(ln, x, 0);
|
|
86
|
+
const tbt = thetaAt(ln, x, boot);
|
|
87
|
+
const row: Vec3[] = [];
|
|
88
|
+
const seg = (t0: number, t1: number, k: number, first: boolean) => {
|
|
89
|
+
for (let i = first ? 0 : 1; i <= k; i++) {
|
|
90
|
+
const [y, z] = ln.section(x, t0 + ((t1 - t0) * i) / k);
|
|
91
|
+
row.push([x, y, z]);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
seg(0, tw, na, true);
|
|
95
|
+
seg(tw, tbt, 1, false);
|
|
96
|
+
seg(tbt, Math.PI / 2, nc, false);
|
|
97
|
+
return row;
|
|
98
|
+
});
|
|
99
|
+
const nrm = normalsOf(grid);
|
|
100
|
+
for (const row of nrm) {
|
|
101
|
+
const n = row[0];
|
|
102
|
+
if (n) {
|
|
103
|
+
const l = Math.hypot(n[0], n[2]) || 1;
|
|
104
|
+
row[0] = [n[0] / l, 0, n[2] / l];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const b = new MeshBuilder();
|
|
108
|
+
const c = o.colors;
|
|
109
|
+
emitBand(b, grid, nrm, 0, na, c.bottom, true);
|
|
110
|
+
emitBand(b, grid, nrm, na, na + 1, c.boot ?? [0.06, 0.06, 0.06], true);
|
|
111
|
+
emitBand(b, grid, nrm, na + 1, na + 1 + nc, c.topsides, true);
|
|
112
|
+
const parts = [b.build()];
|
|
113
|
+
if (hb > 0) parts.push(bulwarks(o, ln, xs, hb, tb));
|
|
114
|
+
if (o.fender && lod < 2) parts.push(...fenders(o.fender, ln, xs, lod));
|
|
115
|
+
if ((o.stern ?? 'round') === 'transom') {
|
|
116
|
+
const x = xs[0] ?? -half;
|
|
117
|
+
const star = (grid[0] ?? []).map((p) => p);
|
|
118
|
+
if (hb > 0) star.push([x, ln.halfBreadth(x), ln.deck(x) + hb]);
|
|
119
|
+
const port = [...star].reverse().map((p): Vec3 => [p[0], -p[1], p[2]]);
|
|
120
|
+
// Without bulwarks the transom's top follows the deck camber through the deck's band seams.
|
|
121
|
+
const yd = ln.halfBreadth(x);
|
|
122
|
+
const arc: Vec3[] = [];
|
|
123
|
+
const w = deckBand(o, lod);
|
|
124
|
+
for (let y = Math.ceil(o.beam / 2 / w) * w; y > -o.beam / 2; y -= w) {
|
|
125
|
+
if (hb === 0 && Math.abs(y) < yd - 1e-9)
|
|
126
|
+
arc.push([x, y, ln.deck(x) + (o.camber ?? o.beam / 50) * (1 - (y / yd) ** 2)]);
|
|
127
|
+
}
|
|
128
|
+
parts.push(transom(dedupe([...port.slice(0, -1), ...star, ...arc]), c.topsides));
|
|
129
|
+
}
|
|
130
|
+
const at = o.at ?? [0, 0, 0];
|
|
131
|
+
return {
|
|
132
|
+
shell: translate(merge(parts), at),
|
|
133
|
+
deck: translate(deckMesh(o, ln, xs, hb > 0 ? tb : 0, lod), at),
|
|
134
|
+
lines: ln,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Bulwark: outer plate up from the deck edge, cap rail, inner face down to the deck. */
|
|
139
|
+
function bulwarks(
|
|
140
|
+
o: HullOptions,
|
|
141
|
+
ln: HullLines,
|
|
142
|
+
xs: readonly number[],
|
|
143
|
+
hb: number,
|
|
144
|
+
tb: number,
|
|
145
|
+
): Mesh {
|
|
146
|
+
const g: Grid = xs.map((x) => {
|
|
147
|
+
const y = ln.halfBreadth(x);
|
|
148
|
+
const z = ln.deck(x);
|
|
149
|
+
const yi = Math.max(0, y - tb);
|
|
150
|
+
return [
|
|
151
|
+
[x, y, z],
|
|
152
|
+
[x, y, z + hb],
|
|
153
|
+
[x, yi, z + hb],
|
|
154
|
+
[x, yi, z],
|
|
155
|
+
];
|
|
156
|
+
});
|
|
157
|
+
const b = new MeshBuilder();
|
|
158
|
+
const top = o.colors.bulwark ?? o.colors.topsides;
|
|
159
|
+
// Each face its own band so the corners stay crisp.
|
|
160
|
+
for (const [j0, color] of [
|
|
161
|
+
[0, o.colors.topsides],
|
|
162
|
+
[1, top],
|
|
163
|
+
[2, top],
|
|
164
|
+
] as const) {
|
|
165
|
+
const sliced = g.map((row) => row.slice(j0, j0 + 2));
|
|
166
|
+
emitBand(b, sliced, normalsOf(sliced), 0, 1, color, true);
|
|
167
|
+
}
|
|
168
|
+
return b.build();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** Rubbing strake / tyre fender along each side just below the sheer. */
|
|
172
|
+
function fenders(
|
|
173
|
+
f: NonNullable<HullOptions['fender']>,
|
|
174
|
+
ln: HullLines,
|
|
175
|
+
xs: readonly number[],
|
|
176
|
+
lod: Lod,
|
|
177
|
+
) {
|
|
178
|
+
const r = f.radius ?? 0.15;
|
|
179
|
+
return [1, -1].map((side) =>
|
|
180
|
+
sweep({
|
|
181
|
+
section: { radius: r, segments: lod === 0 ? 8 : 5 },
|
|
182
|
+
path: xs.map((x): Vec3 => [x, side * (ln.halfBreadth(x) + r * 0.4), ln.deck(x) - r * 1.2]),
|
|
183
|
+
color: f.color,
|
|
184
|
+
caps: true,
|
|
185
|
+
}),
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Flat stern plate facing −X (ear-clipped: the bulwark notch makes it non-convex). */
|
|
190
|
+
function transom(points: readonly Vec3[], color: Vec3): Mesh {
|
|
191
|
+
const b = new MeshBuilder();
|
|
192
|
+
const rect = stripRect('plain');
|
|
193
|
+
const ids = points.map((p) =>
|
|
194
|
+
b.vertex({ p, n: [-1, 0, 0], uv: [rect.u0 + p[1] / rect.metres, rect.v0], color }),
|
|
195
|
+
);
|
|
196
|
+
// CCW in (y, z) faces +X, so each triangle is reversed to face aft.
|
|
197
|
+
for (const [i, j, k] of triangulate(points.map((p) => [p[1], p[2]])))
|
|
198
|
+
b.tri(ids[i] ?? 0, ids[k] ?? 0, ids[j] ?? 0);
|
|
199
|
+
return b.build();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** Add `name` (shell) and `name_deck` parts; returns the lines for placing deckhouses and fittings. */
|
|
203
|
+
export function hull(ctx: BuildContext, o: HullOptions & { readonly name?: string }): HullLines {
|
|
204
|
+
const name = o.name ?? 'hull';
|
|
205
|
+
const m = hullMesh(o, ctx.lod);
|
|
206
|
+
ctx.part(name, m.shell);
|
|
207
|
+
ctx.part(`${name}_deck`, m.deck);
|
|
208
|
+
return m.lines;
|
|
209
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
// Public API of /kinds: domain builders (buildings, vehicles, vessels, vegetation) recipes compose.
|
|
2
|
+
|
|
3
|
+
export { type FacadeOptions, facade, type SetbackTier, type Side, setbacks } from './building.ts';
|
|
4
|
+
export {
|
|
5
|
+
HEAD_RES,
|
|
6
|
+
type HeadInfo,
|
|
7
|
+
type HeadOptions,
|
|
8
|
+
type HeadOverrides,
|
|
9
|
+
head,
|
|
10
|
+
headEdits,
|
|
11
|
+
headParams,
|
|
12
|
+
} from './head.ts';
|
|
13
|
+
export {
|
|
14
|
+
type BeardStyle,
|
|
15
|
+
type BustStyle,
|
|
16
|
+
checkHead,
|
|
17
|
+
type EarShape,
|
|
18
|
+
type HairStyle,
|
|
19
|
+
type HeadColors,
|
|
20
|
+
type HeadParams,
|
|
21
|
+
} from './head-params.ts';
|
|
22
|
+
// Presets by race name (`head(ctx, { race: 'orc' })`); HEADS.orc etc. for tweaking. The bare
|
|
23
|
+
// preset names (`orc`, `human`) stay internal: too generic for the top-level barrel.
|
|
24
|
+
export { HEADS, type HeadPreset } from './head-presets.ts';
|
|
25
|
+
export {
|
|
26
|
+
type HullColors,
|
|
27
|
+
type HullLines,
|
|
28
|
+
type HullMesh,
|
|
29
|
+
type HullOptions,
|
|
30
|
+
hull,
|
|
31
|
+
hullMesh,
|
|
32
|
+
} from './hull.ts';
|
|
33
|
+
export { hullLines } from './hull-lines.ts';
|
|
34
|
+
export { type MassOptions, mass } from './mass.ts';
|
|
35
|
+
export { type OpeningOptions, type OpeningSide, opening } from './openings.ts';
|
|
36
|
+
export { creature } from './planned.ts';
|
|
37
|
+
export { type RoofInfo, type RoofMeshOptions, roof, roofInfo, roofMesh } from './roof.ts';
|
|
38
|
+
export type { RoofChimney } from './roof-chimney.ts';
|
|
39
|
+
export {
|
|
40
|
+
type RoofOptions,
|
|
41
|
+
type RoofSide,
|
|
42
|
+
type RoofType,
|
|
43
|
+
ridgeHeight,
|
|
44
|
+
roofHeightAt,
|
|
45
|
+
} from './roof-shape.ts';
|
|
46
|
+
export {
|
|
47
|
+
type TreeFamilyParams,
|
|
48
|
+
type TreeInfo,
|
|
49
|
+
type TreeOptions,
|
|
50
|
+
tree,
|
|
51
|
+
treeParams,
|
|
52
|
+
treeReal,
|
|
53
|
+
trees,
|
|
54
|
+
} from './vegetation.ts';
|
|
55
|
+
export type {
|
|
56
|
+
BranchLevel,
|
|
57
|
+
CrownShape,
|
|
58
|
+
LeafParams,
|
|
59
|
+
LeafShape,
|
|
60
|
+
TreeParams,
|
|
61
|
+
} from './vegetation-params.ts';
|
|
62
|
+
export { birch, oak, palm, pine, SPECIES, type SpeciesName, willow } from './vegetation-presets.ts';
|
|
63
|
+
export { axle, propeller, trackRun, whyteAxles } from './vehicle.ts';
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// A building mass (walls block) whose masonry is laid at TRUE scale: every side is cut into
|
|
2
|
+
// course bands of the strip's `scaleMetres`, all starting from the ground line, so brick courses
|
|
3
|
+
// match across sides and across stacked masses. `box` stretches one strip band over the whole face
|
|
4
|
+
// — fine for trim, wrong for a 6 m brick wall. LOD2 keeps one quad per side (V squeezed).
|
|
5
|
+
|
|
6
|
+
import { type Lod, type Mesh, MeshBuilder, Ts23dError, type Vec3 } from '../core/index.ts';
|
|
7
|
+
import type { StripId } from '../material/index.ts';
|
|
8
|
+
import { emitFace } from './faces.ts';
|
|
9
|
+
|
|
10
|
+
export interface MassOptions {
|
|
11
|
+
/** Width (X), depth (Y), height (Z). */
|
|
12
|
+
readonly size: Vec3;
|
|
13
|
+
/** Centre of the base. */
|
|
14
|
+
readonly at?: Vec3;
|
|
15
|
+
readonly color: Vec3;
|
|
16
|
+
readonly strip?: StripId;
|
|
17
|
+
/** Courses start at this world z (default 0, the ground) so stacked masses line up. */
|
|
18
|
+
readonly courseOrigin?: number;
|
|
19
|
+
/** Skip faces nobody sees (bottom on the ground, top under a roof, a party wall). */
|
|
20
|
+
readonly omit?: readonly ('top' | 'bottom' | 'front' | 'back' | 'left' | 'right')[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function mass(o: MassOptions, lod: Lod = 0): Mesh {
|
|
24
|
+
const [w, d, h] = o.size;
|
|
25
|
+
if (!(w > 0 && d > 0 && h > 0))
|
|
26
|
+
throw new Ts23dError('T3D_RECIPE_INVALID', {
|
|
27
|
+
cause: `mass size is [${o.size.join(', ')}]`,
|
|
28
|
+
fix: 'give width (X), depth (Y) and height (Z) in metres, all > 0',
|
|
29
|
+
});
|
|
30
|
+
const [cx, cy, z0] = o.at ?? [0, 0, 0];
|
|
31
|
+
const [x0, x1, y0, y1, z1] = [cx - w / 2, cx + w / 2, cy - d / 2, cy + d / 2, z0 + h];
|
|
32
|
+
const b = new MeshBuilder();
|
|
33
|
+
const strip = o.strip ?? 'brick';
|
|
34
|
+
const origin: Vec3 = [0, 0, o.courseOrigin ?? 0];
|
|
35
|
+
const sides: [NonNullable<MassOptions['omit']>[number], Vec3, Vec3[]][] = [
|
|
36
|
+
[
|
|
37
|
+
'front',
|
|
38
|
+
[1, 0, 0],
|
|
39
|
+
[
|
|
40
|
+
[x1, y0, z0],
|
|
41
|
+
[x1, y1, z0],
|
|
42
|
+
[x1, y1, z1],
|
|
43
|
+
[x1, y0, z1],
|
|
44
|
+
],
|
|
45
|
+
],
|
|
46
|
+
[
|
|
47
|
+
'back',
|
|
48
|
+
[-1, 0, 0],
|
|
49
|
+
[
|
|
50
|
+
[x0, y1, z0],
|
|
51
|
+
[x0, y0, z0],
|
|
52
|
+
[x0, y0, z1],
|
|
53
|
+
[x0, y1, z1],
|
|
54
|
+
],
|
|
55
|
+
],
|
|
56
|
+
[
|
|
57
|
+
'left',
|
|
58
|
+
[0, 1, 0],
|
|
59
|
+
[
|
|
60
|
+
[x1, y1, z0],
|
|
61
|
+
[x0, y1, z0],
|
|
62
|
+
[x0, y1, z1],
|
|
63
|
+
[x1, y1, z1],
|
|
64
|
+
],
|
|
65
|
+
],
|
|
66
|
+
[
|
|
67
|
+
'right',
|
|
68
|
+
[0, -1, 0],
|
|
69
|
+
[
|
|
70
|
+
[x0, y0, z0],
|
|
71
|
+
[x1, y0, z0],
|
|
72
|
+
[x1, y0, z1],
|
|
73
|
+
[x0, y0, z1],
|
|
74
|
+
],
|
|
75
|
+
],
|
|
76
|
+
];
|
|
77
|
+
for (const [name, normal, points] of sides) {
|
|
78
|
+
if (o.omit?.includes(name)) continue;
|
|
79
|
+
emitFace(b, {
|
|
80
|
+
points,
|
|
81
|
+
normal,
|
|
82
|
+
up: [0, 0, 1],
|
|
83
|
+
vOrigin: origin,
|
|
84
|
+
color: o.color,
|
|
85
|
+
strip,
|
|
86
|
+
banded: lod < 2,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
for (const [name, z, s] of [
|
|
90
|
+
['top', z1, 1],
|
|
91
|
+
['bottom', z0, -1],
|
|
92
|
+
] as const) {
|
|
93
|
+
if (o.omit?.includes(name)) continue;
|
|
94
|
+
emitFace(b, {
|
|
95
|
+
points: [
|
|
96
|
+
[x0, y0, z],
|
|
97
|
+
[x1, y0, z],
|
|
98
|
+
[x1, y1, z],
|
|
99
|
+
[x0, y1, z],
|
|
100
|
+
],
|
|
101
|
+
normal: [0, 0, s],
|
|
102
|
+
up: [0, 1, 0],
|
|
103
|
+
vOrigin: [cx, y0, z],
|
|
104
|
+
color: o.color,
|
|
105
|
+
strip: 'plain',
|
|
106
|
+
banded: false,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return b.build();
|
|
110
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// Windows and doors as one mesh each: a reveal (surround in the wall's colour, so the glass reads
|
|
2
|
+
// set back by `depth`), stone sill and lintel, sash frame with glazing bars, or a panelled door
|
|
3
|
+
// leaf. The wall mass behind stays whole (no boolean cut): half the triangles, no T-junctions.
|
|
4
|
+
// Authored with the face at x = 0 looking +X, then turned to the requested side.
|
|
5
|
+
// LOD0: everything · LOD1: no glazing bars / door panels · LOD2: glass or leaf only.
|
|
6
|
+
|
|
7
|
+
import { type Lod, type Mesh, merge, place, Ts23dError, type Vec3 } from '../core/index.ts';
|
|
8
|
+
import type { StripId } from '../material/index.ts';
|
|
9
|
+
import { box } from '../primitives/index.ts';
|
|
10
|
+
import { mass } from './mass.ts';
|
|
11
|
+
|
|
12
|
+
export type OpeningSide = 'front' | 'back' | 'left' | 'right';
|
|
13
|
+
|
|
14
|
+
export interface OpeningOptions {
|
|
15
|
+
readonly kind: 'window' | 'door';
|
|
16
|
+
/** Clear opening, metres (UK sash ≈ 0.9 × 1.6; door ≈ 0.9 × 2.1). */
|
|
17
|
+
readonly width: number;
|
|
18
|
+
readonly height: number;
|
|
19
|
+
/** Bottom centre of the opening ON the wall face. */
|
|
20
|
+
readonly at: Vec3;
|
|
21
|
+
/** Which way the wall faces (front = +X, left = +Y). */
|
|
22
|
+
readonly facing: OpeningSide;
|
|
23
|
+
readonly glass: Vec3;
|
|
24
|
+
/** Sash frame / door leaf colour. */
|
|
25
|
+
readonly frame: Vec3;
|
|
26
|
+
/** Reveal (surround) colour: the wall's, so the opening reads recessed. */
|
|
27
|
+
readonly wall: Vec3;
|
|
28
|
+
readonly wallStrip?: StripId;
|
|
29
|
+
/** Sill + lintel colour (dressed stone). */
|
|
30
|
+
readonly trim?: Vec3;
|
|
31
|
+
/** Reveal depth, metres. Default 0.12 (half a brick). */
|
|
32
|
+
readonly depth?: number;
|
|
33
|
+
/** Reveal band width either side. Default 0.1. */
|
|
34
|
+
readonly surround?: number;
|
|
35
|
+
/** Glazing panes [across, up]: 2-over-2 sash = [2, 2]. Default window [2, 2]. */
|
|
36
|
+
readonly panes?: readonly [number, number];
|
|
37
|
+
readonly sill?: boolean;
|
|
38
|
+
readonly lintel?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const YAW: Record<OpeningSide, number> = {
|
|
42
|
+
front: 0,
|
|
43
|
+
left: Math.PI / 2,
|
|
44
|
+
back: Math.PI,
|
|
45
|
+
right: -Math.PI / 2,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/** Base-centred box flush on the wall face (x = 0), back face omitted (it is against the wall). */
|
|
49
|
+
const onWall = (size: Vec3, y: number, z: number, color: Vec3, strip?: StripId): Mesh =>
|
|
50
|
+
box({ size, at: [size[0] / 2, y, z], color, omit: ['back'], ...(strip ? { strip } : {}) });
|
|
51
|
+
|
|
52
|
+
export function opening(o: OpeningOptions, lod: Lod = 0): Mesh {
|
|
53
|
+
const { width: w, height: h } = o;
|
|
54
|
+
if (!(w > 0.2 && h > 0.2 && Number.isFinite(w) && Number.isFinite(h)))
|
|
55
|
+
throw new Ts23dError('T3D_RECIPE_INVALID', {
|
|
56
|
+
cause: `${o.kind} opening is ${w} × ${h} m`,
|
|
57
|
+
fix: 'give a clear width and height > 0.2 m (sash ≈ 0.9 × 1.6, door ≈ 0.9 × 2.1)',
|
|
58
|
+
});
|
|
59
|
+
const r = o.depth ?? 0.12;
|
|
60
|
+
const s = o.surround ?? 0.1;
|
|
61
|
+
const trim = o.trim ?? [0.78, 0.75, 0.68];
|
|
62
|
+
const door = o.kind === 'door';
|
|
63
|
+
const parts: Mesh[] = [];
|
|
64
|
+
// The infill: glass flush on the wall, or the door leaf a little proud of it.
|
|
65
|
+
parts.push(
|
|
66
|
+
door
|
|
67
|
+
? onWall([0.05, w, h], 0, 0, o.frame, 'wood')
|
|
68
|
+
: onWall([0.02, w, h], 0, 0, o.glass, 'glass'),
|
|
69
|
+
);
|
|
70
|
+
if (lod < 2) {
|
|
71
|
+
const lintel = o.lintel ?? true;
|
|
72
|
+
// Reveal masonry in true-scale courses aligned with the wall's (courses start at world z 0).
|
|
73
|
+
const reveal = (size: Vec3, y: number, z: number): Mesh =>
|
|
74
|
+
mass(
|
|
75
|
+
{
|
|
76
|
+
size,
|
|
77
|
+
at: [size[0] / 2, y, z],
|
|
78
|
+
color: o.wall,
|
|
79
|
+
strip: o.wallStrip ?? 'plain',
|
|
80
|
+
courseOrigin: -o.at[2],
|
|
81
|
+
omit: ['back'],
|
|
82
|
+
},
|
|
83
|
+
lod,
|
|
84
|
+
);
|
|
85
|
+
for (const side of [-1, 1]) parts.push(reveal([r, s, h], side * (w / 2 + s / 2), 0));
|
|
86
|
+
if (lintel) parts.push(onWall([r + 0.03, w + 2 * s + 0.2, 0.22], 0, h, trim, 'stone'));
|
|
87
|
+
else parts.push(reveal([r, w + 2 * s, s], 0, h));
|
|
88
|
+
if (!door && (o.sill ?? true))
|
|
89
|
+
parts.push(onWall([r + 0.07, w + 2 * s + 0.12, 0.07], 0, -0.07, trim, 'stone'));
|
|
90
|
+
if (!door) parts.push(...sash(o, w, h, lod));
|
|
91
|
+
else if (lod === 0) parts.push(...panels(o, w, h));
|
|
92
|
+
}
|
|
93
|
+
return place(merge(parts), { yaw: YAW[o.facing], at: o.at });
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Sash frame round the glass; glazing bars at LOD0. */
|
|
97
|
+
function sash(o: OpeningOptions, w: number, h: number, lod: Lod): Mesh[] {
|
|
98
|
+
const f = 0.06;
|
|
99
|
+
const d = 0.05;
|
|
100
|
+
const out = [
|
|
101
|
+
onWall([d, f, h], -(w / 2 - f / 2), 0, o.frame),
|
|
102
|
+
onWall([d, f, h], w / 2 - f / 2, 0, o.frame),
|
|
103
|
+
onWall([d, w - 2 * f, f], 0, 0, o.frame),
|
|
104
|
+
onWall([d, w - 2 * f, f], 0, h - f, o.frame),
|
|
105
|
+
];
|
|
106
|
+
if (lod > 0) return out;
|
|
107
|
+
const [across, up] = o.panes ?? [2, 2];
|
|
108
|
+
const bar = 0.03;
|
|
109
|
+
for (let i = 1; i < across; i++)
|
|
110
|
+
out.push(
|
|
111
|
+
onWall([d * 0.8, bar, h - 2 * f], -w / 2 + f + ((w - 2 * f) * i) / across, f, o.frame),
|
|
112
|
+
);
|
|
113
|
+
for (let j = 1; j < up; j++)
|
|
114
|
+
out.push(onWall([d * 0.8, w - 2 * f, bar], 0, f + ((h - 2 * f) * j) / up - bar / 2, o.frame));
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Four raised fielded panels on a door leaf (LOD0). */
|
|
119
|
+
function panels(o: OpeningOptions, w: number, h: number): Mesh[] {
|
|
120
|
+
const out: Mesh[] = [];
|
|
121
|
+
const pw = (w - 0.36) / 2;
|
|
122
|
+
const tone: Vec3 = [o.frame[0] * 0.85, o.frame[1] * 0.85, o.frame[2] * 0.85];
|
|
123
|
+
for (const y of [-1, 1])
|
|
124
|
+
for (const [z0, ph] of [
|
|
125
|
+
[0.15, h * 0.38],
|
|
126
|
+
[0.15 + h * 0.38 + 0.15, h - 0.45 - h * 0.38],
|
|
127
|
+
] as const)
|
|
128
|
+
out.push(
|
|
129
|
+
box({
|
|
130
|
+
size: [0.02, pw, ph],
|
|
131
|
+
at: [0.06, y * (pw / 2 + 0.06), z0],
|
|
132
|
+
color: tone,
|
|
133
|
+
omit: ['back'],
|
|
134
|
+
}),
|
|
135
|
+
);
|
|
136
|
+
// Knob on the lock side.
|
|
137
|
+
out.push(
|
|
138
|
+
box({ size: [0.06, 0.06, 0.06], at: [0.08, w / 2 - 0.12, h * 0.48], color: [0.7, 0.6, 0.3] }),
|
|
139
|
+
);
|
|
140
|
+
return out;
|
|
141
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Kinds with a fixed entry point and no body yet. Each is a library of builders recipes call;
|
|
2
|
+
// the roadmap slice that builds it is named in the error.
|
|
3
|
+
|
|
4
|
+
import { type BuildContext, notImplemented } from '../core/index.ts';
|
|
5
|
+
|
|
6
|
+
/** Stylised creature from a skeleton + SDF flesh (Spore-like). Realistic ones go via /neural. M4. */
|
|
7
|
+
export function creature(
|
|
8
|
+
_ctx: BuildContext,
|
|
9
|
+
_o: { skeleton: 'biped' | 'quadruped' | 'bird'; height: number },
|
|
10
|
+
): void {
|
|
11
|
+
notImplemented('creature (SDF-skinned skeleton)', 'docs/idea/07-what-fits.md');
|
|
12
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// A chimney stack for `roofMesh`: brick shaft from the wall plate (hidden in the attic, so it
|
|
2
|
+
// always meets the roof) to a set height above where it leaves the slope, with an oversailing
|
|
3
|
+
// cap course (LOD0/1) and clay pots (LOD0). Building-regs rule of thumb: ≥ 0.9 m above the
|
|
4
|
+
// highest point where it passes through the roof.
|
|
5
|
+
|
|
6
|
+
import { type Lod, type Mesh, MeshBuilder, merge, type Vec3 } from '../core/index.ts';
|
|
7
|
+
import type { StripId } from '../material/index.ts';
|
|
8
|
+
import { box, lathe } from '../primitives/index.ts';
|
|
9
|
+
import { emitFace } from './faces.ts';
|
|
10
|
+
|
|
11
|
+
export interface RoofChimney {
|
|
12
|
+
/** Centre offset from the roof's `at`, world X/Y metres. */
|
|
13
|
+
readonly at: readonly [number, number];
|
|
14
|
+
/** Stack width (X) and depth (Y). Default [0.9, 0.6]. */
|
|
15
|
+
readonly size?: readonly [number, number];
|
|
16
|
+
/** Height above the highest roof point it touches. Default 0.9. */
|
|
17
|
+
readonly height?: number;
|
|
18
|
+
readonly color: Vec3;
|
|
19
|
+
readonly strip?: StripId;
|
|
20
|
+
/** Clay pots on top (LOD0). Default: one per 0.4 m of width. */
|
|
21
|
+
readonly pots?: number;
|
|
22
|
+
readonly potColor?: Vec3;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function chimney(
|
|
26
|
+
c: RoofChimney,
|
|
27
|
+
heightAt: (x: number, y: number) => number,
|
|
28
|
+
at: Vec3,
|
|
29
|
+
lod: Lod,
|
|
30
|
+
): Mesh {
|
|
31
|
+
const [w, d] = c.size ?? [0.9, 0.6];
|
|
32
|
+
const cx = at[0] + c.at[0];
|
|
33
|
+
const cy = at[1] + c.at[1];
|
|
34
|
+
const corners: [number, number][] = [
|
|
35
|
+
[cx - w / 2, cy - d / 2],
|
|
36
|
+
[cx + w / 2, cy - d / 2],
|
|
37
|
+
[cx + w / 2, cy + d / 2],
|
|
38
|
+
[cx - w / 2, cy + d / 2],
|
|
39
|
+
];
|
|
40
|
+
const exit = Math.max(...corners.map(([x, y]) => heightAt(x, y)));
|
|
41
|
+
const top = exit + (c.height ?? 0.9);
|
|
42
|
+
const z0 = at[2];
|
|
43
|
+
const strip = c.strip ?? 'brick';
|
|
44
|
+
const b = new MeshBuilder();
|
|
45
|
+
corners.forEach(([x0, y0], i) => {
|
|
46
|
+
const [x1, y1] = corners[(i + 1) % 4] ?? [x0, y0];
|
|
47
|
+
emitFace(b, {
|
|
48
|
+
points: [
|
|
49
|
+
[x0, y0, z0],
|
|
50
|
+
[x1, y1, z0],
|
|
51
|
+
[x1, y1, top],
|
|
52
|
+
[x0, y0, top],
|
|
53
|
+
],
|
|
54
|
+
normal: [y1 - y0, -(x1 - x0), 0],
|
|
55
|
+
up: [0, 0, 1],
|
|
56
|
+
vOrigin: [0, 0, z0],
|
|
57
|
+
color: c.color,
|
|
58
|
+
strip,
|
|
59
|
+
banded: lod < 2,
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
emitFace(b, {
|
|
63
|
+
points: corners.map(([x, y]) => [x, y, top] as Vec3),
|
|
64
|
+
normal: [0, 0, 1],
|
|
65
|
+
up: [0, 1, 0],
|
|
66
|
+
vOrigin: [cx, cy, top],
|
|
67
|
+
color: c.color,
|
|
68
|
+
strip: 'plain',
|
|
69
|
+
banded: false,
|
|
70
|
+
});
|
|
71
|
+
const parts = [b.build()];
|
|
72
|
+
if (lod < 2) {
|
|
73
|
+
const k = 0.06;
|
|
74
|
+
const cap: Vec3 = [c.color[0] * 0.85, c.color[1] * 0.85, c.color[2] * 0.85];
|
|
75
|
+
parts.push(box({ size: [w + 2 * k, d + 2 * k, 0.1], at: [cx, cy, top - 0.22], color: cap }));
|
|
76
|
+
parts.push(box({ size: [w + k, d + k, 0.07], at: [cx, cy, top - 0.07], color: cap }));
|
|
77
|
+
}
|
|
78
|
+
if (lod === 0) {
|
|
79
|
+
const n = c.pots ?? Math.max(1, Math.round(w / 0.4));
|
|
80
|
+
const pot = c.potColor ?? [0.62, 0.32, 0.2];
|
|
81
|
+
for (let i = 0; i < n; i++) {
|
|
82
|
+
const x = cx - w / 2 + (w * (i + 0.5)) / n;
|
|
83
|
+
parts.push(
|
|
84
|
+
lathe({
|
|
85
|
+
profile: [
|
|
86
|
+
[0.13, 0],
|
|
87
|
+
[0.1, 0.36],
|
|
88
|
+
[0.125, 0.4],
|
|
89
|
+
[0.125, 0.46],
|
|
90
|
+
],
|
|
91
|
+
segments: 8,
|
|
92
|
+
caps: true,
|
|
93
|
+
at: [x, cy, top - 0.02],
|
|
94
|
+
color: pot,
|
|
95
|
+
}),
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return merge(parts);
|
|
100
|
+
}
|