Skip to content

Render Fulgora's composite through the engine (#363) - #372

Merged
wormeyman merged 1 commit into
mainfrom
fulgora-all-through-wasm
Aug 31, 2026
Merged

Render Fulgora's composite through the engine (#363)#372
wormeyman merged 1 commit into
mainfrom
fulgora-all-through-wasm

Conversation

@wormeyman

Copy link
Copy Markdown
Collaborator

PR 2 of 2, and the one an ordinary user sees. ElevationPreviewPanel.vue's
effectiveView returns "all" for every non-dev-mode Fulgora request, so until
this commit the DEFAULT Fulgora render was the one view still served by
TypeScript while the two dev-mode views went to the engine. Every planet's
default view now renders through the engine.

What changed

ABI the Fulgora block grew 48 -> 64 bytes, so a request is 120 rather than 104. scrap_frequency and scrap_size are appended AFTER the trig, because the block is append-only and grouping them with the island sliders would move offsets every existing reader knows
engine render_fulgora grows a composite arm for VIEW_RESOURCES and VIEW_ALL, using PR 1's FulgoraScrapPlacement; the supported match names both
dispatcher elevationRenderRequest.ts routes "all" and "resources" to the engine
fixture wasm-request.v2.json regenerated, and the independent Python decoder in verify-wasm-request.py grew both new offsets

"resources" and "all" are the same picture, since Fulgora has no cliffs and
no rocks. One arm serves both codes and a test asserts they are equal, so the
collapse is checked rather than assumed.

The TypeScript arm is NOT dead. It still serves an engineless request, which is
what the no-engine half of the parity specs runs, and it is the thing the engine
is graded against.

Two things the tests could not see, found by planting breaks

Break B was NOT caught by the first version of the slider test. It moved
scrapFrequency to 4 and scrapSize to 3 together, and a module that hard-coded
scrap_frequency: 1.0 passed it. Sweeping the slider explains why:

sliders (frequency, size) scrap pixels same bytes as neutral?
(1, 1) 149 -
(4, 1) 149 yes
(0.25, 1) 104 no
(1, 3) 194 no
(1, 0.25) 118 no

Raising frequency above neutral does not move the picture at all, measured
on a 64x64 window at (-500, 3000), seed 123456. So the chosen value was in a
dead zone. The test now moves ONE slider at a time, downward for frequency, and
pins the dead zone itself so nobody rewrites the test I wrote first.

The composite parity test was nearly vacuous on the overlay. The four
existing windows carry 0, 1, 11 and 0 overlay pixels - 12 in 7,685 - so
byte-identity was passing on terrain agreement. Sweeping origins on a +/-3000
grid found two scrap-dense windows, 149 and 134 pixels, which are now in the
comparison. Near spawn there is genuinely no scrap, because the starting mask
suppresses it, so the "origin" window reading 0 is a property rather than bad
luck.

Planted and watched, not predicted

Each break was applied to the engine, the module rebuilt, and the spec run:

planted break caught by
composite paints the FOOTPRINT instead of the roll - the mistake #363's body would have led to both composite parity tests and the slider parity test
scrap_frequency ignored, hard-coded to neutral the frequency parity case
scrap_size ignored, hard-coded to neutral both size parity cases
the two fields read from swapped offsets every slider case

The first was caught before the test was strengthened; the other three were not,
which is why the test was strengthened.

Measured

engine.wasm 321,381 -> 322,057 bytes, +676, which is PR 1's placement code
becoming reachable - it was dead-code eliminated until this arm called it.

Gates

gate result
scripts/verify-rust.sh VERIFY_RC=0
pnpm run verify VERIFY_RC=0, 9m40s, 162 test files, 1,600 passed, 3 skipped

Both exit codes were written into their logs and read back from there. The test
count is up 11 from PR 1's 1,589.

CLAUDE.md is updated: it said a Fulgora request is 104 bytes and that the
block "has not moved a byte", both now wrong. The reading level of the added
prose is Flesch-Kincaid 9.55, computed rather than guessed.

Closes #363.

