Commit graph

73 commits

Author SHA1 Message Date
Kelsi
f85036d580 feat(editor): add --gen-texture-snowflake 6-fold ice crystal
84th procedural texture: 6-fold symmetric snowflake stamp
tiled per cell. Built by computing polar (r, theta) from
the cell center and folding theta into a [0, pi/6] wedge,
so a single arm-shape definition replicates 12 times via
mirror + 60-degree rotation.

Each arm is a thin sliver (sin-based perpendicular distance
test) thickened at two perpendicular knobs at r = 0.40 and
0.70 of the cell-half radius — the knobs provide the
classic "branched ice crystal" silhouette without needing
a separate per-arm subdivision pass.

A small filled center dot anchors the motif at small cell
sizes where the knobs vanish.

Useful for: arctic / winter zones, frost spell effects,
frost-mage themed gear icons, holiday-event decoration,
crystal-shrine backdrops, snowstorm overlays.

Distinct from --gen-texture-snow (random tiny dots, not a
patterned crystal) and --gen-texture-frost (spider-web
crackle, not radial). The first 6-fold-symmetric texture in
the catalogue.
2026-05-09 15:06:32 -07:00
Kelsi
de35ad7814 feat(editor): add --gen-texture-damask 4-petal wallpaper motif
83rd procedural texture: ornate damask wallpaper pattern.
Per cell: 4-fold radial petal lobes formed by sin(theta*2)^2,
faded out toward the cell edge, plus a small filled center
dot to anchor the motif visually.

Reads as gilded fabric / palace wallpaper / noble-faction
tapestry — the missing classic-ornament category in the
catalogue (chevron / herringbone / argyle / houndstooth
cover modern geometric patterns; damask covers the older
Western-European decorative arts side).

Useful for: throne-room walls, cathedral interiors, royal
banners, tavern wallpaper, cushion textures, scroll backgrounds,
manuscript decoration, alchemy-shop bottle-label backdrops.
2026-05-09 14:42:23 -07:00
Kelsi
706c820f8a feat(editor): add --gen-texture-moon disc with phase shadow
82nd procedural texture: solid filled circle of moonHex on
bg, with an optional crescent shadow created by subtracting
a second bg-colored disc offset by `phase` pixels along +X.

Phase reads as the lunar-cycle moment:
  • phase = 0           — full moon
  • 0 < phase < moonR    — gibbous (waning right)
  • phase = moonR        — half moon
  • phase > moonR        — crescent (thinner as phase grows)

Useful for night-sky overlays, banner moons (heraldry of
night-themed orders), shrine medallion centers, druid /
priest emblem inserts, lunar-festival decoration, vampire-
zone backdrops.

The simplest centered-disc texture in the catalogue —
pairs naturally with --gen-texture-stars for a complete
night-sky composite.
2026-05-09 14:26:57 -07:00
Kelsi
25ada9bbfb feat(editor): add --gen-texture-bayer ordered-dither pattern
81st procedural texture: classic 4x4 Bayer ordered-dither
matrix tiled across the image. Each pixel's color comes
from interpolating bg → fg by the matrix value at
(x mod 4, y mod 4) normalized to [0, 1]:

       0  8  2 10
      12  4 14  6
       3 11  1  9
      15  7 13  5

cellSize parameter scales the matrix block (default 4 px,
giving a 16-px seamless tile; cellSize=8 gives a 32-px
chunky retro look).

Useful for 8-bit / monochrome-CRT-style backdrops, ordered-
shadow approximations on low-bit palettes, retro arcade
splash overlays, paper-spritesheet rendering, and as a
deterministic alternative to --gen-texture-noise for
binary or near-binary palettes.
2026-05-09 14:20:02 -07:00
Kelsi
0a7c6c096d feat(editor): add --gen-texture-halftone gradient-modulated dots
80th procedural texture: regular grid of dots whose radii
grow with a configurable gradient direction. Three modes:

  • v (vertical)    — radii grow top-to-bottom
  • h (horizontal)  — radii grow left-to-right
  • r (radial)      — radii grow from texture center outward

Mimics the comic-print / newspaper image-reproduction trick
of varying dot size to encode grayscale. Distinct from
--gen-texture-dots (uniform radius across the grid) and
--gen-texture-studs (uniform with derived inner highlight)
— halftone is the gradient-modulated variant.

Useful for retro-comic / newspaper-aesthetic surfaces, vintage-
poster overlays, sci-fi monitor screens (radial mode reads as
CRT vignette), banner gradient detail, dawn/dusk sky overlays.

