Commit graph

114 commits

Author SHA1 Message Date
Kelsi
30e58ae0b2 feat(editor): add --gen-texture-houndstooth classic-textile motif
67th procedural texture: the classic 19th-century Scottish
houndstooth broken-check pattern via a hard-coded seamless
8x8 motif:

    1 1 1 1 0 0 0 0
    1 1 1 1 0 0 0 1
    1 1 1 0 0 0 1 1
    1 1 0 0 0 1 1 1
    0 0 0 0 1 1 1 1
    0 0 0 1 1 1 1 1
    0 0 1 1 1 1 1 0
    0 1 1 1 1 1 0 0

Each motif cell scales to `cellSize` pixels (default 4 → 32
px tile), so a 256x256 texture shows 8 motifs in each axis.
Tile-seam-perfect: no row offset or fractional pixel issues
since lookup is integer mod 8.

Useful for noble-house tabard accents, formal-attire trim,
upholstery in palace dining rooms, drapes / wall hangings,
gentry-quarter banners. Distinct from --gen-texture-tartan
(weighted multi-color stripes) and --gen-texture-checker
(simple binary squares) — houndstooth has the iconic
4-pointed "tooth" silhouette.
2026-05-09 12:52:31 -07:00
Kelsi
4e64f833a7 feat(editor): add --list-packs introspection + --gen-temple-pack
Two related changes:

  • --list-packs walks kArgRequired and surfaces every flag
    matching --gen-*-pack (excluding --gen-mesh-* and
    --gen-texture-* which are individual primitives). Sister
    command to --list-primitives. Auto-tracks new packs as
    they're added — no parallel registry.

  • --gen-temple-pack composite — temple/shrine ritual hall
    (altar + shrine + brazier + pillar + statue + portal +
    podium). Fourth themed mesh pack after camp / blacksmith /
    village.

list-packs now surfaces 9 composites including the pre-
existing zone-* / project-starter packs that match the
naming convention. All 7 temple-pack outputs validate clean.
2026-05-09 12:51:10 -07:00
Kelsi
c18d88015a feat(editor): add --gen-mesh-stone-bench heavy seating
72nd procedural mesh primitive. Long stone bench from 3
axis-aligned boxes:

  • horizontal seat slab spanning the full length on top
  • 2 vertical block supports near the ends, inset by
    supportInset from each end so the seat slab overhangs
    them slightly (the standard "seat rests on legs" look)

Distinct from --gen-mesh-bench (wooden 4-leg construction
with thinner pieces) — this is the heavier stone variant
for parks, temple courtyards, ruined cities, dwarven mead
halls, library-courtyard reading nooks.

Watertight under weld (verified 54 manifold edges, 0
boundary, 0 non-manifold). Default 2.0 m × 0.4 m bench at
0.45 m sit height reads at adult-human proportions.

Uses every shared helper added in recent batches —
new gen-mesh handlers now consistently land at ~50 lines
including parse + validate + geometry + finalization.
2026-05-09 12:48:55 -07:00
Kelsi
14c77b1af5 feat(editor): add --gen-texture-diamond-grid solid-shape tile
66th procedural texture: axis-aligned grid of solid diamond
shapes (no row offset) separated by visible bg gaps. Each
cell hosts one diamond computed via L1 (taxicab) metric:
|dx|/halfW + |dy|/halfH < fillFrac.

Distinct from --gen-texture-snake-skin (brick-offset diamonds
that touch tangentially with a derived dark outline) — this
variant uses uniform spacing and a configurable fill fraction
so diamonds float in clean grid rows.

fillFrac = 0.80 default gives a 20% bg-gap moat between
diamonds; bump near 1.0 for nearly-touching chevron-floor
look, drop to 0.5 for sparse polka-diamond.

Useful for clean tile floors, mosaic inlay panels, banner
seamless backgrounds, formal heraldry trim, jeweled-cloak
tabards.
2026-05-09 12:47:28 -07:00
Kelsi
790fe64824 feat(editor): add --gen-village-pack composite
Third composite pack (after --gen-camp-pack and
--gen-blacksmith-pack), emitting a 7-primitive village-square
scene into <outDir>:

  • house — main dwelling
  • outhouse — privy beside it
  • chimney — for the house roof piece
  • hitching-post — at the hitching rail
  • well — village square centerpiece
  • signpost — pointing the way out of town
  • haystack — from the nearby farm

Together these form a recognizable rural-village hub when
arranged in a zone. Uses the existing emitMeshPack helper —
the new pack is just an 8-line declarative table.

All 7 outputs validate clean (--validate-wom PASSED across
the board). Composite-pack catalogue now: camp + blacksmith
+ village.
2026-05-09 12:45:25 -07:00
Kelsi
ca38f77fd0 feat(editor): add --gen-mesh-gravel-pile rubble heap
71st procedural mesh primitive. Hash-distributed pile of
stone cubes in a roughly conical heap. Each stone gets:

  • polar position (radial, theta) with sqrt(rand) on radial
    so stones aren't bunched at center
  • height limited by yMax = pileH * (1 - radial/baseR), so
    larger / more numerous stones land near the base and
    smaller ones perch on top — natural gravel-pile profile
  • size in the 40-100% range of maxStoneSize

The second multi-box "scene" composite primitive (after
--gen-mesh-crate-stack), but using irregular hashed
placement instead of a regular N×M×K grid. Deterministic
from seed: re-running with same args reproduces the
identical pile.

Useful for mine entrances, construction sites, quarries,
ruined walls, abandoned-fort rubble, pirate-cove stash
mounds. Default 24 stones at 0.6 m base radius gives a
reasonable medium-pile.

