Commit graph

4362 commits

Author SHA1 Message Date
Kelsi
d053f91f0d feat(editor): add --gen-texture-star solid polygon
79th procedural texture: solid N-pointed star polygon
centered on the texture. Each pixel computes its polar
(r, θ); the star boundary at any θ alternates between
outer and inner radii using a 2π/N triangular-wave pattern
(0 at sector edges = points, 1 at sector center = valley).
Pixels with r < boundary(θ) are filled with the star color.

Distinct from --gen-texture-starburst (thin rays with bg
between them) and --gen-texture-pinwheel (alternating
solid wedges) — star is a single solid polygon shape.

innerFrac controls the star's "sharpness": near 0 gives
spike-thin star arms; near 1 approximates a circle. Default
0.40 with 5 points gives the classic American-flag star.
The first point is rotated to the top (-Y screen direction)
for canonical orientation.

Useful for medallion centers, shield emblems, religious /
order symbols, magic-circle icons, banner emblems, sheriff-
badge inserts.
2026-05-09 14:03:07 -07:00
Kelsi
8f16a27253 feat(pipeline): add WOL preset variants for cave/dungeon/night
Three new single-keyframe WOL presets complement the
existing 4-keyframe day/night cycle from --gen-light:

  • --gen-light-cave    — dim cool ambient (0.05, 0.05, 0.07)
                          + heavy short-range fog (15..80)
                          for cave / mine interiors
  • --gen-light-dungeon — warm torchlit ambient (0.18, 0.14,
                          0.10) + medium fog (25..200) for
                          dungeon / crypt interiors
  • --gen-light-night   — cold blue ambient (0.06, 0.07, 0.12)
                          + moonlit directional + far fog
                          (80..500) for always-night zones

Each preset emits a single-keyframe WOL since enclosed /
fixed-time scenes don't vary with time-of-day. All three
share an emitLightPreset helper so adding more presets
(e.g. --gen-light-tundra, --gen-light-volcanic) is one
line of registration + a maker function.

All four WOL outputs validate clean under --validate-wol
(1 or 4 keyframe(s) valid).
2026-05-09 14:01:26 -07:00
Kelsi
2b96863db9 feat(editor): add --gen-mesh-scroll-case library prop
84th procedural mesh primitive. Cylindrical scroll case /
map tube:

  • body — thin tall Y-axis cylinder (the case proper)
  • cap (optional) — shorter wider cylinder on top, set
    capR=0 to skip for a bare stick / rolled-document spine

Distinct from --gen-mesh-chalice (foot + stem + bowl
silhouette) and --gen-mesh-lantern (4-tier base + globe +
neck + cap) — scroll case is the simplest 1-or-2-tier
"tube with lid" prop.

Useful for wizard-tower libraries, archive shelves, mage-
hut detail trim, scribe-table props, scout-courier waist
gear. Validates that capR >= bodyR so the lid always reads
as a proper top closure rather than a degenerate band.

Watertight under weld (verified 168 manifold edges, 0
boundary, 0 non-manifold). Two more clean uses of the
addClosedCylinderY helper.
2026-05-09 13:58:22 -07:00
Kelsi
8c79b732e3 feat(editor): add --gen-texture-crackle Voronoi cell-boundary
78th procedural texture: fine cracks following Voronoi cell
boundaries. For each pixel, the algorithm finds the two
nearest jittered cell centers (across 9 surrounding cells);
the difference between (distance to second-nearest) and
(distance to nearest) approximates distance to the cell
boundary line. Pixels under crackW from the boundary get
the crack color; inside cells get the base.

Distinct from --gen-texture-cracked (wide stone cracks at
large scale via random walk) and --gen-texture-frost
(6-spike crystal rosettes from seeded points) — crackle
is the fine-mud / dry-leather / parched-earth variant for
desert ground / aged-document / drought-cracked-mud zones.

Useful for desert-floor zones, aged-leather armor sections,
parched-earth dungeon floors, dragon-burned ground,
mummified-flesh trim, ancient-document parchment.
2026-05-09 13:56:41 -07:00
Kelsi
dc29f7f135 feat(pipeline): add WOL validation + time-of-day sampling
Three additions to the Wowee Open Light format that landed
last commit:

  • WoweeLightLoader::sampleAtTime(light, timeMin) returns
    the linearly-interpolated keyframe at any time-of-day,
    correctly handling wrap-around between the last keyframe
    and the first (e.g. 21:00 blends from dusk toward
    midnight by going forward through 00:00).

  • --validate-wol <wol-base> [--json] walks every keyframe
    and reports structural problems: time bounds (must be
    [0, 1440)), strict-ascending sort order, fogEnd >
    fogStart, finite color components. Exit code 0 PASS /
    1 FAIL — CI-friendly.

  • --info-wol-at <wol-base> <HH:MM|minutes> samples the
    interpolated state at a specific time of day. Useful
    for previewing what the renderer would feed in at a
    given moment, debugging keyframe gaps, or previewing
    a sub-range of the cycle.