Default 16-stride / maxR=7 / vertical reads as classic comic
shading at 256x256.
2026-05-09 14:12:04 -07:00
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
b8cfc90fba feat(editor): add --gen-texture-blueprint drafting-paper grid
63rd procedural texture: minor + major grid lines on a base.
Minor lines at every `minorStride` pixels (default 16);
every `majorEvery` minor lines a thicker major line is drawn
(default every 4). Both axes get the same treatment so the
result is a sectioned drafting / engineer's paper look.

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

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

Default 16-stride / every-4-major gives the classic blue
graph-paper aesthetic at 256x256. First procedural texture
that takes 4 numeric layout params plus W/H — exercises the
new parseOpt* helpers across more args than usual.
2026-05-09 12:27:15 -07:00
Kelsi
ba1f458ad3 feat(editor): add --gen-texture-bamboo jungle-stalk pattern
62nd procedural texture: vertical bamboo stalks with
cylindrical sin² brightness shading + horizontal darker
node bands at regular Y intervals. Each stalk gets a small
hash-derived hue jitter (±15) so adjacent stalks don't
read as a perfect repeat.

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

Useful for jungle huts, pandaren / asian-themed architecture,
swamp boardwalks, tropical-tribe weapon trim, brewmaster
zone trim. Default 24-pitch / 64-spacing / 4-band reads as
adult-bamboo at typical 256x256 wall-tile scale.
2026-05-09 12:20:11 -07:00
Kelsi
b1fd3382a9 feat(editor): add --gen-texture-mesh-screen orthogonal grid
61st procedural texture: thin horizontal + vertical wires
forming an axis-aligned grid. Distinct from
--gen-texture-lattice (which uses ±45° diagonals to make
diamond openings) — this gives the right-angle window-
screen / chain-link / sci-fi-grille look.

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

Useful for window screens, anti-pest grates, fish nets,
sewer grilles, sci-fi vent panels, prison-cell windows,
goblin-workshop catwalks. Default 12-stride / 2-wide
gives a coarse mesh; finer versions read as bug screen.
2026-05-09 12:14:10 -07:00
Kelsi
dc762eb7ce refactor(editor): extract setPixelRGB inner-loop helper
29 procedural-texture inner loops in cli_gen_texture.cpp
open-coded the same 4-line "compute index, write 3 RGB
bytes" block:

  size_t idx = (static_cast<size_t>(y) * W + x) * 3;
  pixels[idx + 0] = r;
  pixels[idx + 1] = g;
  pixels[idx + 2] = b;

Hoist into cli_png_emit.hpp as inline setPixelRGB(pixels,
W, x, y, r, g, b). Header-inline because the procedural
handlers call this once per pixel — the abstraction must
not cost a function-call frame per write.

Each call site collapses to 1 line. cli_gen_texture.cpp
loses ~90 lines from inner-loop bodies. Output bytes
verified identical via PNG diff for moss / camo / snake-skin
— byte-for-byte the same files as previously generated.

(One frost-blend site keeps the open-coded form because
it does a read-modify-write alpha blend rather than a
pure write.)
2026-05-09 12:12:21 -07:00
Kelsi
adb7e014ef feat(editor): add --gen-texture-snake-skin diamond-scale pattern
60th procedural texture: brick-offset grid of diamond-shaped
scales using L1 (taxicab) metric so |dx|/halfW + |dy|/halfH
< 1 inside each diamond. Even rows are aligned with the cell
grid; odd rows shift by halfW so adjacent scales touch
tangentially along their points — the classic snake/dragon
hide pattern.

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

Distinct from --gen-texture-scales (overlapping circles for
fish/dragon scales) and --gen-texture-chainmail (rings for
metal mail). Useful for snake-cult robe trim, naga skin,
dragon-scale armor inserts, lizardman set dressing,
basilisk-themed dungeon decor.
2026-05-09 12:08:11 -07:00
Kelsi
e1e505984f refactor(editor): extract parseHexOrError + hoist parseHex
parseHex was a static helper in cli_gen_texture.cpp. 81 sites
across the file each open-coded the same 6-line "if !parseHex
then fprintf 'X is not a valid hex color' and return 1" block.

Hoist parseHex into cli_png_emit.hpp as inline (header-only,
non-trivial but only called once per handler at startup so
inlining cost is negligible). Add inline parseHexOrError that
wraps it with the canonical error message.

