clone

an endless marble-race generator in the browser; the url is the seed, so every track can be shared

Island shoulder trim: WFC coherence rules for wedge blocks (no more jagged rims)

Dami committed 28d4438
Two sources of the sawtooth silhouette on island edges:
- the per-cell 0.7 trim coin left random full cubes standing inside
  bevel runs. Trim is now an ISLAND-level trait (rng child "trim",
  0.75): the whole rim bevels or the island stays blocky — never
  speckled.
- a cell open on two OPPOSITE sides (1-wide ridge) got a wedge whose
  high edge leaned on nothing, and adjacent ridge cells could slope
  opposite ways. Support law: a wedge must lean against mass, so
  opposite-open cells keep the full cube (only single-open sides and
  adjacent-open corners trim).
commit
28d443810e581761da9fb38b07aa116e5afafdde
parent
73a6248131e4bc224e272b91681acf8067405237
author
Dami <dami.etoile@gmail.com>
1 file changed, +16 -7
Msrc/gen/endless/islands.ts23++++++++++++++++-------
M src/gen/endless/islands.ts +16 -7
@@ -268,6 +268,12 @@ export function buildIsland(
268268 dropAt(c, dx, dz) >= 0.99;269269 const shaped = new Set<string>(); // no caps/decor on these tops270270 271+ // Shoulder trim is an ISLAND-level trait (WFC coherence rule, USER RULE:272+ // triangles must never read jagged): either the whole rim bevels or the273+ // island stays blocky. The old per-cell 0.7 coin left random full cubes274+ // standing inside bevel runs — a sawtooth silhouette.275+ const trimIsland = rng.child("trim").chance(0.75);276+271277 // Waterfall pick (per island): one qualifying edge column.272278 let waterfallCell: string | null = null;273279 {
@@ -345,10 +351,15 @@ export function buildIsland(
345351 346352 // Waterfall column: waterfallTop at the crest, waterfall faces below.347353 const isFall = k === waterfallCell && open.length > 0;348- // Shoulder trim on plain edge tops (never on the waterfall).349- const trim = !isFall && !c.onRun && c.dist >= 1 && c.depth >= 1 &&350- open.length >= 1 && open.length <= 2 &&351- cellRng.chance(0.7);354+ // Shoulder trim on plain edge tops (never on the waterfall). Support355+ // law: a wedge leans against mass, so its high side must be CLOSED —356+ // a cell open on two OPPOSITE sides (1-wide ridge) keeps the full357+ // cube instead of a wedge with a floating high edge.358+ const adjacentOpen = open.length === 2 &&359+ open[0][0] !== open[1][0] && open[0][1] !== open[1][1];360+ const trim = trimIsland && !isFall && !c.onRun && c.dist >= 1 &&361+ c.depth >= 1 &&362+ (open.length === 1 || adjacentOpen);352363 353364 // One face per waterfall column — water can't zigzag around the354365 // corner course to course (the old per-course re-pick did).
@@ -384,9 +395,7 @@ export function buildIsland(
384395 // open too (else the cut face jams into that block's corner), and385396 // with two open sides the slope descends toward the LOWER one.386397 const dirs = open.map(([dx, dz]) => dirOf(dx, dz));387- const adjacent = open.length === 2 &&388- (open[0][0] !== open[1][0] && open[0][1] !== open[1][1]);389- const corner = adjacent &&398+ const corner = adjacentOpen &&390399 dropAt(c, open[0][0] + open[1][0], open[0][1] + open[1][1]) >= 0.99;391400 const slopeDir = open.length === 1392401 ? dirs[0]