@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.
- 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 +90 -0
- package/CLAUDE.md +85 -0
- package/LICENSE +21 -0
- package/README.md +385 -2
- package/dist/chunk-6b05mnmx.js +19 -0
- package/dist/chunk-6b05mnmx.js.map +11 -0
- package/dist/chunk-7rtfjh9f.js +45 -0
- package/dist/chunk-7rtfjh9f.js.map +10 -0
- package/dist/chunk-8j4c28jt.js +4085 -0
- package/dist/chunk-8j4c28jt.js.map +46 -0
- package/dist/chunk-d1fv6hrm.js +2532 -0
- package/dist/chunk-d1fv6hrm.js.map +43 -0
- package/dist/chunk-dbq4qf52.js +902 -0
- package/dist/chunk-dbq4qf52.js.map +25 -0
- package/dist/chunk-drna2rny.js +836 -0
- package/dist/chunk-drna2rny.js.map +17 -0
- package/dist/chunk-dxvypr7y.js +89 -0
- package/dist/chunk-dxvypr7y.js.map +11 -0
- package/dist/chunk-f6yme003.js +1589 -0
- package/dist/chunk-f6yme003.js.map +30 -0
- package/dist/chunk-hg7pf34j.js +465 -0
- package/dist/chunk-hg7pf34j.js.map +19 -0
- package/dist/chunk-jq4e17tj.js +1031 -0
- package/dist/chunk-jq4e17tj.js.map +21 -0
- package/dist/chunk-y63c6zcv.js +2668 -0
- package/dist/chunk-y63c6zcv.js.map +53 -0
- package/dist/cli/args.d.ts +30 -0
- package/dist/cli/bin.d.ts +2 -0
- package/dist/cli/bin.js +348 -0
- package/dist/cli/bin.js.map +15 -0
- package/dist/cli/load.d.ts +2 -0
- package/dist/cli/manifest.d.ts +53 -0
- package/dist/cli/render-cmds.d.ts +12 -0
- package/dist/cli/run.d.ts +1 -0
- package/dist/cli/texture-cache.d.ts +4 -0
- package/dist/core/asset.d.ts +10 -0
- package/dist/core/definition.d.ts +155 -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/credits.d.ts +4 -0
- package/dist/export/glb-options.d.ts +48 -0
- package/dist/export/glb.d.ts +8 -0
- package/dist/export/hierarchy.d.ts +23 -0
- package/dist/export/index.d.ts +5 -0
- package/dist/export/index.js +40 -0
- package/dist/export/index.js.map +9 -0
- package/dist/export/lights.d.ts +8 -0
- package/dist/export/lod-coverage.d.ts +12 -0
- package/dist/export/materials.d.ts +23 -0
- package/dist/export/merge-pivots.d.ts +6 -0
- package/dist/export/metadata.d.ts +21 -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 +457 -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 +5 -0
- package/dist/kinds/head-beard.d.ts +6 -0
- package/dist/kinds/head-bust.d.ts +5 -0
- package/dist/kinds/head-extras.d.ts +15 -0
- package/dist/kinds/head-face.d.ts +8 -0
- package/dist/kinds/head-garb.d.ts +4 -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 +31 -0
- package/dist/kinds/head-mouth.d.ts +4 -0
- package/dist/kinds/head-params.d.ts +116 -0
- package/dist/kinds/head-presets.d.ts +19 -0
- package/dist/kinds/head-rim.d.ts +10 -0
- package/dist/kinds/head-tone.d.ts +10 -0
- package/dist/kinds/head-torso.d.ts +35 -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/cc0.d.ts +4 -0
- package/dist/material/define.d.ts +34 -0
- package/dist/material/generator.d.ts +4 -0
- package/dist/material/index.d.ts +9 -0
- package/dist/material/index.js +70 -0
- package/dist/material/index.js.map +9 -0
- package/dist/material/library.d.ts +7 -0
- package/dist/material/material-def.d.ts +30 -0
- package/dist/material/paint/bond.d.ts +3 -0
- package/dist/material/paint/canvas.d.ts +39 -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 +4 -0
- package/dist/material/paint/fabric.d.ts +4 -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/image-strip.d.ts +4 -0
- package/dist/material/paint/kit.d.ts +5 -0
- package/dist/material/paint/masks.d.ts +3 -0
- package/dist/material/paint/metal.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 +65 -0
- package/dist/material/paint/validate.d.ts +3 -0
- package/dist/material/palette.d.ts +14 -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/slots.d.ts +5 -0
- package/dist/material/texture-source.d.ts +34 -0
- package/dist/material/trim-sheet.d.ts +38 -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 +27 -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 +56 -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 +117 -0
- package/docs/architecture/materials.md +151 -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/idea/10-sculpting.md +166 -0
- package/docs/idea/11-materials-authoring.md +132 -0
- package/docs/idea/12-blender-bridge.md +136 -0
- package/docs/idea/13-asset-pipeline-research.md +89 -0
- package/docs/landscape.md +49 -0
- package/docs/plans/roadmap.md +139 -0
- package/examples/build-with-bun.ts +41 -0
- package/llms.txt +47 -0
- package/package.json +100 -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 +53 -0
- package/recipes/boxcar/boxcar.ts +1000 -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 +75 -0
- package/recipes/goblin_head/goblin_head.ts +38 -0
- package/recipes/human_head/README.md +68 -0
- package/recipes/human_head/human_head.ts +38 -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 +189 -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 +78 -0
- package/recipes/orc_head/orc_head.ts +41 -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 +125 -0
- package/src/cli/bin.ts +7 -0
- package/src/cli/load.ts +17 -0
- package/src/cli/manifest.ts +95 -0
- package/src/cli/render-cmds.ts +66 -0
- package/src/cli/run.ts +192 -0
- package/src/cli/texture-cache.ts +24 -0
- package/src/core/asset.ts +129 -0
- package/src/core/definition.ts +156 -0
- package/src/core/errors.ts +50 -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/credits.ts +25 -0
- package/src/export/glb-options.ts +53 -0
- package/src/export/glb.ts +187 -0
- package/src/export/hierarchy.ts +122 -0
- package/src/export/index.ts +34 -0
- package/src/export/lights.ts +49 -0
- package/src/export/lod-coverage.ts +71 -0
- package/src/export/materials.ts +126 -0
- package/src/export/merge-pivots.ts +146 -0
- package/src/export/metadata.ts +62 -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 +181 -0
- package/src/kinds/head-beard.ts +133 -0
- package/src/kinds/head-bust.ts +184 -0
- package/src/kinds/head-extras.ts +150 -0
- package/src/kinds/head-face.ts +242 -0
- package/src/kinds/head-garb.ts +181 -0
- package/src/kinds/head-geom.ts +31 -0
- package/src/kinds/head-hair.ts +193 -0
- package/src/kinds/head-layout.ts +63 -0
- package/src/kinds/head-mesh.ts +195 -0
- package/src/kinds/head-mouth.ts +111 -0
- package/src/kinds/head-params.ts +162 -0
- package/src/kinds/head-presets.ts +155 -0
- package/src/kinds/head-rim.ts +128 -0
- package/src/kinds/head-tone.ts +52 -0
- package/src/kinds/head-torso.ts +230 -0
- package/src/kinds/head.ts +176 -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/cc0.ts +41 -0
- package/src/material/define.ts +130 -0
- package/src/material/generator.ts +63 -0
- package/src/material/index.ts +60 -0
- package/src/material/library.ts +196 -0
- package/src/material/material-def.ts +84 -0
- package/src/material/paint/bond.ts +60 -0
- package/src/material/paint/canvas.ts +101 -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 +106 -0
- package/src/material/paint/default-sheet.ts +73 -0
- package/src/material/paint/fabric.ts +63 -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/image-strip.ts +88 -0
- package/src/material/paint/kit.ts +37 -0
- package/src/material/paint/masks.ts +46 -0
- package/src/material/paint/metal.ts +109 -0
- package/src/material/paint/noise.ts +52 -0
- package/src/material/paint/normal.ts +52 -0
- package/src/material/paint/orm.ts +108 -0
- package/src/material/paint/planks.ts +101 -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 +48 -0
- package/src/material/paint/surface.ts +60 -0
- package/src/material/paint/types.ts +94 -0
- package/src/material/paint/validate.ts +74 -0
- package/src/material/palette.ts +46 -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/slots.ts +18 -0
- package/src/material/texture-source.ts +86 -0
- package/src/material/trim-sheet.ts +166 -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 +121 -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 +204 -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,131 @@
|
|
|
1
|
+
// A truss between two points: bridges, girders, crane jibs, signal gantries, pylons, towers.
|
|
2
|
+
// Planar (two chords) or, with `width`, a box truss (four chords, every face braced). Members are
|
|
3
|
+
// square tubes or angle iron with flat normals, written into one builder. `from → to` is the
|
|
4
|
+
// base chord (or the centreline with `centred`); `depth` rises along `up`. Patterns per bay:
|
|
5
|
+
// warren /\/\/\ diagonals only pratt |\|\|/|/| verticals, diagonals down to centre
|
|
6
|
+
// howe |/|/|\|\| the reverse x |X|X|X| verticals + both diagonals
|
|
7
|
+
// Pratt/Howe put an X in the middle bay when `bays` is odd. LOD knobs: `bays`, `section`, and
|
|
8
|
+
// dropping `width` (box → planar), chosen by the recipe with ctx.pick.
|
|
9
|
+
// triangles = chords·(S + C) + faces·web·S S = 8 square | 12 angle, C = 4 | 8 (end caps)
|
|
10
|
+
// chords = 2 | 4, faces = 1 | 4, web = warren k · pratt/howe 2k + 1 + (k odd) · x 3k + 1
|
|
11
|
+
|
|
12
|
+
import { type Mesh, MeshBuilder, normalize, type Vec3 } from '../core/index.ts';
|
|
13
|
+
import { type StripId, stripRect } from '../material/index.ts';
|
|
14
|
+
import { count, invalid, positive } from './check.ts';
|
|
15
|
+
import { emitMember, type SectionKind, section } from './member.ts';
|
|
16
|
+
|
|
17
|
+
export type TrussPattern = 'warren' | 'pratt' | 'howe' | 'x';
|
|
18
|
+
|
|
19
|
+
export interface LatticeOptions {
|
|
20
|
+
readonly from: Vec3;
|
|
21
|
+
readonly to: Vec3;
|
|
22
|
+
/** Chord-to-chord height in metres (at `from`; `depthEnd` tapers it toward `to`). */
|
|
23
|
+
readonly depth: number;
|
|
24
|
+
readonly depthEnd?: number;
|
|
25
|
+
/** Box truss: chord spacing across, metres (and `widthEnd`). Omit for a planar truss. */
|
|
26
|
+
readonly width?: number;
|
|
27
|
+
readonly widthEnd?: number;
|
|
28
|
+
/** Which way depth rises. Default world Z (world X for a vertical truss). */
|
|
29
|
+
readonly up?: Vec3;
|
|
30
|
+
readonly centred?: boolean;
|
|
31
|
+
readonly pattern?: TrussPattern;
|
|
32
|
+
/** Panels along the length. Default ≈ length / depth. */
|
|
33
|
+
readonly bays?: number;
|
|
34
|
+
/** Chord member width, metres. */
|
|
35
|
+
readonly chord: number;
|
|
36
|
+
/** Web member width. Default 0.6 · chord. */
|
|
37
|
+
readonly web?: number;
|
|
38
|
+
readonly section?: SectionKind;
|
|
39
|
+
readonly color: Vec3;
|
|
40
|
+
readonly strip?: StripId;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type Line = (t: number) => Vec3;
|
|
44
|
+
|
|
45
|
+
export function lattice(o: LatticeOptions): Mesh {
|
|
46
|
+
const d: Vec3 = [o.to[0] - o.from[0], o.to[1] - o.from[1], o.to[2] - o.from[2]];
|
|
47
|
+
const len = Math.hypot(d[0], d[1], d[2]);
|
|
48
|
+
if (!(len > 1e-6))
|
|
49
|
+
invalid('lattice: from and to coincide', 'give the truss two distinct end points in metres');
|
|
50
|
+
const depth = positive('lattice depth', o.depth, 'e.g. 2 for a 2 m deep girder');
|
|
51
|
+
const chord = positive('lattice chord', o.chord, 'e.g. 0.2');
|
|
52
|
+
if (chord >= depth)
|
|
53
|
+
invalid(
|
|
54
|
+
`lattice chord ${chord} m ≥ depth ${depth} m`,
|
|
55
|
+
'make the chord member thinner than the depth',
|
|
56
|
+
);
|
|
57
|
+
const web = positive('lattice web', o.web ?? chord * 0.6, 'e.g. 0.6 · chord');
|
|
58
|
+
const k = count('lattice bays', o.bays ?? Math.max(1, Math.round(len / depth)), 1, 2000);
|
|
59
|
+
const w = normalize(d);
|
|
60
|
+
const upHint: Vec3 = o.up ?? (Math.abs(w[2]) > 0.95 ? [1, 0, 0] : [0, 0, 1]);
|
|
61
|
+
const dotU = upHint[0] * w[0] + upHint[1] * w[1] + upHint[2] * w[2];
|
|
62
|
+
const upR: Vec3 = [upHint[0] - w[0] * dotU, upHint[1] - w[1] * dotU, upHint[2] - w[2] * dotU];
|
|
63
|
+
if (Math.hypot(upR[0], upR[1], upR[2]) < 1e-6)
|
|
64
|
+
invalid('lattice: up is parallel to from → to', 'pass an `up` perpendicular to the truss axis');
|
|
65
|
+
const up = normalize(upR);
|
|
66
|
+
const side: Vec3 = [
|
|
67
|
+
w[1] * up[2] - w[2] * up[1],
|
|
68
|
+
w[2] * up[0] - w[0] * up[2],
|
|
69
|
+
w[0] * up[1] - w[1] * up[0],
|
|
70
|
+
];
|
|
71
|
+
const dEnd = positive('lattice depthEnd', o.depthEnd ?? depth, 'e.g. 1');
|
|
72
|
+
const wid = o.width === undefined ? 0 : positive('lattice width', o.width, 'e.g. 2');
|
|
73
|
+
const wEnd =
|
|
74
|
+
o.width === undefined ? 0 : positive('lattice widthEnd', o.widthEnd ?? wid, 'e.g. 1');
|
|
75
|
+
const c0 = o.centred ? -0.5 : 0;
|
|
76
|
+
/** A chord line at lateral sign a (−1/0/+1) and height c (0 = base, 1 = top). */
|
|
77
|
+
const line =
|
|
78
|
+
(a: number, c: number): Line =>
|
|
79
|
+
(t) => {
|
|
80
|
+
const along = len * t;
|
|
81
|
+
const lat = (a * (wid + (wEnd - wid) * t)) / 2;
|
|
82
|
+
const h = (c0 + c) * (depth + (dEnd - depth) * t);
|
|
83
|
+
return [
|
|
84
|
+
o.from[0] + w[0] * along + side[0] * lat + up[0] * h,
|
|
85
|
+
o.from[1] + w[1] * along + side[1] * lat + up[1] * h,
|
|
86
|
+
o.from[2] + w[2] * along + side[2] * lat + up[2] * h,
|
|
87
|
+
];
|
|
88
|
+
};
|
|
89
|
+
const neg = (v: Vec3): Vec3 => [-v[0], -v[1], -v[2]];
|
|
90
|
+
// Each face: two chord lines, the face normal (members' section up).
|
|
91
|
+
const faces: [Line, Line, Vec3][] =
|
|
92
|
+
o.width === undefined
|
|
93
|
+
? [[line(0, 0), line(0, 1), side]]
|
|
94
|
+
: [
|
|
95
|
+
[line(-1, 0), line(-1, 1), neg(side)],
|
|
96
|
+
[line(1, 0), line(1, 1), side],
|
|
97
|
+
[line(-1, 1), line(1, 1), up],
|
|
98
|
+
[line(-1, 0), line(1, 0), neg(up)],
|
|
99
|
+
];
|
|
100
|
+
const chords: Line[] =
|
|
101
|
+
o.width === undefined
|
|
102
|
+
? [line(0, 0), line(0, 1)]
|
|
103
|
+
: [line(-1, 0), line(1, 0), line(-1, 1), line(1, 1)];
|
|
104
|
+
const rect = stripRect(o.strip ?? 'iron');
|
|
105
|
+
const sc = section(o.section ?? 'square', chord);
|
|
106
|
+
const sw = section(o.section ?? 'square', web);
|
|
107
|
+
const mb = new MeshBuilder();
|
|
108
|
+
for (const c of chords) emitMember(mb, sc, c(0), c(1), up, true, o.color, rect);
|
|
109
|
+
for (const [lo, hi, n] of faces)
|
|
110
|
+
for (const [ta, la, tb, lb] of webMembers(o.pattern ?? 'warren', k))
|
|
111
|
+
emitMember(mb, sw, (la ? hi : lo)(ta), (lb ? hi : lo)(tb), n, false, o.color, rect);
|
|
112
|
+
return mb.build();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Web members of one face as [t0, onTop0, t1, onTop1], in a fixed order (determinism). */
|
|
116
|
+
export function webMembers(pattern: TrussPattern, k: number): [number, boolean, number, boolean][] {
|
|
117
|
+
const out: [number, boolean, number, boolean][] = [];
|
|
118
|
+
const t = (i: number): number => i / k;
|
|
119
|
+
if (pattern !== 'warren') for (let i = 0; i <= k; i++) out.push([t(i), false, t(i), true]);
|
|
120
|
+
for (let i = 0; i < k; i++) {
|
|
121
|
+
const down: [number, boolean, number, boolean] = [t(i), true, t(i + 1), false]; // "\"
|
|
122
|
+
const rise: [number, boolean, number, boolean] = [t(i), false, t(i + 1), true]; // "/"
|
|
123
|
+
const middle = k % 2 === 1 && i === (k - 1) / 2;
|
|
124
|
+
const left = i < k / 2;
|
|
125
|
+
if (pattern === 'warren') out.push(i % 2 === 0 ? rise : down);
|
|
126
|
+
else if (pattern === 'x' || middle) out.push(rise, down);
|
|
127
|
+
else if (pattern === 'pratt') out.push(left ? down : rise);
|
|
128
|
+
else out.push(left ? rise : down);
|
|
129
|
+
}
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// Skin ordered closed rings with equal vertex counts: haystacks, grain sacks, wheat stooks, hulls,
|
|
2
|
+
// fuselages, buttressed trunk flares. SMOOTH normals (central differences around and along; caps
|
|
3
|
+
// flat), forced outward whichever way the rings wind. Positions are absolute (no `at`). UVs:
|
|
4
|
+
// 'length' (default) U = metres along the ring centroids, V once around the band; 'row' U =
|
|
5
|
+
// metres around each ring, V along; 'swap' one unscaled wrap (U around 0–1, V along 0–1).
|
|
6
|
+
// Triangles = 2·N·(R−1) + N per cap (N vertices per ring, R rings).
|
|
7
|
+
|
|
8
|
+
import { type Mesh, MeshBuilder, Ts23dError, type Vec3 } from '../core/index.ts';
|
|
9
|
+
import { type StripId, stripRect } from '../material/index.ts';
|
|
10
|
+
|
|
11
|
+
export type LoftColor = Vec3 | ((ring: readonly Vec3[], i: number, p: Vec3) => Vec3);
|
|
12
|
+
|
|
13
|
+
export interface LoftOptions {
|
|
14
|
+
readonly rings: readonly (readonly Vec3[])[];
|
|
15
|
+
/** One colour, or one per vertex from (ring, ring index, point). */
|
|
16
|
+
readonly color: LoftColor;
|
|
17
|
+
readonly strip?: StripId;
|
|
18
|
+
readonly capStart?: boolean;
|
|
19
|
+
readonly capEnd?: boolean;
|
|
20
|
+
readonly uv?: 'length' | 'row' | 'swap';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** An elliptical ring in the plane z = centre.z, CCW seen from +Z; `wobble(angle)` scales radius. */
|
|
24
|
+
export function ringXY(
|
|
25
|
+
centre: Vec3,
|
|
26
|
+
rx: number,
|
|
27
|
+
ry: number,
|
|
28
|
+
segments: number,
|
|
29
|
+
wobble?: (angle: number) => number,
|
|
30
|
+
phase = 0,
|
|
31
|
+
): Vec3[] {
|
|
32
|
+
const out: Vec3[] = [];
|
|
33
|
+
for (let k = 0; k < segments; k++) {
|
|
34
|
+
const a = phase + (k / segments) * Math.PI * 2;
|
|
35
|
+
const w = wobble ? wobble(a) : 1;
|
|
36
|
+
out.push([centre[0] + rx * Math.cos(a) * w, centre[1] + ry * Math.sin(a) * w, centre[2]]);
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const invalid = (cause: string, fix: string): Ts23dError =>
|
|
42
|
+
new Ts23dError('T3D_RECIPE_INVALID', { cause, fix });
|
|
43
|
+
|
|
44
|
+
const centroid = (r: readonly Vec3[]): Vec3 => {
|
|
45
|
+
let x = 0;
|
|
46
|
+
let y = 0;
|
|
47
|
+
let z = 0;
|
|
48
|
+
for (const p of r) {
|
|
49
|
+
x += p[0];
|
|
50
|
+
y += p[1];
|
|
51
|
+
z += p[2];
|
|
52
|
+
}
|
|
53
|
+
return [x / r.length, y / r.length, z / r.length];
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export function loft(o: LoftOptions): Mesh {
|
|
57
|
+
const R = o.rings.length;
|
|
58
|
+
if (R < 2) throw invalid(`loft has ${R} ring(s)`, 'pass at least 2 rings (bottom → top)');
|
|
59
|
+
const N = o.rings[0]?.length ?? 0;
|
|
60
|
+
if (N < 3) throw invalid(`loft rings have ${N} vertices`, 'give every ring at least 3 vertices');
|
|
61
|
+
for (const [i, r] of o.rings.entries()) {
|
|
62
|
+
if (r.length !== N) {
|
|
63
|
+
throw invalid(
|
|
64
|
+
`loft ring ${i} has ${r.length} vertices, ring 0 has ${N}`,
|
|
65
|
+
'build every ring with the same vertex count (same `segments` in ringXY)',
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const at = (i: number, k: number): Vec3 => o.rings[i]?.[((k % N) + N) % N] ?? [0, 0, 0];
|
|
70
|
+
const cents = o.rings.map(centroid);
|
|
71
|
+
const along = [0];
|
|
72
|
+
for (let i = 1; i < R; i++) {
|
|
73
|
+
const a = cents[i - 1] ?? [0, 0, 0];
|
|
74
|
+
const b = cents[i] ?? a;
|
|
75
|
+
along.push((along[i - 1] ?? 0) + Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]));
|
|
76
|
+
}
|
|
77
|
+
const total = along[R - 1] || 1;
|
|
78
|
+
// Raw normals (around × along); the sign of their sum against "outward from the centroid"
|
|
79
|
+
// decides the winding for the whole loft.
|
|
80
|
+
const raw: Vec3[] = [];
|
|
81
|
+
let facing = 0;
|
|
82
|
+
for (let i = 0; i < R; i++) {
|
|
83
|
+
const c = cents[i] ?? [0, 0, 0];
|
|
84
|
+
const ax = cents[Math.min(R - 1, i + 1)] ?? c;
|
|
85
|
+
const bx = cents[Math.max(0, i - 1)] ?? c;
|
|
86
|
+
const axis: Vec3 = [ax[0] - bx[0], ax[1] - bx[1], ax[2] - bx[2]];
|
|
87
|
+
for (let k = 0; k < N; k++) {
|
|
88
|
+
const p = at(i, k);
|
|
89
|
+
const u0 = at(i, k - 1);
|
|
90
|
+
const u1 = at(i, k + 1);
|
|
91
|
+
const v0 = at(Math.max(0, i - 1), k);
|
|
92
|
+
const v1 = at(Math.min(R - 1, i + 1), k);
|
|
93
|
+
const tu: Vec3 = [u1[0] - u0[0], u1[1] - u0[1], u1[2] - u0[2]];
|
|
94
|
+
const tv: Vec3 = [v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2]];
|
|
95
|
+
let n: Vec3 = [
|
|
96
|
+
tu[1] * tv[2] - tu[2] * tv[1],
|
|
97
|
+
tu[2] * tv[0] - tu[0] * tv[2],
|
|
98
|
+
tu[0] * tv[1] - tu[1] * tv[0],
|
|
99
|
+
];
|
|
100
|
+
if (Math.hypot(n[0], n[1], n[2]) < 1e-12) n = i === 0 ? [-axis[0], -axis[1], -axis[2]] : axis;
|
|
101
|
+
facing += n[0] * (p[0] - c[0]) + n[1] * (p[1] - c[1]) + n[2] * (p[2] - c[2]);
|
|
102
|
+
raw.push(n);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const flip = facing < 0 ? -1 : 1;
|
|
106
|
+
const rect = stripRect(o.strip ?? 'plain');
|
|
107
|
+
const du = rect.u1 - rect.u0;
|
|
108
|
+
const dv = rect.v1 - rect.v0;
|
|
109
|
+
const mode = o.uv ?? 'length';
|
|
110
|
+
const color = (i: number, p: Vec3): Vec3 =>
|
|
111
|
+
typeof o.color === 'function' ? o.color(o.rings[i] ?? [], i, p) : o.color;
|
|
112
|
+
const b = new MeshBuilder();
|
|
113
|
+
for (let i = 0; i < R; i++) {
|
|
114
|
+
let around = 0;
|
|
115
|
+
for (let k = 0; k <= N; k++) {
|
|
116
|
+
const p = at(i, k);
|
|
117
|
+
if (k > 0) {
|
|
118
|
+
const q = at(i, k - 1);
|
|
119
|
+
around += Math.hypot(p[0] - q[0], p[1] - q[1], p[2] - q[2]);
|
|
120
|
+
}
|
|
121
|
+
const n = raw[i * N + (k % N)] ?? [0, 0, 1];
|
|
122
|
+
const l = (Math.hypot(n[0], n[1], n[2]) || 1) * flip;
|
|
123
|
+
const s = (along[i] ?? 0) / rect.metres;
|
|
124
|
+
const uv: [number, number] =
|
|
125
|
+
mode === 'row'
|
|
126
|
+
? [rect.u0 + (around / rect.metres) * du, rect.v0 + ((along[i] ?? 0) / total) * dv]
|
|
127
|
+
: mode === 'swap'
|
|
128
|
+
? [rect.u0 + (k / N) * du, rect.v0 + ((along[i] ?? 0) / total) * dv]
|
|
129
|
+
: [rect.u0 + s * du, rect.v0 + (k / N) * dv];
|
|
130
|
+
b.vertex({ p, n: [n[0] / l, n[1] / l, n[2] / l], uv, color: color(i, p) });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
for (let i = 0; i + 1 < R; i++) {
|
|
134
|
+
const r0 = i * (N + 1);
|
|
135
|
+
const r1 = r0 + N + 1;
|
|
136
|
+
for (let k = 0; k < N; k++) {
|
|
137
|
+
if (flip > 0) b.quad(r0 + k, r0 + k + 1, r1 + k + 1, r1 + k);
|
|
138
|
+
else b.quad(r0 + k, r1 + k, r1 + k + 1, r0 + k + 1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const ends: [number, boolean][] = [
|
|
142
|
+
[0, o.capStart === true],
|
|
143
|
+
[R - 1, o.capEnd === true],
|
|
144
|
+
];
|
|
145
|
+
for (const [i, on] of ends) {
|
|
146
|
+
if (!on) continue;
|
|
147
|
+
const c = cents[i] ?? [0, 0, 0];
|
|
148
|
+
const other = cents[i === 0 ? 1 : R - 2] ?? c;
|
|
149
|
+
const d: Vec3 = [c[0] - other[0], c[1] - other[1], c[2] - other[2]];
|
|
150
|
+
const l = Math.hypot(d[0], d[1], d[2]) || 1;
|
|
151
|
+
const nn: Vec3 = [d[0] / l, d[1] / l, d[2] / l];
|
|
152
|
+
const mid = b.vertex({ p: c, n: nn, uv: [rect.u0, rect.v0], color: color(i, c) });
|
|
153
|
+
for (let k = 0; k < N; k++) {
|
|
154
|
+
const p = at(i, k);
|
|
155
|
+
b.vertex({ p, n: nn, uv: [rect.u0, rect.v1], color: color(i, p) });
|
|
156
|
+
}
|
|
157
|
+
// Cap winding: CCW seen from outside (along nn). Ring order relative to nn sets the sense.
|
|
158
|
+
const e1 = at(i, 0);
|
|
159
|
+
const e2 = at(i, 1);
|
|
160
|
+
const cr: Vec3 = [
|
|
161
|
+
(e1[1] - c[1]) * (e2[2] - c[2]) - (e1[2] - c[2]) * (e2[1] - c[1]),
|
|
162
|
+
(e1[2] - c[2]) * (e2[0] - c[0]) - (e1[0] - c[0]) * (e2[2] - c[2]),
|
|
163
|
+
(e1[0] - c[0]) * (e2[1] - c[1]) - (e1[1] - c[1]) * (e2[0] - c[0]),
|
|
164
|
+
];
|
|
165
|
+
const ccw = cr[0] * nn[0] + cr[1] * nn[1] + cr[2] * nn[2] >= 0;
|
|
166
|
+
for (let k = 0; k < N; k++) {
|
|
167
|
+
const a = mid + 1 + k;
|
|
168
|
+
const z = mid + 1 + ((k + 1) % N);
|
|
169
|
+
if (ccw) b.tri(mid, a, z);
|
|
170
|
+
else b.tri(mid, z, a);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return b.build();
|
|
174
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Marching-cubes triangle table (Lorensen & Cline 1987; Paul Bourke's public-domain listing,
|
|
2
|
+
// as shipped by three.js): case → edge triples, one hex digit per edge, cases joined by '.'.
|
|
3
|
+
// Corner bit i set = corner i inside. Corners/edges follow Bourke's numbering (marching-cubes.ts).
|
|
4
|
+
|
|
5
|
+
const PACKED =
|
|
6
|
+
'.083.019.183981.12a.08312a.92a029.2832a8a98.3b2.0b28b0.19023b.1b219b98b.3a1ba3.0a108a8ba.3' +
|
|
7
|
+
'903b9ba9.98aa8b.478.430734.019847.419471731.12a847.34730412a.92a902847.2a9297273794.8473b2' +
|
|
8
|
+
'.b47b24204.90184723b.47b94b9b2921.3a13ba784.1ba14b1047b4.47890b9bab03.47b4b99ba.954.954083' +
|
|
9
|
+
'.054150.854835315.12a954.30812a495.52a542402.2a5325354348.95423b.0b208b495.05401523b.21525' +
|
|
10
|
+
'828b485.a3ba13954.4950818a18ba.54050b5bab03.54858aa8b.978579.930953573.078017157.153357.97' +
|
|
11
|
+
'8957a12.a12950530573.802825857a52.2a5253357.7957893b2.95797292027b.23b018178157.b21b17715.' +
|
|
12
|
+
'958857a13a3b.5705097b010aba0.ba0b03a50807570.ba57b5.a65.0835a6.9015a6.1831985a6.165261.165' +
|
|
13
|
+
'126308.965906026.598582526328.23ba65.b08b20a65.01923b5a6.5a61929b298b.63b653513.08b0b50515' +
|
|
14
|
+
'b6.3b6036065059.65969bb98.5a6478.43047365a.1905a6847.a65197173794.612651478.125526304347.8' +
|
|
15
|
+
'47905065026.739794329596269.3b2784a65.5a647242027b.01947823b5a6.9219b294b7b45a6.8473b53515' +
|
|
16
|
+
'b6.51b5b610b7b404b.059065036b63847.65969b4797b9.a4964a.4a649a083.a01a60640.83181686461a.14' +
|
|
17
|
+
'9124264.308129249264.024426.832824426.a49a64b23.08228b49a4a6.3b201606461a.64161a48121b8b1.' +
|
|
18
|
+
'964936913b63.8b1810b61914641.3b6360064.648b68.7a678a89a.0730a709a67a.a671a7178180.a67a7117' +
|
|
19
|
+
'3.126168189867.269291679093739.780706602.732672.23ba68a89867.20727b09767a9a7.1801781a767a2' +
|
|
20
|
+
'3b.b21b17a61671.896867916b63136.091b67.7807063b0b60.7b6.76b.308b76.019b76.819831b76.a126b7' +
|
|
21
|
+
'.12a3086b7.2902a96b7.6b72a3a83a98.723627.708760620.276237019.162186198876.a76a17137.a7617a' +
|
|
22
|
+
'187108.03707a0a96a7.76a7a88a9.684b86.36b306046.86b846901.946963931b36.6846b82a1.12a30b06b0' +
|
|
23
|
+
'46.4b846b0292a9.a93a32943b36463.823842462.042462.190234246438.194142246.8138618466a1.a10a0' +
|
|
24
|
+
'6604.4634386a3039a93.a946a4.49576b.083495b76.50154076b.b76834354315.954a1276b.6b712a083495' +
|
|
25
|
+
'.76b54a42a402.348354325a52b76.723762549.954086062687.362376150540.628687218485158.954a1617' +
|
|
26
|
+
'6137.16a176107870954.40a4a503a6a737a.76a7a854a48a.6956b9b89.36b063056095.0b805b01556b.6b36' +
|
|
27
|
+
'35531.12a95b9b8b56.0b306b09656912a.b85b56805a52025.6b36352a3a53.589528562382.956960062.158' +
|
|
28
|
+
'180568382628.156216.13616a386569896.a10a06950560.03856a.a56.b5a75b.b5ab75830.5b75ab190.a75' +
|
|
29
|
+
'ab7981831.b12b71751.08312717572b.9759279022b7.75272b592328982.25a235375.820852875a25.9015a' +
|
|
30
|
+
'35373a2.982921872a25752.135375.087071175.903935537.987597.5845a8ab8.5045b05abb30.01984a8ab' +
|
|
31
|
+
'a45.ab4a45b34941314.2512852b8458.04b0b345b2b151b.0250592b5458b85.9452b3.25a352345384.5a252' +
|
|
32
|
+
'4420.3a235a385458019.5a2524192942.845853351.045105.845853905035.945.4b749b9ab.0834979b79ab' +
|
|
33
|
+
'.1ab1b414074b.3143481a474bab4.4b79b492b912.9749b791b2b1083.b74b42240.b74b42834324.29a27923' +
|
|
34
|
+
'7749.9a7974a27870207.37a3a274a1a040a.1a2874.491417713.491417081871.403743.487.9a8ab8.30939' +
|
|
35
|
+
'bb9a.01a0a88ab.31ab3a.12b1b99b8.30939b1292b9.02b80b.32b.23828aa89.9a2092.23828a0181a8.1a2.' +
|
|
36
|
+
'138918.091.038.';
|
|
37
|
+
|
|
38
|
+
/** TRI[c] = flat edge-index list for cube case c (length a multiple of 3). */
|
|
39
|
+
export const TRI: readonly (readonly number[])[] = PACKED.split('.').map((c) =>
|
|
40
|
+
[...c].map((h) => Number.parseInt(h, 16)),
|
|
41
|
+
);
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// One straight structural member written into a shared MeshBuilder: a 2D section (square tube or
|
|
2
|
+
// angle iron) extruded from → to with flat normals. Lattice emits hundreds of these, so there is
|
|
3
|
+
// no per-member Mesh or merge; the section and its cap triangulation are computed once.
|
|
4
|
+
|
|
5
|
+
import type { MeshBuilder, Vec2, Vec3 } from '../core/index.ts';
|
|
6
|
+
import type { UvRect } from '../material/index.ts';
|
|
7
|
+
import { stripU, stripV } from './strip-uv.ts';
|
|
8
|
+
import { triangulate } from './triangulate.ts';
|
|
9
|
+
|
|
10
|
+
export type SectionKind = 'square' | 'angle';
|
|
11
|
+
|
|
12
|
+
export interface Section {
|
|
13
|
+
/** Profile in the member's (x, y) plane, CCW seen from the far end. */
|
|
14
|
+
readonly ring: readonly Vec2[];
|
|
15
|
+
readonly caps: readonly (readonly [number, number, number])[];
|
|
16
|
+
/** Cumulative perimeter run at each ring vertex, as a fraction 0..1 (V across the strip). */
|
|
17
|
+
readonly run: readonly number[];
|
|
18
|
+
/** Side triangles per member (caps add 2 · caps.length). */
|
|
19
|
+
readonly sideTris: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** A section of outside width `w`; angle legs are 15% of the width thick. */
|
|
23
|
+
export function section(kind: SectionKind, w: number): Section {
|
|
24
|
+
const h = w / 2;
|
|
25
|
+
const t = w * 0.15;
|
|
26
|
+
const ring: Vec2[] =
|
|
27
|
+
kind === 'square'
|
|
28
|
+
? [
|
|
29
|
+
[-h, -h],
|
|
30
|
+
[h, -h],
|
|
31
|
+
[h, h],
|
|
32
|
+
[-h, h],
|
|
33
|
+
]
|
|
34
|
+
: [
|
|
35
|
+
[-h, -h],
|
|
36
|
+
[h, -h],
|
|
37
|
+
[h, -h + t],
|
|
38
|
+
[-h + t, -h + t],
|
|
39
|
+
[-h + t, h],
|
|
40
|
+
[-h, h],
|
|
41
|
+
];
|
|
42
|
+
const lens = ring.map((a, i) => {
|
|
43
|
+
const b = ring[(i + 1) % ring.length] ?? a;
|
|
44
|
+
return Math.hypot(b[0] - a[0], b[1] - a[1]);
|
|
45
|
+
});
|
|
46
|
+
const total = lens.reduce((s, l) => s + l, 0);
|
|
47
|
+
let acc = 0;
|
|
48
|
+
const run = lens.map((l) => {
|
|
49
|
+
const r = acc / total;
|
|
50
|
+
acc += l;
|
|
51
|
+
return r;
|
|
52
|
+
});
|
|
53
|
+
return { ring, caps: triangulate(ring), run, sideTris: ring.length * 2 };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Extrude `s` from a to b. `y` is the section's local up (must not be parallel to b − a): put it
|
|
58
|
+
* on the face normal so members lie flush in their truss plane. Caps close both ends.
|
|
59
|
+
*/
|
|
60
|
+
export function emitMember(
|
|
61
|
+
mb: MeshBuilder,
|
|
62
|
+
s: Section,
|
|
63
|
+
a: Vec3,
|
|
64
|
+
b: Vec3,
|
|
65
|
+
y: Vec3,
|
|
66
|
+
caps: boolean,
|
|
67
|
+
color: Vec3,
|
|
68
|
+
rect: UvRect,
|
|
69
|
+
): void {
|
|
70
|
+
const d: Vec3 = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
|
|
71
|
+
const len = Math.sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
|
|
72
|
+
const w: Vec3 = [d[0] / len, d[1] / len, d[2] / len];
|
|
73
|
+
// y ⟂ w (Gram–Schmidt), x = y × w so (x, y, w) is right-handed.
|
|
74
|
+
const k = y[0] * w[0] + y[1] * w[1] + y[2] * w[2];
|
|
75
|
+
const yr: Vec3 = [y[0] - w[0] * k, y[1] - w[1] * k, y[2] - w[2] * k];
|
|
76
|
+
const yl = Math.sqrt(yr[0] * yr[0] + yr[1] * yr[1] + yr[2] * yr[2]);
|
|
77
|
+
const yy: Vec3 = [yr[0] / yl, yr[1] / yl, yr[2] / yl];
|
|
78
|
+
const x: Vec3 = [
|
|
79
|
+
yy[1] * w[2] - yy[2] * w[1],
|
|
80
|
+
yy[2] * w[0] - yy[0] * w[2],
|
|
81
|
+
yy[0] * w[1] - yy[1] * w[0],
|
|
82
|
+
];
|
|
83
|
+
const at = (p: Vec2, end: Vec3): Vec3 => [
|
|
84
|
+
end[0] + x[0] * p[0] + yy[0] * p[1],
|
|
85
|
+
end[1] + x[1] * p[0] + yy[1] * p[1],
|
|
86
|
+
end[2] + x[2] * p[0] + yy[2] * p[1],
|
|
87
|
+
];
|
|
88
|
+
const n = s.ring.length;
|
|
89
|
+
const u1 = stripU(rect, len);
|
|
90
|
+
const u0 = stripU(rect, 0);
|
|
91
|
+
for (let i = 0; i < n; i++) {
|
|
92
|
+
const p = s.ring[i] ?? [0, 0];
|
|
93
|
+
const q = s.ring[(i + 1) % n] ?? p;
|
|
94
|
+
const ex = q[0] - p[0];
|
|
95
|
+
const ey = q[1] - p[1];
|
|
96
|
+
const el = Math.hypot(ex, ey);
|
|
97
|
+
// Outward 2D normal of a CCW edge is (ey, −ex).
|
|
98
|
+
const nx = ey / el;
|
|
99
|
+
const ny = -ex / el;
|
|
100
|
+
const nrm: Vec3 = [x[0] * nx + yy[0] * ny, x[1] * nx + yy[1] * ny, x[2] * nx + yy[2] * ny];
|
|
101
|
+
const v0 = stripV(rect, s.run[i] ?? 0);
|
|
102
|
+
const v1 = stripV(rect, i + 1 < n ? (s.run[i + 1] ?? 1) : 1);
|
|
103
|
+
const i0 = mb.vertex({ p: at(p, a), n: nrm, uv: [u0, v0], color });
|
|
104
|
+
const i1 = mb.vertex({ p: at(q, a), n: nrm, uv: [u0, v1], color });
|
|
105
|
+
const i2 = mb.vertex({ p: at(q, b), n: nrm, uv: [u1, v1], color });
|
|
106
|
+
const i3 = mb.vertex({ p: at(p, b), n: nrm, uv: [u1, v0], color });
|
|
107
|
+
mb.quad(i0, i1, i2, i3);
|
|
108
|
+
}
|
|
109
|
+
if (!caps) return;
|
|
110
|
+
for (const [end, sign] of [
|
|
111
|
+
[a, -1],
|
|
112
|
+
[b, 1],
|
|
113
|
+
] as const) {
|
|
114
|
+
const nrm: Vec3 = [w[0] * sign, w[1] * sign, w[2] * sign];
|
|
115
|
+
const first = mb.vertex({
|
|
116
|
+
p: at(s.ring[0] ?? [0, 0], end),
|
|
117
|
+
n: nrm,
|
|
118
|
+
uv: [u0, stripV(rect, 0)],
|
|
119
|
+
color,
|
|
120
|
+
});
|
|
121
|
+
for (let i = 1; i < n; i++) {
|
|
122
|
+
const p = s.ring[i] ?? [0, 0];
|
|
123
|
+
mb.vertex({ p: at(p, end), n: nrm, uv: [u0, stripV(rect, s.run[i] ?? 0)], color });
|
|
124
|
+
}
|
|
125
|
+
for (const [i, j, l] of s.caps) {
|
|
126
|
+
if (sign > 0) mb.tri(first + i, first + j, first + l);
|
|
127
|
+
else mb.tri(first + i, first + l, first + j);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
// Seeded 2D noise kit for terrain and maps: gradient (Perlin) and value noise, fBm, ridged
|
|
2
|
+
// multifractal (Musgrave: sharp ridgelines), billow (rounded hills), domain warp (Quílez: folded,
|
|
3
|
+
// flowing ranges) and terraces. Everything derives from an Rng and uses only + − × ÷ sqrt floor,
|
|
4
|
+
// so the same seed gives the same bits on every engine (no sin/pow/exp in the hot path).
|
|
5
|
+
// A Noise2 takes metres (x, y) and returns roughly [−1, 1] (ridged: [0, 1]).
|
|
6
|
+
|
|
7
|
+
import type { Rng } from '../core/index.ts';
|
|
8
|
+
|
|
9
|
+
export type Noise2 = (x: number, y: number) => number;
|
|
10
|
+
|
|
11
|
+
export interface FractalOptions {
|
|
12
|
+
/** Metres per base feature (the first octave's wavelength). Default 1. */
|
|
13
|
+
readonly scale?: number;
|
|
14
|
+
readonly octaves?: number;
|
|
15
|
+
/** Frequency multiplier per octave. Default 2. */
|
|
16
|
+
readonly lacunarity?: number;
|
|
17
|
+
/** Amplitude multiplier per octave (persistence). Default 0.5. */
|
|
18
|
+
readonly gain?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const R = Math.SQRT1_2;
|
|
22
|
+
/** Eight unit gradients with exact constants (no trig: bitwise identical everywhere). */
|
|
23
|
+
const GX = [1, -1, 0, 0, R, -R, R, -R];
|
|
24
|
+
const GY = [0, 0, 1, -1, R, R, -R, -R];
|
|
25
|
+
|
|
26
|
+
function permutation(rng: Rng): Uint8Array {
|
|
27
|
+
const p = new Uint8Array(512);
|
|
28
|
+
for (let i = 0; i < 256; i++) p[i] = i;
|
|
29
|
+
for (let i = 255; i > 0; i--) {
|
|
30
|
+
const j = rng.int(0, i);
|
|
31
|
+
const t = p[i] ?? 0;
|
|
32
|
+
p[i] = p[j] ?? 0;
|
|
33
|
+
p[j] = t;
|
|
34
|
+
}
|
|
35
|
+
for (let i = 0; i < 256; i++) p[i + 256] = p[i] ?? 0;
|
|
36
|
+
return p;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const fade = (t: number): number => t * t * t * (t * (t * 6 - 15) + 10);
|
|
40
|
+
|
|
41
|
+
/** Perlin gradient noise, feature size 1 m, ≈ [−1, 1]. */
|
|
42
|
+
export function gradientNoise2(rng: Rng): Noise2 {
|
|
43
|
+
const p = permutation(rng);
|
|
44
|
+
const grad = (ix: number, iy: number, dx: number, dy: number): number => {
|
|
45
|
+
const g = (p[(p[ix & 255] ?? 0) + (iy & 255)] ?? 0) & 7;
|
|
46
|
+
return (GX[g] ?? 0) * dx + (GY[g] ?? 0) * dy;
|
|
47
|
+
};
|
|
48
|
+
return (x, y) => {
|
|
49
|
+
const ix = Math.floor(x);
|
|
50
|
+
const iy = Math.floor(y);
|
|
51
|
+
const fx = x - ix;
|
|
52
|
+
const fy = y - iy;
|
|
53
|
+
const u = fade(fx);
|
|
54
|
+
const v = fade(fy);
|
|
55
|
+
const a = grad(ix, iy, fx, fy);
|
|
56
|
+
const b = grad(ix + 1, iy, fx - 1, fy);
|
|
57
|
+
const c = grad(ix, iy + 1, fx, fy - 1);
|
|
58
|
+
const d = grad(ix + 1, iy + 1, fx - 1, fy - 1);
|
|
59
|
+
const top = a + (b - a) * u;
|
|
60
|
+
return (top + (c + (d - c) * u - top) * v) * Math.SQRT2;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Value noise (smoothed random lattice), feature size 1 m, [−1, 1]. Blobbier than gradient. */
|
|
65
|
+
export function valueNoise2(rng: Rng): Noise2 {
|
|
66
|
+
const p = permutation(rng);
|
|
67
|
+
const vals = new Float64Array(256);
|
|
68
|
+
for (let i = 0; i < 256; i++) vals[i] = rng.next() * 2 - 1;
|
|
69
|
+
const at = (ix: number, iy: number): number => vals[p[(p[ix & 255] ?? 0) + (iy & 255)] ?? 0] ?? 0;
|
|
70
|
+
return (x, y) => {
|
|
71
|
+
const ix = Math.floor(x);
|
|
72
|
+
const iy = Math.floor(y);
|
|
73
|
+
const u = fade(x - ix);
|
|
74
|
+
const v = fade(y - iy);
|
|
75
|
+
const top = at(ix, iy) + (at(ix + 1, iy) - at(ix, iy)) * u;
|
|
76
|
+
const bot = at(ix, iy + 1) + (at(ix + 1, iy + 1) - at(ix, iy + 1)) * u;
|
|
77
|
+
return top + (bot - top) * v;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Sum octaves of `shape(n(x·f, y·f))`, normalised by the amplitude sum. */
|
|
82
|
+
function fractal(n: Noise2, o: FractalOptions, shape: (v: number) => number): Noise2 {
|
|
83
|
+
const s = 1 / (o.scale ?? 1);
|
|
84
|
+
const octaves = o.octaves ?? 5;
|
|
85
|
+
const lac = o.lacunarity ?? 2;
|
|
86
|
+
const gain = o.gain ?? 0.5;
|
|
87
|
+
return (x, y) => {
|
|
88
|
+
let sum = 0;
|
|
89
|
+
let amp = 1;
|
|
90
|
+
let norm = 0;
|
|
91
|
+
let f = s;
|
|
92
|
+
for (let i = 0; i < octaves; i++) {
|
|
93
|
+
// Offset each octave so lattice zeros never line up at the origin.
|
|
94
|
+
sum += amp * shape(n(x * f + i * 17.31, y * f - i * 9.73));
|
|
95
|
+
norm += amp;
|
|
96
|
+
amp *= gain;
|
|
97
|
+
f *= lac;
|
|
98
|
+
}
|
|
99
|
+
return sum / norm;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Fractal Brownian motion: the default rolling-hills / rough-surface noise, ≈ [−1, 1]. */
|
|
104
|
+
export const fbm = (n: Noise2, o: FractalOptions = {}): Noise2 => fractal(n, o, (v) => v);
|
|
105
|
+
|
|
106
|
+
/** Billow: |noise| octaves, rounded domes and sharp creases (hills, clouds), [−1, 1]. */
|
|
107
|
+
export const billow = (n: Noise2, o: FractalOptions = {}): Noise2 =>
|
|
108
|
+
fractal(n, o, (v) => 2 * Math.abs(v) - 1);
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Ridged multifractal (Musgrave): inverted |noise| squared, each octave weighted by the last, so
|
|
112
|
+
* detail piles up on the ridgelines and valleys stay smooth. [0, 1].
|
|
113
|
+
*/
|
|
114
|
+
export function ridged(n: Noise2, o: FractalOptions & { readonly offset?: number } = {}): Noise2 {
|
|
115
|
+
const s = 1 / (o.scale ?? 1);
|
|
116
|
+
const octaves = o.octaves ?? 6;
|
|
117
|
+
const lac = o.lacunarity ?? 2;
|
|
118
|
+
const gain = o.gain ?? 0.5;
|
|
119
|
+
const offset = o.offset ?? 1;
|
|
120
|
+
return (x, y) => {
|
|
121
|
+
let sum = 0;
|
|
122
|
+
let norm = 0;
|
|
123
|
+
let amp = 1;
|
|
124
|
+
let weight = 1;
|
|
125
|
+
let f = s;
|
|
126
|
+
for (let i = 0; i < octaves; i++) {
|
|
127
|
+
const crest = offset - Math.abs(n(x * f + i * 17.31, y * f - i * 9.73));
|
|
128
|
+
const signal = crest * crest * weight;
|
|
129
|
+
weight = Math.min(1, Math.max(0, signal * 2));
|
|
130
|
+
sum += signal * amp;
|
|
131
|
+
norm += amp * offset * offset;
|
|
132
|
+
amp *= gain;
|
|
133
|
+
f *= lac;
|
|
134
|
+
}
|
|
135
|
+
return sum / norm;
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Domain warp: sample `n` at a point pushed by two other noises × `amount` metres (Quílez). */
|
|
140
|
+
export const warp =
|
|
141
|
+
(n: Noise2, wx: Noise2, wy: Noise2, amount: number): Noise2 =>
|
|
142
|
+
(x, y) =>
|
|
143
|
+
n(x + amount * wx(x, y), y + amount * wy(x, y));
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Terraces: snap a height to steps of `step` metres. `sharpness` is the share of each step that is
|
|
147
|
+
* a flat tread (0 = no terracing, 1 = flat treads and vertical risers); the rest is a smooth riser.
|
|
148
|
+
* Strata, rice paddies, open-pit benches.
|
|
149
|
+
*/
|
|
150
|
+
export function terrace(h: number, step: number, sharpness = 0.5): number {
|
|
151
|
+
const k = Math.floor(h / step);
|
|
152
|
+
const t = h / step - k;
|
|
153
|
+
const s = Math.min(1, Math.max(0, sharpness));
|
|
154
|
+
const u = s >= 1 ? 0 : Math.min(1, Math.max(0, (t - s) / (1 - s)));
|
|
155
|
+
const riser = u * u * (3 - 2 * u);
|
|
156
|
+
return (k + t + (riser - t) * s) * step;
|
|
157
|
+
}
|