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.
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.
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).
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.
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.
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.
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.
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).
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.
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).
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.
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.
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.
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.
21 procedural mesh handlers used the same two-line bounds
stanza for primitives whose footprint is symmetric in X+Z
and rises from y=0:
wom.boundMin = glm::vec3(-halfX, 0, -halfZ);
wom.boundMax = glm::vec3( halfX, maxY, halfZ);
Hoist into cli_box_emitter.hpp as inline setCenteredBoundsXZ
(WoweeModel&, halfX, halfZ, maxY). Each call site collapses
to one line.
Output bytes verified identical: firepit bbox 1.200 × 0.200
× 1.200 unchanged, haystack bbox 1.200 × 0.900 × 1.200
unchanged. Asymmetric bounds (e.g. handlePodium with
different X and Z extents on the min/max lines) are
deliberately left untouched — the helper only matches the
common symmetric case.
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.
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.
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.
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).
Two more boilerplate patterns repeated across cli_gen_mesh.cpp:
• init: 64 sites set wom.name = path-stem and wom.version = 3
in 3 lines. Hoisted to initWomDefaults(wom, base) — 1 line.
• save: 65 sites had identical 5-line "if save fails, fprintf
stderr and return 1" blocks. Hoisted to saveWomOrError(wom,
base, cmdName) returning bool, used as
`if (!saveWomOrError(...)) return 1;` — also 1 line.
Net cli_gen_mesh.cpp drops by ~254 lines (from 6424 to 6170).
Output bytes verified identical: firepit surface area 2.1100
m² unchanged, cube vertex/index/bounds counts unchanged.
After this batch's prior helpers (addFlatBox, addVertex,
stripExt, finalizeAsSingleBatch, parseOpt*), a typical new
gen-mesh handler now needs zero copy-paste boilerplate to
get a working primitive — every shared bit lives in
cli_box_emitter.hpp and cli_arg_parse.hpp.
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.
53 procedural mesh primitives ended with the same 5-line
batch-finalization boilerplate:
wowee::pipeline::WoweeModel::Batch batch;
batch.indexStart = 0;
batch.indexCount = static_cast<uint32_t>(wom.indices.size());
batch.textureIndex = 0;
wom.batches.push_back(batch);
Hoist into cli_box_emitter.hpp as inline finalizeAsSingleBatch
(WoweeModel&). Each call site collapses to:
finalizeAsSingleBatch(wom);
cli_gen_mesh.cpp drops by ~210 lines. Output bytes verified
identical: firepit batch idx 0 / iStart 0 / iCount 360 /
opaque blend, surface area 2.1100 m² unchanged.
Procedural builders only ever emit one batch per primitive;
multi-batch primitives (none currently exist) would still
be free to construct batches manually.
64 sites in cli_gen_mesh.cpp open-coded the same 4-line
"strip .wom suffix from base path if user typed it" pattern:
if (womBase.size() >= 4 &&
womBase.substr(womBase.size() - 4) == ".wom") {
womBase = womBase.substr(0, womBase.size() - 4);
}
Hoist into cli_box_emitter.hpp as inline stripExt(string&,
const char*). Generic on the suffix string so future callers
can use it for ".wob" / ".woc" / ".png" too — uses
string::compare instead of substr to avoid the temporary
allocation the original did per check.
Each call site collapses to a single line:
stripExt(womBase, ".wom");
cli_gen_mesh.cpp drops by ~96 lines. Output bytes verified
identical: firepit surface area 2.1100 m² unchanged.
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).
Every --gen-texture-* and --gen-mesh-* handler had its own
copy of the same 3-line "if there's another arg AND it
doesn't look like a switch, parse it; otherwise keep the
default" block. 458 sites across cli_gen_texture.cpp and
cli_gen_mesh.cpp duplicated this pattern.
Hoist into cli_arg_parse.hpp as inline parseOpt{Int,Float,Uint}
(int& i, int argc, char** argv, T& value). Each call site
collapses from 3 lines to 1:
if (i + 1 < argc && argv[i + 1][0] != '-') {
try { width = std::stof(argv[++i]); } catch (...) {}
}
becomes
parseOptFloat(i, argc, argv, width);
cli_gen_mesh.cpp drops by ~250 lines, cli_gen_texture.cpp
by ~430 lines. Output bytes verified identical: firepit
default-arg surface area 2.1100 m² unchanged.
Future texture/mesh primitives now opt in by including one
header instead of pasting the lambda.
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.
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).
After the addBox extraction, 21 procedural mesh primitives
each still open-coded the same 5-line addV vertex-emit lambda.
Add inline addVertex(WoweeModel&, vec3, vec3, vec2) to
cli_box_emitter.hpp (header so the per-vertex hot loop stays
inlineable), plus a per-float overload for the four handlers
(--gen-mesh-stairs, --gen-mesh-tube, --gen-mesh-capsule,
--gen-mesh-arch) that compute pos/normal/uv components inline
rather than building intermediate glm vectors.
Each lambda site collapses from a 5-line body to a 3-line
forwarding wrapper. Output bytes verified identical via
--info-mesh-stats: firepit surface area 2.1100 m² unchanged
across all variants tested (stairs/tube/capsule/arch/
firepit/mushroom).
Sets up the pattern so the next "shared mesh helper" is one
line of include, not another paste-in.
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.
36 procedural mesh primitives in cli_gen_mesh.cpp each open-
coded the same ~30-line lambda for emitting a flat-shaded
axis-aligned box (per-face vertices for unique normals,
6 faces × 4 verts × 2 tris). Hoist the implementation into
cli_box_emitter.{hpp,cpp} as addFlatBox(WoweeModel&, ...)
with two overloads:
• addFlatBox(wom, cx, cy, cz, hx, hy, hz)
center + half-extents form, used by 34 primitives
• addFlatBox(wom, glm::vec3 lo, glm::vec3 hi)
lo/hi corners form, used by --gen-mesh-archway and
--gen-mesh-fence which compute corners directly
Each lambda site collapses from ~30 lines to a 3-line thin
wrapper: cli_gen_mesh.cpp drops from 7374 to 6989 lines.
Output bytes verified identical via --info-mesh-stats
(firepit surface area 2.1100 m² unchanged, vertex/triangle
counts match across firepit/canopy/dock/archway/fence).
Future box-based primitives now opt in by including one
header instead of pasting the lambda again.
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.
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.
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.
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.
The +X gable's door-fan was wrong: it emitted 5 triangles
including {b, c, br} which spanned across the door cutout
area, and left bl unreferenced. --info-mesh-stats caught
both — surface area was over-reported by 0.10 m^2 and one
triangle was degenerate.
Replace with the correct 4-triangle fan from R1 around the
six-vertex polygon B → bl → dt → br → C → R1 (the original
gable triangle minus the bl-br-dt door notch). All six
vertices are now referenced, no triangle covers the door
area, and surface area matches the visible canvas.
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.
Collapse the 60-entry handcoded if-chain in handleGenMesh
into a static MeshEntry table { flag, minNextArgs, fn } that
the dispatcher walks linearly. Saves ~120 lines and makes
adding a primitive a single-row append instead of a paste-
fest. Also drop a dead inner-ring computation block in
handleArchway and an unused barCY local in handleCage that
were producing -Wunused-but-set-variable warnings — full
project now compiles cleanly with no warnings.
53rd procedural mesh primitive. Builds a watertight A-frame
tent:
• two sloped roof panels meeting at a ridge that runs along
the X axis
• two triangular gables sealing the ends
• optional inverted-V door notch carved out of the +X gable
(parameterized by doorH and doorW; either set to 0 disables
the cutout for a solid gable)
• bottom face for collision-bake watertightness
Useful set dressing for Horde encampments, troll camps,
Defias bandit hideouts, scout/quartermaster overlooks, and
generic outdoor quest hubs.
Default footprint 1.6 x 1.0 with 0.9 ridge height and a
0.5 x 0.4 door notch — all dimensions overridable on the CLI.
58th procedural mesh: 5-box double archway — 3 vertical posts
(left / shared center / right) plus 2 horizontal lintels each
spanning one opening. Pairs with the existing single
--gen-mesh-archway for plaza approaches, double-door tomb
fronts, formal garden entrances, paired temple entries.
Defaults to 1.40m × 2 openings with 2.40m opening height
(~3.16m total width × 2.60m height including lintels).
57th procedural mesh: 7-box brazier — square base plate,
narrow vertical stem, wider bowl on top of the stem, and 3
flame boxes of varying heights rising from the bowl. The
flame layout is a triangle (tallest center, two shorter on
either side) so the silhouette reads as fire rather than a
uniform block.
Useful for dungeons, temples, watchtowers, throne rooms,
goblin camps — anywhere a fantasy world needs visible light
sources. Defaults to 0.55m bowl on a 0.80m stem (~1.28m
total height).
56th procedural mesh: stepped pyramid speaker stand —
configurable number of steps (2..8) tapering from base to top
with equal step heights for visual rhythm, plus a small
lectern box positioned at the back of the top platform so a
speaker has room in front. Top platform is half the base
footprint, with each step shrinking by an equal increment.
Useful for throne rooms, ceremonial dais, NPC speaker
positions, monument bases, judgment platforms. Defaults to
1.60m base × 3 steps with a 0.30m lectern (~0.96m total).
55th procedural mesh: 6-box garden sundial — square base
plate at floor, central vertical gnomon slab spanning the
diameter (long axis along Z, the blade that casts a shadow),
and 4 small hour-marker nubs at the cardinal points (N/S/E/W)
around the rim.
Useful for monastery courtyards, mage tower observatories,
druidic stone circles, manor gardens — anywhere a fantasy
world wants visible time-keeping. Defaults to 0.80m square
base with 0.35m gnomon (~0.41m total height).
54th procedural mesh: 5-box cruciform farm pest deterrent —
vertical body post, horizontal cross arm, head box on top of
the body, brimmed hat box that's wider than the head, and a
narrower-but-taller crown box on top of the hat brim. The
cross silhouette + brimmed-hat read as a scarecrow without
needing rotated geometry.
Useful for crop fields, abandoned villages, harvest set
dressing, ritual circles, fields after a battle. Defaults
to 1.80m body × 1.40m arm span (~2.18m total height).
53rd procedural mesh: 6-box rooftop wind indicator — base
plate, tall vertical post, perpendicular N-S and E-W cross
arms (cardinal direction markers), a long horizontal arrow
on top of the cross, and a small tail box at the back end of
the arrow that visually balances the head and gives the arrow
its directional read.
Useful for farm rooftops, chapel spires, town halls,
lighthouse caps, manor turrets — anywhere a fantasy world
wants visible wind direction. Defaults to a 1.50m post with
0.40m cross arms and a 0.55m-half-length arrow (~1.67m total).
52nd procedural mesh: woven straw beehive (skep) — 4 stacked
tiers of decreasing width approximating a dome (100% / 90% /
70% / 40% of base width), an optional foundation plate
underneath, and a small entrance notch box on the +Z face
that reads as a cutout rather than texture detail.
Useful for druidic groves, beekeeper farms, hunter camps,
peasant cottages — anywhere a fantasy world wants honey
production. Defaults to 0.70m base × 0.85m tall with a
small 0.05m foundation plate.
51st procedural mesh: 5-box wooden gate — 2 vertical posts on
either side and 3 horizontal cross rails (top, middle, bottom)
spanning the opening. The gate sits flat in the X-Y plane
(rails along X, posts along Y) so it can hang in a wall slot
or fence gap without needing rotation.
Useful for fenced fields, manor entrances, pen openings,
courtyard barriers, dungeon archway closures. Defaults to a
1.80m opening with 1.30m-tall posts. Pairs with
--gen-mesh-fence for complete enclosures, exporting through
the open-format ecosystem (WOM -> OBJ / GLB / STL) so designers
can preview the gate-to-fence joinery in any external tool.
Milestone: 50th procedural mesh primitive. 7-box witch's
cauldron — 4 small corner legs at the floor, then three
stacked tiers approximating the curved silhouette of a
cast-iron pot: narrow bottom (60% of rim width), wider mid
(90%), and a still-wider thin rim at the top (100%).
Without rotated faces this stacked-tier approximation is
the cleanest cast-iron-pot read available.
Pairs with --gen-mesh-shrine / --gen-mesh-totem for ritual
and alchemy set dressing — witch huts, druid camps, dungeon
laboratories. Defaults to 0.80 rim width × 0.70 body height
(0.80m total with legs).
49th procedural mesh: 5-box backless stool — flat square seat
on 4 short legs at the corners. Smaller-footprint counterpart
to --gen-mesh-bench, pairs with --gen-mesh-table for taverns,
workshops, NPC market stalls, dwarven taprooms.
Defaults to 0.36m square seat at 0.49m total height — typical
3-legged-bar-stool proportions. Customizable per dimension so
the same primitive covers child stools, milking stools, and
tall workshop stools.
48th procedural mesh: 5-box wooden shipping crate — main
cube body plus 4 reinforcement posts running along the
vertical edges. The posts extend slightly proud of the body
on each axis so they read as separate rails rather than
texture detail, and don't z-fight the body's faces from any
viewing angle.
Useful for dock yards, warehouse interiors, dungeon room
set dressing, NPC merchant shops. Defaults to a 0.80m cube
with 0.05m post half-thickness.