Skip to content
← Documentation

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.03 rather than per-channel RGB. It affects the magnitude of the interference, not its existence or its repair.

207 → 211 tests, 26 DOM, tsc clean.