Uses every shared helper introduced this batch (printWomWrote,
printWomMeshStats, setCenteredBoundsXZ, addFlatBox,
saveWomOrError, parseOpt*, stripExt).
2026-05-09 12:43:03 -07:00
Kelsi
90063037c4 feat(editor): add --gen-texture-plaid translucent-bands pattern
65th procedural texture: 2 sets of parallel "translucent"
bands — one horizontal, one vertical — overlaid on a base.
Each band contributes 0.5 alpha, so where bands cross both
half-alphas combine for the darkest color (the unmistakable
plaid grid intersection).

Distinct from --gen-texture-tartan (3-4 colors with
asymmetric stripe pitches) — this is the simple symmetric
2-color variant. Distinct from --gen-texture-checker (hard
binary squares) — plaid uses 3-tone alpha-blend gradient.

Useful for pub-table cloths, country-tavern napery, dwarven
formal-attire trim, picnic blankets, peasant-clothier
swatches. Default 24-stride / 8-band reads as classic
country-checked at 256x256.

First procedural texture to also use the new printPngWrote
helper from this batch.
2026-05-09 12:39:38 -07:00
Kelsi
26af6d9df6 feat(editor): add --gen-mesh-archery-target training prop
70th procedural mesh primitive. Round-faced archery target on
a 2-post stand:

  • face: closed cylinder along the Z axis (flat ±Z caps face
    the archer line, side wall is the rim) of radius faceR
    centered at height postH
  • stand: 2 vertical posts at the bottom, sized to reach
    from ground to the bottom of the face, with a horizontal
    cross-beam joining them just below the face for rigidity

Concentric scoring rings live in texture space, not geometry —
the cap discs are the natural canvas for a separate target-
ring texture (or use --gen-texture-rings / --gen-texture-
starburst on top).

Pairs naturally with --gen-mesh-training-dummy /
--gen-mesh-fence for sparring grounds, training yards,
militia drill squares, mid-summer fair scenes.

Watertight under weld (verified 198 manifold edges, 0
boundary, 0 non-manifold).
2026-05-09 12:35:15 -07:00
Kelsi
78c7aed888 feat(editor): add --gen-texture-rust-streaks vertical-drip pattern
64th procedural texture: vertical rust drips on a metal base.
Each streak is a hash-derived (x position, width 1..4 px,
top y, length H/3..H) band that fades from full rust at the
top to bg at the bottom — the "streak" effect of years of
rain washing rust down from rivets and seams.

Distinct from --gen-texture-rust (generic surface noise) —
this is the directional-drip variant for:
  • weathered metal walls (especially under high windows)
  • sewer-grate backings under standing puddles
  • ship-hull stains below scupper ports
  • abandoned-machinery panels under leaking pipes

Deterministic from seed: re-running with same args produces
the byte-identical image. Default 40 streaks at 256x256
gives a reasonable "lightly aged" intensity; bump
streakCount for heavier corrosion.
2026-05-09 12:33:25 -07:00
Kelsi
facaacd0c6 feat(editor): add --gen-blacksmith-pack + extract emitMeshPack
Two changes in one commit because they're co-designed:

  • Extract emitMeshPack(outDir, packName, items) as a shared
    helper that takes a vector of PackItem {flag, fn, leaf}
    and runs each handler with a synthetic argv. Keeps the
    "build a 2-element argv per sub-handler" wiring in one
    place instead of copy-pasted per pack.

  • Add --gen-blacksmith-pack on top: a smithy-themed
    composite emitting forge + anvil + workbench +
    water-trough + crate-stack + hitching-post into outDir.
    The classic forge-floor layout in 6 .wom files.

Refactors --gen-camp-pack to use emitMeshPack (verified
unchanged: 6 .wom files still land in the camp dir).
Pattern is now established for future packs (--gen-village-
pack, --gen-temple-pack, --gen-dock-pack…) — each is just a
list of primitives in 8 lines of code.
2026-05-09 12:31:34 -07:00
Kelsi
006beffb83 feat(editor): add --gen-mesh-forge blacksmith hearth
69th procedural mesh primitive. Built from up to 3 axis-
aligned boxes:

  • stone hearth: rectangular base spanning width × depth ×
    baseH, where the smith's fire would sit
  • hood: smaller smoke-collector box on top of the hearth,
    inset by hoodInset on each side so it reads as the
    chimney's flared base
  • optional thin chimney rising from the hood — set
    chimneyH=0 for an open-vented forge

Pairs naturally with --gen-mesh-anvil and
--gen-mesh-workbench for blacksmith/armorer/farrier scenes,
and with --gen-mesh-bench / --gen-mesh-crate-stack for
the storage corner of a smithy.

Watertight under weld (verified 54 manifold edges, 0
boundary, 0 non-manifold). Default 1.4×1.0×0.9 m hearth +
0.5 m hood + 1.2 m chimney reads as a normal village smithy.
2026-05-09 12:29:09 -07:00
Kelsi
b8cfc90fba feat(editor): add --gen-texture-blueprint drafting-paper grid
63rd procedural texture: minor + major grid lines on a base.
Minor lines at every `minorStride` pixels (default 16);
every `majorEvery` minor lines a thicker major line is drawn
(default every 4). Both axes get the same treatment so the
result is a sectioned drafting / engineer's paper look.

Distinct from --gen-texture-mesh-screen (uniform line
weight) — this is the periodic-emphasis variant. Good for:

  • drafting-table surfaces
  • technical-schematic backdrops
  • architect-shop / cartographer-shop walls
  • engineer / scholar ritual tables
  • star-chart room floors

