Files
VoxelForge/COMPOSER-NOTES.md
T
Fr0zkaandClaude Opus 5 b7cf12af4c docs(composer): the depths regenerate, the city does not -- game design session
Second design session. Started on the composer, ended up with the whole game's
economic loop, and one terminology fix that was overdue.

The loop, closed: the surface is a sky island or an unclimbable mountain, so
resources must come from below; the depths supply them; the resources build the
settlement; the settlement enables deeper descent. The settlement is communal,
identical for everyone, and permanent -- a season advances it one tier
(camp, village, town, city). So the wipe means something beyond freshness: the
world is impermanent, the civilization is not. We lost our maps, but we built a
town.

I had that arc backwards and it is marked as such in the file, along with the
vocabulary that caused it: "the world" was being used for two different things.
The depths are what VoxelForge generates and what regenerates each season; the
city is a plain Unreal level, permanent, and entirely outside this plugin. That
distinction is now pinned at the top of the notes.

Also settled: no bottom, boss strates every ~5 as intermediary gates, gear stats
capped around depth 30 with deeper loot buying better rolls and unique materials
rather than bigger numbers, materials tagged by difficulty tier rather than
depth so their location is rediscovered every season, and death leaving a
possessed corpse that copies your weapons without taking them -- a mirror match
that self-balances at every tier forever, provided the copied gear is never
lootable.

Two design records worth keeping: the manifest is two things (a tiny stored
spine and an infinite hash-addressable field, where the ID encodes the position
so resolving it needs no table), and the opening cinematic -- civilization
emerged from the depths, humans crystallized in the first artificial strate --
justifies the authored/generated seam in fiction. A player who senses strate 1
feels different from strate 2 is reading the story correctly, not spotting the
join.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DPUuCtn5zTLui6WybLbkNb
2026-08-28 11:56:23 +02:00

98 KiB
Raw Blame History

COMPOSER-NOTES.md — running notes on the world-composer conversation

Started 2026-08-17. Small on purpose: what we decided, what's still open, what must not be forgotten. Not a design doc — that comes later, if it earns it.

⚠️ VOCABULARY — read this first

Jahni pinned these terms on 2026-08-17 because my notes used "world" for two different things.

term what it means
THE SURFACE / THE CITY The hand-authored plain Unreal level (not voxel terrain). Sky island or unclimbable mountain, so resources cannot come from up here. Communal, identical for everyone, and it NEVER resets. It progresses across seasons: camp → village → town → city → advanced city.
THE DEPTHS Everything VoxelForge generates: subterranean, bounded, stacked strates below the city hole. Some strates only mimic being outdoors. THIS is what is regenerated every season.
A SEASON One generation of the depths (~6–12 months), plus the settlement tier it earns. The wipe replaces the depths and leaves the city standing.

⚠️ Earlier sections of this file say "the world" when they mean THE DEPTHS. Wherever a note talks about wiping, regenerating, seeds, strates, the manifest or the composer, read the depths. The city is never any of those things — it is authored, permanent, and outside VoxelForge entirely.

The idea, in one line

Jahni authors the vocabulary; the system writes the sentences. He makes data assets (ops, biomes, deco sets, set-pieces, whole handmade levels/strates); the system assembles strates and worlds out of them from the seed, logically.

This is op-stack Phase 3 + a composer layer above it. The 2026-08-16 handoff's "do NOT start Phase 3" is superseded — it closed the door on the one thing he actually wants.

Decided

  • Ambition level (c): the seed invents parameters within authored ranges. Not preset-picking.
  • Two seeds differ in everything — not the same strates spawn, nor the details.
  • ⭐ Primordial law: every strate has an entrance and an exit, exposed to air, findable.
  • Handmade content plugs in as stamps and as whole strates (e.g. a unique boss strate) — entries in the pool with special placement rules.
  • Build the connections first, generate around them. Reachability by construction, not by luck. Precedent: the (0,0) spine is already a guaranteed vertical connector. Generate-then-check gets brutal at 8 strates/world.
  • Validation is 3 layers: (1) construct-by-design so the law can't break, (2) measurable checks for accidents — air fraction, continuous walkable surface, feature size vs voxel scale, strate height sanity, (3) reject-and-resample: fold the attempt number into the hash (hash(seed, strateSlot, attempt)) so every seed still yields a valid world and peers stay in lockstep.
  • The AI good/bad judge is second, not first. Not a fool idea — but the cost is labels, and Jahni is the only labeller. Layers 1–3 remove the numeric garbage; what's left is genuine taste, a much smaller job. The dataset then accumulates for free from seeds he plays and reacts to.
  • F4 save/load is the LOCK on the density field, not a feature. Everything field-changing lands before it. The composer is the largest field-changing work that exists ⇒ far ahead of F4.
  • Acceptance criteria get stated up front and confirmed by Jahni — never inferred. (The bit-identity criterion was self-imposed and cost 3 weeks; peer determinism never required matching an older build. Determinism = same build, all machines. Version stability = a gen-version byte.)

