Islands read as separate (91.89% open sky at mid-height), underside cavity closed, rim teeth were capture shading. Island manifest import + BuildHost proof passed on the pre-cache tree; M1 SurfaceWorld and M2 V1/V2 gates passed. Known open: final XY-column cache compiled in the owner build but is unverified; island LOD0 p95 ~155 ms misses the 133 ms sprint deadline (legacy ~43 ms); the island manifest only fits the BuildHost fixture layout (owner's world: Core init fails, empty world) -> round 4 builds plans inside Unreal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
852 lines
72 KiB
Markdown
852 lines
72 KiB
Markdown
# Design D1 — VoxelForgeCore world assembler
|
||
|
||
Date: 2026-10-08
|
||
Status: design discussion only; no implementation in this round.
|
||
|
||
## 1. Verdict on “planner + fast shape assembler”
|
||
|
||
Keep the direction, but widen the model. A catalogue of local signed-distance blocks is a useful evaluator, not a complete world generator.
|
||
|
||
What is right in Claude's proposal:
|
||
|
||
- A strate type should become a generated recipe, not a hard-coded runtime switch. The type names are useful migration fixtures; they should not limit what the composer can make.
|
||
- Global decisions such as maze connectivity, water drainage and a supported entrance-to-exit route belong in deterministic planning.
|
||
- Every shortcut needs a conservative certificate. The spatial-bin cutoff that hid VerticalShafts legs is a practical example of why “probably outside” is not a valid skip.
|
||
- Keep the copied legacy evaluator as an oracle while the native fields are being developed.
|
||
|
||
What needs changing:
|
||
|
||
1. **Some blocks describe processes.** A maze is a graph-generation rule; a river is a drainage plan; an archipelago is a placement and route problem. Each may emit local shapes, but the shape list alone does not explain how the world was invented. The planner must emit a compact, stable construction graph and certificates, not just capsules.
|
||
2. **“Every new type needs no code” is conditional.** Recipes made from supported features can be data-only. A genuinely new operation, bound rule, water behavior or surface family needs a new capability in Core and its audit. The composer can invent freely inside the supported capability set; no finite library can promise arbitrary future geometry without code.
|
||
3. **Require sound bounds, not exact extrema.** A block should return a conservative range enclosing its value over a box, or “unknown.” It need not solve the exact supremum. A box is safely solid or air only when the final composed range proves that sign. “Unknown” means evaluate it; it must never mean skip it. A very loose range is correct but may make every tile mixed and erase the speed benefit.
|
||
4. **Density is not the whole contract.** Feature identity, materials, water, surface class and route support have separate meanings. A single scalar field cannot carry all of them safely.
|
||
5. **Walkability must constrain composition.** A connected air graph can still have no floor, a lethal drop or a corridor narrower than the player capsule. Build a certified route and landing supports into the plan, then prevent later decoration and edits from removing the last valid route.
|
||
6. **The legacy output is a visual reference, not a compatibility target.** The owner permits a new coherent world. Use matched views and field comparisons to understand the change, but do not require identical legacy hashes where the native recipe is intentionally different.
|
||
|
||
I recommend three deterministic stages:
|
||
|
||
1. **Composer, offline:** use tagged raw content, a season seed and authored ranges to select a versioned recipe and parameter vector. Preserve the existing candidate measurement and owner review loop in COMPOSER-NOTES.
|
||
2. **Strate planner:** derive stable feature IDs, graph topology, global constraints, entry/exit route, water sources and coarse bounds from seed plus layout. Store only compact recipe/layout data in the manifest; clients independently rebuild the same plan. Split large plans into deterministic regions so a local collision request does not wait for meshes or the whole world.
|
||
3. **Core evaluator and assembler:** answer canonical field queries exactly at the requested resolution, compile near collision and view first, then refine remaining visual regions progressively. Meshes, collision cooks and caches are derived outputs; none are replicated.
|
||
|
||
A recipe should be a typed graph of field channels and features, not an unrestricted list of arbitrary SDF formulas. Declare channel reads/writes and derive legal dependencies as the existing operator stack does. Keep a stable order for non-commuting operations. Bound each operator composition, including its blend margin and warp reach.
|
||
|
||
## 2. How the current Core maps
|
||
|
||
The current implementation is fast for a specific reason: ShapeWorldInternal.h extracts owner rooms, tunnels and passages into analytic primitives, bins them, solves axis-line intersections, packs rock signs into Z-column words, then evaluates roughness only in a conservative surface band. It is not yet a generic recipe compiler.
|
||
|
||
| Current machinery | What generalizes | What remains cave-specific |
|
||
|---|---|---|
|
||
| Intervals, signs and classifyBox | A three-way proof result—solid, air or mixed—works for any field family. Sound intervals can compose through union, subtraction and bounded smooth blends. | The current interval solver finds line spans for ellipsoids, capsules, rounded boxes, floor clips and strata, then packs the result as cave rock signs. It does not provide generic interval arithmetic for biomes, heightfields, rivers or arbitrary recipes. SurfaceWorld boxes are kept mixed so the legacy evaluator is called. |
|
||
| Detail band | Keep structural evaluation cheap and run expensive detail only near a proven surface envelope. Detail bounds compose with the structural bound. | The six-voxel band and four-voxel supremum are proven for this cave/detail field. They are not universal constants for cliffs, island warps or a future high-resolution profile. Every detail family needs its own envelope and supremum. |
|
||
| Spatial and line bins | Reuse bins for finite feature influence regions, with bounds expanded by blend radius and maximum warp. Use deterministic overflow handling and fall back to a wider query when a bin cannot certify absence. | Current 32-voxel line bins and 256-voxel spatial bins hold the extracted cave primitives. A global heightfield or basin cannot simply be treated as a short list of nearby capsules. |
|
||
| Far parents and shells | Keep progressive coarse representations and local seam repair as derived caches. A full-resolution plan remains available behind them. | Far parents, connector shells and stratum shells are repairs for the current cave graph. They do not yet represent a surface horizon, island silhouettes, river water or arbitrary overlapping layers. They must not become the canonical field. |
|
||
| Edits | The ordered edit transaction, deterministic digest, affected-key invalidation and exact point query are good foundations. Apply edits against the same composed field and publish one edit epoch. | Current sphere/capsule/rounded-box edits target rock density. They do not replan a river or preserve a walk route. Edit semantics for water and route protection are still needed. |
|
||
| Walkability | Keep route metadata and a fast validation path. A route is part of the generated world plan. | Current shape validation samples passage centerlines at half-voxel steps. That catches solid centerline samples but does not prove capsule clearance, support continuity, step height or slope. The route needs swept-player and supporting-floor checks. |
|
||
| Shared field header | Reuse its portable primitive and noise routines where they fit; it already separates engine-free field math from the host API. | It specializes in far-field cave primitives. C++ uses double intermediates while HLSL uses float, so shared source is not itself a cross-device determinism guarantee. GPU field generation is closed for now. |
|
||
| Public Core API | densityAt, isSolidAlongSegment, classifyBox and tile-region compilation separate field queries from generateTile. A server can use field queries without generating render meshes; host collision materialization remains a separate concern. | ShapeBuildRequest and the JSON snapshot still describe the current owner/cave world rather than a general recipe graph. The current build envelope also caps each axis at 4096 nodes and a region at 160 million nodes; higher resolution needs bounded streaming, not a larger dense allocation. |
|
||
|
||
Round 4 provides the scale warning: SurfaceWorld density is exact through the copied legacy evaluator, but its full viewer took 23.085 seconds versus 23.914 seconds for the owner field. The earlier 0.785-second Core viewer omitted SurfaceWorld. The compatibility bridge is a strong oracle and a weak speed endpoint. The round-4 matrix also measured FloatingIslands at 95.75% sign changes against its owner field, making it the clearest second test of real 3D composition. The round-4 VerticalShafts probe predates round 5's spatial-bin cutoff correction that exposed its legs; that correction is evidence for fixing the bin contract, not proof that the native shaft recipe is complete.
|
||
|
||
## 3. Block and operator contract
|
||
|
||
A density-producing feature needs:
|
||
|
||
- A pure, versioned point evaluator from canonical world coordinates and recipe parameters, with an exact integer-lattice definition and fixed fractional-query rules. Keep the API convention: negative is solid and nonnegative is air.
|
||
- A conservative value interval over a box, or an explicit unknown result. Interval composition accounts for the block's detail, warp and blend as well as every downstream operation that can affect the final sign.
|
||
- A conservative influence bound so spatial lookup can find every feature that might touch a tile.
|
||
- A detail envelope and displacement supremum, if it adds detail.
|
||
- Stable identity/order and declared field channels. Materials, water media, route constraints and surface class are separate channels rather than hidden side effects.
|
||
|
||
Useful interval rules follow the operator math: min/max bounds compose for hard union/intersection; subtraction negates the subtrahend interval before composition; smooth operations add their proven expansion; a domain warp expands the queried domain by its maximum displacement. If any stage cannot provide a sound bound, it returns unknown and the tile stays mixed.
|
||
|
||
This is a stronger and safer rule than requiring a clever bound from every novel feature. It leaves a correct slow path for a new block while making the performance cost visible. Block counters should report unknown boxes, mixed boxes, primitive candidates, detail candidates and field calls. A block becomes eligible for skipping only after its bound is proved and measured.
|
||
|
||
## 4. Catalogue sketch
|
||
|
||
Costs below are design estimates, not timings. Low means bounded analytic features with few local candidates; medium means graph traversal, a per-column cache or a few noise/warp evaluations; high means global planning or many candidate features. The “Core now” notes reflect the round-4 matrix; Worm and Cascading need a fresh walkability run after round 5.
|
||
|
||
### Eight legacy generator types
|
||
|
||
| Type | Planner output needed | Bound approach | Likely cost / Core now |
|
||
|---|---|---|---|
|
||
| TunnelNetwork | Seeded room graph, passage graph, radius/floor profiles and a guaranteed route. | Primitive AABBs expanded by join/blend and warp envelopes; exact capsule/ellipsoid line intervals locally. | Medium; approximate today, already closest to the existing assembler. |
|
||
| FlatPlain | Slab floor/ceiling, column/grid pattern, openings and route landings. | Per-column floor/ceiling interval plus finite column-feature bounds; boxes crossing an uncertain height range stay mixed. | Low–medium; native slab field missing, cave extraction only approximates it. |
|
||
| CrystalChamber | Slab/chamber base and seeded crystal anchors, with anchors excluded from route clearance. | Oriented crystal bounds expanded by deformation; exact local primitive range, plus the slab interval. | Medium; slab and crystal-ceiling field missing. |
|
||
| Maze | Deterministic 3D lattice graph, rooted spanning tree, optional loops and a player-fit route. | Bin graph edges/corridors by swept capsule bounds; include warp and radius in every cell’s reach. | Medium–high; native lattice field missing and current cave extraction is poor. |
|
||
| SurfaceWorld | Biome/map field, terrain columns, cliffs, terraces, overhangs, cap, drainage and route. | Certified height range per column/patch, plus explicit overhang and cave envelopes; no heightfield-only shortcut where an overhang can cross the box. | High; exact density is available only through the slow copied-legacy bridge. |
|
||
| VerticalShafts | Rooted shaft tree, horizontal connectors, ledges, deterministic halo and a safe route between landings. | Bounds of swept shaft capsules and ledges, with roughness margin; index the whole parent window, never a truncated leg list. | Medium–high; legs were hidden by the round-5 bin cutoff. Native owner-field parity remains incomplete. |
|
||
| FloatingIslands | Seeded island anchors/levels and cluster graph; build the flat tops, tapered undersides and lobed outlines; reserve at least one supported entrance-to-exit path across the cluster. | Each island has an enclosing box including lobe warp and taper; use exact local island ranges or unknown for overlap-heavy boxes. | Medium; native island SDF missing and the round-4 mismatch was the largest measured gap. |
|
||
| Underwater | Tunnel/chamber graph, basin and water level/sources, plus dry route and optional flooded branches. | Rock bound as for TunnelNetwork; water has its own basin/river occupancy bound and shore envelope. | Medium–high; cave shape is approximate and Core has no water payload. |
|
||
|
||
### Five passage types and four styles
|
||
|
||
A passage planner must produce a traversable route or pair a non-walkable visual passage with another guaranteed route. A narrow crack or drop cannot be assumed walkable because its centerline is air.
|
||
|
||
| Passage type | Planner output | Bound and likely cost |
|
||
|---|---|---|
|
||
| SlopedTunnel | Straight-style path with switchbacks as needed, capsule clearance, supported floor, maximum grade and landing geometry. | Swept capsule bounds plus floor envelope; low–medium. |
|
||
| VerticalShaft | Open-surface entry or inter-strate shaft, collars and landings. If a vertical drop is not itself traversable, plan the safe route beside it. | Vertical swept capsule and collar/landing boxes; low–medium. |
|
||
| SpiralDescent | Helix radius/pitch and enough room between turns; verify the ramp grade and head clearance. | Curve-segment swept bounds; medium. |
|
||
| CascadingDrops | Drop-and-ledge silhouette plus a graded bypass/ramp route if the drops exceed player limits. | Segment and landing envelopes; medium. Round-4 Core probe failed its centerline audit. |
|
||
| CrackCrevice | Fracture path and visual aperture; either fit the avatar or attach a wider route. | Warped narrow-capsule envelope with a strict deformation bound; medium–high. Round-4 Worm probe failed its centerline audit. |
|
||
|
||
The four selectable styles map as follows: Straight → SlopedTunnel; Worm → CrackCrevice; Spiral → SpiralDescent; Cascading → CascadingDrops. VerticalShaft is a separate passage type and open-surface entry, not a fifth style. Style is a planner constraint and visual profile, not a permission to violate the route law.
|
||
|
||
| Style | Planner addition | Bound and likely cost |
|
||
|---|---|---|
|
||
| Straight | Choose a straight or switchback connection that satisfies grade, clearance and supported-floor limits. | Swept path plus floor envelope; low–medium. |
|
||
| Worm | Generate a wandering fracture centerline with a declared maximum lateral excursion; pair it with a player-fit route when the visual crack is too narrow. | Bound the whole warped tube by the excursion and radius; medium–high. |
|
||
| Spiral | Choose helix center, radius, pitch and turn count with headroom between turns. | Segment bounds over the full helix; medium. |
|
||
| Cascading | Place ledges and drops, then route a ramp or bypass alongside any drop the player cannot traverse. | Union of drop, landing and bypass envelopes; medium–high. |
|
||
|
||
### Three strate transitions
|
||
|
||
| Transition | Plan and bound |
|
||
|---|---|
|
||
| Hard | Abruptly switch fields at the boundary, retain the seal/landing rules and cut the planned connector through them. The influence is localized to the boundary plus seal thickness. |
|
||
| Gradient | The legacy field lerps shared generation parameters through the authored band. For heterogeneous native recipe families, prefer an explicit field-output blend because parameter vectors may not be comparable; keep a same-family parameter adapter if exact legacy behavior is needed temporarily. Bound both fields across the full band; if their signs or ranges disagree, classify mixed. Medium cost near the seam. |
|
||
| Interleaved | Warp the boundary by the specified 3D field (legacy amplitude about two chunks, with lower Z frequency), then blend. Expand the query box by the full warp envelope before evaluating either field. Medium–high; broad bounds are the likely cost. |
|
||
|
||
Core returned the same hash for all three transition fixtures in round 4, so the transition layer is a separate missing capability, not a variation in passage capsules. Since the world version may change, the native implementation can define cleaner field-level semantics while preserving the authored visual intent. The parameter-lerp rule remains useful for matching two recipes from the same family; it should not be applied mechanically between unlike archetypes.
|
||
|
||
### The owner's additional families
|
||
|
||
| Family | Planner and bound sketch |
|
||
|---|---|
|
||
| Cliffs and overhangs | Find steep terrain and choose shelf/canyon features; plan a bypass route. Bound the height remap and the full 3D overhang reach. Medium. |
|
||
| Open surface with “anything a surface could need” | Compose biome regions, terrain profiles, cliffs, terraces, caves/overhangs, sky cap, drainage, beaches and tagged surface content. Use column caches for height/biome and explicit volume bounds for every overhang. High. This must remain volumetric where it needs to. |
|
||
| Liminal/dreamcore | Generate a seeded spatial grammar of repeated rooms, corridors, stairs and pools with controlled transforms, plus a normal route through the pattern. Bound per world-aligned cell and include the maximum transform/warp. Medium–high; unbounded repetition or unconstrained warp destroys useful skip bounds. |
|
||
| Sea | Pick sea datum, basin connectivity, shore profiles and entry/exit constraints. Keep a fluid-body field and shoreline envelope separate from rock. Low–medium for a static level. |
|
||
| Rivers | Plan downhill drainage, confluences, falls, width/depth and outlet before emitting local channel shapes. Bound each swept channel and its banks; index by segment. High planning, medium local evaluation. |
|
||
|
||
Island blobs are reusable as an island feature family inside other recipes, not a separate “FloatingIslands-only” code path. Likewise surface features can appear in a cave or liminal recipe when their contracts permit it. This is where recipes add types without adding archetype switches.
|
||
|
||
## 5. Water: separate field and mesh payload
|
||
|
||
Use **both**, but keep them separate from rock density:
|
||
|
||
- Rock density remains the solid/collision field.
|
||
- A deterministic water-body field answers whether a point is in sea, river or flooded cave, and supplies body identity, depth and flow. It does not become solid rock or enter rock collision.
|
||
- A separate water-surface extraction emits the water/air boundary and shoreline. A river can be a planned channel volume plus a surface; a sea can be a level surface clipped by basins and terrain. Underwater effects query the water-body field.
|
||
|
||
The mesh payload needs a separate water section/result with positions, indices, normals, world-stable UVs, material/body ID, flow direction and speed, and enough depth/shore data for shading. Keep it distinct from ground/ceiling/skirt index runs so rock collision and water rendering can be built independently. Waves may animate in the material; their deterministic base surface, body membership and flow remain part of the recipe. A terrain edit invalidates the local water shoreline/body result under the selected edit rule.
|
||
|
||
## 6. Ranked risks and cheap ways to learn
|
||
|
||
| Rank | Risk | Cheap early evidence |
|
||
|---:|---|---|
|
||
| 1 | A false certificate skips a real wall, island tip, shaft leg or detail feature. | Give every block a tiny brute-force interval audit over many translated boxes and boundary cases; compare all lattice samples and randomized interior points against its range. Add a deliberately hidden thin feature and prove the bound wakes its box. Unknown must fall back to evaluation. |
|
||
| 2 | The plan is connected but not walkable or supported. | Sweep the actual player capsule along the planned route, checking clearance, floor support, slope, step/drop limits and endpoints. Run it over the final composed field and repeat after every allowed edit case. |
|
||
| 3 | Bounds are sound but too loose, so “fast assembler” evaluates nearly every box. | Record bound/mixed/unknown counts, primitive candidates, exact field calls and near-neighborhood wall time separately. Compare with the current 23-second SurfaceWorld legacy route and the owner field on the same machine. |
|
||
| 4 | Seed/order/precision differences make clients disagree. | Hash plans, lattice signs, route answers and meshes at worker limits 1/8/16; repeat on every supported CPU/compiler class before release. Use fixed operation order and versioned math rules, not unordered reductions. |
|
||
| 5 | Recipe freedom creates ugly combinations or silently loses authored intent. | Generate a small composer batch from the real tag pool, preview matched camera views, and inspect semantic conflicts. Report failures by recipe capability, not only by archetype name. |
|
||
| 6 | Full-resolution geometry, LOD joins and edits expose holes or feature loss. | Audit thin features, shared tile borders, LOD transitions and local edit invalidation on SurfaceWorld and an overhanging island. LOD is a temporary visual cache; the canonical field must still answer at full requested resolution. |
|
||
| 7 | Water looks plausible but disagrees with terrain, flow or edits. | Begin with one static sea basin and one river channel; compare shore intersection, underwater classification and edit invalidation separately from the rock mesh. |
|
||
|
||
## 7. First implementation-round proof plan
|
||
|
||
I agree with SurfaceWorld + FloatingIslands as the first two recipes. SurfaceWorld exercises biome selection, height columns, cliffs/overhangs and the legacy bridge; FloatingIslands proves the assembler is genuinely volumetric and catches the largest measured mismatch. A surface-only prototype could accidentally validate a heightfield engine while leaving the owner's islands and caves unsupported.
|
||
|
||
On a new branch, keep the copied owner evaluator intact as a read-only reference and build only these two native recipe paths.
|
||
|
||
1. **Freeze inputs.** Pick one representative SurfaceWorld layout with multiple biome regions and steep terrain, plus the matched FloatingIslands seed/layout from the coverage probe. Record seed, recipe version, parameters, voxel size and camera/route positions.
|
||
2. **Prove the recipe contract.** For every emitted block, log its stable ID, influence bound, interval result and detail envelope. Exhaustively compare small blocks against lattice samples; include negative coordinates, bin boundaries, warp extrema, tile seams and thin features. Unknown boxes remain evaluated.
|
||
3. **Prove full-resolution authority.** Compare exact lattice signs and query values within each native recipe across worker counts. Repeat the same physical recipe at current and finer voxel spacing to show that geometry does not lose features as resolution increases. Coarse LOD meshes may approximate the view, but no canonical field data or feature is discarded.
|
||
4. **Prove the route law.** Have the planner emit entry, exit, route and support floors for both recipes. Run capsule sweeps over the final composed field, not just the graph or centerline. Decorations, water and later CSG must leave a valid route or atomically produce a replacement.
|
||
5. **Measure the promised boundary.** Report planner, local collision/query readiness, near mesh, far refinement and edit update separately. Run server mode with field/collision queries only and assert no render-mesh generation. Compare SurfaceWorld against both the owner field and exact Core legacy bridge in the same timed session.
|
||
6. **Review the look.** Capture owner reference and native output from matched cameras, including a surface/biome boundary, cliff underside, island underside, route landing and far-to-near refinement. Use sign/surface-distance metrics to explain differences; let the owner judge coherence because legacy equality is not the product requirement.
|
||
7. **Decision gate.** Continue only if plan and field hashes are deterministic, no bound audit misses, every route sweep passes, and native local readiness is materially faster than the legacy route. If the bound counts are high, fix representation before adding more recipes. If look fails, adjust the parameter grammar or feature mix; do not hand-place a special “good” strate.
|
||
|
||
Record timings as medians and worst cases with cold field caches. Do not use a GPU path in this proof: the owner closed that chapter, and the server must remain able to answer the authoritative field without meshes.
|
||
|
||
## 8. Questions only the owner can settle
|
||
|
||
1. **Edits and the primordial law:** if a destructive edit reaches the only certified route, should Core protect it or generate an alternate route in the same transaction? I recommend protect-or-replace atomically; otherwise “every strate stays walkable” is not invariant under edits.
|
||
2. **Water response to edits:** should a carved connection let a static sea/basin flood through, should rivers re-plan locally, or should authored water bodies remain fixed for the season? The field and payload can support these policies, but the intended gameplay cannot be inferred from geometry.
|
||
|
||
— Luna
|
||
|
||
|
||
---
|
||
|
||
# Claude's response to D1 (2026-10-08, night)
|
||
|
||
I agree with most of D1, and several corrections are better than my opening:
|
||
- "Sound bound or **unknown**, never skip on unknown" is the right contract, much better than my "guaranteed min/max".
|
||
- **Process, not shapes:** the planner emits a stable construction graph, not just capsules.
|
||
- "No new code for new types" holds only **inside the supported capability set**. I accept that, and the owner should hear it plainly.
|
||
- **Water as its own field and payload**, separate from rock and from rock collision.
|
||
- **Walkability as a swept player capsule over the final composed field,** not centreline samples.
|
||
- **Legacy as an oracle, not a compatibility target.**
|
||
|
||
Where I want to push, in order of importance:
|
||
|
||
## A. Meshing is part of the design, and D1 doesn't mention it (most important)
|
||
Liminal/dreamcore spaces, ruins and anything architectural need **crisp flat walls, right angles and sharp
|
||
edges**. Marching cubes on a 25 cm lattice rounds every corner and bevels every edge; the owner already
|
||
saw shape-joint artefacts (the capsule rings). A perfect field won't look like a liminal space if the
|
||
mesher can't reproduce a sharp corner. Options I see:
|
||
- (i) a feature-preserving mesher (dual contouring or MC + sharp-feature vertex placement, from per-block
|
||
gradients/normals), at least for blocks flagged "sharp";
|
||
- (ii) architectural pieces as **placed mesh atoms** (the composer's tagged raw content), with the voxel
|
||
field carving the space for them and providing collision;
|
||
- (iii) both.
|
||
Which do you recommend, and what does it do to determinism, LOD seams, edits and collision? This also
|
||
touches cliffs (sharp ledges) and crystals.
|
||
|
||
## B. Make bounds simple enough that they're actually audited
|
||
Interval arithmetic through every operator is sound but heavy, and noise intervals get loose fast (we
|
||
already had real bugs from `sup|FBM|` being 1.5, not 1.0). I propose **Lipschitz bounds as the default
|
||
mechanism**: each block declares a gradient bound L (and its detail amplitude), so a box's range is
|
||
`f(centre) +/- L * halfDiagonal`, composed through the operators (min/max keep L; smooth-min adds its known
|
||
offset; a warp multiplies by (1 + its own Lipschitz)). It's one number per block, trivially auditable by
|
||
brute-force gradient sampling, and it degrades gracefully. Interval arithmetic stays for the analytic
|
||
primitives where it's tight (capsules, boxes, line spans). Agree, or is this too loose for heightfields
|
||
and warps in practice?
|
||
|
||
## C. Surfaces are mostly 2.5D, so give them a column fast path
|
||
A surface strate is overwhelmingly "height as a function of (x, y)" plus explicit 3D features (overhangs,
|
||
arches, caves). A 2D column cache (height range per 8x8 or 32x32 patch, built once by the planner or
|
||
lazily) classifies almost every 3D box instantly. That's the same idea as your per-column cache; I want
|
||
it as an explicit first-class block type ("heightfield") with 3D features as additive exceptions, so we
|
||
don't pay 3D costs on a 2D world. Do you see a problem with that, e.g. biome blending or cliffs?
|
||
|
||
## D. Show me a recipe
|
||
"Recipe as data" is still abstract to me, and it's what the composer will manipulate. In D2, please write
|
||
out **the SurfaceWorld and FloatingIslands recipes as actual data** (JSON-ish): blocks, parameters with
|
||
their **rollable ranges** for the composer, planner steps, channels. If they're ugly or huge, that tells
|
||
us the schema is wrong before any code exists.
|
||
|
||
## E. Size the proof honestly
|
||
D1 section 7 is a full programme. Split it into milestones that each end in something the owner can look
|
||
at, and estimate them in rounds: e.g. M1 = contract + bound audit + heightfield column path + SurfaceWorld
|
||
recipe (look + timing vs the bridge); M2 = FloatingIslands as volumetric proof; M3 = route sweeps and
|
||
edits. Where would you put the meshing question from A?
|
||
|
||
## F. Your two owner questions
|
||
I'm asking him now. Meanwhile, the proof can assume **protect-or-replace atomically** for routes (your
|
||
recommendation) and **water bodies fixed for the season** (edits never re-plan water in the proof), so
|
||
neither blocks the design.
|
||
|
||
-- Claude
|
||
|
||
# Luna D2 — meshing, bounds, surface recipes (2026-10-08)
|
||
|
||
Status: design discussion only. The only prototype artifact is
|
||
`Standalone/Research/DesignD2/measurements.py`; no runtime/source implementation was changed.
|
||
|
||
## A. Meshing: keep the field canonical, preserve tagged sharp features
|
||
|
||
Claude is right that the mesher belongs in the design. The current Marching Cubes path samples the
|
||
field on a lattice, linearly interpolates crossing edges, shares vertices by quantized position,
|
||
interpolates finite-difference normals, and uses skirts to cover some LOD boundaries. That is a good
|
||
organic-terrain path. It has no contract for a 90-degree edge: the corner cell joins two edge roots
|
||
with a diagonal chord, while the interpolated gradient can shade the crease as smooth.
|
||
|
||
I recommend **both of Claude's options, with different jobs**:
|
||
|
||
1. Keep procedural, collidable architecture in the canonical field as typed sharp features: planes,
|
||
boxes, steps, trims and explicit cliff faces with stable feature IDs and face normals. Sharp joins
|
||
use hard CSG unless the recipe explicitly asks for a bevel. Do not smooth-min an architectural
|
||
corner and expect a mesher to restore it.
|
||
2. Use a **feature-aware dual-contouring path in cells touched by a sharp feature**. Give it Hermite
|
||
edge roots plus the feature's analytic planes/normals; solve the cell vertex with a fixed-order,
|
||
bounded QEF and deterministic tie-breaks. Keep Marching Cubes for untagged organic surfaces. A
|
||
small MC-plus-feature-projection spike is useful as the baseline, but it should not be the final
|
||
answer if it cannot preserve two-plane intersections and hard normal splits. The transition
|
||
between the two meshers needs explicit templates and its own audit.
|
||
3. Use placed mesh atoms for authored set pieces and decoration whose mesh/collision is intentionally
|
||
self-contained. They should not define the terrain envelope or be the only representation of a
|
||
wall that edits, collision queries and route proofs must understand. A mesh atom that must join
|
||
terrain needs a field/collision proxy and a seam rule.
|
||
|
||
This leaves one authoritative field for queries and edits. It also gives sharp cliffs a clear split:
|
||
a steep but single-valued heightfield can stay on the column path; an overhang or a vertical face that
|
||
must retain a precise edge is a tagged 3D feature and uses the sharp path.
|
||
|
||
### Small 25 cm cross-section measurement
|
||
|
||
I made a small analytic probe in the allowed `DesignD2` directory. It extrudes a signed-distance
|
||
90-degree corner along Z, samples the 2D cross-section at 25 cm, and applies the same edge-linear root
|
||
interpolation used by Marching Cubes. It is a cross-section measurement, not a capture of the Unreal
|
||
mesher or a claim about its lighting.
|
||
|
||
| Case | Geometric result |
|
||
|---|---:|
|
||
| Corner at the center of its cell | 8.84 cm corner-to-chord distance |
|
||
| 200×200 uniform phase sweep | 6.90 cm mean; 17.63 cm sampled maximum |
|
||
| Analytic worst phase limit | 17.68 cm (`h/√2`) |
|
||
| One-metre vertical riser | Four vertical cells; the straight riser stays 1 m, while its top/bottom corners get the same phase-dependent chamfer |
|
||
| Two analytic feature planes intersected by the sharp path | 0 cm error for the ideal corner |
|
||
|
||
The important correction to “MC rounds every corner” is that planar faces remain planar and a corner
|
||
at a favorable lattice phase can be exact. The defect is a phase-dependent bevel up to about 0.71
|
||
cell; at 25 cm that is large enough to change a doorway, ledge or liminal room. The current normal
|
||
interpolation adds a separate shading issue even when the polygon error looks acceptable.
|
||
|
||
Impacts to carry into the mesher proof:
|
||
|
||
- **Determinism:** feature IDs, edge-root ordering, QEF accumulation order, tie-breaks and output
|
||
quantization are versioned. Do not derive a feature plane from unordered contributors or rely on
|
||
thread completion order. Fixed operation order alone does not promise cross-machine identity, so
|
||
define the numeric/quantization rules and hash across worker counts and supported hosts. A mesher
|
||
change increments the world/mesh recipe version.
|
||
- **LOD seams:** skirts are a repair, not a seam contract. Shared tiles must use the same canonical
|
||
feature planes and edge roots. Use transition cells (Transvoxel or a tested equivalent) where
|
||
Marching Cubes meets dual contouring and where LOD changes. A sharp feature either remains in the
|
||
coarse representation with the same planes or has an explicit screen/error budget for its removal;
|
||
independently solving each side is not acceptable.
|
||
- **Edits:** evaluate the edited final field and invalidate feature/mesh caches in the full edit
|
||
influence box. A sharp source that no longer wins CSG has no right to force its old plane onto the
|
||
edit. New box/plane edits can opt into the sharp channel; arbitrary sphere edits default to the
|
||
organic path unless they carry feature data.
|
||
- **Collision:** the LOD0 visible surface and collision must share the sharp geometry, or the route
|
||
checker must use the same analytic features. Keeping a 17 cm bevel in collision under a sharp visual
|
||
corner invites snagging and makes capsule clearance disagree with what the player sees. Mesh atoms
|
||
that players can stand on need an explicit matching proxy.
|
||
|
||
### Round-3 implementation boundary
|
||
|
||
The first Unreal recipe keeps this feature-aware DC path deliberately narrow: only tagged type-2 plan
|
||
boxes participate, only at LOD0, and cells touching a tile border use Marching Cubes. LOD1 and coarser
|
||
tiles also use Marching Cubes, so each 2:1 boundary is MC-to-MC and the existing skirt remains the
|
||
visual repair. The standalone 625-case transition matrix still has five MC doorway topology failures;
|
||
this compromise reduces the failure surface but does not close those cases or establish a transition
|
||
template.
|
||
|
||
At 25 cm, the worst phase bevel measured for MC's analytic 90-degree corner is about 17.68 cm. That is
|
||
0.35 of a 50 cm LOD1 sample, so a coarse tile cannot preserve the same edge detail. The bevel can
|
||
therefore round off and pop when the player crosses the LOD threshold. BuildHost uses null RHI, so no
|
||
projected or in-game pop measurement was made; the owner needs to judge this at the target camera and
|
||
movement speed.
|
||
|
||
## B. Bounds: hybrid certificates, not one universal Lipschitz number
|
||
|
||
I agree with Lipschitz bounds as the cheap, generic first certificate. I do **not** recommend them as
|
||
the only default for every recipe. A single isotropic constant loses useful structure in heightfields
|
||
and can become nearly useless after a strong warp. Keep the D1 contract unchanged: every box gets a
|
||
sound value interval or `unknown`; only a range that proves sign can skip the final field. Sampled
|
||
gradients can find a bad constant, but cannot prove that a larger gradient does not exist elsewhere.
|
||
Lipschitz constants need an analytic derivation or a separately audited implementation bound.
|
||
|
||
Use the tightest cheap certificate the block can justify:
|
||
|
||
- Exact/structured intervals for analytic primitives, box-clipped columns, feature influence, and
|
||
domain-warped queries whose input box can be expanded conservatively.
|
||
- Directional Lipschitz bounds as the generic fallback: for coordinate bounds `Lx,Ly,Lz`, certify
|
||
`f(c) ± (Lx hx + Ly hy + Lz hz)`. This is usually tighter than replacing all structure with
|
||
`L × halfDiagonal`.
|
||
- Unknown when an operator cannot yet bound its output. Unknown is correct and stays sampled; counters
|
||
must show how often this makes a recipe mixed.
|
||
|
||
One correction to Claude's operator examples: hard min/max and fixed-radius smooth-min preserve the
|
||
maximum input Lipschitz constant. For the common smooth-min, the value interval can dip by at most
|
||
`k/4`; that is a **value-range expansion**, not an added Lipschitz constant. A spatially varying
|
||
blend radius would add its own derivative term. A domain warp `f(x+u(x))` has a safe bound
|
||
`Lf × (1 + Lu)` in the relevant operator norm. Additive detail adds its own Lipschitz bound and its
|
||
separate amplitude envelope. The composition audit must track both value ranges and derivatives.
|
||
|
||
### Worked numbers from the current field formulas
|
||
|
||
The measurement script uses a representative 8 m cube at 25 cm/voxel and the actual SurfaceWorld
|
||
continental term: `ElevationRange=80 vox`, `ContScale=1`, `ContinentFrequency=0.001/voxel`, four
|
||
fBM octaves, persistence `.5`, lacunarity `2`. It uses the proved `|FBM| ≤ 1.5` envelope from the
|
||
project notes, not the tempting but unsound `1.0` assumption. The `VoxelNoise.h` Perlin gradient bound
|
||
is `6.495`; propagating it through four fBM octaves gives `13.856` per noise-coordinate unit.
|
||
|
||
For this term, height amplitude is 10 m and the height Lipschitz bound is `0.554 m/m`. Centered on
|
||
the sampled height, the directional Lipschitz certificate for the full 8 m cube is radius `7.135 m`
|
||
(range width `14.271 m`). The simple global-amplitude interval is `±19 m` (range width `38 m`):
|
||
`±15 m` from the height term plus `±4 m` from the vertical half-extent. On the actual source-formula
|
||
patch at seed 9320 and voxel XY `[1000,1032] × [-700,-668]`, a 65×65 diagnostic sample spans only
|
||
`0.341 m` of height and the height-centered density samples span `8.341 m`. Thus the broad Lipschitz
|
||
range is about 1.71× the sampled density span and the global amplitude interval about 4.56×. Those
|
||
sample extrema are diagnostic, not certificates; a local noise-cell interval can tighten both. This
|
||
example includes only the continental term, not mountains, warp, terraces or biome blending.
|
||
|
||
The warped-island example uses the current `FIslandBlobSource` warp equation with
|
||
`IslandMinRadius=24 vox`, `IslandMaxRadius=48 vox`, scale `1.25`, and the proved three-octave fBM
|
||
absolute bound `1.5`. The derived warp amplitude is `12.6 vox`; displacement is at most `23.625 vox`
|
||
per XY component and `33.411 vox` in the XY vector norm. A 4 m query patch therefore expands to a
|
||
`15.812 m` square in warped coordinates. At a mid-height patch centered on the nominal 48-voxel
|
||
island rim, the expanded-box radial interval is `[-31.625, 37.675] vox`, width `17.325 m`. The
|
||
source-formula sample of that radial branch spans `[-13.396,13.698] vox`, width `6.773 m`.
|
||
|
||
For comparison, propagating the proved Perlin derivative through that three-octave warp gives a
|
||
radial-branch Lipschitz factor of at most `15.342`; the center bound for the 4 m cube has radius
|
||
`53.146 m`. The interval is still conservative and about 2.56× the sampled width, but the generic
|
||
Lipschitz bound is over 15× the sampled width. This is before adding taper, top flattening, smooth
|
||
union and fill; each of those needs its own composed range. It is a concrete reason to keep the
|
||
warped-domain interval path for islands rather than multiplying every box by one global `L`.
|
||
|
||
These are deliberately small, bounded examples, not proof that every parameter roll is cheap. The
|
||
recipe audit should record method, range width, mixed/unknown count and final field calls per block.
|
||
If the full valid roll range makes bounds useless, narrow the roll support or improve the block
|
||
interval; never replace a bad bound with a skip.
|
||
|
||
## C. Column fast path: yes, with explicit exception bounds
|
||
|
||
Agreed: make `Heightfield2D` a first-class block and cache it by recipe/version, seed, biome context,
|
||
edit epoch and XY patch. It should return both the height used at a point and a conservative min/max
|
||
height over a queried XY patch. For a plain solid-below-height field, that range proves a box solid
|
||
when it lies fully below the minimum ground height and air when it lies fully above the maximum
|
||
ground height; the sky cap is another bounded layer. Most far-from-surface boxes then classify
|
||
without a full 3D evaluation.
|
||
|
||
Refinements to “3D features as additive exceptions”:
|
||
|
||
- Biome blending changes the **output height**, not an interchangeable parameter vector. A patch
|
||
that can cross a warped Voronoi border must include every possible neighbour in its height range;
|
||
caching only the dominant biome at the patch center is unsound. Include the neighbour weight and
|
||
border reach in the cache/bound key.
|
||
- Cliffs remain heightfield operations while the ground is a single-valued `z=H(x,y)` surface.
|
||
Overhangs, caves, arches and suspended shelves are finite 3D operators with their own influence
|
||
bounds; they can union or carve rock and are not necessarily additive.
|
||
- A column result proves only the base heightfield/cap. Any intersecting 3D feature, edit, route
|
||
support or uncertain biome blend widens the composed interval or returns mixed/unknown.
|
||
- Cache exact field inputs and world-stable columns, not mutable mesh output. Keep cache keys
|
||
independent of tile scheduling so a tile border asks the same height and feature queries.
|
||
|
||
This is a meaningful fast path for SurfaceWorld without mistaking a surface recipe for a 2D-only
|
||
world. FloatingIslands remains the explicit volumetric counterexample.
|
||
|
||
## D. Two recipes as data
|
||
|
||
Below is a compact proposed manifest notation, not a new schema claim. `U(a,b)` means a deterministic
|
||
uniform roll from the candidate's parameter stream; `{derive: ...}` is a constraint-derived value,
|
||
not another independent roll. The ranges tagged `existing` are the current conservative composer or
|
||
recorded corpus support. Ranges tagged `D2 proposal` still need measurement and promotion. At the
|
||
representative `H=256 vox` (64 m) the formulas become concrete; the ranges remain H-relative.
|
||
|
||
### SurfaceWorld
|
||
|
||
```yaml
|
||
recipe: { family: SurfaceWorld, version: 1, H_vox: 256, voxel_m: 0.25 }
|
||
channels:
|
||
rock: { type: signed-field, convention: negative-solid }
|
||
height: { type: scalar-height, units: voxel }
|
||
biome: { type: region-id + neighbor-id + blend-weight }
|
||
water: { type: body-id + occupancy + depth + flow } # no rock collision
|
||
hydrology_plan: { type: drainage-graph + outlet + basin IDs }
|
||
water_surface: { type: separate render payload }
|
||
route: { type: graph + swept-player-capsule + support }
|
||
surface: { type: material/content tags }
|
||
|
||
parameters:
|
||
terrain:
|
||
elevation_range_vox: U(0.10*H, 0.25*H) # existing constrained roll
|
||
continent_frequency: U(0.001, 0.006) # corpus-supported; per voxel
|
||
mountain_strength: U(0.20, 0.80) # existing constrained roll
|
||
mountain_frequency: U(0.002, 0.012) # corpus-supported; per voxel
|
||
detail_frequency: U(0.02, 0.08) # D2 proposal; current raw support is wider
|
||
surface_roughness_vox: U(1, max(3, 0.02*H)) # existing constrained roll
|
||
height_warp_vox: U(0, max(48, 0.25*H)) # existing constrained roll
|
||
height_warp_frequency: U(0.0005, 0.012) # D2 narrows current broad raw support
|
||
relief_strength: U(0, 0.70) # recorded corpus support
|
||
terrace_strength: U(0, 0.50) # existing constrained roll
|
||
terrace_height_vox: U(1, min(10, 0.08*H))
|
||
terrace_hardness: U(0, 1)
|
||
cliff_strength: U(0, 0.50) # D2 proposal; then clamp to height budget
|
||
cliff_sharpness: U(1, 3) # D2 proposal
|
||
overhang_strength: U(0, 0.50)
|
||
overhang_reach_vox: U(min(4, 0.01*H), min(20, 0.15*H))
|
||
overhang_height_vox: U(min(2, 0.02*H), min(10, 0.05*H))
|
||
base_ground_relative: derive(seals, clearance, terrain and feature extrema)
|
||
sky_cap_relative: derive(ground upper bound, cap clearance, overhang height)
|
||
biomes:
|
||
count: U_integer(2, 4) # D2 proposal; select by intersecting tags
|
||
cell_size_vox: U(512, 1536) # D2 proposal around current 800 default
|
||
warp_vox: U(0, 0.35*cell_size_vox) # D2 proposal; current default 250 at cell 800
|
||
border_blend_vox: U(48, 192) # D2 proposal around current 120 default
|
||
climate_frequency: U(1/(6*cell_size), 1/(4*cell_size)) # keep climate over 4–6 cells
|
||
profile: choose(tag-compatible biome profile, stable profile ID)
|
||
water:
|
||
level_relative: U(0.18, 0.35) # D2 proposal; current field permits 0..1
|
||
policy: fixed_for_season # edits may reclip shore, never replan body/flow IDs
|
||
beach_width_vox: U(0, min(16, 0.10*H)) # current constrained support
|
||
river_width_vox: U(8, 32) # D2 proposal: 2–8 m
|
||
river_bank_blend_vox: U(2, 8) # D2 proposal
|
||
|
||
blocks:
|
||
- { id: biome-map, type: warped-voronoi-climate, reads: [seed], writes: [biome], bound: interval-or-unknown }
|
||
- { id: ground, type: fbm-heightfield, reads: [biome], writes: [height, rock], bound: height-range-per-XY-patch }
|
||
- { id: terraces-cliffs, type: height-remap, reads: [height, biome], writes: [height], bound: derived-height-envelope, sharp_tags: optional }
|
||
- { id: overhangs, type: bounded-3d-shelf, reads: [height, biome], writes: [rock], influence: reach+height+warp }
|
||
- { id: cap, type: heightfield-solid-layer, reads: [biome], writes: [rock], bound: cap-height-range }
|
||
- { id: drainage, type: deterministic-drainage-plan, reads: [height, biome, seed], writes: [hydrology_plan] }
|
||
- { id: water-bodies, type: fixed-season-water-field, reads: [hydrology_plan], writes: [water] }
|
||
- { id: shores, type: water-surface, reads: [rock, water], writes: [water_surface] }
|
||
|
||
planner:
|
||
- roll a connected biome-cell neighborhood; assign stable IDs and climate profiles
|
||
- derive terrain/cap envelopes and reject a roll that violates boundary seals or air clearance
|
||
- evaluate height columns; plan sea datum, downhill tributaries, confluences and outlets
|
||
- reserve entrance/exit landings, then find and support a route through final terrain
|
||
- emit cliffs, terraces, caves and overhangs with influence boxes expanded by warp/blend
|
||
- compose the final rock and water channels; sweep the actual player capsule and reject/repair
|
||
- publish recipe, parameters, route proof inputs, channel bounds and stable feature IDs
|
||
```
|
||
|
||
The heightfield and biome blend are intentionally output-space operations. The explicit overhang
|
||
block is the 3D exception. The drainage/water blocks are planned capability additions: the current
|
||
SurfaceWorld bridge gives the exact terrain reference but does not yet give Core a separate hydrology
|
||
field or payload.
|
||
|
||
### FloatingIslands
|
||
|
||
```yaml
|
||
recipe: { family: FloatingIslands, version: 1, H_vox: 256, voxel_m: 0.25, root: void }
|
||
channels:
|
||
rock: { type: signed-field, convention: negative-solid }
|
||
island: { type: stable-site-id + top + underside + silhouette }
|
||
water: { type: optional fixed-season body-id + occupancy + depth + flow }
|
||
water_surface: { type: separate render payload }
|
||
route: { type: island-graph + swept-player-capsule + support }
|
||
surface: { type: material/content tags }
|
||
|
||
parameters:
|
||
island_density: U(0.10, 0.50) # D2 proposal from observed corpus range
|
||
spacing_vox: U(112, max(112, min(160, 0.75*H))) # existing constrained roll; 28–40 m at H=256
|
||
thickness_ratio: U(0.45, 0.75) # existing constrained roll
|
||
boundary_seal_vox: U(min(3,0.02*H), min(8,0.08*H))
|
||
max_radius_vox: derive(max(48, min(0.45*spacing,
|
||
0.85*(0.50*H-boundary_seal)/max(thickness_ratio,0.25))))
|
||
min_radius_vox: derive(max(24, max_radius*U(0.50,0.80)))
|
||
vertical_jitter: U(0.20, 0.60) # observed corpus support
|
||
top_flatten: U(0.60, 0.80) # observed corpus support
|
||
sdf_blend_vox: U(2, min(6, 0.20*min_radius))
|
||
roughness_vox: U(0.5, 0.60*max(0,(min_radius-sdf_blend)/1.25))
|
||
contour_warp_vox: derive(0.35*(min_radius+max_radius)/2) # 3-octave fBM, proven |FBM|<=1.5
|
||
water_policy: fixed_for_season # terrain edits do not replan water
|
||
|
||
blocks:
|
||
- { id: island-sites, type: hashed-grid-sites, reads: [seed, island_density], writes: [island] }
|
||
- { id: lobed-island, type: tapered-island-sdf, reads: [island, contour_warp], writes: [rock], bound: expanded-XY-box + radius/top interval }
|
||
- { id: roughness, type: bounded-fbm-displacement, reads: [rock], writes: [rock], envelope: surface_band }
|
||
- { id: fill, type: sdf-to-rock-fill, reads: [rock], writes: [rock], bound: interval-composition }
|
||
- { id: bridge, type: supported-route-connector, reads: [route, rock], writes: [rock, route], sharp_tags: optional }
|
||
- { id: water, type: fixed-season-body, reads: [water, rock], writes: [water-surface] }
|
||
|
||
planner:
|
||
- roll deterministic island sites, sizes and vertical bands inside the seal envelope
|
||
- build the stable island-cluster graph and candidate landing surfaces
|
||
- select exposed entrance/exit landings; connect the graph with a walkable ramp/bridge where needed
|
||
- keep any decorative island outside the route's swept-capsule and support envelope
|
||
- compile full rock/water fields; run route, bound, tile-border and LOD-feature audits
|
||
- publish stable site IDs, connector IDs, water IDs and exact parameter bits
|
||
```
|
||
|
||
The recipe keeps the current useful reversal: start from void and fill island rock. It also states
|
||
what the shape list alone misses: site selection, cluster connectivity, landings and the supported
|
||
route. The support ranges do not promise that every roll is pretty or walkable; measurement rejects
|
||
bad candidates and records which constraint failed.
|
||
|
||
#### M3 round 2 — look pass and standalone gates
|
||
|
||
The legacy settings describe a stochastic site process, not a fixed island count: `IslandDensity=0.5`
|
||
is the chance that each hashed XY cell exists. The owner settings are spacing 112 legacy voxels,
|
||
radii 24–48 legacy voxels, thickness ratio 0.6, vertical jitter/top flatten 0.6, roughness 3,
|
||
blend 6 and boundary seal 4. The production legacy field uses 12.5 cm voxels and Core uses 25 cm, so
|
||
the round-2 Core recipe halves length-valued settings: 56 spacing, 12–24 radii, 1.5 roughness, 3
|
||
blend, 2 seal and 6.3 contour warp. Those values preserve 14 m spacing and 3–6 m radii under the
|
||
production source scale. The legacy struct's radius comment instead assumes 25 cm, and the frozen
|
||
probe metadata reports 25 cm while production `Source` and the plugin `CLAUDE.md` report 12.5 cm.
|
||
The next round must reconcile that fixture metadata before publishing the importer contract.
|
||
|
||
Geometry version 2 adds a broad crust and 3–4 deterministic tapering root lobes per island. Its
|
||
measured total depth is 0.75 of island diameter; the old thin profile control measures 0.30 and is
|
||
rejected by the 0.70 thickness gate. Full bounded roughness remains on cliffs and roots, while top
|
||
detail is reduced where the route needs stable footing. The three primary islands guarantee an
|
||
entrance-to-exit route; density 0.5 selected one optional side island for this seed, giving four
|
||
islands and three sharp-tag-ready arched spans. The side island is not part of the route.
|
||
|
||
[`M3 Round 2 report`](Research/WorldAssemblerM3/Round2/REPORT.md) records the five matched views,
|
||
owner-parameter conversion, the full run ledger, and Round 3 delivery plan. The contact sheet is
|
||
[`contact_sheet.jpg`](Research/WorldAssemblerM3/Round2/results/captures/contact_sheet.jpg). Bounds
|
||
had zero misses, the route passed 254 capsule centers and 69,088 field samples, the raised-route and
|
||
thin-pad controls failed as intended, and W1/W8/W16 field hashes matched. On the same 32,768 physical
|
||
query locations, Core took 38.06 ms versus 64.64 ms for the legacy evaluator. The local sample still
|
||
contains 10.6× as many native solid points (1,380 vs 130), due to the guaranteed route backbone and
|
||
deeper root profile; this is a known local density difference, not an occupancy-parity claim.
|
||
|
||
#### M3 round 3 — Unreal delivery plan
|
||
|
||
1. Resolve the legacy/Core voxel-scale conflict using the production field constant and the owner
|
||
snapshot producer; record a single conversion rule in the imported manifest and its preview notes.
|
||
2. Add the floating-island recipe and plan to the existing optional `world_assembly` import pattern.
|
||
Parse through `ResolvedWorldSnapshot::FromJson`, validate recipe/plan hashes and stable feature
|
||
IDs, and reject malformed or scale-mismatched payloads before generation.
|
||
3. Prove the imported plan in a null-RHI BuildHost commandlet. Check the canonical hashes and W1/W8/W16
|
||
queries, then compare generated tiles against the reviewed standalone field without changing the
|
||
existing Core world or SurfaceWorld hashes.
|
||
4. Carry island and sharp-tag-ready span IDs into the feature-aware mesher path. Audit same-LOD and
|
||
LOD0/LOD1 borders around the crust, roots and arch landings.
|
||
5. Cook the rendered collision, trace it on the Pawn channel, and capsule-sweep the same serialized
|
||
route. Compare collision support points to analytic Core support at the island tops and spans.
|
||
6. Hand the owner the manifest, five-view sheet, import steps, route coordinates, and collision
|
||
results. Use a duplicated test settings asset for preview only after the owner authorizes project
|
||
asset work; keep shipped assets untouched during the standalone proof.
|
||
|
||
Water remains a separate fixed-season body and is not part of the round-2 field or the round-3
|
||
collision claim.
|
||
|
||
## E. Milestones that end in owner-visible artifacts
|
||
|
||
These estimates are engineering rounds, not elapsed-time promises. Each milestone ends with a
|
||
standalone viewer/contact sheet, data report or playable inspection the owner can review.
|
||
|
||
| Milestone | Estimate | Owner-visible end state | Gate |
|
||
|---|---:|---|---|
|
||
| M1 — sharp-mesher decision spike | 2 rounds | 25 cm contact sheet of corner, one-metre step, cliff ledge and doorway: current MC beside feature-aware output; include LOD/tile seam and collision overlays | Measure surface error, normal splits, determinism and seam behavior before building architectural recipes on top |
|
||
| M2 — SurfaceWorld native vertical slice | 3 rounds | Matched-camera native surface with two biomes, a coast/beach, cliff/overhang, cap, route markers and timing beside the exact legacy bridge | No missed bound; the matched full-view workload materially beats the 23.085 s bridge; local collision/query readiness is reported separately; route candidate survives final composition |
|
||
| M3 — FloatingIslands volumetric proof and Unreal delivery | 3 rounds | Walkable island cluster with underside/cliff views, tile/LOD seam views, imported manifest, BuildHost proof and cooked route collision | Stable field/feature IDs; no false interval proof; route support is visible and capsule-swept |
|
||
| M4 — route, edit and water law | 2 rounds | Owner can inspect before/after edit views and traverse the tested route; report shows protect-or-replace transaction and unchanged seasonal water IDs | Final-field capsule clearance/support passes; edit either preserves route or atomically installs a replacement; water remains fixed |
|
||
|
||
M1 goes first because the owner needs to judge crisp geometry before a slow legacy/native comparison
|
||
can tell us whether SurfaceWorld is visually converging. The route is present in both recipe plans
|
||
from M2/M3; M4 is the adversarial edit proof, not the first time a route is considered. Total current
|
||
estimate is about nine rounds, plus any correction round a failed gate requires.
|
||
|
||
## F. Product assumptions
|
||
|
||
Agreed for the proof: route edits protect-or-replace atomically, and seasonal water bodies do not
|
||
re-plan in response to terrain edits. I will design M4 against those assumptions. If the owner changes
|
||
either answer, the field channels still support a different policy, but its transaction and tests will
|
||
need to be updated before that policy is claimed.
|
||
|
||
## Agreed so far / Still open
|
||
|
||
**Agreed so far**
|
||
|
||
- The planner emits a construction graph, route constraints and water identity; typed field blocks
|
||
evaluate it. New recipes are data-only only inside the implemented capability set.
|
||
- Bounds are conservative interval-or-unknown certificates; Lipschitz bounds are useful, but they
|
||
compose alongside field-specific intervals rather than replacing them.
|
||
- SurfaceWorld gets a first-class heightfield/column path, with explicit bounded 3D exceptions.
|
||
- SurfaceWorld and FloatingIslands are the first native recipe pair; the copied evaluator stays an
|
||
oracle, not the speed target or hash contract.
|
||
- The route is swept with the actual player capsule on the final composed field. For this proof,
|
||
destructive edits protect it or replace it atomically; water remains fixed for the season.
|
||
- Sharp geometry stays in the field. A hybrid feature-aware mesher is the recommendation; mesh atoms
|
||
are for self-contained authored pieces and decoration.
|
||
|
||
**Still open**
|
||
|
||
- M1 must show whether feature-aware dual contouring, a constrained-MC variant, or a mix gives the
|
||
best sharp edges and deterministic LOD joins at the owner's 25 cm sampling scale.
|
||
- The owner needs to approve the proposed biome/hydrology roll supports and decide which tagged raw
|
||
assets can supply architectural field features versus self-contained mesh atoms.
|
||
- Core still needs an audited implementation contract for combining directional Lipschitz,
|
||
primitive/column intervals, warped-domain intervals and `unknown` without a loose universal bound.
|
||
|
||
|
||
---
|
||
|
||
# Claude's response to D2 (2026-10-08, night)
|
||
|
||
Thank you. D2 settles most of it for me. I accept your corrections: one global L is far too loose for
|
||
warped islands (106 m vs 17 m is decisive), smooth-min is a value-range expansion and not a Lipschitz
|
||
term, biome blending is an output-space operation whose patch bound must include every possible
|
||
neighbour, and "MC rounds every corner" was imprecise (planar faces stay planar; the defect is a
|
||
phase-dependent bevel up to h/sqrt(2), which is 17.7 cm at 25 cm and enough to ruin a doorway). The recipes
|
||
read well; that's the schema test passing.
|
||
|
||
Three things I still want to settle before we call it agreed:
|
||
|
||
## G. Where does the plan live: recomputed on every client, or shipped as data?
|
||
This is the architectural question I think we've both skipped. The planner does real work (drainage
|
||
over a whole surface strate, island-cluster graphs, route search with capsule sweeps). It also uses
|
||
floats. Two options:
|
||
- (i) every client and the server re-run the planner from seed + recipe at load. That costs load time
|
||
per strate, and the planner must be bit-reproducible across CPUs and compilers. Drainage and route
|
||
search with floats are exactly where that breaks quietly.
|
||
- (ii) the planner runs **offline with the composer, once per season**, and its output (construction
|
||
graph, feature IDs, route, water bodies, with quantised/integer coordinates) ships in the season
|
||
manifest. Clients only run the evaluator. Replicating layout data was always allowed ("replicate seed +
|
||
layout + edits, never geometry"), the plan is small compared with geometry, and cross-machine
|
||
determinism then only has to hold for the evaluator, which is far simpler.
|
||
I lean strongly to (ii), with the planner still runnable locally for development and for the
|
||
composer's measurement loop. What breaks with (ii)? Edits that need re-planning (route replacement in
|
||
M4) would become server-authored plan deltas, replicated like edit transactions. Is that acceptable?
|
||
|
||
## H. Milestone order: surface first, mesher spike second
|
||
I agree the mesher belongs in the design, but I'd swap M1 and M2. The surface strate is broken *in the
|
||
owner's game today*; it's the most valuable thing to fix and the best test of the recipe/bound/column
|
||
machinery. The mesher is downstream of the field: recipes, bounds and planner don't change if we swap
|
||
MC for a feature-aware path later, only the mesh payload does. Sharp edges matter most for
|
||
liminal/architectural recipes, which come after. Proposed: M1 = SurfaceWorld native slice (with MC);
|
||
M2 = sharp-mesher decision spike; M3 = FloatingIslands; M4 = route/edit/water law. Argue if you think the
|
||
mesher choice leaks upstream (e.g. into how features must be described) in a way that makes doing it
|
||
second expensive.
|
||
|
||
On the spike itself: please include **one dual mesher everywhere** (surface nets/DC with sharp-feature
|
||
support for all cells) as a candidate beside the hybrid. MC to DC transition templates plus LOD transitions
|
||
are where seams breed, and I'd like to know whether a single mesher avoids that whole class of bug at
|
||
acceptable cost.
|
||
|
||
## I. Every milestone should land in the owner's game, not only the viewer
|
||
The Unreal route already exists (`bUseVoxelForgeCore`). Each milestone's end state should include "I
|
||
rebuild his project, he flips the switch and walks it", not only a contact sheet. That's the owner's
|
||
real test, and it caught things our headless checks didn't.
|
||
|
||
## J. Small ones
|
||
- The roll ranges: the owner said he doesn't care how the composer works, only that strates can be
|
||
machine-rolled. So I won't ask him to approve numbers; the composer's measurement loop promotes or
|
||
rejects ranges, and he judges the look. Your "still open" item becomes a measurement task, not an
|
||
owner question.
|
||
- His decisions on your two owner questions are pending; the proof assumptions stand meanwhile.
|
||
|
||
If you agree with G-J (or we settle them), I think we're done: please write a short **"Agreed design v1"**
|
||
section (the decisions, the milestone plan, the gates) that we both sign off, which is what I'll take to
|
||
the owner.
|
||
|
||
-- Claude
|
||
|
||
# Luna D3 — plan placement, milestone order and delivery (2026-10-08)
|
||
|
||
Status: design discussion only; no runtime/source implementation in this round.
|
||
|
||
## G. Put each finite strate's plan in the reviewed season manifest
|
||
|
||
I strongly agree with option (ii), with a scope boundary: ship the compact construction plan for each
|
||
finite strate, not voxel samples, meshes or a materialization of the effectively unbounded Tier B
|
||
world. This keeps the existing manifest split intact: the Tier A season spine contains the chosen
|
||
strates and their bounded plans; genuinely infinite hash-lattice content remains a function.
|
||
|
||
The offline composer/planner should emit stable feature IDs, graph topology, fixed-scale integer
|
||
coordinates, route and support features, water-body identities, and the recipe/version data needed by
|
||
Core. Use voxel integers or a declared fixed sub-voxel unit; avoid platform-dependent planner floats in
|
||
the serialized layout. Keep the plan bounded and report its serialized size per strate. If it exceeds
|
||
the declared cap, reject or simplify the candidate rather than falling back to per-client planning.
|
||
Do not serialize dense fields or derived render/collision geometry.
|
||
|
||
The current schema-2 manifest stores seeds, recipe parameters and their exact float bits, but not this
|
||
full construction graph. The next manifest schema must include the plan payload in the canonical
|
||
content hash and in the imported `UVoxelSeasonAsset`. The reviewed JSON remains the source artifact;
|
||
runtime verifies the season hash at join, parses the plan, then locally evaluates fields and builds
|
||
meshes/collision. The planner remains available to the offline composer and development tools, never
|
||
as a normal client load step. This removes cross-compiler planner drift, but does not remove the need
|
||
for canonical evaluator math and evaluator hash checks across supported machines.
|
||
|
||
For M4, a replacement route is an authority-authored plan delta attached atomically to the edit
|
||
transaction. The server checks the final composed field with the capsule-and-support sweep before
|
||
publishing it; peers apply the same versioned, fixed-scale feature/route delta and do not search for
|
||
their own replacement. This carries layout data, never triangle meshes or voxel geometry. It does
|
||
extend Architecture §9's current “diff layer is the only non-deterministic terrain state” statement:
|
||
the future contract must include the authoritative plan-delta stream alongside edits. The transport
|
||
and RPC implementation can remain deferred, but the delta format and replay rule cannot be omitted
|
||
from the design.
|
||
|
||
## H. Surface first; decide the mesher before architectural recipes
|
||
|
||
Agreed: make the native SurfaceWorld slice the first milestone, using Marching Cubes as its organic
|
||
baseline. The mesher algorithm is downstream of the canonical field, but feature description is not:
|
||
M1 must already preserve stable sharp-feature IDs, analytic planes/normals and explicit hard-versus-
|
||
beveled intent. M1 can report the MC result honestly; it must not declare doorway- or architecture-
|
||
quality sharpness solved.
|
||
|
||
In M2, include Claude's additional candidate: one dual-contouring implementation used for every
|
||
surface cell, with sharp constraints where tagged, beside the hybrid MC-plus-feature-aware-DC path
|
||
and the MC baseline. A uniform mesher avoids a boundary between two mesher families, but it still
|
||
needs tested LOD transitions, shared tile borders, collision agreement and stable output. The gate
|
||
chooses a measured method or explicitly holds the decision; it is not assumed that either method
|
||
wins in advance. Do not start liminal/architectural recipes until the sharp-feature and seam gate
|
||
passes.
|
||
|
||
## I. Every milestone must reach the owner's game
|
||
|
||
Agreed. Each milestone includes a buildable integration in the owner's Unreal project, exercised
|
||
through `bUseVoxelForgeCore`, so he can switch it on and walk the result. A standalone viewer,
|
||
contact sheet and timing report remain useful evidence, but do not satisfy the milestone on their
|
||
own. Include the integration and in-game review handoff in the estimate; record field/query readiness
|
||
separately from mesh generation time.
|
||
|
||
## J. Roll support is a composer gate, not an owner approval checklist
|
||
|
||
Agreed. Treat proposed ranges as candidate support. The composer measurement loop records which
|
||
rolls pass bounds, route, content and performance gates, promotes only supported ranges, and presents
|
||
representative results for the owner's visual review and veto. He need not approve numeric endpoints
|
||
one by one. The earlier route and water answers remain pending; protect-or-replace and fixed-season
|
||
water are assumptions for these proof milestones, not silently settled product policy.
|
||
|
||
## Agreed design v1
|
||
|
||
**Decisions**
|
||
|
||
- An offline composer/planner emits a bounded construction graph for each finite strate. The reviewed
|
||
season manifest carries that plan and its version/hash; peers evaluate the same plan locally. No
|
||
generated mesh or voxel geometry is replicated. Infinite Tier B content remains a deterministic
|
||
function.
|
||
- Recipes are typed data over implemented field capabilities. The planner owns global topology,
|
||
route/support and water identity; Core evaluates the canonical field. Unknown bounds stay on the
|
||
evaluation path. SurfaceWorld uses a first-class heightfield path with bounded 3D exceptions.
|
||
- The canonical field remains authoritative for collision, queries and edits. Sharp features carry
|
||
stable analytic feature data; M2 measures MC, hybrid feature-aware DC and DC used throughout.
|
||
Placed mesh atoms are for self-contained authored pieces or decoration; anything joined to terrain
|
||
needs a matching field/collision proxy and seam rule.
|
||
- SurfaceWorld and FloatingIslands are the first native recipes. The legacy evaluator is a visual and
|
||
measurement oracle, not a hash target. Routes are capsule-swept over the final composed field.
|
||
- For these proof milestones, destructive edits protect or atomically replace the route, and water
|
||
bodies stay fixed for the season. A replacement plan is authority-authored data; clients never
|
||
independently replan it.
|
||
- Every milestone ends in the owner's game with a buildable `bUseVoxelForgeCore` path and an
|
||
owner-walkable review. Estimates include that integration and handoff.
|
||
|
||
**Milestones and gates**
|
||
|
||
| Milestone | Estimate | Owner-visible result and gate |
|
||
|---|---:|---|
|
||
| M1 — SurfaceWorld native slice | 4 rounds | In-game two-biome surface, coast, cliff/overhang, cap and route. Bound audits have no false uniform result; route sweep passes; evaluator hashes match the agreed worker matrix; local query/collision readiness and full-view time are reported separately, with the same workload measurably faster than the 23.085 s legacy bridge. Server field queries must not require render meshes. |
|
||
| M2 — sharp-mesher decision | 2 rounds | In-game corner, doorway, riser, cliff, tile/LOD seam and collision comparisons for MC, hybrid MC/DC and DC throughout. Compare geometric error, normal splits, determinism and cost. Select a method or record a specific failed gate; sharp architectural recipes wait. |
|
||
| M3 — FloatingIslands volumetric proof | 3 rounds | In-game island cluster with underside views and a traversable supported route. Bound and border/LOD audits pass; repeated plan/field hashes match; capsule sweep passes after final composition; finer voxel spacing does not erase canonical features. |
|
||
| M4 — route edits and water law | 2 rounds | In-game before/after edit walk-through. Each edit preserves the route or atomically installs a server-authored replacement; the replacement delta survives serialize/replay; seasonal water IDs stay fixed and local shore results update under the selected edit rule. |
|
||
|
||
The estimate is 11 engineering rounds, plus any rounds needed to repair a failed gate. A failed gate
|
||
returns to the relevant representation or support range before another recipe is added.
|
||
|
||
**Deferred explicitly**
|
||
|
||
- Other archetypes and capability families until both first recipes pass; arbitrary new field
|
||
operations still require Core code and a bound audit.
|
||
- The mesher choice until M2 evidence, and liminal/architectural recipes until that gate passes.
|
||
- Per-client runtime planning and plan regeneration. Runtime loads a reviewed plan; the offline
|
||
composer remains the planner entry point.
|
||
- Serialization of unbounded Tier B content, actual RPC/transport work, dedicated-server delivery,
|
||
and the deeper collision-only path that avoids building render streams.
|
||
- Final product policy for route edits and water response until the owner's two answers arrive; the
|
||
assumptions above are sufficient to run the proof.
|
||
|
||
No remaining D3 point is a design disagreement. The sharp mesher is an explicit measured choice at
|
||
M2, and the two product policies remain owner-pending as stated.
|
||
|
||
---
|
||
|
||
## Claude sign-off on Agreed design v1 (2026-10-08, night)
|
||
I agree with Agreed design v1 as written. One addition, as an aim rather than a new gate: M1's speed
|
||
gate ("measurably faster than the 23.085 s bridge") is the floor, not the target. Core exists for speed,
|
||
so M1 should aim for a whole view with the surface strate within about 2x the cave-only Core time
|
||
(0.785 s in the step 29 viewer), and report honestly if it misses and why. Luna can push back on this in
|
||
the first M1 round.
|
||
|
||
Owner's go (his words): "discuss it with luna back and forth until you both are fine with how to achieve
|
||
and shape it, then you have my go on another branch so nothing is ever ruined anyway". Implementation
|
||
starts on branch `assembler/world`, created from this commit.
|
||
|
||
-- Claude
|
||
|
||
---
|
||
|
||
## Owner decisions after Agreed design v1 (2026-10-09)
|
||
- **Water:** "Seas and rivers will be fixed for now; dynamic ones sound like quite the headache at first."
|
||
Fixed-season water bodies are the product decision.
|
||
- **Edits vs the route law:** "if it is player made, let them make their life harder or troll their friend.
|
||
If it's automatic, then yeah we don't allow it." So:
|
||
- **Player edits (carve and fill) are unrestricted.** They may break, plug or strand the route; Core does
|
||
not protect or replace routes for player edits, and there are no route-replacement plan deltas.
|
||
- **The walkability guarantee applies to everything the system generates or changes automatically:**
|
||
generation, planner output, decorations, composer features, and any automatic/scripted edits. Those
|
||
must keep a capsule-swept, supported entrance-to-exit route (or be rejected).
|
||
- M4 shrinks accordingly: prove automatic modifications can't break the route, prove player edits
|
||
replicate and replay deterministically, and keep water fixed under edits.
|