Default 16-stride / every-4-major gives the classic blue
graph-paper aesthetic at 256x256. First procedural texture
that takes 4 numeric layout params plus W/H — exercises the
new parseOpt* helpers across more args than usual.
2026-05-09 12:27:15 -07:00
Kelsi
ec76077b44 feat(editor): add --list-primitives focused introspection
Filtered subset of --list-commands: just procedural primitive
flags (--gen-mesh-* and --gen-texture-*). Walks the shared
kArgRequired registry so it auto-tracks new primitives as they
land — no parallel list to maintain. Useful when authoring
content packs to discover what's available without scrolling
through the full --help dump.

Flags:
  --mesh        — show only --gen-mesh-* (default: both)
  --texture     — show only --gen-texture-* (default: both)
  --json        — JSON output with meshCount/textureCount totals

Currently surfaces 70 procedural mesh primitives and 62
procedural texture primitives. JSON form is well-suited for
piping into sortable / searchable UIs (e.g. content-pack
authoring tools).
2026-05-09 12:25:51 -07:00
Kelsi
68db1be97a feat(editor): add --gen-mesh-outhouse small-shed primitive
68th procedural mesh primitive. Built from 3 axis-aligned
boxes:

  • solid body slab spanning width × depth × (height-roofT)
  • thin door slab on the +Z face (pushed slightly outward
    so it visually sits on the wall — gives doorframe-like
    relief without a real cutout)
  • roof slab slightly larger than the body footprint and
    sitting on top, controlled by roofOverhang

Distinct from --gen-mesh-house (multi-walled, peaked-roof
dwelling). An outhouse is the single-room privy / tool shed
variant — useful for villages, frontier outposts, small
farms, refuse-shed corners.

Watertight under weld (verified 54 manifold edges, 0
boundary, 0 non-manifold). First handler to use the new
setCenteredBoundsXZ helper from this batch.
2026-05-09 12:24:00 -07:00
Kelsi
0b1cf65854 feat(editor): add --gen-camp-pack convenience composite
Convenience composite command: emits a complete outdoor-camp
scene (tent + firepit + bedroll + canopy + woodpile +
haystack) into <outDir>/ as 6 .wom files in one invocation.

Internally builds a synthetic argv array per primitive and
calls each existing handler — so the camp pack always
matches the per-primitive defaults exactly. Users wanting
custom dimensions should call the individual --gen-mesh-*
commands.

Smoke tested:
  • Creates outDir if needed
  • All 6 .wom files validate clean (--validate-wom PASSED)
  • Vertex / triangle counts match per-primitive defaults
    (firepit 240/120, woodpile 324/288, etc.)

The first composite command in the editor — establishes the
pattern for future packs (--gen-village-pack, --gen-dock-pack,
etc.) by showing how synthetic argv arrays let one handler
delegate to many others without spawning subprocesses.
2026-05-09 12:22:37 -07:00
Kelsi
ba1f458ad3 feat(editor): add --gen-texture-bamboo jungle-stalk pattern
62nd procedural texture: vertical bamboo stalks with
cylindrical sin² brightness shading + horizontal darker
node bands at regular Y intervals. Each stalk gets a small
hash-derived hue jitter (±15) so adjacent stalks don't
read as a perfect repeat.

Per-pixel logic:
  • 10% horizontal gap between stalks (gapFrac=0.10) →
    visible bg seam between bamboo stalks
  • Inside the stalk, brightness = sin²(insetFraction * π)
    rising from 0 at the stalk edge to 1 at the centerline
  • Every nodeY pixels, a `nodeBand`-tall horizontal strip
    has its brightness knocked down to 2/3 — the segmented
    bamboo joint look

Useful for jungle huts, pandaren / asian-themed architecture,
swamp boardwalks, tropical-tribe weapon trim, brewmaster
zone trim. Default 24-pitch / 64-spacing / 4-band reads as
adult-bamboo at typical 256x256 wall-tile scale.
2026-05-09 12:20:11 -07:00
Kelsi
38d9575eb2 feat(editor): add --gen-mesh-hitching-post stable fixture
67th procedural mesh primitive. Standard town/stable
hitching post:

  • two vertical posts separated by `span`
  • horizontal cross-bar at upper-post height (length =
    span - postW so it tucks INSIDE the post inner faces,
    matching real fence joinery)
  • optional decorative caps on each post — set capH=0
    for a bare working-yard post

All axis-aligned boxes, exercises every shared helper
(stripExt, initWomDefaults, addFlatBox,
finalizeAsSingleBatch, saveWomOrError). Watertight under
weld (verified 90 manifold edges, 0 boundary, 0
non-manifold).

Useful for stables, taverns with mount parking, town
squares, frontier outposts, ranger camps, post-and-rail
fence segments.
2026-05-09 12:15:41 -07:00
Kelsi
b1fd3382a9 feat(editor): add --gen-texture-mesh-screen orthogonal grid
61st procedural texture: thin horizontal + vertical wires
forming an axis-aligned grid. Distinct from
--gen-texture-lattice (which uses ±45° diagonals to make
diamond openings) — this gives the right-angle window-
screen / chain-link / sci-fi-grille look.

Tested per-axis: a row is "on a wire" if (y % stride) <
wireW; a pixel falls on a wire if either its row OR its
column tests positive. Result is the unmistakable
orthogonal-mesh appearance.