Each call site collapses from 6 lines to 1:

  if (!parseHexOrError(stoneHex, sr, sg, sb,
                       "gen-texture-cobble")) return 1;

Bonus: 29 compound-color sites that used a single
"one of the hex colors is invalid" message are split into
separate parseHexOrError calls per color — now the error
identifies WHICH color failed instead of just saying
"one of them".

cli_gen_texture.cpp drops by ~320 lines (4877 → 4557). Output
bytes verified identical for cobble / mosaic / stained-glass.
Error message contract improved: 'NOTHEX' now reports
"'NOTHEX' is not a valid hex color" everywhere instead of
the generic compound message.
2026-05-09 12:06:49 -07:00
Kelsi
5b24b54d09 feat(editor): add --gen-texture-camo woodland-disruption pattern
59th procedural texture: 2-octave bilinear value noise
thresholded into hard bg/fg blobs. Sharp edges read as
real military camouflage rather than the smooth gradient
--gen-texture-noise-color produces.

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

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

Useful for guard cloaks, military uniforms, ghillie suits,
druid robes, hunter blinds, scout cloaks. First procedural
texture to use the new savePngOrError helper from
cli_png_emit.hpp.
2026-05-09 12:01:11 -07:00
Kelsi
d073f6f608 refactor(editor): extract savePngOrError helper
58 procedural-texture handlers in cli_gen_texture.cpp ended
with the same 6-line stbi_write_png + error-handling block:

    if (!stbi_write_png(outPath.c_str(), W, H, 3,
                        pixels.data(), W * 3)) {
        std::fprintf(stderr,
            "gen-texture-foo: stbi_write_png failed for %s\n",
            outPath.c_str());
        return 1;
    }

Hoist into cli_png_emit.hpp as inline savePngOrError, used as
`if (!savePngOrError(outPath, W, H, pixels, "cmd")) return 1;`.

cli_gen_texture.cpp drops by ~118 lines. Output bytes verified
identical via diff: regenerating moss.png with same args
produces byte-for-byte the same file.

This is the texture-side counterpart to saveWomOrError in
cli_box_emitter.hpp — same write-check-fprintf pattern, same
1-line API.
2026-05-09 11:59:37 -07:00
Kelsi
d7941bd4ce feat(editor): add --gen-texture-pinstripe formal-fabric pattern
58th procedural texture: thin vertical lines at every
`stride` x position, with optional thicker "feature" line
every Nth stripe. The periodic doubled-thickness emphasis
is what distinguishes this from --gen-texture-stripes
(which renders wide alternating bands of each color).

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

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

Default 12-pixel stride, 1-pixel line, feature every 6th
stripe gives the classic suit-pinstripe look at 256x256.
2026-05-09 11:56:01 -07:00
Kelsi
68af5c10c9 feat(editor): add --gen-texture-carbon fiber-weave pattern
57th procedural texture: 2x2 cell pattern where alternating
cells hold horizontal vs vertical fiber segments. Each
segment gets a sin² brightness profile across its
perpendicular axis — 0 at the segment edge, peak at center —
giving the rounded highlight of a real woven fiber bundle.

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

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

Default 12-pixel cell at 256x256 reads cleanly with about
21 visible weave segments per side.
2026-05-09 11:49:20 -07:00
Kelsi
7f7104623d feat(editor): add --gen-texture-woodgrain end-cut tree-rings
56th procedural texture: concentric annual growth rings
centered slightly off-image (at -W*0.2, H/2) so the texture
shows sweeping arcs across most of its area rather than the
bullseye --gen-texture-rings produces.

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

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

Useful for tabletops, log-end caps (chopped firewood
stumps), barrel lids, beam cross-sections, plank ends —
distinct from --gen-texture-wood which renders vertical
grain streaks for plank surfaces.
2026-05-09 11:44:33 -07:00
Kelsi
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
65b3352b9f feat(editor): add --gen-texture-moss organic-mottling pattern
55th procedural texture: irregular spots scattered on a hash-
jittered grid. Each cell tests its 8 neighbors so spots near
cell boundaries don't get clipped at the cell wall.

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

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

Default 16-stride / 70-density on a stone-grey base reads
cleanly at 256x256 with about half the surface mossed over.
2026-05-09 11:38:03 -07:00
Kelsi
f1528f2dd7 feat(editor): add --gen-texture-studs riveted-armor pattern
54th procedural texture: grid of round rivet caps with an
inner highlight. Each stud has:

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

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