Smoke-tested: dawn-to-midnight blend at 03:00 yields a
plausible mid-fade ambient (0.18, 0.16, 0.15) and dusk-to-
midnight wrap at 21:00 yields the symmetric (0.19, 0.145,
0.14). The default 4-keyframe day/night cycle from
makeDefaultDayNight passes --validate-wol cleanly.
2026-05-09 13:54:57 -07:00
Kelsi
d58ee0af7d feat(pipeline): add Wowee Open Light (.wol) atmosphere format
New open replacement for WoW's Light.dbc / LightParams.dbc /
LightIntBand.dbc / LightFloatBand.dbc stack — a single .wol
file holds a list of time-of-day keyframes for one zone,
each capturing the ambient + directional + fog state at that
moment. The renderer interpolates between adjacent keyframes
by time-of-day.

Binary layout:
  magic[4] = "WOLA", version (uint32),
  nameLen + name bytes,
  keyframeCount + keyframes (each 13 floats + 1 uint32 time)

Per keyframe:
  • timeOfDayMin (0..1439 = minutes since midnight)
  • ambientColor.rgb, directionalColor.rgb, directionalDir.xyz
  • fogColor.rgb, fogStart, fogEnd

CLI:
  • --gen-light <wol-base> [zoneName] — emit a starter file
    with 4-keyframe day/night cycle (midnight/dawn/noon/dusk)
    using reasonable outdoor defaults
  • --info-wol <wol-base> [--json] — inspect: zone name +
    per-keyframe time-of-day + colors + fog distances

The 7th open-format addition to the Wowee pipeline:
  M2  → WOM (model)
  WMO → WOB (building)
  WMO collision → WOC
  ADT → WOT (terrain)
  DBC → JsonDBC
  BLP → PNG
  Light.dbc family → WOL  ← new

Smoke-tested round-trip: gen → info shows correct 4 keyframes
at 00:00 / 06:00 / 12:00 / 18:00 with the canonical color
ramps. JSON output for tooling integration.
2026-05-09 13:52:07 -07:00
Kelsi
1ad1977ad6 feat(editor): add --gen-mesh-standing-torch hall-lining torch
83rd procedural mesh primitive. Tall standing floor torch:

  • post — thin Y-axis cylinder rising from the floor
  • bowl — wider shallow Y-axis cylinder (the fire bowl)
    sitting on top of the post

Distinct from --gen-mesh-brazier (squat fire-bowl on a
short stem with a wide-base silhouette) — standing-torch
is the tall thin walking-height variant for lining
hallways, ceremonial paths, dungeon entries, palace
entrance walks, watch-station lighting.

Validates that postR < bowlR so the silhouette always
reads as the wider-bowl-on-thinner-pole shape.

Watertight under weld (verified 168 manifold edges, 0
boundary, 0 non-manifold). Two clean addClosedCylinderY
calls — pattern is now well-established for cylindrical
prop primitives.
2026-05-09 13:47:37 -07:00
Kelsi
2d566dbe63 feat(editor): add --gen-texture-scratched-metal worn-surface
77th procedural texture: base metal color overlaid with N
short angled line segments brightened against the base.
Each scratch is a hash-derived (cx, cy, length, angle)
segment drawn via integer-stepped line walking from
-len/2 to +len/2 along the angle.

Useful for weathered armor, worn weapon blades (especially
old swords / axes that have seen real use), well-used metal
tools, salvaged hull plating, ancient relic surfaces,
dwarven heirloom finishes.

Default 100 scratches at maxLen=24 gives a moderately worn
look on 256x256; bump scratchCount + maxLen for a heavily
battle-scored aesthetic. Deterministic from seed.
2026-05-09 13:46:11 -07:00
Kelsi
574369bd97 feat(editor): add --gen-arena-pack composite
Tenth themed mesh pack after camp / blacksmith / village /
temple / graveyard / garden / dock / tavern / mining.
Combat-training / gladiator-pit / militia-drill-yard scene
emitting a 7-primitive arena layout:

  • training-dummy — practice target
  • archery-target — range station
  • workbench — weapons-rack stand
  • crate-stack — gear storage
  • bench — audience seating
  • water-trough — between-bout refresh
  • hitching-rail — mount parking