Useful for window screens, anti-pest grates, fish nets,
sewer grilles, sci-fi vent panels, prison-cell windows,
goblin-workshop catwalks. Default 12-stride / 2-wide
gives a coarse mesh; finer versions read as bug screen.
2026-05-09 12:14:10 -07:00
Kelsi
b311916c6c feat(editor): add --gen-mesh-training-dummy sparring prop
66th procedural mesh primitive. Combat training dummy from
axis-aligned boxes:

  • vertical post from ground to baseH (the stand)
  • cubic torso block stacked on top of the post
  • horizontal cross-bar arms at upper-third torso height
    spanning armSpan along the X axis
  • optional head cube above the torso (set headSize=0
    for a headless training-block style)

Pairs with --gen-mesh-anvil / --gen-mesh-workbench /
--gen-mesh-fence for sparring grounds, militia drill
squares, training yards, weapon-master compounds. Useful
for any "things-to-hit" set dressing where animated NPCs
would target a static prop.

Watertight under weld (verified 72 manifold edges, 0
boundary, 0 non-manifold). Default 1.0 m post + 0.4 m
torso + 0.18 m head reads at adult-human height.
2026-05-09 12:09:36 -07:00
Kelsi
adb7e014ef feat(editor): add --gen-texture-snake-skin diamond-scale pattern
60th procedural texture: brick-offset grid of diamond-shaped
scales using L1 (taxicab) metric so |dx|/halfW + |dy|/halfH
< 1 inside each diamond. Even rows are aligned with the cell
grid; odd rows shift by halfW so adjacent scales touch
tangentially along their points — the classic snake/dragon
hide pattern.

A thin dark outline at d ∈ [outlineFrac, 1] gives definition;
outline color is automatically derived as scaleHex × 0.4
(2/5 brightness). Set outlineW=0 to skip the outline for a
smoother painted-scale look.

Distinct from --gen-texture-scales (overlapping circles for
fish/dragon scales) and --gen-texture-chainmail (rings for
metal mail). Useful for snake-cult robe trim, naga skin,
dragon-scale armor inserts, lizardman set dressing,
basilisk-themed dungeon decor.
2026-05-09 12:08:11 -07:00
Kelsi
4cb1c33335 feat(editor): add --gen-mesh-water-trough basin primitive
65th procedural mesh primitive. Open-top rectangular basin
built from 5 axis-aligned boxes (uses every shared helper
from cli_box_emitter):

  • bottom slab spanning full footprint at wallT thickness
  • +X / -X side walls spanning full length
  • +Z / -Z front/back walls spanning the inner length so
    they tuck inside the side walls without overlap

Inner cavity (length-2*wallT × height-wallT × width-2*wallT)
is the open water/feed volume. Useful for stables, farmsteads,
taverns, stockyards, alchemist mixing basins.

Default 1.4 × 0.5 × 0.5 m is a reasonable horse-trough size;
configurable for smaller hand-basins or larger livestock
troughs.
2026-05-09 12:02:35 -07:00
Kelsi
5b24b54d09 feat(editor): add --gen-texture-camo woodland-disruption pattern
59th procedural texture: 2-octave bilinear value noise
thresholded into hard bg/fg blobs. Sharp edges read as
real military camouflage rather than the smooth gradient
--gen-texture-noise-color produces.

Two octaves combined at 0.7/0.3 weights:
  • low frequency at cellSize lattice → large dominant blobs
  • high frequency at cellSize/4 lattice → finer mottling
    overlay so blob edges aren't perfectly smooth

Threshold parameter shifts the bg/fg balance — lower values
expose more accent color (good for leaf-pattern), higher
values keep the dominant color dominant (good for rock/sand).

Useful for guard cloaks, military uniforms, ghillie suits,
druid robes, hunter blinds, scout cloaks. First procedural
texture to use the new savePngOrError helper from
cli_png_emit.hpp.
2026-05-09 12:01:11 -07:00
Kelsi
c10b1b0fb1 feat(editor): add --gen-mesh-watchpost sentry tower primitive
64th procedural mesh primitive. A simple scout/sentry
watchpost from axis-aligned boxes:

  • tall central pole rising from ground to postH
  • square platform slab on top of the pole, wider than
    the pole so it overhangs as the lookout deck
  • 4 corner railing posts on the platform — set
    railingH=0 for a bare deck

Distinct from --gen-mesh-tower (round castle tower with
crenellated battlements). A watchpost is the rough scout/
forward-outpost variant — just wood and rope, no masonry.

Pairs naturally with --gen-mesh-tent / --gen-mesh-firepit
for camp + lookout scenes, and --gen-mesh-fence for
perimeter setups. Watertight under weld (verified
108 manifold edges, 0 boundary, 0 non-manifold).
2026-05-09 11:57:38 -07:00
Kelsi
d7941bd4ce feat(editor): add --gen-texture-pinstripe formal-fabric pattern
58th procedural texture: thin vertical lines at every
`stride` x position, with optional thicker "feature" line
every Nth stripe. The periodic doubled-thickness emphasis
is what distinguishes this from --gen-texture-stripes
(which renders wide alternating bands of each color).

Each stripe is centered within its column and has
configurable lineW; feature stripes are 2× the regular
width. Set featureEvery=0 to disable feature emphasis for
a uniform pinstripe pattern.

Useful for noble-house tabards, formal-attire fabric,
banker's counter cloth, sci-fi panel detailing, royal-
guard uniform trim, library / archive carpet runners.

Default 12-pixel stride, 1-pixel line, feature every 6th
stripe gives the classic suit-pinstripe look at 256x256.
2026-05-09 11:56:01 -07:00
Kelsi
a10efed8f5 feat(editor): add --gen-mesh-crate-stack scene primitive
63rd procedural mesh primitive. The first to explicitly
compose a *scene* of multiple objects rather than a single
structure: an N×M×K arrangement of cube crates with a small
gap between each so they read as discrete shipping boxes
rather than one merged solid.