Useful for studded leather armor, riveted plate, banded
mail trim, dwarven hauberks, prison-cell door reinforcement,
ship hull plating. Default 24-stride grid with R=7 reads
cleanly at typical body-armor scale.
2026-05-09 11:31:27 -07:00
Kelsi
63048c1356 feat(editor): add --gen-texture-starburst radial-rays pattern
53rd procedural texture: N rays radiating from the texture
center. Each pixel computes its angle via atan2 and finds
the angular distance to the nearest ray axis (handling the
±π wrap so rays around the seam are continuous). Pixels
inside any ray's angular band get the ray color.

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

Useful for sun motifs, holy/divine symbols, paladin
insignias, mage-robe trim, mosaic medallion centers,
shrine floor inlays, and any "radiant glory" surface.
2026-05-09 11:20:31 -07:00
Kelsi
0137ca8707 feat(editor): add --gen-texture-caustics water-shimmer pattern
52nd procedural texture: water-surface caustics via four
superimposed sine waves running along x, y, x+y, and x-y.
Each wave is taken in absolute value before multiplication
so peaks shine on either side of the wave centerline,
giving the bright-line interference network you see on a
pool floor or sunlit shallow streambed.

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

Useful as the floor texture under transparent water
volumes, magic-fountain pools, fish-tank ground plates,
ritual scrying basins, and any "submerged surface seen
through clear water" effect.
2026-05-09 11:12:28 -07:00
Kelsi
9031bdb620 feat(editor): add --gen-texture-rope twisted-cordage pattern
51st procedural texture: two interleaved sinusoidal strands
running along the Y axis. Each strand's X position oscillates
as W/4·sin(2π·y/period); the second strand is phase-shifted
by π so the two snake around each other forming the classic
helical twist of a tightened rope.

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

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

Default 24-pixel period with 8-pixel strands renders cleanly
at 256x256 with about 10 visible twists.
2026-05-09 11:03:33 -07:00
Kelsi
a7989cc7ab feat(editor): add --gen-texture-corrugated metal-sheet ridges
50th procedural texture: smooth cosine ridges that lerp
between bgHex (trough) and hiHex (crest) over a configurable
period. Direction defaults to vertical ridges (wave varies
along X) — the standard corrugated-sheet-metal-roof look —
with optional horizontal mode for siding panels and pipe
texturing.

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

Default 16px period at 256x256 reads cleanly with about 16
ridges across the tile.
2026-05-09 10:50:46 -07:00
Kelsi
f8bd4c70c8 feat(editor): add --gen-texture-planks floor-board pattern
49th procedural texture: horizontal plank-floor pattern.
Each plank gets:

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

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

Default 16px plank height with 5 grain streaks gives a
recognizable floor at 256x256 without aliasing.
2026-05-09 10:44:13 -07:00
Kelsi
86377df7ad refactor(editor): table-driven --gen-texture-* dispatcher
Mirror the kMeshTable pattern from cli_gen_mesh.cpp: replace
the 48-row handcoded if/strcmp chain in handleGenTexture
with a static TextureEntry table that the dispatcher walks
linearly. minNextArgs preserves the per-flag arg-count guards
(noise needs 1, gradient needs 3, stained-glass needs 5)
so missing-arg behavior is byte-identical to the old chain.

Each new texture primitive now lands as a one-line table
append instead of another paste-fest at the bottom of the
dispatcher. Saves ~80 lines.
2026-05-09 10:35:31 -07:00
Kelsi
033c929576 feat(editor): add --gen-texture-chainmail interlinked rings
48th procedural texture: brick-offset ring outlines. Even
and odd rows are shifted by half a cell width so each ring
interlocks visually with its neighbors above and below —
the classic chainmail-armor pattern. Each pixel is tested
against the nearest ring center; if its distance lies
inside [ringR - strokeW/2, ringR + strokeW/2] it's
painted as the ring color, otherwise background.

Useful for armor textures (mail tunics, helms, gauntlets),
metallic fabric set dressing on guard NPCs, and dungeon
gate/grate textures. Default ring radius 5 on a 14x10
brick spacing reads cleanly at 256x256 without aliasing.
2026-05-09 10:34:02 -07:00
Kelsi
a9f4e322d5 feat(editor): add --gen-texture-knit V-stitch fabric pattern
47th procedural texture: knit fabric V-stitch — each stitch
occupies a cellW x cellH cell holding the V-shape made by
two diagonal strokes meeting at the apex (cellW/2, 0) and
dropping to the cell's bottom corners. Cells tile contiguously
in both axes giving the iconic chevron-zigzag appearance of
knitted fabric stitches.

