Commit graph

54 commits

Author SHA1 Message Date
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
783b0f167f refactor(editor): extract initWomDefaults + saveWomOrError
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.
2026-05-09 11:54:35 -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
02503e87df refactor(editor): extract finalizeAsSingleBatch helper
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.
2026-05-09 11:50:29 -07:00
Kelsi
9347290335 refactor(editor): extract stripExt into cli_box_emitter
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.
2026-05-09 11:48:03 -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
56c12bc252 refactor(editor): extract optional-arg parse helpers
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run
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.
2026-05-09 11:42:55 -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
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
849aaeb7e0 refactor(editor): extract addVertex helper from 21 cli_gen_mesh sites
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.
2026-05-09 11:29:52 -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
6b5f9938a3 refactor(editor): extract addBox into shared cli_box_emitter
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.
2026-05-09 11:24:35 -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
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
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
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
afdf754c13 fix(editor): correct --gen-mesh-tent door fan triangulation
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.
2026-05-09 10:45:27 -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
Kelsi
190cb3d3fa refactor(editor): table-driven --gen-mesh-* dispatcher
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.
2026-05-09 10:32:26 -07:00
Kelsi
e746e400dd feat(editor): add --gen-mesh-tent A-frame canvas tent
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.
2026-05-09 10:25:38 -07:00
Kelsi
3db5d05519 feat(editor): add --gen-mesh-archway-double twin-passage primitive
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).
2026-05-09 10:11:24 -07:00
Kelsi
09d21f08dd feat(editor): add --gen-mesh-brazier fire-pit primitive
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).
2026-05-09 09:56:38 -07:00
Kelsi
b1f6563c0a feat(editor): add --gen-mesh-podium ceremony-platform primitive
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).
2026-05-09 09:46:59 -07:00
Kelsi
993e90f0ee feat(editor): add --gen-mesh-sundial garden-timekeeper primitive
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).
2026-05-09 09:37:13 -07:00
Kelsi
96bb1f6d04 feat(editor): add --gen-mesh-scarecrow farm-prop primitive
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).
2026-05-09 09:27:56 -07:00
Kelsi
4932947631 feat(editor): add --gen-mesh-weathervane rooftop primitive
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).
2026-05-09 09:20:08 -07:00
Kelsi
822efff70f feat(editor): add --gen-mesh-beehive (skep) primitive
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.
2026-05-09 09:11:36 -07:00
Kelsi
bd2d8ffbd0 feat(editor): add --gen-mesh-gate wooden farm-gate primitive
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.
2026-05-09 09:02:04 -07:00
Kelsi
51ed1e5860 feat(editor): add --gen-mesh-cauldron — 50th procedural mesh
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).
2026-05-09 08:54:27 -07:00
Kelsi
29c7ff6af6 feat(editor): add --gen-mesh-stool small-furniture primitive
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.
2026-05-09 08:44:51 -07:00
Kelsi
f29cf0f29c feat(editor): add --gen-mesh-crate shipping-crate primitive
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.
2026-05-09 08:28:53 -07:00
Kelsi
a953142b50 feat(editor): add --gen-mesh-tombstone graveyard primitive
47th procedural mesh: 3-box vertical headstone — wide low
base plinth, tall thin main slab on top, and a slightly-
wider decorative crown that acts as a flat-cap stand-in for
the arched-top headstone shape (which would need rotated
faces). Pairs with --gen-mesh-grave (horizontal mound) and
--gen-mesh-coffin for graveyards, dungeon crypts, haunted-
zone set dressing.

Vertical layout: 15% base, 75% slab, 10% crown. Defaults to
0.60 wide x 1.10 tall x 0.18 deep with the base 1.45x wider
than the slab on each footprint axis.
2026-05-09 08:19:04 -07:00
Kelsi
f1a2e6850b feat(editor): add --gen-mesh-mailbox wayside primitive
46th procedural mesh: 4-box mailbox — vertical post with a
horizontal box body on top and a small flag (pole + plate)
mounted on the right (+X) side near the front. Useful for
inns, post stations, manor gates, frontier outposts, courier
routes between zones.

Defaults to a 1.10m post + 0.45L x 0.20W x 0.20H body
(~1.44m total). The box body is intentionally slightly wider
than the post on each axis so the body visually caps the
post. Flag plate extends +X away from the body so it reads
as a raised flag from the road side.
2026-05-09 08:08:37 -07:00
Kelsi
af3c4f0bd6 feat(editor): add --gen-mesh-signpost wayfinding primitive
45th procedural mesh: 4-box signpost — stone base anchor,
tall vertical pole, thin sign board mounted face-out near
the top, and a small decorative cap. Useful for crossroads,
tavern fronts, town entrances, dungeon area markers, quest
hub indicators.