Default 2×2×2 = 8 crates with 0.40 m sides on a 0.02 m gap
gives a tight pyramidal pile. Larger configurations (e.g.
4×3×2 = 24 crates) read as warehouse pallets.

Uses every shared helper added this batch — addFlatBox for
each crate, finalizeAsSingleBatch for the trailing batch,
stripExt for the .wom suffix, parseOptInt/Float for the
optional dimension args. Each crate emits the standard
24-vert / 12-tri box, so an N×M×K stack is a clean
N*M*K-multiple in vertices and triangles.

Useful for warehouses, cargo holds, dock loading bays,
market stalls, dwarven mining caches, pirate stash piles.
Watertight under weld — the gap keeps adjacent crates
from sharing corner positions.
2026-05-09 11:52:20 -07:00
Kelsi
68af5c10c9 feat(editor): add --gen-texture-carbon fiber-weave pattern
57th procedural texture: 2x2 cell pattern where alternating
cells hold horizontal vs vertical fiber segments. Each
segment gets a sin² brightness profile across its
perpendicular axis — 0 at the segment edge, peak at center —
giving the rounded highlight of a real woven fiber bundle.

Cell-pair parity (cx + cy) % 2 determines orientation, so
adjacent cells always alternate weave direction in both X
and Y. Reads as the unmistakable carbon-fiber checkerboard
even at small scales.

Useful for sci-fi armor, sleek tech panels, vehicle bodies,
ritual obsidian inlays, dwarven runeplate accents — any
"machined composite" surface where flat dark grey would
read as plain plastic.

Default 12-pixel cell at 256x256 reads cleanly with about
21 visible weave segments per side.
2026-05-09 11:49:20 -07:00
Kelsi
47641bf0b4 feat(editor): add --gen-mesh-workbench crafter table
62nd procedural mesh primitive. A blacksmith / crafter
workbench built from axis-aligned boxes (uses the new
cli_box_emitter helper plus the new cli_arg_parse helpers
for all 7 optional dimension args):

  • flat top slab spanning length × depth at topT thickness
  • 4 corner legs sized so their outer faces line up with
    the top edges (post-style, no overhang)
  • optional vise box at the +X end of the top — set
    viseSize=0 for a bare bench
  • optional raised tool tray along the +Z back edge —
    set trayH=0 to omit

Pairs naturally with --gen-mesh-anvil (existing) for
blacksmith forge scenes, and --gen-mesh-cauldron for
alchemist labs. Default 1.6×0.7×0.85 m bench reads at
realistic adult-human working height.

Watertight under weld (verified via --info-mesh-stats:
126 manifold edges, 0 boundary, 0 non-manifold).
2026-05-09 11:46:05 -07:00
Kelsi
7f7104623d feat(editor): add --gen-texture-woodgrain end-cut tree-rings
56th procedural texture: concentric annual growth rings
centered slightly off-image (at -W*0.2, H/2) so the texture
shows sweeping arcs across most of its area rather than the
bullseye --gen-texture-rings produces.

Per-ring jitter shifts the dark-band center within each
ring's annular cell, so adjacent rings don't read as a
perfect modulus pattern — mimics real annual-growth
variation. Brightness lerps from lightHex (early-wood)
to darkHex (late-wood / heartwood) with a smooth
triangular falloff at the dark-band peak.

First procedural texture to use the new cli_arg_parse
helpers for the optional spacing/seed/W/H args.

Useful for tabletops, log-end caps (chopped firewood
stumps), barrel lids, beam cross-sections, plank ends —
distinct from --gen-texture-wood which renders vertical
grain streaks for plank surfaces.
2026-05-09 11:44:33 -07:00
Kelsi
e23b3faa1c feat(editor): add --gen-mesh-bedroll camp sleeping prop
61st procedural mesh primitive. Builds a bedroll prop:

  • horizontal closed cylinder along the Z axis sitting at
    y = R so it rests on the ground (radius defaults to
    0.16 m, length 1.4 m — adult-human-shaped)
  • optional pillow box at the +Z end (squashed cube,
    pillowSize controls extent)
  • per-segment N-sided cylinder uses the new addVertex
    helper; pillow uses addFlatBox

Set pillowSize=0 for a bare rolled mat. Watertight under
weld (verified via --info-mesh-stats: 90 manifold edges,
0 boundary, 0 non-manifold).

Pairs naturally with --gen-mesh-tent / --gen-mesh-firepit /
--gen-mesh-canopy for outdoor camp scenes — completes the
tent-side camping kit.
2026-05-09 11:39:33 -07:00
Kelsi
65b3352b9f feat(editor): add --gen-texture-moss organic-mottling pattern
55th procedural texture: irregular spots scattered on a hash-
jittered grid. Each cell tests its 8 neighbors so spots near
cell boundaries don't get clipped at the cell wall.

Per-cell hashing controls:
  • presence — density 0-100 chance the cell hosts a spot
  • position — uniform jitter inside the cell
  • radius — 25-75 % of stride, so adjacent spots vary in size

Result reads as random patches of organic growth rather than
a visible lattice. Useful for forest floors, weathered stone
walls, dungeon flagstones, swamp ground, ruined-temple
overlay, fungal-cavern detail.

Default 16-stride / 70-density on a stone-grey base reads
cleanly at 256x256 with about half the surface mossed over.
2026-05-09 11:38:03 -07:00
Kelsi
db2db04ffe feat(editor): add --bake-zone-collision aggregator
Walks every .wom and .wob under <zoneDir>, optionally welds
each one independently (per-mesh / per-WOB-group), and
appends its triangles to a single WoweeCollision. Useful for
shipping a zone — one .woc artifact holds all object collision
so the server side has just one file to load.

Per-file weld preserves between-object boundaries: two
distinct WOMs sitting at the same world position keep
their topology separate even if their corner positions
happen to overlap.

Same flag surface as the single-file bakers: optional
[out.woc] (defaults to <zoneDir>/zone.woc), --weld <eps>,
--steep <deg> for the walkable/steep slope cutoff.

Smoke tested over /tmp/migtest: scanned 79 WOM + 1 WOB,
produced 9259-triangle WOC (1563 walkable, 1943 steep)
with correct world bounds.
2026-05-09 11:36:38 -07:00
Kelsi
836fab7f2d feat(editor): add --gen-mesh-chimney brick-stack primitive
60th procedural mesh primitive. Builds a chimney as two
axis-aligned boxes (uses the shared addFlatBox helper):

  • main shaft: rectangular brick stack of width × depth ×
    (height - capH)
  • protective cap: a slightly wider box on top (capExtra
    wider than shaft on every side) — the rain-throw crown
    that sits on real masonry chimneys

Set capH=0 for a bare unfinished stack. Default 0.45×0.45×
1.8 m shaft with a 0.10-tall cap reads at human scale for
rooftop placement.

Useful for cottage rooflines, blacksmith forges, alchemist
labs, dwarven longhouses — any structure with a fireplace
that needs visible vent. Watertight under weld (verified
via --info-mesh-stats: 36 manifold edges, 0 boundary, 0
non-manifold).
2026-05-09 11:34:24 -07:00
Kelsi
26f1947c84 feat(editor): add --audit-watertight-wob building QA tool
Sibling of --audit-watertight that walks every .wob under
<root> and runs the welded watertight check on every group.
A WOB passes only if every group is closed — interior rooms
in a real building should each be a closed solid even
though the building as a whole has intentional portal
openings between them.

Per-failure detail lists which groups failed and why
(boundary edge count + non-manifold edge count). Exit code
is the number of failed buildings (capped at 255) — same
CI-friendly contract as the WOM audit.

Smoke tested against /tmp/migtest cube.wob: PASS, 12 tris,
exit code 0.
2026-05-09 11:33:10 -07:00
Kelsi
f1528f2dd7 feat(editor): add --gen-texture-studs riveted-armor pattern
54th procedural texture: grid of round rivet caps with an
inner highlight. Each stud has:

  • outer ring (40%-100% of studR) at the studHex base color
  • inner core (0-40% of studR) at studHex × 1.4 brightness
  • bg color outside studR

The 40% bright core sells the 3D rivet appearance — a flat
solid circle (which --gen-texture-dots already produces)
reads as a polka dot, while the bright/dim concentric pair
reads as a metal stud catching light.

Useful for studded leather armor, riveted plate, banded
mail trim, dwarven hauberks, prison-cell door reinforcement,
ship hull plating. Default 24-stride grid with R=7 reads
cleanly at typical body-armor scale.
2026-05-09 11:31:27 -07:00
Kelsi
6ff5df41eb feat(editor): add --gen-mesh-pergola garden-arbor primitive
59th procedural mesh primitive. Builds an open-top pergola
from axis-aligned boxes (uses the new addFlatBox helper):

  • 4 corner posts sized so their outer faces line up with
    the footprint perimeter
  • 2 long perimeter beams resting on top of the posts
    along the long edges
  • N cross beams running between the perimeter beams
    (slightly thinner so the lattice has visible crossings)

Distinct from --gen-mesh-canopy because there's no closed
overhead panel — the open lattice top reads as a sun-trellis
or vine-arbor instead of a market-stall awning. Useful for
palace courtyards, druid groves, garden mazes, viewing
arbors, harvest-festival entrance pieces.

Set crossbeams=0 for a bare 4-post + 2-beam frame; default
5 crossbeams gives a pleasing alternating pattern.
2026-05-09 11:26:15 -07:00
Kelsi
63048c1356 feat(editor): add --gen-texture-starburst radial-rays pattern
53rd procedural texture: N rays radiating from the texture
center. Each pixel computes its angle via atan2 and finds
the angular distance to the nearest ray axis (handling the
±π wrap so rays around the seam are continuous). Pixels
inside any ray's angular band get the ray color.

Brightness tapers linearly with distance from center: 1.0
at the hub, 0.4 at the texture diagonal — gives sun-rays
that fade as they extend outward instead of reading as
infinite lines.

Useful for sun motifs, holy/divine symbols, paladin
insignias, mage-robe trim, mosaic medallion centers,
shrine floor inlays, and any "radiant glory" surface.
2026-05-09 11:20:31 -07:00
Kelsi
173ad7796e feat(editor): add --bake-wob-collision multi-group WOB→WOC
Sibling of --bake-wom-collision for buildings. Walks every
group in a WOB, optionally welds vertices PER GROUP (groups
are intentionally separate — rooms with portals between them,
so welding across groups would fuse walls that should remain
distinct collision surfaces), and appends each to a single
WoweeCollision via WoweeCollisionBuilder::addMesh.

Same flag surface as the WOM variant: optional [out.woc]
output path, --weld <eps> for per-group vertex merge,
--steep <deg> for the walkable/steep slope cutoff.

