docs/fog-interference.md
Fog interference — measured, and repaired
First result under the new mode: a derivation must end in a visible improvement or a measurable defect. This produced both.
tests/fog-interference.test.ts, src/lib/world/framing.ts.
The defect
worldscene-freedoms.md classified four ungrounded freedoms as sitting on the activity channel, and closed by admitting they were classified, not measured. This measures the first.
No pixel buffer was needed. Three.js linear fog is a closed-form lerp toward the fog colour by depth, and every input was a constant in the file:
fog ["#07080b", 220, 620] emissive 0.12 + activity * 0.85
camera setLookAt(205, 165, 205, 0, 0, 0)
So the lightness a viewer receives is computable from the scene as written, and
the existing orderedFidelity instrument scores it.
100 buildings · depth 263–828 · 10 distinct activity values
control (no fog): faithful
with fog: 1635 of 4500 activity comparisons inverted (36.3%)
The estate spans depths 263–828 and the fog band started at 220 — so every
building was fogged. Fog dims; emissiveIntensity is the assigned carrier of
activity. A viewer comparing two buildings' activity was wrong more than a
third of the time, and the error is systematic: far reads as quiet.
The control is what makes this a fog finding rather than a channel finding. With fog removed, the channel is faithful.
Locating the cause before repairing it
fog 220–620 (as written): 36.3% inverted
fog 2000–4000: 0.0% inverted
The defect is the band relative to the estate, not fog as such. That distinction decides whether the repair is a constant or a redesign.
The repair
The theory's own prescription: an arbitrary freedom on an asserting channel is either neutralised or bound to something semantic. It is now bound.
export function estateFogNear(buildings) {
const farthest = Math.max(...buildings.map((b) => depthFrom(b.position)));
return farthest + FOG_MARGIN.value;
}
estate reaches depth 828; fog now starts at 868
before 36.3% inverted → after 0.0%
Fog attenuates only what lies beyond the world, and the band grows with the estate, so a larger world cannot silently reintroduce the defect.
distance fog moves from arbitrary to derived, and the freedoms audit
retires the finding — it failed on the change, which is the mechanism working.
What was lost
A depth cue over the estate. That is a real cost and it is not measured: legibility is condition 3. The trade taken is a measured 36.3% error for an unmeasured aesthetic cue, which is the right way round by this project's standard, and it is reversible in one constant.
A dual-ownership defect fixed on the way
The camera vantage was written in WorldScene.tsx and restated in the test —
two authorities for one quantity, free to diverge, with nothing detecting it.
src/lib/world/framing.ts now owns VANTAGE, depthFrom and estateFogNear,
and both consume it.
The FOG_MARGIN of 40 is a residual freedom, declared: it changes nothing
about the ordering, only how far past the estate the band sits.
Standing
| Measurable defect exposed? | yes — 36.3%, with a clean control |
| Measurable improvement? | yes — 0.0%, asserted against regression |
| Ontology expanded? | no |
What is still not established
- Three lightness collisions remain unmeasured: key light direction, fill light levels, material response. Key light is the harder one — it needs face normals, so the closed-form trick will not work and it needs a rendered surface.
- The measurement uses
atScale(10)fixtures, not the live substrate. - Fog lightness is approximated as a scalar
0.03rather than per-channel RGB. It affects the magnitude of the interference, not its existence or its repair.
207 → 211 tests, 26 DOM, tsc clean.