Sign board's long axis runs along Z so the player reads the
sign when facing parallel to the road. Defaults to a 2.5 m
post with a 0.8 x 0.35 m board (~2.7 m total).
2026-05-09 07:58:45 -07:00
Kelsi
549bdaf191 feat(editor): add --gen-mesh-well village-prop primitive
44th procedural mesh: 7-box water well — 4 stone walls
arranged in a hollow square (interior visible, like a real
well shaft) + 2 vertical roof posts on opposite sides + 1
horizontal cross beam at the top where rope/bucket would
mount. Useful for village squares, courtyards, dungeon
water sources, druidic shrines.

Defaults to 1.4 m square footprint with 0.8 m walls and
1.6 m roof posts (~2.4 m total height). The east/west
walls are shortened so the corner joints line up cleanly
without overlap geometry.
2026-05-09 07:47:15 -07:00
Kelsi
55a768f1f3 feat(editor): add --gen-mesh-ladder utility primitive
43rd procedural mesh: 2 vertical rails + N evenly-spaced
horizontal rungs. Sits flat against +Z (the climbing face)
so it can be parented to walls, wagons, ship hulls, mage
tower trapdoors, attic openings, dungeon shafts.

Defaults to 3.0m tall × 0.6m wide with 8 rungs (typical
home/loft ladder). Rung spacing computes as height/(rungs+1)
so the first rung sits a half-step from the floor and the
last rung the same distance from the top — keeps the ladder
visually symmetric regardless of rung count.
2026-05-09 07:36:02 -07:00
Kelsi
8d71618c28 feat(editor): add --gen-mesh-bed bedroom-prop primitive
42nd procedural mesh: 8-box bed — 4 corner legs, mattress
slab, tall headboard at the +Z end, shorter footboard at the
-Z end, and a small pillow on the mattress near the headboard.
Pairs with --gen-mesh-table / --gen-mesh-bookshelf for inn
rooms, manor bedrooms, barracks, dungeon cells.

Defaults to 2.0 × 1.2 (length × width) with 0.30 leg height
and 0.20 mattress thickness — proportions of a single bed.
Customizable per dimension so the same primitive covers
single, double, and king-size beds plus child cots.
2026-05-09 07:25:11 -07:00
Kelsi
6c9edc8130 feat(editor): add --gen-mesh-lamppost urban-prop primitive
41st procedural mesh: 4-box urban lighting fixture — square
base plinth, tall thin vertical pole, lantern body box around
the pole top (overlaps so the lamp visually caps the pole),
and a slightly-wider cap plate that reads as an awning.

Useful for streets, plazas, courtyards, taverns — anywhere
that wants explicit lighting fixtures without modeling each
one by hand. Defaults to 3-meter pole + 0.5-meter lantern
(~3.6m total). Customizable per dimension to cover everything
from candlestick-stands to tall ornate streetlamps.
2026-05-09 07:12:46 -07:00
Kelsi
61bc9dfb15 feat(editor): add --gen-mesh-table furniture primitive
40th procedural mesh: simple 5-box table — flat top slab on
4 vertical corner legs. Pairs with --gen-mesh-bench /
--gen-mesh-throne / --gen-mesh-bookshelf for taverns,
dining halls, libraries, and study set dressing.

Defaults to 1.6 × 1.0 base × 0.85 tall, 0.10-square legs,
0.06-thick top — sensible dining-table proportions.
Customizable per dimension so a single primitive covers
desks, end tables, and big banquet tables.
2026-05-09 06:58:38 -07:00
Kelsi
ecb97428aa feat(editor): add --gen-mesh-bookshelf cabinet primitive
39th procedural mesh: 5-panel cabinet (back / left / right /
top / bottom) divided into N bays by N-1 horizontal shelves,
with rows of pseudo-random book boxes on each level. Book
widths and heights vary per bay (seeded by bay index so
re-generating the same shelf gives the same layout) so the
result reads as a stocked library instead of a perfect grid.

Defaults to 1.5x2.0x0.4 with 4 shelves (~72 books). Useful
for studies, libraries, mage towers, anywhere that needs
filled-out furniture set dressing.
2026-05-09 06:39:39 -07:00
Kelsi
2658e8297a feat(editor): add --gen-mesh-coffin hexagonal-prism primitive
38th procedural mesh: classic 6-sided coffin with the
narrow-head / wide-shoulder / tapered-foot top-down profile
that's instantly recognizable from any angle. Built as 6 side
quads + top lid fan + bottom panel fan, all with face-shared
normals so it shades cleanly under any lighting.

Pairs with --gen-mesh-grave for graveyard set dressing.
Defaults to 2.0×0.8×0.6 (length × shoulder-width × height).
2026-05-09 06:18:42 -07:00
Kelsi
b75924762e feat(editor): add --gen-mesh-throne regal-seat primitive
5-box composite: low pedestal slab + seat block + tall
vertical backrest at -Z + 2 small armrests on the +X/-X
sides. Pedestal is wider than the seat for a stable
foundation, seat thickness is 30% of total seat height.

Defaults: seatW=0.8, seatH=0.5, backH=1.5, pedSize=1.2.
Useful for throne rooms, hero seats, judgement halls,
royal court set dressing. Brings the procedural mesh
primitive set to 37.
2026-05-09 05:50:23 -07:00
Kelsi
9973da07ab feat(editor): add --gen-mesh-cage prison-cell primitive
Square cage frame: top + bottom thin slabs + 4 corner posts
(thicker than bars) + N evenly-spaced bars per side. Bars on
each side span perpendicular to that side's plane so the
cage reads as enclosed from any viewing angle.

Defaults: width=1.5, height=2.0, barsPerSide=5, barR=0.04.
Useful for prison cells, animal pens, dungeon set dressing,
caged exhibits. Brings the procedural mesh primitive set to 36.
2026-05-09 05:25:39 -07:00
Kelsi
47e78d4e08 feat(editor): add --gen-mesh-totem stacked carved totem primitive
Stack of N square blocks with alternating widths: even-indexed
blocks (0, 2, 4...) get full base width, odd blocks (1, 3, 5...)
get 70% — gives the carved-segment look characteristic of
totem poles.

Defaults: baseW=0.5, 5 segments, segH=0.5. Useful for tribal
zones, druid groves, fairgrounds, primitive village markers.
Brings the procedural mesh primitive set to 35.
2026-05-09 04:57:33 -07:00
Kelsi
887dce647e feat(editor): add --gen-mesh-shrine canopy primitive
6-component composite: square base slab + 4 cylindrical
pillars (12-segment, inset by pillarR so they sit fully on
the base) + flat roof slab on top with 5% overhang past the
base footprint. Pillars + roof create an open canopy.

Defaults: size=1.5, pillarH=2, pillarR=0.1, roofT=0.15.
Useful for wayside shrines, gazebos, well covers, market
stalls, religious altars in temples. Brings the procedural
mesh primitive set to 34.

Milestone: kArgRequired entries reaches 300.
2026-05-09 04:25:52 -07:00
Kelsi
0a5f508f4e feat(editor): add --gen-mesh-bench wooden bench primitive
Three-box composite: long thin seat plank on top + 2 leg
slabs at the ends (positioned at 90% along the bench length
to leave a small overhang on each side). Legs are vertical
Y-aligned slabs spanning the full height from floor to
bottom-of-seat, ~5% of bench length thick.

Defaults: length=1.5, seatY=0.5, seatT=0.06, seatW=0.4. Useful
for taverns, plazas, roadside rest stops, council halls.
Brings the procedural mesh primitive set to 33.
2026-05-09 03:43:11 -07:00
Kelsi
dab7705c0f feat(editor): add --gen-mesh-grave tombstone primitive
Two-box composite: a wider low base + a vertical tablet
centered on top. Base is deeper than tablet (1.5×) and base
height is 20% of tablet height — proportions that read as a
stable foundation supporting an upright stone.

Defaults: tablet 0.6×1.0×0.15, base width 0.8. Useful for
graveyards, undead zones, memorial set dressing, ruined
chapel courtyards. Brings the procedural mesh primitive set
to 32.
2026-05-09 03:00:19 -07:00
Kelsi
0c1f873029 feat(editor): add --gen-mesh-banner pole + flag primitive
Composite banner: 12-segment vertical pole cylinder with top
and bottom caps + a rectangular flag attached at the top of
the pole, draped along -Z. The flag is two-sided (front faces
+X, back faces -X) so it reads from both viewing angles
without needing backface-culling-disabled materials.

Defaults: poleH=3, poleR=0.05, flagW=0.8, flagH=1.2. Useful
for guild halls, faction territory markers, military camps,
parade dressing. Brings the procedural mesh primitive set
to 31.
2026-05-09 02:10:23 -07:00
Kelsi
d0c8ea582e feat(editor): add --gen-mesh-cart wagon primitive
Composite cart: rectangular bed box + 2 axis-along-Z cylindrical
wheels mounted on each side at the bottom of the bed. Each wheel
has 16 angular segments + front/back caps. Bed sits at y=wheelR
so the wheels touch the ground at y=0.

Defaults: 1.6×0.8×0.5 bed, wheelR=0.35. Useful for medieval
village clutter, market scenes, NPC vendor decoration. Brings
the procedural mesh primitive set to 30.
2026-05-09 00:52:13 -07:00
Kelsi
326f7bcdaa feat(editor): add --gen-mesh-mushroom forest-prop primitive
Composite mushroom: 12-segment cylindrical stalk + 16×8
hemisphere cap on top (top half of a UV sphere). Cap radius
is independent of stalk radius so the silhouette can match
anything from a slim toadstool to a wide morel. Stalk has a
bottom cap and the hemisphere's lower edge is sealed against
a flat -Y disc (the "gills") so the mesh is watertight from
all viewing angles.

Defaults: stalkR=0.1, stalkH=0.6, capR=0.4. Useful for
forest decoration, swamp zones, fairy-ring set dressing.
Brings the procedural mesh primitive set to 29.
2026-05-08 23:48:03 -07:00