Composite-pack catalogue: camp + blacksmith + village +
temple + graveyard + garden + dock + tavern + mining +
arena = 10 themed mesh packs. --list-packs surfaces 15
total composites including the pre-existing zone/project
starter packs.

Milestone: ten themed mesh packs covering the full life
cycle of a typical role-playing-game town from outdoor
camp to blacksmith forge to gladiator arena.
2026-05-09 13:44:48 -07:00
Kelsi
8a73324a5a feat(editor): add --gen-mesh-chalice ceremonial goblet
82nd procedural mesh primitive. 3-tier ceremonial chalice:

  • foot — wide flat base disc (the goblet's footprint on
    the table)
  • stem — thin tall connecting column (the holding-grip)
  • bowl — wider shallow cup at the top

Validates that stemR < both footR and bowlR so the
silhouette always reads as the classic wide-narrow-wide
goblet shape rather than a degenerate cylinder stack.

Three more primitives that consume the addClosedCylinderY
helper this batch (lantern + chalice from the previous
two commits + this), pattern is now well-established.

Useful for chapel altars, treasure rooms, royal-court
banquet tables, ritual / cult scenes, dwarven mead halls,
fairy-tale storybook props. Watertight under weld
(verified 252 manifold edges, 0 boundary, 0 non-manifold).

Milestone: kArgRequired now reaches 420 documented flags.
2026-05-09 13:42:58 -07:00
Kelsi
c9892f29d0 feat(editor): add --gen-texture-pinwheel sector mandala
76th procedural texture: N alternating colored triangular
wedges radiating from the texture center, each subtending
2π/N radians. Each pixel computes its angle via atan2 and
maps to a sector index; even sectors get color A, odd get
color B.

Distinct from --gen-texture-starburst (thin rays with bg
between them) and --gen-texture-swirl (curved spiral arms)
— pinwheel uses solid-fill alternating wedges with no bg.

Useful for ceiling-decoration medallions, sun-mandala
designs, magical-wheel symbols, wind-rose floor inlays,
heraldic radial backgrounds, druid-circle ground markings.

Default 8 sectors gives the classic pinwheel look; bump
to 12-16 for finer subdivisions, or drop to 2-4 for bold
quadrant patterns.
2026-05-09 13:41:40 -07:00
Kelsi
2e973c0f00 feat(editor): add --gen-mining-pack composite
Ninth themed mesh pack after camp / blacksmith / village /
temple / graveyard / garden / dock / tavern. Mining-shaft
/ quarry-floor scene emitting a 7-primitive working-mine
layout:

  • gravel-pile — loose rubble from the dig
  • crate-stack — raw-ore cargo waiting for transport
  • mine-cart — underground transport
  • pillar-row — roof support pillars (the colonnade
    pattern reads as mine-shaft supports underground)
  • lantern — light source
  • workbench — assay / sorting station
  • hitching-post — mule / cart tie

Together these form a complete working-mine entrance /
quarry-floor layout. Uses 3 primitives newly added in
recent batches (mine-cart, pillar-row, lantern).

Composite-pack catalogue: camp + blacksmith + village +
temple + graveyard + garden + dock + tavern + mining =
9 themed mesh packs. --list-packs surfaces 14 total
including the pre-existing zone/project starters.
2026-05-09 13:40:18 -07:00
Kelsi
c0ea12d2cb feat(editor): add --gen-mesh-lantern hand-lantern primitive
81st procedural mesh primitive. Hand-held oil lantern via
4 stacked Y-axis cylinders:

  • base — short narrow disc (the foot the lantern sits on)
  • globe — wider taller cylinder (the glass enclosure
    holding the wick)
  • neck — narrow constriction above the globe (where the
    cap meets the body)
  • cap — wider short top (the metal hood that lets vent
    smoke escape)

Distinct from --gen-mesh-candle (just wax + saucer) and
--gen-mesh-urn (4-tier pottery shape) — lantern's
wide-narrow-wide tier sequence reads as a glass-enclosed
wick under a metal hood.

Useful for night-watch stations, ranger camps, dwarven
mine tunnels, mausoleum interiors, vigil scenes,
witch-hut shelves. Watertight under weld (verified 336
manifold edges, 0 boundary, 0 non-manifold).
2026-05-09 13:38:06 -07:00
Kelsi
a65d61b492 feat(editor): add --gen-texture-dewdrops scattered-droplets
75th procedural texture: N small water droplets at hash-
derived (cx, cy, R) positions blended onto bg via radial
brightness — bright at the drop center fading to bg at its
edge. Where drops overlap they accumulate brighter
(max-of-individual-contributions, not additive — so the
result stays inside the [bg, drop] color range).

