Skip to content

ground-plan step 3: the mesh on level-17 terrain nodes (#3196) - #3207

Merged
timohueser merged 6 commits into
ground-planfrom
claude/gp-mesh-level17
Nov 8, 2026
Merged

timohueser merged 6 commits into
ground-planfrom
claude/gp-mesh-level17

Conversation

@timohueser

Copy link
Copy Markdown
Owner

Step 3 of the ground plan (#3196, epic #3096): the mesh on level-17 terrain nodes, candidate (a′) of the design comment on #3196. Into ground-plan, not develop.

What changes

  • Crate (mesh/strip.rs, mesh/mod.rs): the fan of a strip cell cuts along the terrain's level-17 diagonal (north-east to south-west), so three triangles tile each half. halves(i, j) gives the two halves. The strip triangles of a half whose three corners lie on ∂R go to runs of their own, last. Head word 9 counts those runs: HEAD 10, MAGIC 0x4f424d03. New test: over 400 shapes of R, each strip cell is drawn once, by the strip or by the terrain, at level 18 and 17, and no fixed point stands on the side of a terrain half.
  • Viewer:
    • The meshes draw over mesh level M = min(finest, 18), none below 17 (meshLevel, pieces.ts). At M = 17 the draw skips the level-18 runs.
    • At level M the terrain sinks its vertices nearer than S = range / 2^18.3 and does not snap there (terrain.wgsl, cells.wgsl).
    • At finest 17 a terrain vertex of the strip is the terrain's own level-17 vertex (piece.wgsl).
    • The fade is in metres: whole to S + 2 level-17 cells, gone at range / 2^18 (corridor.wgsl).
    • meshCells keeps the cells at every finest level.
    • Hysteresis: below 17 the meshes stop in that frame. They draw again after CALM (120) frames in a row at 17 or finer. CALM moved to lod.ts, and the terrain's quality uses the same value.
    • A page of level M waits for its cell's mesh, as the level-18 page did.
  • Debug options:
    • finest=16..18 is a page option, read once (finestOf).
    • debug=owned draws the meshes green and the terrain red. It draws blue where the strip's rule gives the point to the mesh, so a blue pixel is a fault from any view.
  • All PROBE code of the prototype is removed: tie, hold, owned=cover, probe=frames, probe_a.

Deviation from the prototype: debug=owned does not blend additively. A runtime debug view would need a second set of terrain pipelines for that. The meshes draw before the terrain with the depth test, so a blue pixel already marks terrain in front of the mesh or in a hole. The count is the blue pixels.

Gates

GTX 1660 SUPER, Engelberg fixture, one page at a time under the GPU lock. Frame time is GP0's method (flight.mjs --gpu, clock held). The finest level is pinned by the quality (one step past the screen's steps), as for the prototype, except where noted.

Gate Result
obc test -p obc-ground-plan 105/105
clippy -p obc-ground-plan --all-targets -D warnings, cargo fmt --all clean
check 7 (check-bytes.sh) 256 of 256 cells give the native digest
WASM size guard (ground-plan) raw 1,798,983 / 1,802,240 B (100 %, margin 3,257 B); gzip + glue 690,759 / 704,512 B (98 %, margin 13,753 B). Passes; the raw margin is small.
vitest src/lib/trailview 412/412 (new: meshLevel, which holds the mesh level and the hysteresis)
npm run check, npm run check:wgsl 0 errors, 0 warnings; 69 ok
debug=owned, 50 top views finest 18: 4 blue px (1 px in 4 views), 0 black. Finest 17: 5 blue px (1 px in 5 views), 0 black. Each blue px lies on a mesh/terrain edge (a red pixel next to it). These are the same views and pixels as the prototype: the rounding of the rule test at triangle edges. 0 blue px off an edge. finest=17 from the address (3 views): 0.
debug=owned, walk and drive, every 10th frame finest 18: 1 px in 5 of 182 frames. Finest 17: 1 px in 9 of 182 frames. Never more than 1 px.

Frame time, all passes per frame (ms), walk / drive:

develop 9cca126 ground-plan f518fd8 this branch
finest 18 3.82 / 3.59 4.12 / 3.93 4.21 / 4.00
finest 17 3.61 / 3.44 3.61 / 3.33 (no mesh) 3.92 / 3.71

At 17 the mesh draws 436 k / 216 k triangles (18: 438 k / 217 k). At 18 the branch is 0.07–0.09 ms over ground-plan, as the prototype measured. Not traced.

Time to a clean frame (shots every 0.5 s from navigation; clean = every later shot is within 1 % of the final idle frame). This is the fixture page, not live data, so the loads are short. One run each:

View this branch, 18, cold / warm this branch, finest=17, cold / warm ground-plan, 18 develop, 18
v17 (eye 1.7 m) 5.4 / 5.6 s 5.5 / 5.3 s 5.7 / 5.3 s 5.3 / 5.5 s
m1 Trübsee 3.5 / 3.2 s 3.5 / 3.1 s 3.5 / 3.5 s 3.5 / 3.2 s

Renders at finest 17, develop | ground-plan | this branch, labelled, 9 owner views at eye height and from above: step3/runs/gates/renders/sheets/ on timosPC. At 17 this branch draws the mesh (kerbs, walls, markings). Ground-plan draws the far look there.

Not done here: the iPhone probe (IPHONE-PROBE.md). The owner runs it on the phone.

Public docs: not changed.

Requirements: none

🤖 Generated with Claude Code

timohueser and others added 2 commits November 7, 2026 21:40
…-17 halves draw last

Each strip cell's fan now cuts along the terrain's diagonal (north-east to south-west), so three
triangles tile each half of the cell. A half with all three corners on the region's border is the
terrain's own level-17 triangle: its strip triangles go to runs of their own after all others, and
head word 9 counts those runs (HEAD 10, MAGIC 0x4f424d03). Over a level-17 node the viewer skips
them; over a level-18 node it draws them.

The strip test checks over 400 shapes of R that each strip cell is drawn once, by the strip or by
the terrain, at level 18 and at level 17, and that no fixed point stands on the side of a terrain
half.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The meshes draw over the nodes of mesh level M = min(finest, 18), and none below 17. At level M
the terrain sinks its vertices nearer than level 18's morph start and takes no snap there; at
finest 17 a terrain vertex of the strip is the terrain's own level-17 vertex, and the draw skips
the level-18 runs. The meshes fade out in metres, so the band is the same at 18 and 17.

Below level 17 the meshes stop in that frame and return after CALM frames in a row at 17 or finer.
Their cells stay wanted and built at any finest level, so a return builds nothing again. A page of
level M waits for its cell's mesh, as the level-18 page did.

Debug options: `finest=16..18` caps the finest level, and `debug=owned` draws the meshes green and
the terrain red, blue where the strip's rule gives the point to the mesh: a fault from any view.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f591cbe5-9b5b-4140-ad8d-68d8f639bf2f

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

timohueser and others added 2 commits November 7, 2026 23:33
…e zero-area strip triangle

The 400-shape test now builds each cell with `mesh_cell` and draws, at level 18 and 17, its mesh
and the terrain's triangles without a sunk corner. Every sample point must be drawn once and every
edge must close. Every other shape forces two parts of R to touch at a corner, and the test asserts
that such contacts occur. It also asserts that the level-18 runs hold exactly the strip triangles
of halves with three corners on the border of R.

strip.rs now says that at morph 1 a strip triangle can lose its plan area and still close the
surface, so no step may drop one for a zero area.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and no vertex snaps where they draw whole

- While the meshes count calm frames to draw again, the terrain keeps the frames going, so a still
  view gets them back without input.
- Below level 17 the meshes rest: they ask for no stamp and make no corner, and the records build
  their cells only after the whole target, so the recovery from the shortage comes first.
- The terrain takes no snap to S + two level-17 cells, as far as the mesh draws whole.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@timohueser

Copy link
Copy Markdown
Owner Author

Review fixes

New commits 1d560812d (crate test) and 3a05e799c (viewer). There is no force-push.

  1. A still view gets the meshes back. While the meshes count their CALM frames to draw again, Pieces.returning is true. Terrain.working then keeps the frames going. A new vitest walks 18 → 17 → 16 → 17 with frames only while returning. It ends with mesh level 17 after exactly CALM frames.
  2. Below level 17 the meshes rest. No stamp of a mesh cell is wished for (Pieces.update and the terrain's stamp wishes skip them), and no corner is made. The records build the mesh cells and their rings only after the whole target (Records.update(…, meshLater)). The cells stay, so a return builds no records again. Stale pieces at rest ask for no frames.
  3. Invariant 4. plan_near (no snap) now holds to S + PLAN_TRIANGLE_UNITS (two level-17 cells), which is as far as the mesh draws whole. Sinking still stops at S. The band ends before range / 2^18, where the coarser node begins.
  4. strip.rs now says that at morph 1 the zero-area triangle (m10, c00, c20) closes the straight west border, so no step may drop a strip triangle for a zero area.
  5. Tests. The 400-shape test now builds each cell with mesh_cell (an empty cell's plan and records, R from sharp marks). At level 18 and 17 it draws the mesh (at 17 without the level-18 runs, terrain vertices at their even point) and the terrain triangles without a sunk corner. It asserts that each sample point is drawn once and each edge closes. Every other shape forces a corner contact, and the test asserts that contacts occur. It asserts that the level-18 runs hold exactly the strip triangles of halves with three corners on ∂R. A local check: when the level-18 runs also draw at 17, the test fails with a double cover.
Gate Result
cargo test -p obc-ground-plan 105/105
clippy --all-targets -D warnings, cargo fmt --all clean
check 7 256 of 256 cells give the native digest
WASM guard unchanged: raw 1,798,983 / 1,802,240 B, gzip 690,759 / 704,512 B
vitest src/lib/trailview 413/413
npm run check, check:wgsl 0 / 0; 69 ok
debug=owned, 50 top views 18: 4 px, 17: 5 px, 0 black; all on a mesh/terrain edge, as before
debug=owned, walk and drive, every 10th frame 18: 1 px in 8 of 182 frames; 17: 1 px in 10 of 182 frames; never more than 1 px
Return without input, quality free (step3/scripts/return3.mjs, GPU) After idle at 18, one write each sets the quality to finest 17, then 16; nothing writes it after that. v17: 18 → 17 → 16 (meshes off in that frame) → the terrain raises to 17 at frame 309 → meshes on at frame 429 (CALM frames later) → 18. m1: the same path, meshes on 120 frames after 17. Both end idle with meshes at 18 and 0 frames after idle. In both runs the pools had room, so the quality rose on its own. Here the raisable count also kept the frames going. The vitest covers the still case with the quality stopped at 17.

Not run again: frame time, time to a clean frame, renders. The draw path changed only in the snap band S … S + 6.5 m.

Public docs: not changed.

Requirements: none

@timohueser
timohueser marked this pull request as ready for review November 7, 2026 23:58
timohueser and others added 2 commits November 8, 2026 01:07
`touched` names only the pages of one frame, so pages that arrived or left during the rest did not
mark a piece stale, and its plain-ground corners kept the old heights. When a rest begins, each
piece forgets its plain key and reads it again on return.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@timohueser

Copy link
Copy Markdown
Owner Author

Delta finding D4 and merge of ground-plan (#3188)

  • a7207f040: when a rest below level 17 begins, each piece forgets its plain key, so it reads its page keys again on return. A new vitest fails without the change.
  • a54ac0fff: merge of origin/ground-plan e810ec3. No conflicts.
Gate on the merged build Result
cargo test -p obc-ground-plan 113/113
vitest src/lib/trailview 414/414
npm run check, check:wgsl 0 / 0; 69 ok
WASM guard raw 1,868,974 / 1,904,640 B (98 %), gzip + glue 717,144 / 731,136 B (98 %)
debug=owned, 50 top views, 18 1 blue px, on an edge. 1 black px in conn-path-off-track-top at (1009, 442), deep inside the mesh's green. It comes back on each new shot of the merged build (2 of 2). The build before the merge gives 0 there.
debug=owned, 50 top views, 17 5 blue px, all on edges; 0 black

The black pixel is a pinhole inside a mesh, away from the strip. It first shows with the merge of #3188. I did not check whether ground-plan alone shows it.

Not run: clippy and check 7 on the merged build.

@timohueser
timohueser merged commit 42c0c3b into ground-plan Nov 8, 2026
26 checks passed
@timohueser
timohueser deleted the claude/gp-mesh-level17 branch November 8, 2026 00:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant