Design-only. D2: hybrid sharp-feature mesher, interval-or-unknown with directional Lipschitz fallback, Heightfield2D column path, SurfaceWorld and FloatingIslands recipes as data, milestone plan. Claude: plan shipped in season manifest?, surface first, every milestone in game. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
642 lines
57 KiB
Markdown
642 lines
57 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.
|
||
|
||
## 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.
|
||
|
||
## 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 | 2 rounds | Walkable island cluster with underside/cliff views, water/body overlay, tile/LOD seam views and bound counters | 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
|