Useful for sweater fabric, woolly NPC clothing, blanket
textures, mitten/scarf set dressing, dwarven knitwork.
Defaults to 16x12 cells with 2-px stroke width.
2026-05-09 10:18:22 -07:00
Kelsi
f6f5b7d9a0 feat(editor): add --gen-texture-zebra wavy-stripe pattern
46th procedural texture: zebra-print stripes — base
horizontal stripes with a sinusoidal y-shift in x so they
undulate organically rather than aligning to the row grid.
Two-color (bg + stripe) for the iconic black-on-white animal-
print effect. Each pixel computes y + amplitude*sin(2π*x/wavelength)
then mods by the stripe period.

Useful for animal-print fabric, savanna grass mats, tribal
clothing, fur tiles. Defaults to 24-px period with 8-px
amplitude on an 80-px wavelength wave.
2026-05-09 10:03:27 -07:00
Kelsi
c4ff7e583c feat(editor): add --gen-texture-leopard animal-print pattern
45th procedural texture: leopard print spots done as the
union of 4 small overlapping sub-circles per spot. The
sub-circle offsets are jittered per-spot so each spot has
an irregular non-circular silhouette without authoring per-
spot polygons. Two-color (bg + spot) for the classic
leopard look.

Useful for animal-print fabric, fur tiles, druidic robes,
shamanic hide drums, hunter armor textures. Defaults to 60
spots of ~8-px radius across 256×256.
2026-05-09 09:51:58 -07:00
Kelsi
288c4e93b6 feat(editor): add --gen-texture-runes magical-glyph pattern
44th procedural texture: scattered angular runes drawn as
3-5 random stroke segments per glyph. Each stroke uses one
of 8 cardinal/diagonal angles (0/45/90/135/...°) so the
strokes read as deliberate runic carvings rather than random
scribbles. Layout is a sparse grid with per-slot jitter and
~5% empty slots so the result looks hand-carved rather than
mechanical.

Useful for ancient ruins, magical zones, dwarven walls,
necromancer altars, druidic shrines. Defaults to a 64-px
grid spacing yielding ~15 runes in a 256×256 image.
2026-05-09 09:42:10 -07:00
Kelsi
47b4501767 feat(editor): add --gen-texture-cracked branching-walk pattern
43rd procedural texture: organic crack network done via
recursive random walks from N seed nuclei. Each seed spawns
a crack that walks in a random direction for some length,
then with 60% chance branches into one or two more cracks
of half-remaining length. Most cracks die out after a step
or two, a few branch into longer networks — the bias matches
real-world fissure formation.

Useful for cracked mud, dry earth, broken glass, weathered
stone, dragon skin overlays, ice-shard effects. Defaults
to 12 seeds at 40-px max length. Iterative DFS instead of
true recursion so deep branching chains never blow the
stack.
2026-05-09 09:06:56 -07:00
Kelsi
98e3bbd58c feat(editor): add --gen-texture-honeycomb hexagonal-cell pattern
42nd procedural texture: hexagonal cell tiling produced by
Voronoi over a triangular seed lattice — alternating-row hex
seeds at horizontal step sqrt(3)*s and vertical step 1.5*s
naturally produce perfect hexagonal Voronoi cells without
needing the full pointy-top hex-tile math.

Border pixels are detected by ratio of second-nearest /
nearest seed distances (1.04x threshold) so border thickness
scales naturally with hex size and stays a couple of pixels
across the whole image. Useful for beehives, dragon scales,
sci-fi panels, magical wards, mosaic tile floors. Defaults
to 16-px hex side.
2026-05-09 08:49:51 -07:00
Kelsi
16f9c072c7 feat(editor): add --gen-texture-lattice diagonal-grid pattern
41st procedural texture: garden trellis / mesh fence done as
two perpendicular sets of diagonal lines (+45° and -45°)
drawn simultaneously across the whole image so they form
diamond-shaped openings between the lines.

Distinct from --gen-texture-herringbone (which alternates
strip orientation): lattice draws both diagonal sets at every
pixel. Useful for trellises, wire mesh fences, dragon-scale
chain mail, decorative window grilles. Defaults to 24-px line
spacing with 3-px line width.
2026-05-09 08:40:14 -07:00