Each drop gets a hash-derived radius in the [maxR/4, maxR]
range so the surface has a natural mix of small and large
droplets. Two-pass (compute brightness map, then write
pixels) so overlap accumulation works correctly.

Useful for morning-grass blades, wet-glass overlays, leaf
surfaces after rain, magic-pool fizz, snake-fountain
splash zones, dragon-breath-aftermath ground.
2026-05-09 13:36:39 -07:00
Kelsi
67e1a7246e refactor(editor): adopt addClosedCylinderZ in bedroll + archery-target
Two more handlers retire their open-coded Z-axis cylinder
geometry and call addClosedCylinderZ instead:

  • --gen-mesh-bedroll: 60-line inline cylinder (side wall +
    end-cap fans) → 1 helper call.
  • --gen-mesh-archery-target: same 60-line block for the
    target face → 1 helper call. The unused local pi
    constant drops out as a side benefit.

Output bytes verified identical: bedroll surface area
1.6746 m² unchanged; archery-target 1.9504 m² unchanged.

Cylinder-helper rollout now complete on the Z-axis side:
woodpile (last batch) + bedroll + archery-target all use
addClosedCylinderZ. Future Z-axis tubes (e.g. mine-cart
axles, well-pail handles, scroll cases) opt in by
including cli_box_emitter.hpp.
2026-05-09 13:35:06 -07:00
Kelsi
b47649b078 feat(editor): add --gen-mesh-candle wax-pillar primitive
80th procedural mesh primitive. Wax pillar candle:

  • saucer (optional) — wider shallow disc base, the drip
    catcher that sits on the table
  • wax — thin tall pillar standing on the saucer (or
    directly on the ground if saucerR=0)

Uses the addClosedCylinderY helper for both pieces — same
two-cylinder pattern as --gen-mesh-bird-bath but with a
much skinnier upper cylinder. The 81-line handler is
mostly arg parsing + validation; geometry is just two
helper calls.

Useful for chapels / shrines, vigil scenes, witch-hut
ritual surfaces, alchemist labs, séance tables, festival-
of-lights ground decoration. Set saucerR=0 for a plain
candle without the saucer (e.g. for stack-them-on-a-cake
contexts).

Watertight under weld (verified — wax + saucer are two
independent closed cylinders).

Milestone: now at 80 procedural mesh primitives.
2026-05-09 13:32:43 -07:00
Kelsi
74b8795aa3 feat(editor): add --gen-texture-lightbeam vertical-ray gradient
74th procedural texture: vertical light-beam / sun-ray
gradient. Each pixel's brightness is the product of two
fade factors:

  • vertical: 1.0 at the bright end, vFadeFrac at the dim
    end (direction flag selects bright-top 'd' or bright-
    bottom 'u')
  • radial: 1.0 inside the bright core (within beamHalfW of
    centerline), then linearly to 0.0 at the texture edge

Two-color blend from bgHex to beamHex by combined brightness.

Useful for dust-mote sunbeams through cathedral windows,
holy radiance auras, crystal glow halos, lighthouse beams,
projector / stage-light columns, ritual-summoning effects.
First procedural texture with a directional flag (u / d) —
flexible orientation for ceiling-down vs floor-up beams.
2026-05-09 13:30:57 -07:00
Kelsi
4565ce29e9 refactor(editor): extract addClosedCylinderZ + adopt in woodpile
Z-axis sibling of addClosedCylinderY: emits a watertight tube
lying horizontally along the Z axis, centered at (cx, cy) on
the XY plane and spanning z=z0..z=z1. Mirrors the Y helper's
side-wall + ±Z cap-fan layout.

Refactor --gen-mesh-woodpile to use the new helper. Its
addLog lambda collapses from 60 lines of inline cylinder
geometry to a 3-line wrapper:

    auto addLog = [&](float cx, float cy) {
        addClosedCylinderZ(wom, cx, cy, logR, -halfL, +halfL, sides);
    };

Output bytes verified identical: woodpile surface area
3.3416 m² unchanged.

Establishes the helper for future Z-axis cylindrical
primitives — bedroll and archery-target (which currently
inline similar code) can adopt it next.
2026-05-09 13:29:07 -07:00
Kelsi
60470eaa35 feat(editor): add --gen-mesh-urn 4-tier pottery vessel
79th procedural mesh primitive. Vertical urn built from 4
stacked tiers using the new addClosedCylinderY helper:

  • foot — wide short cylinder (the ground-meeting base)
  • body — tall main cylinder (the storage volume)
  • neck — narrow constriction
  • lip — slightly wider rim cap

Each tier is an independent watertight Y-axis cylinder with
its own ±Y end caps; they're stacked vertically with each
sitting on the previous tier's top.