PR 2 of 2, and the one an ordinary user sees. `ElevationPreviewPanel.vue`'s
`effectiveView` returns `"all"` for every non-dev-mode Fulgora request, so until
this commit the DEFAULT Fulgora render was the one view still served by
TypeScript while the two dev-mode views went to the engine. Every planet's
default view now renders through the engine.

## What changed

| | |
| --- | --- |
| ABI | the Fulgora block grew 48 -> 64 bytes, so a request is 120 rather than 104. `scrap_frequency` and `scrap_size` are appended AFTER the trig, because the block is append-only and grouping them with the island sliders would move offsets every existing reader knows |
| engine | `render_fulgora` grows a composite arm for `VIEW_RESOURCES` and `VIEW_ALL`, using PR 1's `FulgoraScrapPlacement`; the `supported` match names both |
| dispatcher | `elevationRenderRequest.ts` routes `"all"` and `"resources"` to the engine |
| fixture | `wasm-request.v2.json` regenerated, and the independent Python decoder in `verify-wasm-request.py` grew both new offsets |

`"resources"` and `"all"` are the same picture, since Fulgora has no cliffs and
no rocks. One arm serves both codes and a test asserts they are equal, so the
collapse is checked rather than assumed.

The TypeScript arm is NOT dead. It still serves an engineless request, which is
what the no-engine half of the parity specs runs, and it is the thing the engine
is graded against.

## Two things the tests could not see, found by planting breaks

**Break B was NOT caught by the first version of the slider test.** It moved
`scrapFrequency` to 4 and `scrapSize` to 3 together, and a module that hard-coded
`scrap_frequency: 1.0` passed it. Sweeping the slider explains why:

| sliders (frequency, size) | scrap pixels | same bytes as neutral? |
| --- | --- | --- |
| (1, 1) | 149 | - |
| (4, 1) | 149 | **yes** |
| (0.25, 1) | 104 | no |
| (1, 3) | 194 | no |
| (1, 0.25) | 118 | no |

**Raising `frequency` above neutral does not move the picture at all**, measured
on a 64x64 window at (-500, 3000), seed 123456. So the chosen value was in a
dead zone. The test now moves ONE slider at a time, downward for frequency, and
pins the dead zone itself so nobody rewrites the test I wrote first.

**The composite parity test was nearly vacuous on the overlay.** The four
existing windows carry 0, 1, 11 and 0 overlay pixels - 12 in 7,685 - so
byte-identity was passing on terrain agreement. Sweeping origins on a +/-3000
grid found two scrap-dense windows, 149 and 134 pixels, which are now in the
comparison. Near spawn there is genuinely no scrap, because the starting mask
suppresses it, so the "origin" window reading 0 is a property rather than bad
luck.

## Planted and watched, not predicted

Each break was applied to the engine, the module rebuilt, and the spec run:

| planted break | caught by |
| --- | --- |
| composite paints the FOOTPRINT instead of the roll - the mistake #363's body would have led to | both composite parity tests and the slider parity test |
| `scrap_frequency` ignored, hard-coded to neutral | the frequency parity case |
| `scrap_size` ignored, hard-coded to neutral | both size parity cases |
| the two fields read from swapped offsets | every slider case |

The first was caught before the test was strengthened; the other three were not,
which is why the test was strengthened.

## Measured

engine.wasm 321,381 -> 322,057 bytes, +676, which is PR 1's placement code
becoming reachable - it was dead-code eliminated until this arm called it.

## Gates

| gate | result |
| --- | --- |
| `scripts/verify-rust.sh` | `VERIFY_RC=0` |
| `pnpm run verify` | `VERIFY_RC=0`, 9m40s, 162 test files, 1,600 passed, 3 skipped |

Both exit codes were written into their logs and read back from there. The test
count is up 11 from PR 1's 1,589.

`CLAUDE.md` is updated: it said a Fulgora request is 104 bytes and that the
block "has not moved a byte", both now wrong. The reading level of the added
prose is Flesch-Kincaid 9.55, computed rather than guessed.

Closes #363.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@wormeyman
wormeyman merged commit aca4e5e into main Aug 31, 2026
9 checks passed
@wormeyman
wormeyman deleted the fulgora-all-through-wasm branch August 31, 2026 20:02
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.

Fulgora's default view renders entirely in TypeScript, so #227's done-when is not met

1 participant