Smoke tested on a 1-group cube WOB: 8 verts → 12-triangle
WOC with proper bounds (-1,-1,-1)..(1,1,1) and walkable/
steep classification matching the cube face orientations.
2026-05-09 11:19:09 -07:00
Kelsi
dadb08baee feat(editor): add --gen-mesh-dock pier-on-stilts primitive
58th procedural mesh primitive. Builds a wooden waterside
dock from axis-aligned boxes:

  • flat plank deck slab spanning length × width at deckT
    thickness, sitting at deckHeight off the ground
  • N pairs of square pilings under the long edges, evenly
    spaced from end to end
  • pilings inset by pilingW so the deck overhangs slightly
    (the standard "boards rest ON TOP of the posts" look)

Distinct from --gen-mesh-bridge which arches OVER an
obstacle — a dock walks straight out from a shoreline on
stilts to the water. Useful for fishing villages, port
warehouses, lake settlements, ferry stations, smuggler
hideouts.

Watertight under weld (--audit-watertight passes): pilings
sit below the deck overhang and don't share corners with it.
2026-05-09 11:17:28 -07:00
Kelsi
0137ca8707 feat(editor): add --gen-texture-caustics water-shimmer pattern
52nd procedural texture: water-surface caustics via four
superimposed sine waves running along x, y, x+y, and x-y.
Each wave is taken in absolute value before multiplication
so peaks shine on either side of the wave centerline,
giving the bright-line interference network you see on a
pool floor or sunlit shallow streambed.

Two-color lerp from bgHex (depth) to hiHex (highlight).
Default 24-pixel period reads at the right scale for water-
plane underlay; pass a smaller period for tighter ripple.

Useful as the floor texture under transparent water
volumes, magic-fountain pools, fish-tank ground plates,
ritual scrying basins, and any "submerged surface seen
through clear water" effect.
2026-05-09 11:12:28 -07:00
Kelsi
89b7e2f505 feat(editor): add --audit-watertight project-level QA tool
Walk every .wom under <zoneDir|projectDir>, run the welded
watertight check from cli_weld + the same edge-analysis as
--info-mesh-stats, and report PASS/FAIL with the per-mesh
failure detail (boundary / non-manifold edge counts).

Exit code is the number of failures (capped at 255), so
CI pipelines can gate on `--audit-watertight $project` and
fail the build if any mesh isn't a closed solid.

Smoke-tested over 61 procedurally-generated WOMs:
  • 49 PASS — most stand-alone primitives are watertight
  • tent_fixed FAIL with 5 boundary edges = the intentional
    door cutout (correct surface count)
  • woodpile / bed / well variants FAIL with non-manifold
    edges = adjacent stacked cylinders/legs sharing corners
    (correct geometry callout)

Defaults to weld eps 1e-4 — a good balance for procedural
output where positions are exact rationals at typical scales.
2026-05-09 11:11:09 -07:00
Kelsi
e732894b4c feat(editor): add --gen-mesh-haystack terraced farm haystack
57th procedural mesh primitive. Builds a layered haystack:
N stacked frustums, each smaller than the one below, with
the topmost layer tapering to an apex point. The visible
shelves where each layer overhangs the smaller one above
read as bound straw shocks rather than the smooth
silhouette --gen-mesh-pyramid produces.

Per layer: vertical side wall ring (no taper within a
single layer) plus a top "shelf" annulus where it meets
the next layer up. Final layer is a cone fan to a single
apex vertex. Closed bottom disc keeps the model a solid
for collision baking — verified watertight under weld.

Useful for farms, granaries, stables, harvest-festival
clearings, druid groves with bound bundles. Default 3
layers at 12 sides reads cleanly at typical NPC scale.
2026-05-09 11:08:39 -07:00
Kelsi
9031bdb620 feat(editor): add --gen-texture-rope twisted-cordage pattern
51st procedural texture: two interleaved sinusoidal strands
running along the Y axis. Each strand's X position oscillates
as W/4·sin(2π·y/period); the second strand is phase-shifted
by π so the two snake around each other forming the classic
helical twist of a tightened rope.

Within each strand, brightness rises from 0.55 at the edge
to 1.0 at the centerline (cos² falloff) — gives the rounded
3D appearance of cylindrical fibers without a separate
shadow pass.

Useful for hanging ropes, ship rigging, tied-bundle textures,
suspension bridges, market-stall awning ties, and any
"twisted cord" surface where a flat color would read as
ribbon rather than rope.

Default 24-pixel period with 8-pixel strands renders cleanly
at 256x256 with about 10 visible twists.
2026-05-09 11:03:33 -07:00
Kelsi
069e76057e feat(editor): add --bake-wom-collision WOM→WOC pipeline
Convert any WOM mesh into a WOC collision file via
WoweeCollisionBuilder::addMesh, with optional --weld <eps>
that merges shared positions into a single canonical index
before baking. The weld pass is what makes per-face-shaded
procedural primitives produce a properly indexed collision
mesh — adjacent faces that previously authored 4 unique
verts per face now share 1 corner across all incident
faces, so raycasts can traverse edges naturally.

Also accepts --steep <deg> to control the walkable/steep
classification threshold (default 50° from horizontal,
matching the terrain pipeline).

Smoke-tested end-to-end:
  • firepit: 240 verts → WOC with 120 tris (20 walkable
    floor, 20 steep stone walls, rest neutral)
  • tent_solid: 18 verts welds to 6, produces 8-tri WOC
  • canopy: 216 → 56 weld, 108 tris, 30° steep cut

