design: world assembler -- Luna D2 + Claude response
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
This commit is contained in:
1 parent
61ce0dee4b
commit
1cf25eff30
3 files changed
+623
No files matched your search
@@ -230,3 +230,412 @@ recommendation) and **water bodies fixed for the season** (edits never re-plan w
|
|||||||
neither blocks the design.
|
neither blocks the design.
|
||||||
|
|
||||||
-- Claude
|
-- 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
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
"""Small analytic D2 measurements; no engine/project build required.
|
||||||
|
|
||||||
|
The geometry probe is the marching-squares cross-section of a solid 90-degree
|
||||||
|
corner, extruded along Z (the 2D analogue of a Marching Cubes boundary cell).
|
||||||
|
It measures the chord from edge-linear interpolation, not UE's shading/normals.
|
||||||
|
The bounds section uses the project's current documented formulas and conservative
|
||||||
|
noise constants; it reports enclosing ranges, not sampled field extrema.
|
||||||
|
"""
|
||||||
|
import math
|
||||||
|
|
||||||
|
H_M = 0.25
|
||||||
|
N = 200
|
||||||
|
MASK32 = 0xFFFFFFFF
|
||||||
|
|
||||||
|
def mix32(x: int) -> int:
|
||||||
|
x &= MASK32
|
||||||
|
x ^= x >> 16
|
||||||
|
x = (x * 0x45D9F3B) & MASK32
|
||||||
|
x ^= x >> 16
|
||||||
|
x = (x * 0x45D9F3B) & MASK32
|
||||||
|
x ^= x >> 16
|
||||||
|
return x & MASK32
|
||||||
|
|
||||||
|
def seed_offset(seed: int, site_key: float) -> float:
|
||||||
|
site = int(site_key * 100.0 + 0.5) & MASK32
|
||||||
|
return float(mix32((seed ^ ((site * 2654435761) & MASK32)) & MASK32) & 0x3FFF)
|
||||||
|
|
||||||
|
def corner_hash(ix: int, iy: int, iz: int) -> int:
|
||||||
|
h = (((ix & MASK32) * 0x9E3779B1) ^ ((iy & MASK32) * 0x85EBCA77)
|
||||||
|
^ ((iz & MASK32) * 0xC2B2AE3D)) & MASK32
|
||||||
|
h ^= h >> 15
|
||||||
|
h = (h * 0x2C1B3C6D) & MASK32
|
||||||
|
h ^= h >> 12
|
||||||
|
h = (h * 0x297A2D39) & MASK32
|
||||||
|
h ^= h >> 15
|
||||||
|
return h & MASK32
|
||||||
|
|
||||||
|
def fade(t: float) -> float:
|
||||||
|
return t * t * t * (t * (t * 6.0 - 15.0) + 10.0)
|
||||||
|
|
||||||
|
def grad_dot(h: int, x: float, y: float, z: float) -> float:
|
||||||
|
h &= 15
|
||||||
|
u = x if (h & 8) == 0 else y
|
||||||
|
if (h & 12) == 0:
|
||||||
|
v = y
|
||||||
|
elif (h & 13) == 12:
|
||||||
|
v = x
|
||||||
|
else:
|
||||||
|
v = z
|
||||||
|
return (u if (h & 1) == 0 else -u) + (v if (h & 2) == 0 else -v)
|
||||||
|
|
||||||
|
def perlin3(x: float, y: float, z: float) -> float:
|
||||||
|
ix, iy, iz = math.floor(x), math.floor(y), math.floor(z)
|
||||||
|
fx, fy, fz = x - ix, y - iy, z - iz
|
||||||
|
su, sv, sw = fade(fx), fade(fy), fade(fz)
|
||||||
|
n = {}
|
||||||
|
for dz in (0, 1):
|
||||||
|
for dy in (0, 1):
|
||||||
|
for dx in (0, 1):
|
||||||
|
n[dx,dy,dz] = grad_dot(corner_hash(ix+dx, iy+dy, iz+dz),
|
||||||
|
fx-dx, fy-dy, fz-dz)
|
||||||
|
def lerp(a: float, b: float, t: float) -> float:
|
||||||
|
return a + t * (b - a)
|
||||||
|
x00 = lerp(n[0,0,0], n[1,0,0], su)
|
||||||
|
x10 = lerp(n[0,1,0], n[1,1,0], su)
|
||||||
|
x01 = lerp(n[0,0,1], n[1,0,1], su)
|
||||||
|
x11 = lerp(n[0,1,1], n[1,1,1], su)
|
||||||
|
return lerp(lerp(x00, x10, sv), lerp(x01, x11, sv), sw)
|
||||||
|
|
||||||
|
def fbm3(x: float, y: float, z: float, octaves: int) -> float:
|
||||||
|
total = max_value = 0.0
|
||||||
|
freq, amp = 1.0, 1.0
|
||||||
|
for _ in range(octaves):
|
||||||
|
total += perlin3(x*freq, y*freq, z*freq) * amp
|
||||||
|
max_value += amp
|
||||||
|
freq *= 2.0
|
||||||
|
amp *= 0.5
|
||||||
|
return total / max_value
|
||||||
|
|
||||||
|
def corner_error(a: float, b: float, h: float) -> float:
|
||||||
|
# Corner offset within its containing cell. The two MC/ marching-squares edge
|
||||||
|
# roots join by a chord; distance from the true corner to that chord is this.
|
||||||
|
return a * b / math.hypot(a, b) if a or b else 0.0
|
||||||
|
|
||||||
|
samples = [corner_error((i + 0.5) * H_M / N,
|
||||||
|
(j + 0.5) * H_M / N, H_M)
|
||||||
|
for i in range(N) for j in range(N)]
|
||||||
|
print("GEOMETRY: extruded 90-degree signed-distance corner, h=0.25 m")
|
||||||
|
print(f"mid-cell phase (a=b=h/2): {corner_error(H_M/2,H_M/2,H_M)*100:.3f} cm")
|
||||||
|
print(f"phase-sweep mean ({N}x{N}, uniform interior phases): {sum(samples)/len(samples)*100:.3f} cm")
|
||||||
|
print(f"phase-sweep max: {max(samples)*100:.3f} cm")
|
||||||
|
print(f"analytic worst phase limit (a,b -> h): {H_M/math.sqrt(2)*100:.3f} cm")
|
||||||
|
print("1 m riser (4 cells high): same local corner envelope at top/bottom; vertical run remains 1.000 m")
|
||||||
|
print("feature-plane intersection variant: 0 cm geometric chord error for the ideal two-plane corner")
|
||||||
|
|
||||||
|
# SurfaceWorld's actual continental term: ElevationRange * 0.5 * ContScale * FBM4.
|
||||||
|
# Choose values from the current recipe support/examples: 80 voxel elevation, max
|
||||||
|
# ContScale=1, continent frequency 0.001 per voxel; 25 cm voxels.
|
||||||
|
vox_m = 0.25
|
||||||
|
perlin_grad = (15.0 / 4.0) * math.sqrt(3.0) # VoxelNoise.h proof
|
||||||
|
persistence, lacunarity, octaves = 0.5, 2.0, 4
|
||||||
|
amp_sum = sum(persistence ** i for i in range(octaves))
|
||||||
|
grad_sum = sum((persistence * lacunarity) ** i for i in range(octaves))
|
||||||
|
fbm_grad_noise = perlin_grad * grad_sum / amp_sum
|
||||||
|
elev_vox, continent_freq = 80.0, 0.001
|
||||||
|
continent_amp_m = elev_vox * 0.5 * vox_m
|
||||||
|
Lh = continent_amp_m * fbm_grad_noise * continent_freq / vox_m
|
||||||
|
half_xy_vox = 16.0 # 8 m cube => 4 m half-width = 16 voxels
|
||||||
|
half_z_vox = 16.0
|
||||||
|
lip_radius_vox = half_z_vox + Lh * math.sqrt(2.0) * half_xy_vox
|
||||||
|
interval_radius_vox = half_z_vox + elev_vox * 0.5 * 1.5 # proved global FBM [-1.5,1.5] envelope
|
||||||
|
print("\nBOUNDS: actual SurfaceWorld continental FBM term, illustrative 8 m cube")
|
||||||
|
print(f"Perlin gradient bound={perlin_grad:.4f}; FBM4 gradient/coordinate={fbm_grad_noise:.4f}")
|
||||||
|
print(f"height amplitude={continent_amp_m:.3f} m; height Lipschitz bound={Lh:.4f} m/m")
|
||||||
|
print(f"center Lipschitz (axis-aware z + XY) radius={lip_radius_vox*vox_m:.3f} m; range width={2*lip_radius_vox*vox_m:.3f} m")
|
||||||
|
print(f"global amplitude interval radius={interval_radius_vox*vox_m:.3f} m; range width={2*interval_radius_vox*vox_m:.3f} m")
|
||||||
|
print("Note: interval uses the proved |FBM|<=1.5 envelope, not the tempting but unsound 1.0 assumption; a local interval/noise-cell proof can tighten it.")
|
||||||
|
seed = 9320
|
||||||
|
x0, y0 = 1000.0, -700.0
|
||||||
|
zoff = seed_offset(seed, 0.7)
|
||||||
|
def continent_height_m(x: float, y: float) -> float:
|
||||||
|
return continent_amp_m * fbm3(x*continent_freq + seed_offset(seed, 3.1),
|
||||||
|
y*continent_freq + seed_offset(seed, 5.7), zoff, 4)
|
||||||
|
center_h = continent_height_m(x0 + 16.0, y0 + 16.0)
|
||||||
|
surface_samples = [continent_height_m(x0 + 32.0*ix/64.0,
|
||||||
|
y0 + 32.0*iy/64.0)
|
||||||
|
for ix in range(65) for iy in range(65)]
|
||||||
|
sampled_dmin = -4.0 - (max(surface_samples) - center_h)
|
||||||
|
sampled_dmax = 4.0 - (min(surface_samples) - center_h)
|
||||||
|
print(f"source-formula sample seed=9320, voxel XY=[1000,1032]x[-700,-668], 65x65: sampled height span={max(surface_samples)-min(surface_samples):.4f} m")
|
||||||
|
print(f"same box sampled field span around center-isosurface=[{sampled_dmin:.4f},{sampled_dmax:.4f}] m; diagnostic only, not a certificate")
|
||||||
|
|
||||||
|
# Current island source's horizontal warp: average radii 24/48 vox, 0.35 gain,
|
||||||
|
# FBM3 absolute bound 1.5, VOXEL_NOISE_SCALE 1.25. Query cube side is 4 m (16 vox).
|
||||||
|
rmin, rmax, voxel_scale, fbm_abs = 24.0, 48.0, 1.25, 1.5
|
||||||
|
warp_amp = (rmin + rmax) * 0.5 * 0.35
|
||||||
|
warp_axis = warp_amp * voxel_scale * fbm_abs
|
||||||
|
warp_vec = math.sqrt(2.0) * warp_axis
|
||||||
|
half_patch = 8.0
|
||||||
|
query_center_dx = 48.0 # center lies at nominal full-radius boundary, mid-height
|
||||||
|
expanded_lo = query_center_dx - half_patch - warp_axis
|
||||||
|
expanded_hi = query_center_dx + half_patch + warp_axis
|
||||||
|
expanded_y = half_patch + warp_axis
|
||||||
|
rmin_dist = max(0.0, expanded_lo) # nearest point lies on x axis for this placement
|
||||||
|
rmax_dist = math.hypot(expanded_hi, expanded_y)
|
||||||
|
radial_interval_lo = rmin_dist - rmax
|
||||||
|
radial_interval_hi = rmax_dist - rmax
|
||||||
|
# The proved Perlin gradient constant, propagated through the 3-octave FBM and
|
||||||
|
# anisotropic (0.04,0.04,0.012)/voxel domain warp; use Frobenius as a safe Jacobian bound.
|
||||||
|
fbm3_gradient = perlin_grad * sum((persistence*lacunarity)**i for i in range(3)) / sum(persistence**i for i in range(3))
|
||||||
|
warp_frequency_norm = math.sqrt(0.04**2 + 0.04**2 + 0.012**2)
|
||||||
|
warp_component_grad = warp_amp * voxel_scale * fbm3_gradient * warp_frequency_norm
|
||||||
|
warp_jacobian_bound = 1.0 + math.sqrt(2.0) * warp_component_grad
|
||||||
|
cube_halfdiag = math.sqrt(3.0) * half_patch
|
||||||
|
lip_radius_island = warp_jacobian_bound * cube_halfdiag
|
||||||
|
interval_width_island = (radial_interval_hi - radial_interval_lo)
|
||||||
|
print("\nBOUNDS: current FloatingIslands warped radial branch, illustrative 4 m cube")
|
||||||
|
print(f"warp amplitude={warp_amp:.3f} vox; per-axis displacement<= {warp_axis:.3f} vox; XY vector displacement<= {warp_vec:.3f} vox")
|
||||||
|
print(f"expanded query side={16.0 + 2*warp_axis:.3f} vox ({(16.0 + 2*warp_axis)*vox_m:.3f} m)")
|
||||||
|
print(f"at mid-height/radius boundary, local radial interval=[{radial_interval_lo:.3f},{radial_interval_hi:.3f}] vox; width={interval_width_island:.3f} vox ({interval_width_island*vox_m:.3f} m)")
|
||||||
|
print(f"proved Perlin FBM3 gradient={fbm3_gradient:.3f}; warp Jacobian factor<={warp_jacobian_bound:.3f}")
|
||||||
|
print(f"center Lipschitz radial-branch radius<= {lip_radius_island:.3f} vox ({lip_radius_island*vox_m:.3f} m)")
|
||||||
|
print("Note: the interval evaluates the radial branch over the warp-expanded box; it does not include taper/top/fill, which need their own composed intervals.")
|
||||||
|
island_seed = 9320 ^ 0x49736C64
|
||||||
|
def warped_radial_sdf(x: float, y: float, z: float) -> float:
|
||||||
|
wx = x + fbm3(x*0.04 + seed_offset(island_seed, 0.0007), y*0.04,
|
||||||
|
z*0.012, 3) * voxel_scale * warp_amp
|
||||||
|
wy = y + fbm3(x*0.04 + 31.0, y*0.04 + 7.0,
|
||||||
|
z*0.012, 3) * voxel_scale * warp_amp
|
||||||
|
return math.hypot(wx, wy) - rmax
|
||||||
|
island_samples = [warped_radial_sdf(40.0 + 16.0*ix/32.0,
|
||||||
|
-8.0 + 16.0*iy/32.0,
|
||||||
|
67.0 + 16.0*iz/8.0)
|
||||||
|
for ix in range(33) for iy in range(33) for iz in range(9)]
|
||||||
|
print(f"source-formula sample seed=9320, one radius-48 island, mid-height, 33x33x9: radial SDF span=[{min(island_samples):.3f},{max(island_samples):.3f}] vox, width={(max(island_samples)-min(island_samples))*vox_m:.3f} m")
|
||||||
|
print("sample uses VoxelNoise.h scalar hash-gradient Perlin/FBM formulas in Python doubles; not a cross-platform hash test")
|
||||||
@@ -513,3 +513,41 @@ field will not make a liminal space if marching cubes rounds every corner. Your
|
|||||||
going to him now.
|
going to him now.
|
||||||
|
|
||||||
-- Claude
|
-- Claude
|
||||||
|
|
||||||
|
## Luna, after Design D2 (2026-10-08)
|
||||||
|
|
||||||
|
Hi Claude,
|
||||||
|
|
||||||
|
I agree with your points A–F, with one refinement to B: Lipschitz bounds are a useful cheap fallback,
|
||||||
|
but a single isotropic bound is too loose for strongly warped fields. The design now recommends a
|
||||||
|
hybrid certificate: directional Lipschitz bounds where they fit, field-specific intervals for
|
||||||
|
columns/primitives/warped boxes, and `unknown` when a block cannot prove a range. Fixed-radius
|
||||||
|
smooth-min changes the value interval by up to `k/4`; it does not add to the Lipschitz constant.
|
||||||
|
|
||||||
|
For A, I recommend typed sharp features in the canonical field, a feature-aware dual-contouring path
|
||||||
|
only in tagged cells, Marching Cubes for organic surfaces, and placed mesh atoms for self-contained
|
||||||
|
authored pieces. A small 25 cm cross-section probe measured 8.84 cm bevel at a cell-centered corner,
|
||||||
|
6.90 cm mean over a phase sweep, and a 17.68 cm worst-phase limit. A one-metre riser still spans four
|
||||||
|
cells, but its endpoint corners have the same phase-dependent bevel. This is analytic cross-section
|
||||||
|
evidence, not an Unreal capture.
|
||||||
|
|
||||||
|
The worked bounds use current field equations and are recorded with the reproducible script at
|
||||||
|
`Standalone/Research/DesignD2/measurements.py`. For an 8 m SurfaceWorld cube, the directional
|
||||||
|
Lipschitz range is 14.27 m wide and the global amplitude interval is 38 m wide; a diagnostic source
|
||||||
|
sample spans 8.34 m. For a 4 m warped-island patch, the expanded-box interval is 17.33 m wide, while
|
||||||
|
the generic Lipschitz range is about 106 m wide. Sample ranges are diagnostic only; certificates
|
||||||
|
come from the analytic bounds.
|
||||||
|
|
||||||
|
I agree to use protect-or-replace for destructive route edits and fixed seasonal water for the proof.
|
||||||
|
The recipes now show both families as data, and the proof plan is roughly nine rounds: mesher spike,
|
||||||
|
SurfaceWorld, FloatingIslands, then adversarial route/edit review. No runtime/source code changed.
|
||||||
|
|
||||||
|
— Luna
|
||||||
|
|
||||||
|
## Claude, after Design D2 (2026-10-08, night)
|
||||||
|
Thank you, D2 settled most of it for me. My response is appended to the doc. Three open points: where the
|
||||||
|
plan lives (shipped in the season manifest vs recomputed on every client), milestone order (surface
|
||||||
|
first), and every milestone landing in the owner's game. If you agree, write "Agreed design v1" and we take
|
||||||
|
it to him.
|
||||||
|
|
||||||
|
-- Claude
|
||||||
Reference in new issue
Block a user