Useful for temple offerings, mausoleum interiors, kitchen
storage, alchemist labs, funerary scenes, witch-hut detail.
First handler to consume the new addClosedCylinderY helper —
demonstrates the pattern for future cylindrical primitives
(candle, lantern, scroll case, well-pail, etc.).

Watertight under weld (verified 432 manifold edges, 0
boundary, 0 non-manifold).
2026-05-09 13:27:06 -07:00
Kelsi
7d308e6044 feat(editor): add --gen-texture-embroidery cross-stitch grid
73rd procedural texture: a grid of X-shape cross stitches.
Each cell holds an X formed by two diagonal strokes from
opposing cell corners through the center. A pixel falls on
a stitch if its in-cell position is within strokeW/2 of
either diagonal axis.

Distinct from --gen-texture-checker (filled squares),
--gen-texture-knit (V-stitch chevron), --gen-texture-lattice
(diagonal trellis). Embroidery is the explicit two-direction
diagonal stitch mark used by counted-thread textile work.

Useful for sampler-cloth detail, folk-art trim, peasant-
clothier border bands, witch-hut wall hangings, hearth-rug
overlays. Default 12-cell / 2-stroke gives a fine X-stitch
look; bump cellSize for chunkier sampler stitches.
2026-05-09 13:25:41 -07:00
Kelsi
81f605617a refactor(editor): extract addClosedCylinderY into cli_box_emitter
Hoist the local addYCylinder lambda from --gen-mesh-bird-bath
into cli_box_emitter.hpp as inline addClosedCylinderY(wom, R,
y0, y1, sides). Closed Y-axis cylinder (side wall + ±Y end
cap fans) — the standard watertight tube primitive.

bird-bath now reads as two helper calls:

    addClosedCylinderY(wom, stemR, 0.0f, stemH, sides);
    addClosedCylinderY(wom, basinR, stemH, stemH + basinH, sides);

vs the previous 60-line inline lambda. Output bytes verified
identical: bird-bath surface area 1.0788 m² unchanged.

Establishes the helper for future Y-axis cylindrical
primitives (urn, candle, lantern body, scroll case, well
pail, etc.) — they can stack tubes with one call each.
2026-05-09 13:24:12 -07:00
Kelsi
8adbeb237d feat(editor): add --gen-mesh-planter-box garden flowerbox
78th procedural mesh primitive. Long open-top wooden planter
with a visible soil-fill block:

  • 5-piece basin construction (bottom slab + 4 perimeter
    walls), same arrangement as --gen-mesh-water-trough
  • soil block filling the inner cavity from floor up to
    soilTopFrac × height (default 85%), slightly inset from
    walls so it visually sits "inside" the wood

Distinct from --gen-mesh-water-trough (square basin without
a soil-fill block) — planter-box is the long elongated
garden variant. Useful for window sills, kitchen herb
gardens, balcony planters, monastery cloister-walk
container plants, market-stall produce display trays.

The 6 non-manifold edges (--info-mesh-stats) are at the
4-wall corners — same expected pattern as water-trough,
where the inner walls share corner positions with each
other.

Milestone: kArgRequired now reaches 411 documented flags.
2026-05-09 13:21:03 -07:00
Kelsi
805f7ce240 feat(editor): add --gen-texture-mold Worley-noise patches
72nd procedural texture: Worley (cellular) noise thresholded
into mold patches. Each grid cell hosts a hash-jittered
center; each pixel computes its distance to the nearest
center across 9 surrounding cells (current + 8 neighbors)
and is painted as mold if that distance is below
thresholdFrac × stride.

Distinct from --gen-texture-moss (single-spot per cell with
hash-derived presence/jitter/radius) — mold has irregular
field-shaped patches following the Voronoi cell boundaries
rather than discrete circles, mimicking real fungal growth
along surfaces.

Useful for cellars, dungeon walls, plague zones, sewer
overflow, food-warehouse spoilage, witch-hut detail trim.
Default 18-stride / 0.55-threshold gives a moderate
infestation; bump threshold near 0.9 for full coverage.
2026-05-09 13:19:30 -07:00
Kelsi
e95e983988 feat(editor): add --gen-tavern-pack composite
Eighth themed mesh pack after camp / blacksmith / village /
temple / graveyard / garden / dock. Inn/tavern scene
emitting a 7-primitive watering-hole layout:

  • house — the inn building
  • chimney — above the kitchen hearth
  • table — the common-room centerpiece
  • bench — seating
  • barrel — ale / cider stock
  • bookshelf — back-wall record / register / library
  • signpost — the inn-sign post out front

Together these form a minimum-viable tavern setup for any
roadside inn, town watering-hole, road-house mid-route stop.

Composite-pack catalogue: camp + blacksmith + village +
temple + graveyard + garden + dock + tavern = 8 themed mesh
packs. --list-packs surfaces 13 composites total
(including pre-existing zone/project starter packs).
2026-05-09 13:17:49 -07:00
Kelsi
234cfd0663 feat(editor): add --gen-mesh-bird-bath garden water-feature
77th procedural mesh primitive. Garden bird-bath:

  • stem: thin Y-axis closed cylinder (the column)
  • basin: wider shallow Y-axis closed cylinder on top

Both are full closed cylinders (side wall + ±Y cap fans) so
the model is a watertight solid. Local addYCylinder lambda
emits each tier — keeps the per-handler code self-contained
without forcing yet another module-level helper.

Distinct from --gen-mesh-fountain (basin + spout column,
larger water feature) — bird-bath is the small ornamental
garden version. Useful for monastery courtyards, druid
sanctuaries, noble-house pleasure gardens, sanctuary
clearings, ranger huts.

Watertight under weld (verified 192 manifold edges, 0
boundary, 0 non-manifold).
2026-05-09 13:16:06 -07:00
Kelsi
2a5198df42 feat(editor): add --gen-texture-ironbark hardwood-plate pattern
71st procedural texture: vertical wood-grain streaks (like
--gen-texture-bark) overlaid with horizontal "plate" bands
at regular Y intervals — the segmented look of mature
hardwood / ironwood / sycamore bark.

Per-pixel logic:
  • horizontal crack: top crackW pixels of every plateY
    cycle gets the dark crack color
  • vertical streak: per-streak hash determines an offset
    crack position within each streakSpacing block
  • elsewhere: base color modulated by per-streak-and-plate
    brightness jitter (±15) so the surface has natural
    texture variation

Distinct from --gen-texture-bark (vertical-crack only) and
--gen-texture-wood (vertical-streak only). Useful for ancient
trees, druid grove deadwood, dwarven hardwood beams,
fortress door planks, totem-pole carvings.
2026-05-09 13:14:18 -07:00
Kelsi
0a374fd27d feat(editor): add --summary flag to --audit-watertight-wob
Parity with the WOM-side --audit-watertight --summary added
last batch. Same one-line rollup format for CI dashboards:

  watertight-wob: PASS (1 buildings, 0 failure(s)) [/tmp/migtest, weld 0.001000]
  watertight-wob: FAIL (12 buildings, 4 failure(s)) [/tmp/zone, weld 0.001000]

Format: "watertight-wob: <PASS|FAIL> (<N> buildings, <K>
failure(s)) [<root>, weld <eps>]". Exit code unchanged —
failure count capped at 255.

Both --audit-watertight (WOM) and --audit-watertight-wob
(WOB) now offer the same trio of output modes: verbose
(default), --json (machine-readable), --summary (one-line
CI rollup).
2026-05-09 13:12:42 -07:00
Kelsi
f167e1d2cf feat(editor): add --gen-mesh-statue-base monument pedestal
76th procedural mesh primitive. Classic 3-tier square
pedestal for statues / monuments / hero memorials:

  • plinth — bottom block, plinthExtra wider per side than
    the body (the foundation that meets the ground)
  • body — tall central pedestal sitting on the plinth
    (where the inscription would go)
  • capital — small wider cap on top of the body (where
    the statue's feet would rest)

Distinct from --gen-mesh-podium (stepped pyramid with
lectern at back) and --gen-mesh-altar (stacked round
discs) — this is the classic single-statue square
pedestal shape.

Useful for town-square monuments, hero-of-the-revolution
memorials, plaza centerpieces, mausoleum interiors,
saint-statue stands. Watertight under weld (verified 54
manifold edges, 0 boundary, 0 non-manifold).
2026-05-09 13:11:08 -07:00
Kelsi
88ba27f9ea feat(editor): add --summary flag to --audit-watertight
CI-friendly one-line rollup mode for the welded watertight
audit. Replaces the per-mesh PASS/FAIL detail lines with a
single status line:

  watertight: FAIL (121 meshes, 27 failure(s)) [/tmp/migtest, weld 0.001000]
  watertight: PASS (6 meshes, 0 failure(s)) [/tmp/camp, weld 0.001000]

Format: "watertight: <PASS|FAIL> (<N> meshes, <K> failure(s))
[<root>, weld <eps>]". Exit code unchanged — failure count
capped at 255, matching the verbose-mode contract.

Useful for build dashboards / CI grep lines / Slack-bot
notifications where the full per-mesh dump would be too
noisy. Verbose mode is still the default; opt in with
--summary.
2026-05-09 13:09:28 -07:00
Kelsi
8d75dd3867 feat(editor): add --gen-texture-swirl logarithmic-spiral
70th procedural texture: N-arm logarithmic spiral. Each
pixel computes its polar angle minus log(r)*spiralFactor
and tests whether that "spiral phase" falls inside any
arm's angular band (mod 2π/N).

Distinct from --gen-texture-starburst (straight rays from
center) — this is the curved-arm vortex variant. Small
spiralFactor gives loose pinwheel arms; large factor gives
tight whirlpool spirals.

Useful for magic sigils, summoning circles, ritual floor
markings, mystical-pool surfaces, mage-tower mosaic floors,
shaman-totem ground inlays. Center-based pattern (doesn't
tile seamlessly), so best used as standalone decals rather
than wall textures.
2026-05-09 13:08:07 -07:00
Kelsi
bdeb93bedd feat(editor): add --gen-dock-pack composite
Seventh themed mesh pack after camp / blacksmith / village /
temple / graveyard / garden. Harbor / dockyard scene
emitting a 7-primitive port-side layout:

  • dock — the pier itself
  • crate-stack — cargo waiting to be loaded
  • barrel — sailor stash
  • canopy — shade for the dockmaster's station
  • bench — passenger waiting area
  • signpost — port marker
  • hitching-post — for tying up small boats / mounts

Together these form a recognizable harbor / dockside
pickup-and-drop area when arranged in a zone.

Composite-pack catalogue: camp + blacksmith + village +
temple + graveyard + garden + dock = 7 themed mesh packs.
2026-05-09 13:06:37 -07:00
Kelsi
074f299c8b feat(editor): add --gen-mesh-pillar-row colonnade primitive
75th procedural mesh primitive. Row of N stone pillars
evenly spaced along the X axis. Each pillar is a single
tall rectangular box optionally crowned by a slightly-wider
square cap (capExtra wider per side).

End pillars inset by pillarW so they sit at exactly the
±span/2 ends. Set capH=0 for bare un-crowned columns.

Useful for ruined temples, palace colonnades, dungeon
hallways, dwarven mead-hall arcades, ceremonial entry
walks. Distinct from --gen-mesh-pillar (single column) —
this is the regular-multi-column composite, the third
"scene" primitive after --gen-mesh-crate-stack and
--gen-mesh-gravel-pile.

Watertight under weld (verified 144 manifold edges, 0
boundary, 0 non-manifold). Default 4-pillar / 4 m / 2.5 m
spacing reads as a small temple front porch.
2026-05-09 13:04:55 -07:00
Kelsi
ad21d16df0 feat(editor): add --gen-texture-dunes wave-ripple pattern
69th procedural texture: stack of parallel sinusoidal curves
spaced verticalSpacing apart. A pixel falls on a dune line
if its Y is within lineW/2 pixels of the nearest curve at
y = N*spacing + amp*sin(2π*x/period).

Distinct from --gen-texture-corrugated (uniform parallel
lines) and --gen-texture-zebra (sin-shifted strip fills) —
this is the discrete-curve variant for desert ground
textures and shallow-water sand patterns.

Useful for desert ground, shallow-water sand bottoms,
beach close-ups, mirage scene-setters, sand-storm overlays,
zone-specific weathering on stone surfaces.
2026-05-09 13:03:00 -07:00
Kelsi
b3755f8342 feat(editor): add --gen-garden-pack composite
Sixth themed mesh pack after camp / blacksmith / village /
temple / graveyard. Garden-courtyard scene emitting a
7-primitive monastery / kitchen-garden / small park layout:

  • pergola — vine-arbor frame
  • fountain — centerpiece
  • stone-bench — seating
  • shrine — decorative focal
  • beehive — productive prop
  • scarecrow — rural touch
  • well — water source

Together these form a recognizable contemplative-garden /
small park / monastery courtyard when arranged in a zone.

Composite-pack catalogue now: camp + blacksmith + village
+ temple + graveyard + garden = 6 themed mesh packs.
--list-packs surfaces 11 total composite flags.
2026-05-09 13:01:21 -07:00
Kelsi
b74c369efd feat(editor): add --gen-mesh-hitching-rail multi-post variant
74th procedural mesh primitive. Long horizontal hitching
bar held up by N evenly-spaced vertical posts. Distinct
from --gen-mesh-hitching-post (just 2 posts + bar) — this
is the longer multi-post variant for taverns, stockyards,
racecourse parking, market days, festival hitching lines.

Posts auto-spaced from -L/2 to +L/2, inset by postW so the
end posts align with the rail tips. Bar spans the full
length on top of the post tier.

Watertight under weld (verified 90 manifold edges, 0
boundary, 0 non-manifold). Default 4-post / 4 m rail at
1.2 m mount height fits typical mount silhouettes.

Milestone: kArgRequired now reaches 400 documented flags.
2026-05-09 12:59:16 -07:00
Kelsi
2225448dbf feat(editor): add --gen-texture-chevron V-stripe pattern
68th procedural texture: stack of V-shape stripes with
sharp seams. Within each vertical period the upper half
slopes one way and the lower half slopes the other; the
distance from the apex is added as an x-shift to the
stripe-column test, so stripes follow the V profile and
form clean chevrons.

Distinct from --gen-texture-herringbone (which alternates
slab orientation between cells) and --gen-texture-zebra
(sinusoidal stripes with no seam) — chevron has the
characteristic sharp V transition.

Useful for military insignia, sportswear, heraldic banners,
roadwork signage, paladin tabards, ranger cloaks. Default
24-period / 24-stride / 6-wide gives a chunky chevron at
256x256; tighter values read as fine ribbon trim.
2026-05-09 12:57:47 -07:00
Kelsi
9bd9b50bdb feat(editor): add --gen-graveyard-pack composite
Fifth themed mesh pack after camp / blacksmith / village /
temple. Cemetery scene emitting a 7-primitive burial yard:

  • grave — filled plot mound
  • tombstone — marker stone
  • coffin — above-ground or open
  • statue — mourning angel / patron deity
  • stone-bench — for visitors and mourners
  • gravel-pile — loose earth from a fresh dig
  • cage — fence section / mausoleum gate

Together these form the standard town-edge burial yard
when arranged in a zone. Composite-pack catalogue now:
camp + blacksmith + village + temple + graveyard.

All 7 outputs validate clean. --list-packs surfaces 10
composite flags total (5 mesh packs + the pre-existing
zone/project starter packs).
2026-05-09 12:55:50 -07:00
Kelsi
85e02a6132 feat(editor): add --gen-mesh-mine-cart underground transport
73rd procedural mesh primitive. Open-top mining cart on
4 wheel boxes:

  • bin: 5-piece basin construction (bottom slab + 4
    perimeter walls), same arrangement as
    --gen-mesh-water-trough
  • wheels: 4 cube boxes at the corners, inset by
    wheelInset and sitting on the ground (y from 0 to
    2*wheelR)
  • bin sits on top of the wheels at y = 2*wheelR

All axis-aligned — exercises every shared helper. Useful
for mines, dwarven forges, gnomish junk-yards, abandoned-
tunnel set dressing, salvage scenes.

Default 0.9 × 0.5 m bin with 0.08-radius wheels gives the
classic narrow-gauge ore-cart silhouette. The 4-wall basin
construction (verified via --info-mesh-stats: 6 non-manifold
edges at the wall corners — same as --gen-mesh-water-trough's
expected branchy edges) means the cart can hold collision-
visible ore inside if a content author drops in another
primitive.
2026-05-09 12:54:17 -07:00
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
967cb0d12d refactor(editor): extract printWomWrote + printWomMeshStats
Two more print-pattern extractions for the gen-mesh side:

  • printWomWrote(base) — the "Wrote <base>.wom" success line
    every handler emits at the start of its stat report. 71
    sites collapsed.

  • printWomMeshStats(wom) — the canonical final 2-line pair
    "vertices : N" / "triangles : T" emitted at the end of
    every standard primitive's stat report. 49 sites collapsed.

Output bytes verified identical: firepit and tent surface
area / vertex / triangle counts unchanged.

The one remaining open-coded "Wrote" line is in
--gen-mesh-textured which writes both a .wom and a .png in
the same line — different signature, left unchanged.

These complete the print-helper trio (printPngWrote on the
texture side, printWomWrote + printWomMeshStats on the mesh
side). New primitives now end with one helper call instead
of three printfs.
2026-05-09 12:40:58 -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
d0dc64b78e refactor(editor): extract printPngWrote two-line success header
63 procedural-texture handlers each printed the same two-line
success header at the start of their stat block:

  std::printf("Wrote %s\n", outPath.c_str());
  std::printf("  size       : %dx%d\n", W, H);

The size label had minor whitespace variation (label widths
of 8-15 chars chosen to align with longer per-handler labels).
Hoist into cli_png_emit.hpp as inline printPngWrote(outPath,
W, H) which normalizes to a uniform 11-char label.

Each call site collapses to one line. Output bytes
verified identical via PNG diff: regenerating moss.png with
same args produces byte-for-byte the same file. The visible
text output now uses one consistent label width across all
gen-texture-* commands instead of the previous per-handler
spacing tweaks.
2026-05-09 12:37:22 -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