Open

  • What makes a world coherent above the strate level? (depth-driven rules? tag adjacency? an arc?)
  • What is a strate as a unit the composer picks — pool + tags + depth bands? Fixed count per world?
  • "Findable" ≠ "reachable". Reachable is a number; findable is placement (light, airflow, landmark, terrain funnelling you toward it). Whose job, and how expressed?
  • Where do the authored ranges live, and can they be context-dependent (this op's range depends on what else is in the stack)?

Hazards — do not forget

  • ⚠️ Box-verdict bounds under (c). T1.d / ClassifyTile bounds are proved today against hand-set params. If the seed invents params, every bound must hold across the whole authored range, not a value. Wrong ⇒ a tile wrongly proved uniform ⇒ no geometry, no collision, no error, player falls through the floor. The only silent failure mode in the system.
  • ⚠️ ClassifyTile proves anything below TerrainZ solid and skips meshing — it will silently delete 3D caves inside mountains unless guarded.
  • ⚠️ Validation must itself be deterministic across every machine that runs it — including a future headless Linux dedicated server, where float behaviour may not match the Windows client.

2026-08-17 — the FEEL: magical, not logical

Jahni corrected the direction. He does not want a geologically reasoned world. He wants it to feel magical — the game throwing countless worlds at the player, of any kind, any size, any peculiarity. Examples he gave: an alien-looking surface strate; a "dreamcore" strate — repetitive patterns, a strange sense of emptiness.

  • Adjacency rules: CONFIRMED (he agrees with those).
  • Depth-as-meaning: UNDECIDED. The old model was "deeper ⇒ weirder, stranger, spookier"; he is no longer sure that's right. Do not assume it.
  • ⚠️ My earlier pitch ("coherence makes the world readable; depth should mean heat/pressure/danger") was arguing for a different game. Dropped.

Reframe that survives his goal: coherence lives inside a strate, not across the stack. The strate is the unit of authorship — one complete, committed idea, thoroughly itself. Placement can be arbitrary; the strate still feels authored.

Ideas on the table (none decided):

  • Rarity instead of depth. Weird strates are rare, not deep — you could hit dreamcore at −200 m. Descent feels like drawing cards, which serves "countless worlds" better than a gradient.
  • Strangeness needs ordinary to be strange against. Guarantee a share of grounded strates so the weird ones land. A rule about the mix, not about depth.
  • Adjacency rules become PACING rules: no two alike in a row; a grounded strate sets up a weird one; special pairs (flooded over lava) earn a real transition.
  • Size and count are free variables — a 40 m crawlspace strate vs a 2 km cathedral. Cheap to vary, huge effect on feel. "Any size" was explicit in his description.
  • The unique boss strate implies a destination without a gradient. An end is enough; every step need not escalate.

Open question left hanging: does the world have a bottom the player knows about? "Boss strate" implies an end; "countless worlds" implies endless. Those pull in opposite directions.


2026-08-17 — what the GAME is (context that reshapes the above)

Fantasy exploration + combat RPG. Medieval-ish, progressing toward better / more modern infrastructure but staying inside fantasy. Side systems: housing and farming. Needs bosses, and fights that don't feel "blergh."

Consequences for the composer:

  • Progression needs difficulty to correlate with position — but not by killing the magic. Proposal: draw strates freely (rarity, any kind, any size), then SORT the drawn set by their own danger rating. Identity stays random; difficulty comes out ordered by construction. Depth then means danger without ever meaning weirdness.
  • ⚠️ Housing is the real lock on the density field — harder than F4 save/load. A house has a location in a world that must keep existing. Once players build, the generator's output for that seed is frozen forever. Everything field-changing must land before housing ships.
  • Farming/housing need buildable space: flat-ish, stable, safe, reachable, probably surface. A composer that only makes dramatic terrain has nowhere to put a farm. Likely: strate 0 stays the grounded home base.
  • F8 (ore veins) is promoted from reward-loop polish to BACKBONE. "Progression to better infrastructure" is a tech tree, and a tech tree needs a supply chain. Ore quality should ride the same danger ordering.
  • Fights need fightable space. Default caves are hostile to good combat — cramped, no sightlines, bad camera. Good fights want verticality, cover, chokepoints, room to retreat. ⇒ the composer must treat arenas as a first-class output, not hope one occurs. This is exactly why boss strates are handmade.

Next open question: is the home base fixed on the surface with the descent run as expeditions (go down, come back up — cf. F14 lift/teleport anchors), or is it a one-way descent? Decides whether strates are re-entered or passed through once, and shapes the entrance/exit law.


2026-08-17 — the world is a PUBLIC SHARED ARTIFACT (the biggest constraint yet)

  • Home = a hand-authored city, above ground, with a big opening inside (the descent hub). Not generated. Ties to the primordial law: the city opening is the hand-placed entrance to strate 1.
  • Natural buildable space where the world offers it; otherwise terrain-editing tools for players. Underground building: undecided, idea is alive.
  • Strates are revisitable and permanent to the player's view — "fetch fish at the crystalline lake in strate X" must be a valid quest. Places are discovered, and discoveries get shared online.
  • Players share BUILDS across worlds. Everyone's world is the same world, so a bridge one player builds can propagate to other players' worlds if it's liked. Community feeling of exploration. Jahni: "it all fails without players." Landmark names may propagate the same way.
  • Landmarks need names — from a word pool or similar.

What this forces

  • ⚠️ Version stability is now a REAL requirement, and I was too casual about it earlier. A gen-version byte migrates a save file. It cannot migrate a community's shared knowledge. Once wikis, quests, videos and shared builds cite "the crystalline lake at (X,Y,Z)", the density field is frozen globally and permanently, not per-save. ⇒ The composer must be finished before the world becomes public. (This does NOT revive bit-identity to the OLD system — matching a dead build was always pointless. It sharpens when the future freeze lands.)
  • The diff layer is already the correct transport for shared builds: position + compact modification records, deterministic to apply, "replicate diff events, never geometry". A shared build is a diff patch with an address.
  • ⭐ The composer must emit a WORLD MANIFEST, not just a density field. A list of everything notable it placed — stable ID, type, position, extent, strate. Otherwise nothing can name the crystalline lake, no quest can reference it, no map can mark it, no wiki can cite it, no fast travel can target it. The composer already knows what it placed; it just has to write it down instead of discarding it. Cheap now, enormously expensive to retrofit.
  • Naming = two layers. (1) A deterministic procedural name from a word pool, so every landmark has the same name for every player before anyone visits it — that is the substrate that makes quests and wikis possible at all. (2) An optional community name that propagates like builds and overrides the default. Beloved names win; nothing is ever nameless.
  • Shared-build hazards to design in, not bolt on: two builds claiming the same place; a build that seals an entrance/exit and violates the primordial law; and content moderation — auto-propagating user-built voxel content into strangers' worlds needs a report/reject/rollback path, and shared builds must be individually removable client-side.

Open fork: does a shared build travel as raw terrain edits (voxel diff) or as placed structure pieces (a prefab/building system)? Completely different to transmit, validate and moderate.


2026-08-17 — shared builds: BLUEPRINTS, not terrain diffs (fork resolved)

Decided: shared builds are defined blueprint structures (a parent/children blueprint family made for construction), not raw terrain edits. Raw voxel edits are too hard to constrain.

Vote system (Jahni's): votes drive a priority list. Unvoted / negatively voted ⇒ back of the queue. Sufficiently negative ⇒ invalidated for sharing, never pulled again. Where two builds compete for the same zone, higher votes ⇒ better chance to appear.

Why blueprints are the right call beyond moderation

  • Payload is tiny: blueprint class ID + transform + variation params. Bytes, not a voxel diff.
  • Validatable without simulating voxels — bounds are known, so "does it seal a passage / violate the primordial law" is a cheap check.
  • ⭐ It survives content updates. Change the blueprint asset and every placed instance updates. A baked voxel diff can never be improved after the fact.

Open design issues on the vote loop

  • ⚠️ Cold start / rich-get-richer. A build must be seen to be voted on; if appearance is ranked by votes, new builds never appear ⇒ never get votes. Reserve a fraction of appearances for new/unvoted builds (explore vs exploit).
  • Rank by confidence, not raw count — otherwise an old build with 1000 votes permanently outranks a better new one with 10. Some time decay too, or the top calcifies and the world stops changing.
  • "Never pulled again" is a hard delete — needs volume thresholds, not just ratio, so a small group can't bury a build. Keep it soft/reversible server-side even if permanent to clients.
  • Blueprint construction shrinks the crude-content surface but does not remove it (pieces can still be arranged). Report + rollback path still required.

⭐ Proposal: build SLOTS, not free coordinates

The composer marks candidate build sites in the world manifest (type, extent, strate — a bridge site across a chasm, a shrine site at a passage mouth, a camp site on a ledge). Shared builds then compete for slots, not arbitrary positions. Placement becomes valid by construction, "the zone" gets a concrete definition, and conflict resolution is just "who wins this slot."

⚠️ Tension to resolve: canon vs roll

Earlier: the world is the same for everyone, so a wiki can cite it. But vote-weighted "more chances to appear" implies each player rolls which builds they get. Both can't be fully true. Proposed split: terrain and landmarks are canon (identical for all); shared builds are a roll. The wiki cites natural features; builds are the variable garnish. Also: pin a build once a player has seen it — the world may gain builds over time, but shouldn't silently lose one you've come to know (or built your house next to). Player claims beat shared builds — a shared build must never roll into player-owned ground.


2026-08-17 — SEASONS: worlds are wiped (this dissolves the freeze problem)

Decided:

  • The base generation — everything defined at generation time — is the shared world, identical for everyone. Shared builds are a LAYER ON TOP that adds to it. (Confirms the canon/roll split.)
  • New and unvoted builds must be rolled in deliberately, to give new players and new builds a chance. Confirmed.
  • ⭐ A world is STATIC once published, until it is WIPED — perhaps every 6–12 months — to make room for generation changes and other evolution.

What seasons change (important — supersedes my earlier warning)

  • ⚠️ I said two messages ago that once the world goes public the density field is frozen globally and permanently, so the composer had to be finished first. With wipes that is false, and it's the best news in this conversation. Generation is frozen only within a season. Every wipe is a free window to change noise, ops, bounds, archetypes, anything.
  • ⇒ The composer can ship imperfect and improve every cycle. No need to get it right before contact with players. Bit-identity anxiety is now dead permanently — worlds are expected to differ by version, by design.
  • ⇒ A world = seed + generator version + publish date. Stamp the generator version into the published world; that stamp is the whole of "version stability" now.
  • ⇒ Concrete unblock: T2.a (SIMD noise) and anything else that changes generator output was parked in fable-idea.md because it shifts seeds. At a wipe boundary that cost is zero. Same for the large-seed noise-collapse fix in AUDIT-2026-07.md.

⭐ Proposal: the BLUEPRINT LIBRARY is what survives a wipe

Your house dies with the world; your design doesn't. If shared builds are blueprint structures, the corpus of player creations can persist across seasons — so the vote/priority pool grows richer every cycle instead of resetting, and returning players carry something forward into a fresh world. That makes the wipe survivable for the housing/farming players, who otherwise lose the most.

Knowledge dying at the wipe is a FEATURE. Re-discovery is the loop; a wiped world resets the "everything is already solved and on the wiki" state that eventually kills exploration games. The community re-explores together, which is the exact feeling Jahni is after. The hand-authored city stays constant across seasons — the anchor of familiarity.

Open

  • What else survives a wipe? Account progression / unlocks / recipes / reputation / cosmetics? Nothing? (Pure reset is brutal on housing + farming players.)
  • One world at a time globally, or several shards on different seeds?
  • Does singleplayer/offline get a permanent world, or do wipes apply there too? (Many seasonal games run a permanent realm alongside the seasonal one.)

2026-08-17 — wipe scope, housing, and the vote pool

Decided:

  • The wipe is world-only. Everything else survives (account progression etc.).
  • The vote/build pool does NOT survive a seed change — nothing would be placed correctly. It is wiped, with rewards for the top builders (titles etc.), tiered by population (10/50/100/1000).
  • Housing → "instanced worlds": custom personal worlds that are never wiped. Jahni finds this slightly sad — it cuts the player out of the strates and the shared world. Underground building still undecided.
  • Everyone shares one seed, until the game is big enough to offer "reboots" (shards).
  • Singleplayer was never the intent (online-first), but may become an option.

Refinement: placement dies, DESIGN needn't

A blueprint build has two separable parts: where it sits (chasm-specific, absolutely world-bound — Jahni is right that this cannot survive) and the design itself (pieces in relative arrangement, placement-independent). So:

  • Shared/competitive pool: WIPED. And the strongest argument isn't placement — placement could be re-matched to new slots by fit. It's fairness: carrying the corpus forward means season 2 opens already full of season 1's voted builds, and every new player competes against an entrenched corpus forever. A fresh pool gives each season a fresh creative economy.
  • Personal library: KEPT (private). A player keeps their own designs, so they can rebuild a beloved house in the new world and re-submit it to the new pool. The loss is the location, not the work — that is what makes a wipe emotionally survivable.
  • Titles carrying across is what lets reputation survive when the builds don't — a season ending rather than a deletion. Optional knob: a small roll-boost for proven builders, which also softens the cold-start problem (watch that it doesn't recreate rich-get-richer).

⭐ The "slightly sad" instanced world may not be necessary

The hand-authored city is already wipe-proof — it isn't generated, so a generation change can't invalidate it. Put persistent housing there (a district / plots / interiors, city-adjacent authored farmland) and it survives every wipe with no instancing at all, keeping players inside the shared world and visible to each other at the social hub. Instancing then shrinks to the standard, small MMO problem of interiors/plots rather than whole private worlds.

⚠️ HAZARD — a never-wiped generated instanced world reintroduces the freeze problem

If a personal world is generated by generator v3 and is never wiped, then v3 must be kept alive forever — every old code path, every old bound, pinned per world — or that player's world breaks. That is the "support every version forever" trap, in a side corner, undoing exactly what seasons just bought. Avoid by making persistent personal space non-generated (authored plot / city district), or by regenerating it each season and re-placing the blueprints (possible precisely because blueprint builds are placement-independent).


2026-08-17 — housing: bake the plot (and why a MESH is the wrong bake)

Constraints from Jahni:

  • The social hub is later — infrastructure + difficulty. Not now.
  • ⚠️ The surface is very limited, on purpose — story-wise it is why players descend for space and resources. ⇒ housing everyone on the surface does not scale, so the "put housing in the hand-authored city" idea above does not hold as the general answer.
  • His proposal: bake the player's generated instance into a mesh, so the plot no longer depends on the generation system. Players can switch or destroy their house anytime; otherwise it's safe.

That solves the version-pinning hazard properly — a baked region needs no generator, so no old generator has to be kept alive. Right instinct.

⭐ Refinement: snapshot the FIELD, not the mesh

Bake the sampled density + material IDs for the bounded plot region, not triangles:

  • A mesh can't be dug. Housing/farming ship alongside player terrain-editing tools; a baked mesh kills that inside the one place players care most about.
  • A mesh freezes the plot against every future mesher/material improvement (Transvoxel, normals, surface-class polygroups, F6 masks). That just moves the museum problem from the generator to the mesher. A field snapshot re-meshes with whatever the current mesher is.
  • Density fields compress very well — most of a plot is uniformly solid or uniformly air.
  • ⚠️ The plot must be BOUNDED or storage scales with ambition.

Architecturally this is: a per-region override source in the generation path — "this region has a stored field, read it instead of evaluating the op stack."

⭐ Same mechanism ships hand-authored content

A hand-made boss strate or a distributed handmade level is a stored field region. The override source Jahni needs for houses is the same one he needs for authored levels/stamps. One feature, two uses — build it once.

On the wipe, for a plot

Simplest split: the house travels, the ground doesn't. Blueprints are placement-independent, so they re-place in the new world; the terrain regenerates. Avoids having to blend a baked plot into fresh generated terrain (seams at the plot edge) — which would otherwise need a reserved "homestead slot" plus a blend skirt. Keep that harder option in reserve, don't build it first.


2026-08-17 — housing: SETTLED

  • Personal housing = an instanced level, not a place in the shared world. Their own tiny world; never wiped, never re-placed.
  • ⭐ The plot's ground is a snapshot of land the player CHOSE in the shared world and claimed. Their home is from somewhere. After a wipe it is the last surviving fragment of a world that no longer exists — the wipe becomes meaningful rather than lossy, and the descent gains a second motive beyond resources: finding somewhere worth living.
  • One template level, populated from save data — a stored field region + a list of blueprint transforms. Not one .umap per player (cooked assets can't be made at runtime).
  • Invites needed — houses can be shared/visited.
  • Time-based growth computed from elapsed real time on entry, not ticked (the instance isn't loaded while the player is away).

⇒ Concrete plugin work implied: a stored-field source for the voxel world (read a saved region instead of evaluating the op stack) + its save format. Same feature ships hand-authored levels / boss strates. Bounded region size is the one thing to fix early.


STILL AWAITING JAHNI'S RULING (my proposals — do NOT treat as decided)

  1. World manifest — the composer emits a list of everything notable it placed (stable ID, type, position, extent, strate). Needed for landmark names, quest references, maps, fast travel, and build slots. Biggest architectural consequence of anything proposed here.
  2. Danger rating + sort — draw strates freely (any kind, any size, any rarity), then order the drawn set by their own danger rating, so depth means difficulty without ever meaning weirdness.
  3. The mix rule — guarantee a share of grounded/plausible strates so the strange ones land. Strangeness needs ordinary to be strange against.
  4. Build slots — the composer marks candidate build sites; shared builds compete for slots rather than free coordinates.

2026-08-17 — RULINGS from Jahni on the four proposals

1. World manifest — ✅ ACCEPTED, "must not be expensive"

Make it free by inverting it: the manifest is not an export, it is the PLAN. The composer's layout pass runs first — pick strates, place connections, place landmarks/rooms/ arenas — and that decision list is the manifest. The density field is generated from it. So it is never derived by scanning terrain (which is what would be expensive and unreliable).

  • Only explicitly placed decisions go in — landmarks, rooms/POIs, lakes, arenas, entrances/exits, build sites. Not emergent terrain features (every rock, every ledge).
  • Rough size: ~8 strates × 50–200 entries × ~32–64 B ⇒ ~100 KB per world. Computed once, identical for every player.
  • Names are computed, not stored: hash(entryID, seed) → word pool. Zero storage.
  • Must be computable without generating terrain — it is upstream of the field, not downstream.

2. Danger rating — ✅ ACCEPTED. Drives mobs, environmental hazards, and loot.

Refinements proposed:

  • Danger is a RANGE per strate archetype, rolled per world ⇒ one dreamcore asset yields a gentle dreamcore and a terrifying one. Multiplies variety with no extra authoring, and serves "two seeds differ in everything."
  • A strate asset therefore specifies its theme/identity, not its inhabitants; mob/hazard/loot pools are selected by danger × theme tags. Strates become reusable across the whole curve.
  • Ore quality rides the danger tier ⇒ F8's supply chain and the difficulty curve are one axis.
  • ⚠️ Sort with jitter, not strictly. Perfectly monotonic escalation reads flat; an occasional easier strate after a hard one gives relief and pacing.

3. The mix rule — ✅ ACCEPTED, sharpened by Jahni:

dreamcore should be QUITE RARE, so players are puzzled when they find it "because it doesn't have its place there." ⇒ The effect is not-belonging, which is stronger than rarity alone:

  • Anomalous strates must NOT be blended in. Normal neighbours get a coherent transition; an anomaly gets a hard cut — the wrongness lives in the seam. The adjacency system needs a flag for "this strate deliberately does not reconcile with its neighbours."
  • Rare enough that a player may go a whole season without seeing one ⇒ in a single shared world, an anomaly becomes community news ("there's a dreamcore strate at −1400 this season"). Rarity plus one shared seed turns it into an event.

4. Build slots — ⚠️ "not bad but needs refining". Refinement:

  • Slots do not restrict building. Players build anywhere valid. A slot is the qualification for auto-propagation: build in a slot and your build is eligible to spread to everyone; build freely and it is still yours, still visitable, still shareable by invite — just not auto-distributed. Resolves freedom vs safe validation without taking anything away.
  • Slots are DERIVED from the manifest, not separately authored — a chasm entry implies a crossing, a passage mouth implies a marker/shrine, a ledge implies a camp. No new authoring burden.
  • A slot = position + shape constraint (span, clearance, orientation) so blueprint fit is a mechanical check, which is what makes propagation safe.

2026-08-17 — danger: Z-MULTIPLIER, not a sort (Jahni's model — adopted, it beats mine)

Decided: no sorting pass. Danger = a function of depth (Z) × the strate's own multiplier, with a rare chance of a less-difficult strate appearing deep.

Why it's better than my sort:

  • Local, not global. Danger is computed per strate from its Z — no whole-world ordering pass, and a strate's danger is knowable without knowing the rest of the world's strate list.
  • Fully decouples identity from placement. Any strate can appear at any depth; depth supplies the danger. That serves "any world, any kind, anywhere" better than sorting ever could — sorting implicitly binds a strate's identity to a position in the curve.
  • The rare exception is a designed feature, not the fudge-factor jitter I proposed.
  • ⭐ It makes danger ANOMALIES possible in both directions, which sorting structurally cannot:
    • Respite strate — unexpectedly calm, deep. Don't leave it as "lower numbers": make it a designed type. Quiet, visibly calmer, fewer mobs — a sanctuary. Natural home for a safe camp, a merchant, a landmark, a breather in the descent.
    • Danger spike near the surface — the "something is very wrong here" beat. Players find it early, die, and come back for it later. Pairs perfectly with the anomaly/dreamcore concept (out of place in difficulty, not only in look), and in one shared world it becomes season-wide news.

Caveats to build in:

  • ⚠️ Clamp the multiplier range so the depth term dominates on average, or the curve stops being reliable and progression breaks. Rare exceptions are a feature; a noisy curve is a bug.
  • ⚠️ The exception must be LEGIBLE. Unsignalled difficulty variance reads as bad tuning, not design. Each anomaly needs a tell.
  • ⚠️ Danger must be readable at a strate's ENTRANCE, before the player commits. A surprise easy strate is a gift; a surprise deadly one without warning is just an unfair death. Give the entrance a broadcast — visual/audio/NPC warning/UI readout fed from the manifest. Warned-and-ignored is memorable; unwarned is unfair.
  • Danger becomes a manifest property of each strate, so quests, UI and loot tables all read it from one place.
  • The mix rule (grounded vs anomalous) is independent of this and still stands.

2026-08-17 — WHAT THE CODE ACTUALLY SAYS (read pass, no changes made)

⭐ The composer already exists in embryo: UVoxelStrateManager::Initialize

Private/VoxelStrateManager.cpp:29, roughly 100 lines. It already does the job's skeleton:

  1. loads Settings->StratePool (soft ptrs) and Fisher-Yates shuffles it with FRandomStream(WorldSeed);
  2. walks TotalStrates slots, taking Settings->FixedStrates[i] where pinned, else cycling the shuffled pool (ShuffledPool[PoolCursor % Num]);
  3. computes each slot's Z range from Definition->StrateHeightInChunks, leaving InterStrateGapChunks of bedrock between;
  4. calls GeneratePassages — deterministic passages between consecutive strates.

This runs BEFORE any terrain and its result (StrateLayout) is what the density field is derived from. That is exactly the "manifest is the plan, not an export" architecture — it already exists. The composer is an expansion of this function, not a new system.

⭐ The manifest can cost ZERO storage — it needs to be ENUMERABLE, not stored

FStrateLandmark placement (VoxelContentManager.cpp:1263 UpdateLandmarks) is hash-lattice: cell = SpacingChunks chunks, position = lattice point + hash jitter (VoxelHash::Mix(H ^ ...)), plus a PassageMouth anchor mode that enumerates the finite passage list. The file's own comment: "cost scales with the NUMBER of landmarks in range, not the area." ⇒ "what notable things are in this region?" is already a pure deterministic function, answerable without generating terrain and without streaming. So the manifest is an index computed on demand, not a baked table. That fully answers Jahni's "it must not be expensive."

✅ Already exists — do NOT redesign these

  • EVoxelStrateTransition::Hard (per strate, on its lower boundary) is the "anomaly must not blend" mechanism. Already authored per strate. Gradient / Hard / Interleaved.
  • Height already varies 1–256 chunks (~8 m to ~2 km). "Any size" is supported today.
  • GameplayTags on UVoxelStrateDefinition — the tag vocabulary for adjacency rules and mob/hazard/loot selection is already there, and the module already depends on GameplayTags.
  • UVoxelTerrainOpDefinition — ops ARE already data assets (12 types: Terrace, LayerLines, Ribbing, Cliff, Scallop, Overhang, Arch, Column, Pit, Chimney, Dome, Pinch), referenced from the strate's TerrainOperations, merged by BuildParamsFromDefinition.
  • Landmarks already carry AnchorMode, SpacingChunks, JitterFraction, SpawnProbability, ExclusionRadiusChunks, Priority — F7's placement machinery, built. This is the seed of build slots: slots are landmarks of a "build site" kind.

❌ Genuinely missing for the composer

  • No rarity. The pool is a flat TArray shuffled uniformly. Dreamcore-should-be-rare needs a weighted entry ({Def, Weight, Tags, allowed depth band…}), not a bare array.
  • Pool CYCLES (PoolCursor % Num) when TotalStrates > pool size ⇒ repeats in a fixed order. "Two seeds differ in everything" needs a weighted draw instead.
  • No danger concept anywhere in the strate definition or settings. Needs the Z-multiplier model.
  • No adjacency rules — nothing prevents two alike in a row, nothing expresses "sets up" pairs.
  • ⭐ The op COMPOSITION is hardcoded C++: BuildTunnelNetworkStack / BuildMazeStack / BuildSurfaceStack … one builder per archetype, in VoxelDensityOpStack.cpp (252 KB). The ops are composable; the composition is not data. This is exactly the Phase 3 gap — the machine was built and never fed. Confirmed against the code, not inferred.

⚠️ Constraints discovered

  • Layout = f(seed, pool CONTENTS, pool ORDER). FRandomStream + Fisher-Yates over Settings->StratePool means adding or reordering one strate in the pool changes every world. ⇒ new strate types can only land at a wipe. Consistent with the season model, but it must be stated: mid-season content additions cannot touch the pool.
  • ⚠️ FStrateGenerationParams is a giant flat param bag with an X-macro (VF_STRATE_PARAM_FIELDS) driving its Lerp blend. Ambition level (c) wants authored ranges per parameter, and there is no natural home for a per-field range in a flat struct of that size. This is the main engineering obstacle to (c) and the next thing worth designing.

2026-08-17 — the pool entry, and DERIVING distribution instead of authoring it

Jahni's objection to the pool-entry proposal (weight / max / min per entry): that is still hand-authoring the world's composition. He wants the game to produce its own worlds. Real distinction: he authors the vocabulary; he does not want to author the distribution.

⭐ The unifying move: MEASURE each assembled strate, don't declare its numbers

Reuse the coarse validation pass already required for garbage detection (low-res sample of the strate, once at world creation: air fraction, walkable surface, feature size, connectivity). It produces numbers about the place — use them for everything, not just yes/no. One pass, three uses.

Was going to be authored Derived instead
Weight (rarity) Outlier-ness: distance from the pool's centroid in measurement space. Dreamcore is rare because it is unlike everything else. Self-correcting — author five dreamcore-ish strates and they stop being outliers, which is the right answer.
Danger multiplier Measured: verticality (fall distance), openness (sightlines / room to retreat), traversal difficulty (climb/swim share), darkness. Discovered from what the strate generates.
Max per world Weight decay on draw — an entry's weight drops sharply each time it's picked. Rare things don't repeat; common things recur without dominating. No per-entry number.
Min per world (the mix rule) One GLOBAL dial: "a world's total strangeness may not exceed X." One knob for the whole game instead of one per strate.
Some descriptive tags Measurable too — flooded = water volume, vertical = aspect ratio, open = mean free space.

Honest limits (stated to Jahni)

  • Intent can never be derived — which strate is the boss's, which is fixed at the top. Authored, always, and rightly.
  • A measurement can be wrong about how a place FEELS (measures ordinary, plays unsettling). ⇒ derived by default, with an optional per-entry override that is normally empty. The escape hatch exists without being an obligation on every strate.

⇒ Jahni's remaining authoring job: make strates, and turn two or three global dials.

Through-line worth noting: this is the same answer as the AI-judge discussion — measure, don't declare — and it reuses the same pass. The design is cohering on one mechanism.

Still on the table from the earlier proposal: adjacency rules as a small tag-rule list in settings (no two alike adjacent / Anomaly needs a Grounded neighbour above / max run length), the draw must never fail (fallback entry), and making the draw order-independent — hash(seed, slotIndex, attempt) over a pool sorted by a stable key, so reordering the asset in the editor stops changing every world.


2026-08-17 — ⛔ CORRECTION: Jahni does NOT want to author strates either

The line above — "Jahni's remaining authoring job: make strates, and turn two or three global dials" — is WRONG. His words: "I'm not pretty happy to make strates forever, that's actually the opposite. If I could never make any new strate myself and have it do it itself would be genius."

⇒ The system must INVENT strates, not arrange authored ones. I had the composer one level too shallow for this entire conversation. Re-derive from here.

What that means architecturally

  • A strate stops being an asset and becomes generated data. UVoxelStrateDefinition survives as a struct (the generator needs its fields) but nobody fills it in the editor — the composer fills it: draws operators, rolls parameters, assigns materials/content, and hands the generator a strate that has never existed before and won't exist after the wipe.
  • The strate pool / weights / min / max design above is therefore obsolete as stated. Rarity, danger and mix must be properties of invented strates, measured after assembly (the measurement idea survives the correction — it is more necessary now, not less).

⭐ The grammar for inventing a stack ALREADY EXISTS in code

EVoxelOpRole (in Public/VoxelDensityOp.h): FieldSource (what the field IS) · Combiner (how fields merge) · DetailModifier · StructuralPost (spine → seal → passage, appended automatically, never author-omittable). A valid stack already has a defined shape: one source, some modifiers, structural post last. "Invent a strate" = draw a source, draw modifiers, roll parameters, in an order the roles already constrain. The constraint system is sitting there unused.

Where the hard part moved

  • Coherence was free when a human authored the strate. It is not free now. A maze op + an overhang op + a flooded op at incompatible scales = mush. This is the garbage problem at full strength, and it is why the AI-judge idea makes much more sense in this light — it was never about judging hand-made content, it is about judging invented content, in a space too large to eyeball.
  • Dressing must be coherent too — palette, mood, decorations, creatures, audio. Drawn independently you get crystal formations in a lava flow. ⇒ the composer draws a theme first, then pulls operators, materials, decorations, creatures and audio carrying that theme's tags.
  • ⚠️ The RANGE problem is no longer "at some point" — it is the centre of the design. The ranges are the space the system invents inside.

Open question put to Jahni

Where is the floor of authoring? Proposed: the raw content — operators, meshes, materials, sounds, creatures — plus their tags. Those are the atoms; everything above (strates, worlds, layout, danger, rarity) is composed and measured. Every operator added then multiplies with every other one instead of adding one more place. Or does he want the system to invent operators too?


2026-08-17 — floor CONFIRMED; op invention parked

Floor of authoring = raw content + tags. Operators, meshes, materials, sounds, creatures, music — tagged. Jahni accepts this ("I'd need to be thorough and tag every enemy, music and whatnot"). Nothing above that (strates, worlds, layout, danger, rarity) is authored.

Inventing operators — parked, but not impossible

  • ❌ New KINDS of operator cannot be invented ("warp the domain by noise", "carve capsules along a spline"). Those are ideas expressed as code ⇒ program synthesis. Bad bet, not where the value is.
  • ✅ Discovering good COMBINATIONS and promoting them into named reusable units is real and buildable: a sub-stack that measures well becomes one building block. From the composer's view that is a new operator. Compounds across seasons — season 1's discoveries are season 2's vocabulary.
  • ⚠️ Do not chase it early. ~20 ops with rolled parameters already spans a space vastly larger than a hundred seasons could explore. The scarce resource is judgment, not vocabulary — an hour on measurement/validation/the model beats an hour widening a space we use a rounding error of.

Why the tagging burden is smaller than it sounds

  • Per-ASSET, not per-place. Tag a bat once ⇒ every world, every season, forever. Cost scales with content, not with number of places. This is the actual payoff of inventing strates rather than authoring them.
  • GameplayTags are hierarchical and already a plugin dependency — Theme.Volcanic reaches every volcanic context with no enumeration.
  • Some coherence needs no tags: palette can be sampled from a material's dominant colour and clustered. A decoration whose colours sit in the strate's family fits, unstated.
  • Lazy: untagged content is simply never drawn. Ship with 20 enemies and 3 tracks; add more whenever. Nothing breaks, the pool just gets richer.

NEXT: the range problem (now central, not a footnote).


2026-08-17 — THE RANGE PROBLEM (designed; verified against the code)

Verified facts (not remembered — checked)

  • FStrateGenerationParams has 73 scalar fields (+1 bool). Not hundreds — tractable.
  • ✅ The X-macro is IN SYNC. VF_STRATE_PARAM_FIELDS covers 75 entries; the only struct scalar missing from it is Alpha, which is the blend weight and is correctly excluded. CODEMAP's warned trap (add a field, forget the macro, blends silently reset it to default) has not bitten. ⇒ FStrateGenerationParams::Lerp already blends the whole parameter set, and is already load-bearing at strate boundaries. Add a test asserting macro ≡ struct so this stays true.
  • VoxelStrateTypes.h: 135 ClampMin, 52 ClampMax across 216 UPROPERTYs. Most fields have no upper bound. Paired min/max fields exist (MinRoomRadius/MaxRoomRadius, TunnelMin/MaxRadius, RoomFloorCutMin/Max) and some fields carry relational EditConditions.

Why rolling parameters fails (the reason to state plainly)

The coherent region of a 73-dimensional space is a vanishingly thin sheet; uniform sampling in a box never lands on it. The problem is not wrong ranges — it is that independent rolling destroys the CORRELATIONS that make a parameter set coherent (room spacing ↔ room radius ↔ tunnel length ↔ strate height). This is very likely what Jahni was sensing when he reached for an AI judge.

⭐ The design: don't roll parameters — BLEND KNOWN-GOOD ONES

  1. Corpus = known-good parameter vectors. Seeded by Jahni's existing hand-authored strate assets.
  2. Roll = pick 2–3 parents (weighted), blend with random weights, then jitter.
  3. Reuse FStrateGenerationParams::Lerp — it already does exactly this, over exactly this field set, and the world working already tests it. Build nothing.
  4. Constraint satisfaction is FREE: a convex combination preserves every relation that holds in both parents (Min ≤ Max stays true). Correlations survive because they were never broken.
  5. ⭐ Ranges come from the CORPUS SPREAD — per field, how much it varies across existing strates — not from authored numbers and not from the clamps. Clamps are "don't type nonsense" limits, not "this makes a good world" limits. Measure, don't declare, again.
  6. Clamps = hard safety net only. Never the roll range.

Escaping the convex hull

Blending alone only reaches between existing points. Escapes: jitter slightly past the corpus; deliberate extrapolation past a parent away from the centroid (riskier ⇒ validate harder); and ⭐ PROMOTION — every invented strate that measures well and survives players joins the corpus. Season 1 blends ~6 strates; season 5 blends 200 discovered ones. The system's imagination grows from its own history, and the game gets stranger as it ages. (Third appearance of this mechanism today: discovered ops, discovered strates, discovered parameter regions. It is the spine of the design.)

⚠️ Honest caveats

  • UPROPERTY metadata is editor-only — ClampMin/ClampMax do not exist in a packaged build. ⇒ bake them at cook time via a small editor commandlet walking the struct by reflection. Small, real, one-time work.
  • Clamp coverage is partial (52 of ~73 have no max). The net has holes; don't lean on it.
  • A few fields are not tunables — StrateTopWorldZ / StrateBottomWorldZ are runtime Z bounds. Needs an explicit exclusion list for rolling.
  • Bools can't be blended — roll feature toggles by probability, or inherit from the dominant parent.
  • ⚠️ The corpus is small today (~6 strates), so blending alone will not feel like "countless worlds" in season 1. ⇒ early variety must come from STRUCTURE, not parameters — which operators are in the stack at all. 20 ops choose 5 is already thousands of distinct stacks. Rule: vary structure aggressively, vary parameters conservatively — shift the ratio as the corpus grows.

2026-08-17 — theme coherence narrowed; findability first step

  • Thematic mismatch is mostly FINE — Jahni: a lava flow could have crystal formations, it was a bad example. ⇒ my "coherent dressing" worry was overstated. The real garbage is GEOMETRIC: operators at incompatible scales producing mush. Smaller and more mechanical than feared.
  • ⭐ Multiple fitting tags per asset is the mechanism, not a compromise. One tag per thing = rigid buckets. Several tags = a graph with overlaps, and the overlaps are where the system finds combinations Jahni didn't plan that still hang together — which is the "magical" effect he wants. He describes assets; themes emerge from co-occurrence rather than being assigned.
  • Jahni's expected first big job: create themes and tag content with multiple fitting tags.
  • Findability, first step: a subtle beacon glow, initially for debugging. Note it is not throwaway — the debug beacon is the real solution in programmer art. The placement logic is identical; only delivery changes later (light spilling from the passage, a draft, a shift in ambience). Build the ugly version; ship a reskin.

2026-08-17 — the MEASUREMENT PASS (and how "good" ever gets judged)

⭐ The reframe that sets the budget: the composer runs ONCE PER SEASON, OFFLINE

Everyone shares one seed per season ⇒ there is exactly one world per season, ever ⇒ the composer never runs on a player's machine and never runs at load. It runs once, on Jahni's box or a build machine. The problem is not "fast enough for a loading screen", it is "runs overnight." So it can:

  • generate a thousand candidate strates, measure them all, keep the best eight;
  • validate at any resolution it likes;
  • later run a model over the candidates at zero runtime cost to anyone;
  • ⭐ let Jahni review the world before publishing the season. The system does the work; he keeps a veto. Costs nothing because it is all offline anyway.

What ships is small: the season's seed + the chosen strates' parameter vectors. Clients generate terrain from those exactly as today. No runtime composition anywhere.

The pass itself: ONE coarse grid + ONE flood fill → one feature vector → three jobs

Sample the candidate into a coarse voxel grid (a few boxes at hash-chosen XY within its Z band), flood fill the air once, derive everything from that grid. A 4–8× downsample preserves all of it.

Validation (is it garbage?): air fraction · largest connected component share (low = swiss cheese: sealed pockets nobody reaches = generation paid for and never seen) · walkable surface (air above, solid below, survivable slope) · feature scale (median distance-transform of the air — catches "noise fog", structures smaller than a few voxels read as static not rock) · vertical clearance · entrance→exit reachability (the primordial law, as a number).

Danger (same grid, different questions): fall exposure (walkable surface with a long drop beside it) · openness (mean distance to solid from walkable positions — sightlines and room to retreat, which is most of what makes a fight good or "blergh") · traversal mix (walk/climb/swim) · tortuosity (path length ÷ straight-line — maze-likeness).

Rarity: nothing new — the vector of all the above, distance from the corpus centroid.

⚠️ Coarse sampling can LIE about connectivity. A wall thinner than the sample spacing vanishes and two sealed spaces look joined ⇒ a strate could pass the primordial-law check while being impassable. The one metric where a false pass is dangerous. Fix: coarse to FIND the route, then re-verify that one path at full resolution. Cheap — only the corridor you found.

This is the same tool as F1 (fable-idea.md's top-pick 2D world-preview): the measurement pass with a visualisation on top. Build the measurement, get the preview nearly free — and it's needed anyway for reviewing a season before publishing.

Judging "good" — Jahni is right to doubt, but the judge is the CORPUS, not a model

Measurements catch broken, not boring. The gap is narrower than it looks because good never has to be defined — only collected:

  • Rate at the STRATE level, not the world level. Twenty candidates, thumbs up/down = twenty labels in minutes; a hundred in an evening. Approved ones join the corpus and become blend parents. This loop works with ZERO machine learning. A model only makes it faster, later.
  • Player behaviour in a live season — lingering, revisiting, rushing past. Free telemetry, but careful: time spent can mean fascinating or lost and furious.
  • ⭐ Where players choose to SNAPSHOT THEIR HOME. An unambiguous "I love this place", no UI, no prompt, ungameable. The strongest quality signal in the design, and it costs nothing.

⚠️ Known risk: convergence to a comfortable middle. Promote only what you already liked, keep blending near the corpus, and the system slowly stops surprising you. Same failure mode as the build-vote pool, same counter: keep extrapolating past the corpus, and keep some unrated weird candidates in circulation.


2026-08-17 — STACK ASSEMBLY: how the composer builds an op stack

What the three real builders actually look like (read from VoxelDensityOpStack.cpp)

TunnelNetwork (19)   rock source → room graph (SDF) → SdfCarve → 12 density modifiers → worm source → structural
Maze (7)             rock source → lattice corridors (SDF) → SdfRoughness (SDF) → SdfCarve → structural
FloatingIslands (7)  VOID source → island blobs (SDF) → SdfRoughness (SDF) → SdfFill → structural

⭐ 1. Most ordering is MECHANICAL, not aesthetic — derive it, don't author it

Roughness sits on the SDF before conversion in Maze, and on density after conversion in TunnelNetwork — CODEMAP confirms they are literally two different ops for that reason. An op's legal position is fixed by which channel it reads and which it writes. ⇒ Every operator declares its channel reads/writes. Dependencies then form a DAG and any topological sort of that DAG is a legal stack. No authored order, no judgement, and it generates orderings no human ever wrote down.

⭐ 2. Root polarity is a one-bit identity lever

FloatingIslands is the same op classes as Maze but rooted in a void source with a fill instead of a rock source with a carve — and you get islands instead of tunnels. One bit flips the entire character of a strate.

3. FFloorBiasMod — delete the problem instead of documenting it

FloorBias exists purely to undo what FCaveRoughnessMod did to floors. Both are density-space, so channel rules permit either order, but semantically one must follow the other. ⇒ An operator whose only purpose is to correct another operator is not a separate operator. FUSE them into one op with two internal phases. Removes the invalid state rather than annotating it, and leaves the rest genuinely free to shuffle. Fifteen ops that compose in any legal order beat eighteen with a footnote. (Fusing with identical order and math leaves the world bit-identical.)

4. One small declaration covers what's left

Each op is additive (small displacement, commutes freely with peers ⇒ shuffle at will) or transformative (clamps, multiplies, gates ⇒ position matters, needs explicit placement).

5. The structure roll

root polarity → shape source → conversion (follows from polarity) → draw k modifiers legal in the resulting channel space (k itself rolled) → structural post appended automatically. With ~5 shape sources and ~15 modifiers choosing 4–8, that is tens of thousands of structurally distinct stacks before a single parameter is touched — which is what carries early variety while the corpus is small.

⚠️ 6. THE BLOCKER — box verdicts are only correct in the stack they ship in

CODEMAP, on the lattice corridor source: "Its EffectOverBox answers for the source+carve pair (Phase 1 simplification) so it must be told the downstream ExtraReach." The op interface says the same in its own comment: a source that writes only Sdf doesn't touch density itself, so it answers on behalf of the converter that follows it.

That is fine when a human wrote the pair. It breaks the moment the composer assembles a combination nobody verified, and the failure is the silent one: a tile wrongly proved uniform ⇒ no geometry, no collision, no error, player falls through the floor.

⇒ Prerequisite before free composition is safe: every operator's EffectOverBox must be correct in ISOLATION, not correct-given-its-neighbours. That means propagating an SDF interval through the box query instead of letting the source answer for the pair — which the interface comment already names as the Phase 3 version of the contract. Not huge, but load-bearing, and it must land first.

✏️ Correction to yesterday's note

The X-macro / struct diff said "the only struct scalar missing from the macro is Alpha, which is the blend weight and correctly excluded." Alpha is not a field at all — it is the float Alpha parameter of FStrateGenerationParams::Lerp (line 1033), which the regex caught by accident. The macro and the struct are in PERFECT sync, zero exceptions. Now guarded by a test — see below.


2026-08-17 — the X-macro guard (built, green)

Source/VoxelForge/Private/Tests/VoxelForgeStrateParamCoverageTest.cpp → VoxelForge.Determinism.StrateParamBlendCoverage. Built clean first try (Jahni, 2026-08-17). Expands VF_STRATE_PARAM_FIELDS a third way (after LERP and SNAP) into a name list and diffs it against FStrateGenerationParams' UObject reflection. No fixture, no world — a shape test. GExemptFieldNames is empty: every reflected field is covered, and an exemption must be written down as a decision. Matters more under the composer, which invents parameter sets through that same Lerp — a missing field would be constant across every invented strate with nothing to notice it by. CODEMAP §3.12 row added.


2026-08-17 — ⚠️ THE PRIMORDIAL LAW HAS A REAL HOLE (verified in code)

What passages do today

UVoxelStrateManager::GeneratePassages places every inter-strate passage as: FRandomStream Rng(CachedSeed ^ 0x50A55A6E) → random angle around the (0,0) spine → random distance in the config range → random reach into each strate. Endpoints are (PX, PY, TopZ) and (PX, PY, BottomZ). Carving is a structural-post invariant (VF_ApplyPassageCarving), so the tube itself IS air by construction.

⚠️ The hole

Nothing consults the destination strate's actual cave layout. The tube is air, but whether its lower mouth joins the lower strate's connected space is pure luck. A player can descend a passage and arrive in a sealed bubble — legal geometry, air all the way, and nowhere to go. The primordial law is currently a hope, not a guarantee. It gets worse under invented strates, where nobody has eyeballed the layout.

Also: that FRandomStream walks sequentially across all strates, so changing an early strate's connection count shifts every later passage. Same order-dependence as the strate pool ⇒ use hash(seed, strateIndex, connIndex) instead.

⭐ Fix 1 — don't let the passage hope; make the strate OFFER a landing site

Add to the field-source contract something like SuggestOpenPoint(WorldX, WorldY) → optional Z. Every source already knows where its own air is:

source open point
FRoomGraphSource nearest room centre (rooms are hash-placed ⇒ cheap to find)
MakeSlabVoidSource anywhere in the void band
FIslandBlobSource just above an island top
FSurfaceColumnSource just above TerrainZ
MakeLatticeCorridorSource the nearest lattice node

Passage placement becomes: pick XY → ask the lower strate's source for an open Z near it → aim there. Deterministic, cheap, and it keeps working for invented strates because any new source must answer. Nice inversion: the strate offers the landing site instead of the passage gambling.

Fix 2 — verification as the net (reuses the measurement pass)

The measurement pass already flood-fills the air. So: does the upper mouth's air component reach the lower mouth's? If not, re-roll the passage (hash(..., attempt)). Coarse to find, full resolution to confirm the one corridor — as established for the connectivity metric.

Fix 3 — FINDABILITY, and most of it is data, not code

✅ ELandmarkAnchor::PassageMouth already exists — landmarks can anchor at passage mouths, and FStrateLandmark already carries a Light-Orb block. A glowing landmark at every passage mouth is authorable today, with no code at all.

But findable means being drawn there from a distance, not marked once you arrive. Three layers, cheapest first:

  • Light. A glow down a tunnel is the strongest pull in a cave. Already supported.
  • Sound. An emitter with a long attenuation radius at the mouth. Works around corners, which light does not — in a cave you hear the draft before you see the hole. (Ties to F9 audio.)
  • ⭐ Make the mouth a PLACE, not a hole. Fix 1 already lands the passage in a room; make that room distinctive — bigger, lit, decorated. Places are memorable, cracks in walls are not. This is the one that actually makes it findable on the second visit, which is what quests need.
  • Parked (strongest, most invasive): bias the cave network to converge toward the mouth, so simply following tunnels tends to lead there.

2026-08-17 — RULING + BUILD ORDER

Jahni's ruling: guaranteeing an open landing place is needed. And the passage mouth should be a real landmark — a special place, so it shows and is less dismissed. Not merely a lit marker. Also: "not all to be implemented in a row."

The sequencing principle

⭐ Every tier must be worth doing on its own, before the next one exists. Nothing gets built purely as machinery for a later tier. (This is the direct antidote to the 2026-07/08 refactor, where three weeks of correct work produced a world unchanged by a single voxel.)

Tier 0 — safety nets, true regardless of the composer

  • ✅ X-macro guard test — DONE, built green 2026-08-17.
  • Order-independent placement: replace the sequential FRandomStream in Initialize and GeneratePassages with hash(seed, slotIndex[, connIndex, attempt]). Standalone value: Jahni can reorder or tidy the strate pool asset without changing every world. Small, isolated.

Tier 1 — the primordial law (a BUG FIX, not composer work)

  • SuggestOpenPoint(X, Y) → optional Z on field sources; aim passages at it.
  • Passage mouth becomes a room + a distinctive landmark (per the ruling). Standalone value: fixes a live hole in the shipping game — today a player can descend into a sealed pocket. Worth doing even if the composer never happens, and it makes the current world better immediately.

Tier 2 — the measurement pass

Coarse sample + one flood fill + the feature vector (air fraction, largest component, walkable surface, feature scale, clearance, reachability, fall exposure, openness, traversal mix, tortuosity). Standalone value: it is F1, fable-idea.md's top-pick world-preview tool — Jahni can finally see what parameters do instead of tuning blind. It also verifies Tier 1 (does the mouth actually connect?).

Tier 3 — op-system prerequisites for free composition

  • Channel read/write declarations on every op ⇒ ordering derives from a DAG.
  • Fuse corrective ops (FFloorBiasMod into FCaveRoughnessMod) — an op that only repairs another op is not an op.
  • ⚠️ EffectOverBox correct in ISOLATION (SDF interval propagation instead of "the source answers for the pair"). This is the gate on free composition — without it, a novel stack can wrongly prove a tile uniform ⇒ no geometry, no collision, no error. Standalone value: the fuse and the isolation fix are both correctness improvements to the code that ships today.

Tier 4 — the composer proper

Structure roll (root polarity → shape source → k modifiers) · parameter roll (blend the corpus via Lerp) · reject-and-resample driven by Tier 2 · the offline season pipeline with Jahni's review and veto.

Tier 5 — the long game

Promotion (good strates rejoin the corpus) · theme/tag draws for materials, creatures, audio · eventually the model. All of it optional, all of it compounding.


2026-08-17 — WORLD SHAPE + TRAVERSAL (the two holes Codex found, now closed)

Codex read COMPOSER-NOTES.md cold, in isolation, and correctly identified the project, the goal (the corrected one — the system invents strates, Jahni supplies vocabulary), and the intended feel. It found all three marked reversals and no unmarked one. Two of its five "could not determine" items were real holes; Jahni closed them:

Decided

  • ⭐ The world has NO BOTTOM. Endless descent.
  • Boss strates are INTERMEDIARY — roughly every 5 strates. Bosses punctuate, they do not terminate.
  • Return trip, two ways: walk back up through the tunnels (that is content, not a chore), or once a strate has been visited it opens a passage onward, so transport (elevator/other) can carry you down, choosing which strate to travel to.
  • Unlock is LOCAL (per player) for now. Base scope = a local server fed by Jahni's database for community information. Global/world-level unlock is a possible future — gated on strates being large enough that finding the next passage is not "a 10 minute endeavour of searching".

Consequences

  • ⚠️ No bottom breaks "generate the whole world offline at season start." Fix: pre-generate a deep buffer (~30 strates) offline; extend in another offline batch if players approach its end. A season probably never exhausts it, and the review/veto step survives intact.
  • ⚠️ Danger needs a ceiling. danger = f(depth) with no bottom grows forever ⇒ everything eventually unsurvivable. It must plateau or approach an asymptote. Open question that shapes the whole curve: does strate 40 differ from strate 30 in danger, or only in what KIND of place it is?
  • "Every 5th slot is a boss" needs a PERIODIC fixed-slot rule. Settings->FixedStrates is a TMap<int32, …> of absolute indices today — the composer needs slot % N as well.
  • The boss is therefore a GATE, which is where the transport network naturally hangs (the route past strate 10 opens when the boss at 10 falls). Gives the descent a rhythm: five strates, then a wall.
  • "Select which strate to travel to" is a menu — and that menu is the WORLD MANIFEST (names, danger, discovered state). Third time the manifest has paid for itself.
  • ⭐ The global-vs-local call is MEASURABLE, not a guess. The measurement pass already computes entrance→exit path length and tortuosity; a live season gives the real number by telemetry. Decide it from data later. (Same principle as everything else here: measure, don't declare.)

⚠️ Architecture consequence — the community layer must be OPTIONAL AT RUNTIME

Local server + external database means a DB outage, a network hiccup or maintenance must degrade, never break. The world is generated from the seed and needs no DB at all. So: procedural names are the fallback when community names cannot be fetched (the deterministic name always exists by construction), shared builds simply do not appear, votes queue locally and sync later. Cheap now, genuinely painful to retrofit once a hundred call sites assume the fetch succeeded.

⚠️ Clarification — elevator unlocks DIE WITH THE WIPE

The wipe is world-only and "everything else survives", but the unlock network is world-scoped: it references this season's strates, and next season strate 7 is a different place. Carrying it forward would also skip the new season's frontier, which is the point of wiping. Named here before a player discovers it the hard way.


2026-08-17 — DEPTH ECONOMY + material placement (and the manifest is confirmed a NEED)

Decided

  • Gear stats have a CEILING (~depth 30). Past it, loot has the same stats but better natural rolls (Trove-style stat-quality %) ⇒ less material to level up. Depth buys less grind and unique access, never bigger numbers.
  • Past the ceiling, going deeper is about pride, challenge, and seeing new things. Confirmed intent, not an accident.
  • Trading will exist — lightly at first, better once the surface becomes a social hub.
  • ⭐ Depth-locked materials are tagged by TIER, not by strate — e.g. a post difficulty content tag — so placement stays random.
  • ✅ The world manifest is confirmed a NEED, not a proposal.

Why the tier tag is better than a fixed depth (Jahni's call, and it is the stronger one)

A fixed depth is solved once and stays solved forever. A random placement inside a difficulty tier must be found again every wipe, and in a one-seed shared world the answer spreads. "Where is X this season?" becomes a renewable community question — exactly what the shared-knowledge design wants, at zero extra cost.

Consequences

  • Guarantee what recipes depend on; leave the rest to chance. One flag on the material: essential ⇒ the composer must place it somewhere in the generated buffer; optional ⇒ the dice decide, and a season lacking it gets an identity ("the one with no X"). Essential-but-absent is a dead end nobody can fix.
  • ⭐ MANIFEST ≠ PLAYER KNOWLEDGE. The manifest holds ground truth (the composer placed it, and quests/validation/fast-travel need it). Discovery state is a separate overlay, per player. Easy now; awkward to unpick if the client is handed the whole manifest up front.
  • ⚠️ You cannot hide the manifest anyway — the client generates terrain from the seed, so players hold the generator and can enumerate it offline. Not a leak to prevent; a fact to design around, as Minecraft does with seed maps. And it barely matters here: community knowledge spreading is the intent, datamining is only a faster route to it, and the wipe is what makes it not matter — a map of season 4 is worthless in season 5.
  • ⚠️ The danger growth rate past the gear ceiling IS the endgame difficulty curve. Below 30 gear and danger climb together; above it gear is capped and danger is not, so skill/strategy/consumables are the only levers left. That single number decides where the wall sits. Everything else is content; that is tuning.
  • Reward converges while danger does not — a roll-quality % asymptotes at 100. Deliberate: the deep game is sustained by scarcity and pride, not progression.
  • Trading is a community-layer feature ⇒ it must degrade gracefully when the database is unreachable, like shared builds and community names.

2026-08-17 — THE WORLD MANIFEST: design

⭐ It is TWO things, not one

Tier A — the SPINE. Finite, tiny, actually stored. Strate slots + passages. ~30 strates plus a few passages each ⇒ ~100 entries, kilobytes. This already exists as StrateLayout + the passage list, computed once in UVoxelStrateManager::Initialize. It is the world's skeleton.

Tier B — the FIELD. Infinite in XY, therefore NEVER stored. Landmarks, rooms, material deposits, build sites. The world does not end sideways, so this cannot be a table — it is a function: give it a region, it enumerates what is there. Deterministic, hash-based, zero bytes.

⇒ That split is what makes "must not be expensive" true rather than aspirational.

⭐ The trick: THE ID ENCODES THE POSITION

The hard requirement is resolving an ID back to a place (a saved quest target, a fast-travel destination, a wiki citation) — normally a lookup table, which is exactly what we cannot have. Landmarks are placed on a hash lattice, so build the ID from lattice cell + type + slot index within the cell. Then ID → position is ARITHMETIC: no table, no database, no storage. A quest stores strate 4, cell (−128, 73), type Lake, index 2 and resolves it instantly, forever, on any machine, offline.

Names fall out of the same thing: hash(id, seed) → word pool. Every entry in an infinite world has a stable, globally identical name that nobody stored and nobody generated in advance — including entries no player will ever visit. (This is the substrate that makes quests and wikis possible; see the two-layer naming note, community names override on top.)

What earns an entry

One test: can a system need to ask "where is it?" or "what is it called?" If yes, it is an entry. ✅ strates · passage mouths · landmarks · notable rooms · material deposits · build sites · boss arenas · the (0,0) spine. ❌ individual rocks · every tunnel segment · terrain that merely emerged from noise.

Underneath that — ADDRESSABLE vs NOTABLE. Everything hash-placed is addressable for free (it has an ID by construction). Notability is a filter on top, and it is exactly what the measurement pass produces: biggest chamber in a region, the one with a lake, the one at a passage mouth. "Notable rooms" needs no new placement logic, only a threshold.

Discovery sits ON TOP, never inside

A player's discovered set is a set of IDs — small integers, cheap to store, cheap to sync. Community discovery is the union. The manifest never changes; only who has seen what. (Confirms MANIFEST ≠ PLAYER KNOWLEDGE from the depth-economy note.)

⚠️ Two cautions

  • The hash functions become part of the FROZEN SEASON CONTRACT. Change how a lattice cell hashes and every quest target in that season moves. Fine — worlds are frozen within a season — but these functions are not implementation details to tidy mid-season.
  • Tier B is cheap, not FREE. Enumerating rooms in a region needs that region's room-placement pass. Fine for a beacon or nearby markers; a full-continent map view would hurt. ⇒ LOD the query: coarse regions return only high-notability entries — which is what a zoomed-out map wants anyway.

2026-08-17 — NEAR-INFINITE STRATES: three consequences

Jahni: some strates (surface-like especially) are near-infinite in XY — storage is impossible. Confirms the Tier A / Tier B split. But it also quietly weakens three things already decided:

⭐ 1. The (0,0) SPINE is what makes an infinite world navigable — state it as a law

In a bounded cave you eventually stumble onto the way down. In an infinite surface strate you never will — the exit is a point in an endless plane. But GeneratePassages already places passages at a random angle + distance from the origin, within a configured range, so passages cluster near the spine by construction. ⇒ The descent is anchored to the spine; infinity is OPTIONAL content. A lost player walks back to the spine and finds the way down. Everything outward is exploration you choose. ⚠️ This is currently an accident of how the code happens to work, not a stated invariant. It should be written down as a law alongside the entrance/exit one.

2. The measurement pass must sample WHERE PLAYERS GO

An infinite strate cannot be measured, only sampled — and a box a million units out measures a place nobody will ever stand in. ⇒ validate the neighbourhood of the spine and the passage mouths, the load-bearing part. A strate may be beautiful at the origin and mush ten km out; that is genuinely fine. Also: report measurements as distributions (median + spread), not single values — regions really will differ, especially once biomes vary the surface. A mean pretending to describe infinity is a lie.

⚠️ 3. CORRECTION — essential materials need a DENSITY, not a location

Earlier note said the composer must place an essential material "somewhere in the buffer". In an infinite strate "somewhere" is unfindable — it could be a thousand km out. The guarantee must be a placement density within the reachable band: near enough to the spine, common enough to actually meet. Otherwise a season ships a recipe nobody can complete and it reads as a bug, not as scarcity. Conveniently this is measurable: expected number of deposits within N of the spine is a number the composer can check.


2026-08-17 — the CITY is a plain UE level (no seam problem after all)

Correction to my "authored city meets generated surface" worry: the hand-authored city is a normal Unreal level, not voxel terrain. VoxelForge sits under the hole in the city, or possibly instantiated in a whole separate level to be free of the city's constraints. ⇒ There is no authored/generated seam. They are not the same kind of thing.

Open / to confirm

  • ❓ Is the voxel world therefore entirely SUBTERRANEAN? If the real outdoors is the city level, then SurfaceWorld is not a surface — it is a cathedral-sized underground space that reads as outdoors (consistent with the existing design where surface/sky strates are enclosed, lit from within by skylight + gem-star ceiling, never by a sun). Asked, not assumed.
  • ⚠️ Separate level vs sublevel is a real tradeoff, worth settling before both exist. A distinct map gives the voxel world its own world settings, lighting, kill-Z and streaming, free of the city's — genuinely valuable. The cost is that the descent becomes a LOAD rather than a walk. For a game whose core verb is descending, a seamless transition through the hole would feel far better, and UE can do it with both as sublevels of one world — but then the voxel world inherits the city's world settings, which is exactly the constraint being escaped. "Free of constraints" and "you can walk down into it" are in tension.
  • Infinite vs bounded world is UNDECIDED. Jahni: "I might not make infinite world also, but for now I might, so I prefer saying it." ⇒ Keep designing for INFINITE: it degrades gracefully to bounded, while a bounded-assuming design (stored manifest, complete map, exhaustive validation) breaks the moment the world is not. ⇒ But note bounded is a lever, not merely a limit — it would buy complete measurement instead of sampling, a real map, and much easier findability. A live option to pull deliberately one day.

2026-08-17 — BOUNDED world, SUBTERRANEAN confirmed, and the descent shaft

Decided

  • ⭐ The world is BOUNDED. Still gigantic maps, but finite.
  • ✅ The voxel world is entirely SUBTERRANEAN — everything is under the surface; some strates only mimic being surface-like. (The real outdoors is the city's UE level.)
  • Transition: likely a master level holding shared elements (lighting etc.), switching when the player enters the hole, with a transition playing. The elevator can be as long as needed — but Jahni intends to place the first strate well below so travel time covers generation naturally.

What BOUNDED buys

  • ⭐ The primordial law becomes PROVABLE, not sampled. The composer can flood-fill an entire strate at coarse resolution, so entrance→exit reachability is a proof, not a probability. Same for largest-connected-component and walkable surface — true statistics, not estimates from boxes. For the one law Jahni called primordial, that is the difference between a check and a guarantee.
  • Budget note: 8 km × 8 km at 4 m sampling ≈ 200 M cells (too many); at 16 m ≈ 3 M (nothing). Resolution scales with map size. Aliasing caveat still applies — coarse to find the route, full resolution to confirm the one corridor.
  • "Explored" becomes a real number — a finite volume means "the community has explored 34 % of season 5". A genuine collective progress bar for a shared world, free once bounded.

⚠️ NEW REQUIREMENT — an XY world-edge seal, which does not exist

Verified: VF_ApplyBoundarySeal(float& Density, float WorldZ, float StrateTopZ, float StrateBottomZ, float Thickness, float BaseDensity) is purely VERTICAL — it seals each strate's ceiling and floor so nothing punches through except passages. There is no horizontal equivalent, because until now the world had no sides. A bounded world does. ⇒ Build it as a fourth structural invariant alongside spine → seal → passage: a forcing op, appended automatically, not author-omittable. Two reasons that shape is right: an invented strate cannot forget it, and because forcing ops prove AllSolid in their band, the world's outer shell becomes free to skip in tile classification.

The transition, and ⭐ the descent shaft as the game's front door

  • Distance gives a FIXED time budget, not an adaptive one — fall speed × depth is the same wall-clock on every machine, so a slow disk still lands in ungenerated space. An elevator can stall for a ready signal; a free fall cannot. If it's a drop, size it for the worst machine.
  • ⭐ Whatever sits between the hole and the first strate is the highest-traffic space in the game — every player, every session, forever. It is currently an accident (just the gap streaming needed). It should be authored deliberately, because it is already doing several jobs:
    • sets the tone for everything below (a featureless drop reads as a loading screen; a worked shaft with old machinery and lights going into the dark reads as "people have been here");
    • it is the elevator lobby ⇒ the natural home of the manifest-driven strate-select menu, as a real place rather than a floating panel;
    • ⭐ it is where depth becomes legible — wall markings, and the community's depth record for the season marked on the shaft, passed on the way down. The season's collective arc made physical, in the one place everybody looks;
    • later: shops, NPCs, surface-side infrastructure.
  • Costs nothing architecturally (city-level authored geometry, or the top of the spine) but turns a technical necessity into the game's threshold.

2026-08-17 — ACTOR-SPACE sweep (built, working)

Why: the city's hole is not at world (0,0), so the AVoxelWorld actor must be placed under it. Jahni: "we'll have it to be fully actor relative, just in case."

What was actually true before: the plugin was half actor-relative. Correct already — GetBiomeAtWorldLocation, GetVoxelSurfaceHeightAt, UpdateDecorations, UpdateLandmarks, UpdateWater, UVoxelDensityVolume::Update, the passage debug draw, the clipmap material. Not correct — the streaming centre, the streaming anchors, all six carve/fill entry points, GetStrateAtPosition, and UVoxelAtmosphereManager::UpdateForPlayer (whose own comment documented the assumption: "actor at origin/identity"). It only ever worked because the actor sat at the origin.

⚠️ The trap avoided: the content managers already convert internally, so converting PlayerLastPos at the source would have double-converted four call sites. The fix had to be per-boundary, not at the top. Found only by reading each consumer — the estimate before that read was wrong in both directions.

Landed:

  • AVoxelWorld::WorldToLocalCm / WorldToLocalVoxel / LocalVoxelToWorld (BlueprintPure) — declared as the only sanctioned boundary between Unreal coordinates and voxel coordinates.
  • ⭐ A grep-checkable invariant, which is the real deliverable: no / VOXEL_SIZE applied to a parameter named World* outside those three functions. The risk was never a missed site among the ones we found — it is the next one nobody notices.
  • 11 call sites converted (counted before and after; every old pattern now zero).
  • ⚠️ Translation-only guard in BeginPlay — tiles, ClassifyBox, the clipmap window, culling and streaming distance all assume world-axis-aligned boxes. A rotation or non-unit scale breaks that structurally, not gracefully. Logs an Error naming the offending rotation/scale.
  • CODEMAP §3.5 and §6 document the convention.

Nice property: with the actor at the origin every conversion is identity, so this is a no-op until the actor moves. Verify by building, confirming nothing changed, then moving the actor. Jahni built it: "seems to work fine." Then moved the actor off the origin and confirmed again — that is the real test, since the identity case proves only that nothing broke.


2026-08-17 — NAMING (Jahni: "pretty clever")

Failure mode to avoid: slot-filling. "The Crystal Cavern of Whispers." Players learn the template in ten minutes; after that every name is noise, and worse, names stop distinguishing places — if everything is [Adj] [Noun] of [Noun] you cannot remember which was which, which defeats the point.

1. ⭐ Derive names from the MEASUREMENTS, not from a bag

The feature vector already exists per notable entry (volume, openness, verticality, water, feature scale). Let the name generator read it: a vast open chamber draws vast-open words, a flooded one draws water words, a tight vertical shaft draws shaft words. The name then fits the place — a player who hears "the Sink" and later finds a huge drain-like chamber gets a small satisfying click. (Fifth use of the measurement pass.)

2. Several competing GRAMMARS, not one template

Real maps are layers of naming logics from different eras and languages, and that mess is what makes them feel real. Pick a grammar by hash, from ~5:

grammar examples implies
Compound Blackreach, Stonefall, Grimwater short, two morphemes, germanic-ish
Descriptive definite The Long Dark, The Hollow, The Sink plain, spoken
Possessive Varen's Fall, The Mason's Mistake somebody was here, and it went badly
Functional Shaft Nine, The Lower Cut industry, records, someone was organised
Opaque invented phonology (consistent syllable inventory) a language, not keyboard mash
Five grammars reads as history. One grammar reads as a generator.

3. Name SCARCITY — most things get no name at all

If every room is named, names mean nothing. Only notable entries get one (the threshold already defined by addressable-vs-notable); everything else stays addressable but anonymous. Scarcity is what makes a named place feel like a place, and it is free — a threshold, not a feature.

4. Names must survive contact with a WIKI

Players will type these into search boxes and say them aloud. So: short, pronounceable on sight, no apostrophes or unusual glyphs. A name nobody can spell cannot become community knowledge — which is the whole reason names exist in a shared world.

⛔ Parked by Jahni

Varying the naming language by depth (deeper = older, stranger tongue). Liked in principle but parked "for now" — it is still a gradient, and gradients are what he rejected.


2026-08-17 — DEATH: the possessed corpse

Jahni's original intent: dying in the depths (most often) leaves your corpse possessed — you must fight it to get your loot back. His worry: with distance growing horizontally as well as vertically, how much frustration does that create? Floated a bounty hunter NPC you pay to retrieve your stuff.

⚠️ The trap that would break it: gear on the corpse = a DEATH SPIRAL

If the corpse holds your gear, you return without your equipment to fight a copy of yourself wearing it. Every attempt is weaker than the last, and a bad night ends with your best gear permanently orbiting a corpse you can no longer beat. Souls games dodge this by taking only currency, never equipment. ⇒ Fix: the corpse holds your CARGO; you keep your GEAR. The fight becomes you against an equal — exactly the intended challenge, winnable with better play. Self-balancing with zero tuning: a strong player's corpse is a strong enemy, a weak one's is weak, at every depth, forever.

The frustration is the TRAVEL, not the fight

Nobody resents a hard fight; they resent twenty minutes of walking to reach it. Fix travel, leave the fight alone.

  • ✅ The vertical half is already solved — the elevator/unlock network. Unlocked stop at 12, died at 13 ⇒ you travel one strate, not thirteen. An unplanned payoff, and an argument for unlock stops being generous.
  • ✅ CONFIRMED by Jahni 2026-08-17. ⭐ The horizontal half: LET THE CORPSE WALK — it wanders around landmarks near the passage, not arbitrarily. It is possessed — why would it stay put? Move it toward the nearest passage mouth or landmark. It comes partway to meet you, which collapses the distance problem and is better fiction than a static body. Falls out of it:
    • the death location is reported as a NAMED PLACE, not coordinates — "last seen near the Sink" (sixth use of the manifest);
    • the retrieval point is somewhere you were heading anyway;
    • and it is genuinely unnerving — your own corpse, wearing your face, hunting you.

The bounty hunter: price it in TIME, not only gold

A pure money sink either trivialises the corpse run or goes unused. But if he retrieves your cargo and delivers it later (next session / a real-world delay), then the corpse run is the fast path and the hunter is the "I don't have another hour tonight" path. Both stay meaningful, it self-balances across players with different free time, and it gives the city's NPCs a real job.

Open forks

  • Dying while fighting your corpse — one corpse that absorbs the previous, or do they stack?
  • Can another player kill your corpse and take the cargo? A genuine fork: real interaction and real griefing in the same mechanic.

2026-08-17 — DEATH, resolved: the mirror match + the retrieval guild

Decided

  • Only YOU can claim your loot. No PvP looting — keeps the death mechanic out of tension with the otherwise cooperative design.
  • ⭐ The corpse COPIES your weapons; you keep yours too. Better than my cargo/gear split: it keeps a true mirror fight without ever disarming you, so the death spiral cannot happen.
  • Possible later: dead players spawn into multiple instances of the depths, so your corpse becomes an encounter in other players' worlds; killing it earns gold from a retrieving guild (not your loot).

Why the mirror is strong — and the one thing to make deliberate

It tests your own build's weakness (glass cannon ⇒ you fight a glass cannon that hits as hard as you do — a "know thyself" fight), and it self-balances at every gear tier and depth, forever, with zero tuning. ⚠️ But a perfect mirror is a coin flip, and you often arrive having already spent consumables getting there. ⇒ Give the player a small, honest edge, on purpose: you have potions and consumables and the corpse does not; you can retreat, heal and come back, and it cannot. Enough to make the fight winnable through preparation rather than luck — which is exactly the gear-and- strategy test intended. Do not leave this accidental.

⚠️ HARD RULE — copied weapons must NOT be lootable

If the corpse spawns a copy of your legendary sword and drops it, you have built an item duplicator, and it will be found within a week. Copied gear vanishes with the corpse; only the cargo drops. Cheap to get right now, brutal to unwind after a season of duplicated items is in circulation.

⭐ The guild unifies two systems into one

The bounty-hunter NPC and the player-paid retrieval are the same mechanism with two front ends:

path who speed certainty
Player someone finds your corpse in their instance and kills it fast uncertain
NPC nobody came, so the guild sends a professional slow (next session / real delay) guaranteed

Either way the cargo returns to you (mail, or a retrieval office in the city) and the killer is paid by the guild, not out of your pocket. Nobody loses anything, the guild becomes a real institution with a reason to exist, and it is one system to build, not two.

⭐ Your corpse becomes content for other people. In a game about a shared world, your worst night turns into someone else's encounter — a wandering possessed adventurer in the deep dark, wearing better gear than theirs, worth killing. The first mechanic here where failure ADDS to the world instead of only costing you.


2026-08-17 — SESSION SHAPE, PARTY PLAY, and the OPENING (big lore reveal)

Decided

  • Run length: still unknown. But ⭐ a corpse run is a DETOUR, not an evening — 10 minutes at worst. That is now a hard constraint that propagates (see below).
  • The descent is done TOGETHER. Today: a local server on one player's machine or a dedicated one. Later: instances sent per group — different groups never meet in the depths.
  • Creatures: nothing decided yet. Flagged as needed.
  • Corpse location NPC (guild, or near the passage): tells you where your corpse was last seen for a very small fee. ⇒ Refinement: charge for PRECISION, not existence. Free = "last seen near the Sink, strate 12"; paid = exact position / live tracking. Reasons: the decision becomes real (coin vs hunt) instead of a fee-gated UI step; it can never trap a broke player (death → lost cargo → can't afford the info → can't recover is a spiral that hits hardest after a bad run); and "last seen" is honest fiction, since the corpse genuinely wanders. Diegetic too — you talk to someone instead of reading a death screen. (Seventh use of the manifest's names.)

⭐ THE OPENING — and it solves a structural problem

Cinematic: civilization emerged FROM the depths. The first, artificial, hand-made strate holds crystals with humans inside. We are un-crystallized, discover a base camp, and are told we could be adventurers who brave the depths. Then down to "strate 2" — the first GENERATED strate.

  • ⭐ This justifies the authored/generated seam IN FICTION. We had accepted "strate 1 is hand-made, the rest are composed" as a production fact players must not notice. But the hand-made strate is hand-made in-world too — artificial because someone built it; the generated ones below are the natural deep world. A player who senses strate 1 feels different is correctly reading the fiction, not spotting the seam. Rare, and worth protecting.
  • ⭐ Descending is a RETURN, not a conquest. You are going back to where you came from — a far better motive than loot, and it gives the depths an implied history for free. Also seeds mystery: who crystallized them, and why?

Consequences

  • ⭐ PLACE the corpse, don't walk it. If it pathfinds toward a landmark, retrieval time depends on where you happened to die — and dying 40 minutes out breaks the 10-minute cap. So on death, place it at a landmark near the nearest passage / elevator stop, and let it wander only within that neighbourhood for atmosphere. Turns the cap from a hope into a guarantee — the same build-it-in-rather-than-measure-it pattern as the primordial law.
  • ⚠️ CONTRADICTION resolved by Jahni — and my proposed fix was BACKWARDS. I assumed the settlement resets and the arc lives inside a season. No: the settlement PERSISTS and progresses ACROSS seasons. See the dedicated section below.
  • Instancing makes the city the ENTIRE social surface. If groups never meet below, then trade, the guild, shared builds and simply seeing another person all happen up top. Strong argument for a generous city and for the descent-shaft lobby. The depths are shared as knowledge, not presence — which is consistent: wiki, names and discoveries all still work.
  • Strate size and elevator density are now downstream of the 10-minute cap. If a stop anchors retrieval, a strate must be crossable in roughly that order, or dying far from a stop breaks it.
  • Party play changes danger tuning fundamentally — a boss balanced for one is a joke for four. Unresolved: does danger scale with party size, or are strates tuned for a nominal group?

2026-08-17 — ⭐ THE CORE LOOP, CLOSED (the settlement is communal and permanent)

Decided

  • The surface is limited by construction — a sky island, or a mountain so tall no one can descend it. So resources must come from below.
  • The settlement is COMMUNAL — the same for everyone, global. It does NOT reset at the wipe.
  • A SEASON is the unit that advances it: camp → village → town → city → advanced city → … driven by everyone.
  • Players gather resources and donate (to the mayor or similar); a global count rises until the next tier is reached.

⭐ The loop is now closed and coherent

Limited surface → must descend → depths give resources → resources build the settlement → the settlement enables deeper descent. Every system discussed today hangs off this. The sky island does quiet work: it explains why there is no trade with anywhere else, why the depths are the only economy, and why descending is the civilization's project rather than a hobby.

⭐ The wipe gains meaning beyond freshness

The world is impermanent; the civilization persists. "We lost our maps, but we built a town." Season 8 arrives in a place season 3 made. Survives the wipe: the settlement and its tier · account progression · titles · personal blueprint library · housing instances. Dies with the wipe: the world · the shared build pool · the elevator unlock network.

⚠️ Three requirements this creates

  1. The tier threshold MUST scale with active population. A fixed number stalls forever with a small playerbase and is blown through in a week with a large one — either way the promise ("a season advances the settlement") breaks. ⇒ Target one tier per season, and retune the threshold at the season boundary from observed participation. That moment already exists — it is the offline review where Jahni inspects and vetoes the next world. One process, two uses. A quiet season then adjusts rather than permanently stalling the city.
  2. ⚠️ The tier must grant ACCESS and CONVENIENCE, never POWER. Services, NPCs, workshops, bank, fast travel, aesthetics — not better starting gear or stat boosts. Otherwise season-8 players start stronger than season-1 players, early strates trivialize, and the difficulty curve erodes every season until the top half of the world is decoration. This is the SAME rule already chosen for depth (depth buys access and less grind, never bigger numbers) — one consistent economic principle, applied twice. Good sign.
  3. ⭐ Make the city a LEDGER, for late joiners. Someone arriving in season 8 built none of it — alienating, or the best first impression in the game, depending on whether the city records who built it: plaques on the aqueduct, names in the great hall, a monument per tier listing that season's contributors. New players then walk through evidence that people made this place, and veterans get something permanent — pairing exactly with the titles that already survive wipes.

Smaller consequence

Cargo now has two destinations — your own progression, or the city. A real recurring choice with a communal dimension; it gives otherwise-worthless materials a use; and it makes the corpse run hit harder. That ore wasn't just yours — it was the aqueduct.