Pairs naturally with --info-mesh-stats --weld for
collision-quality QA before baking.
2026-05-09 11:01:45 -07:00
Kelsi
51d884c248 feat(editor): add --gen-mesh-canopy market-stall awning
56th procedural mesh primitive. Builds a rectangular awning
on 4 corner posts with a flat overhead panel and optional
drape lips hanging down from each edge:

  • 4 corner posts inset by postR so their outer faces line
    up flush with the panel edges above
  • flat panel slab spanning the full footprint, sitting on
    top of the posts
  • optional drape lips on all four panel edges (set drape=0
    for a clean flat-top canopy with no hanging fabric)

All axis-aligned boxes; the no-drape variant is fully
watertight (verified via --info-mesh-stats --weld). Useful
for market-square stalls, vendor stations, alchemist booths,
caravan rest stops, and tournament viewing platforms.
2026-05-09 10:59:05 -07:00
Kelsi
4112b6d257 feat(editor): --info-wob-stats + fix weld hash collision bug
Add --info-wob-stats reporting per-group + aggregate
triangle counts, surface area, edge analysis, and watertight
check for WOB buildings. Same flag surface as --info-mesh-stats
including --weld <eps> for true topological closure check
on per-face-vertex meshes.

Also fixes a correctness bug in the weld implementation
of --info-mesh-stats: the previous code used a 64-bit hash
of the quantized position as the equality key, which gave
false-positive collisions that incorrectly merged distinct
vertices. A unit cube's 8 corners collapsed to 2 positions
under the buggy hash. Replace with std::map keyed on the
actual quantized (qx, qy, qz) tuple so equality is exact.

Re-verified: cube 8→8 watertight YES; firepit 240→80
watertight YES (was wrongly reporting 56 unique with 48
non-manifold edges); tent_solid 18→6 watertight YES;
tent_fixed 21→9 with 5 boundary edges at the door perimeter
(correct — door is intentionally open).
2026-05-09 10:57:22 -07:00
Kelsi
a7989cc7ab feat(editor): add --gen-texture-corrugated metal-sheet ridges
50th procedural texture: smooth cosine ridges that lerp
between bgHex (trough) and hiHex (crest) over a configurable
period. Direction defaults to vertical ridges (wave varies
along X) — the standard corrugated-sheet-metal-roof look —
with optional horizontal mode for siding panels and pipe
texturing.

Useful for sheet-metal roofing, corrugated-iron walls,
sci-fi paneling, and any "ridged plate" surface where the
existing flat --gen-texture-metal would read as too uniform.

Default 16px period at 256x256 reads cleanly with about 16
ridges across the tile.
2026-05-09 10:50:46 -07:00
Kelsi
c206216676 feat(editor): add --gen-mesh-woodpile firewood-stack primitive
55th procedural mesh primitive. Builds the classic 3-2-1
firewood pyramid:

  • 3 cylindrical logs along the bottom row, sitting on
    the ground at radii apart
  • 2 logs nestled in the gaps of the bottom row
  • 1 log crowning the pile

Vertical step uses cos(30°) = sqrt(3)/2 so adjacent logs
touch tangentially, giving the close-packed look of a real
chopped-wood stack. Logs lie horizontally along the Z axis
with closed end caps; sides parameter controls cross-
section smoothness (default 12, range 6..64).

Pairs naturally with --gen-mesh-firepit and --gen-mesh-tent
for outdoor camp / homestead / lumberyard set dressing.
2026-05-09 10:47:21 -07:00
Kelsi
f8bd4c70c8 feat(editor): add --gen-texture-planks floor-board pattern
49th procedural texture: horizontal plank-floor pattern.
Each plank gets:

  • a hash-derived per-plank brightness offset (-24..+24)
    so adjacent boards read as separate pieces of wood
    rather than one long stripe
  • a 1px horizontal seam at its bottom edge
  • a 1px vertical end-seam at a hash-jittered x position,
    staggering plank ends across rows
  • optional darker grain streaks at evenly-spaced columns
    (jittered per plank so the pattern doesn't grid-align)

Useful for inn/tavern floors, ship deck planking, bridge
surfaces, market-stall counters, and any wood-floor surface
where the existing single-grain --gen-texture-wood would
read as one giant board.

Default 16px plank height with 5 grain streaks gives a
recognizable floor at 256x256 without aliasing.
2026-05-09 10:44:13 -07:00
Kelsi
5e404a9fe6 feat(editor): add --info-mesh-stats geometric audit
Reports total surface area, per-triangle area histogram
(min/max/mean/median), edge analysis (boundary / manifold /
non-manifold counts), watertight check, and degenerate
triangle count for a single WOM.

Watertightness here is the topological notion: every edge
must be shared by exactly 2 triangles via shared vertex
indices. This is what collision bakes and physics queries
actually need — visually-closed primitives whose adjacent
faces don't weld vertices will (correctly) report as
non-watertight.

Already caught a real defect in handleTent's door-fan
triangulation: the fan covers the door cutout area with
a stray triangle and leaves a vertex unreferenced.
Edge analysis is gated by triCount <= 2M to keep the
unordered_map bounded for huge baked terrain meshes.
2026-05-09 10:41:58 -07:00
Kelsi
17a53f192f feat(editor): add --gen-mesh-firepit camp firepit primitive
54th procedural mesh primitive. Builds a recognizable
campfire setup from axis-aligned boxes only:

  • ring of N stone cubes evenly placed at radius ringR
    around the firepit center, sitting on the ground
  • two crossed log boxes at the center (one along X,
    one along Z, slightly raised) — the unmistakable
    visual cue separating a firepit from a generic
    decorative stone ring

Pairs naturally with --gen-mesh-tent for outdoor camp
set dressing (Horde encampments, Defias hideouts, scout
overlooks). Default 0.5-radius ring with 8 stones reads
cleanly at 1:1 player scale.
2026-05-09 10:37:37 -07:00