Skip to content

Roof border shows the un-aged reference color - #140

Merged
thalida merged 3 commits into
mainfrom
feat/issue-118-roof-reference-color
Jul 25, 2026
Merged

Roof border shows the un-aged reference color#140
thalida merged 3 commits into
mainfrom
feat/issue-118-roof-reference-color

Conversation

@thalida

@thalida thalida commented Jul 25, 2026

Copy link
Copy Markdown
Owner

Closes #118

The roof border was the building's current (aged) wall color offset darker, so it carried no information: a faded building had a faded border. It now paints the color the file would have if it were touched today, so the gap between the dim walls and the bright border reads as how much the file has aged. Each building carries its own swatch of what its color should be.

Border strip only. The roof icon/glyph area renders exactly as before.

Reference color

getBuildingColorForRecency(file, 1) is the fresh end of the exact curve the wall color comes off (same extension hue, saturation/lightness at max), so the reference and the wall cannot drift apart. Written per-instance at rebuild; it does not vary with Timeline scrub, so the scrub loops were left alone.

The issue also asked to exclude the border from the grime pass. That turned out to be unnecessary: grime only ever ran inside renderWallFace, so the roof was never grimed.

The attribute repack

The issue sketched passing the reference color as a second per-instance color attribute. That does not fit: the shader sits at exactly 16 vertex attributes, the WebGL2 guaranteed minimum. Custom iCols, iFloors, iOrient, iDoorWidth, iFade, iIconUV, iModifiedAge, iKind (8) plus Three.js-injected position, normal, uv, instanceMatrix (mat4, 4 slots) and instanceColor (8). That ceiling is why iFade already packs 3 values and iIconUV packs 4. A 9th declared attribute breaks on conforming hardware.

So iOrient + iDoorWidth are now one vec2 iDoor, freeing the slot for vec3 iRefColor. Total stays at 16.

That pair was chosen over iModifiedAge/iKind because both are written only in cellMesh and read only in the vertex shader, so the picker and the two per-frame scrub loops stay untouched. They are also semantically one thing (door orientation + door width) and were always written together.

Removed

ROOF_BORDER_LIGHTNESS_DELTA, its uRoofBorderLightnessDelta uniform, and its control-panel field. Nothing derives the border from the wall anymore, so the setting had nothing left to control. Note this is a settings field disappearing from the Buildings panel.

Also on this branch

Bloom THRESHOLD default 0.5 to 1.0. At 0.5 matte walls crossed the cutoff and bloomed alongside the lit windows, softening the whole facade. 1.0 is the point the field's own tip already described as windows-only.

Tests

GLSL cannot be compile-tested in vitest, so coverage targets what can drift silently:

  • building-shader.test.ts asserts exactly 8 declared attributes. Exceeding the ceiling is invisible to every unit test (no GPU) and only fails on real hardware.
  • Attribute-presence and orient-encoding tests updated for iDoor / iRefColor.

Full gate green: 2819 tests, eslint, typecheck, prettier. Verified visually in the dev stack.

🤖 Generated with Claude Code

thalida added 2 commits July 25, 2026 12:50
At 0.5 matte walls crossed the cutoff and bloomed alongside the lit
windows, softening the whole facade. 1.0 is the point the tip already
described as windows-only.
The border was the aged wall color offset darker, so it carried no
information: a faded building had a faded border. It now shows the color
the file would have if it were touched today (same extension hue at the
freshest saturation/lightness), so the gap between the dim walls and the
bright border reads as how much the file has aged. The roof icon area is
untouched, and grime never reached the roof: it is wall-face only.

The shader sits exactly at the WebGL2 16-attribute ceiling, so the
reference color could not simply take a slot. iOrient and iDoorWidth are
now one vec2 iDoor, which frees the slot and groups two door properties
that were already always written together. Picked that pair over
iModifiedAge/iKind because both are written only in cellMesh and read
only in the vertex shader, leaving the picker and the per-frame scrub
loops alone.

Reference color comes from getBuildingColorForRecency(file, 1), the same
curve the wall color comes off, so the two cannot drift apart.
ROOF_BORDER_LIGHTNESS_DELTA and its uniform are removed: nothing derives
the border from the wall anymore.

Closes #118
Every declaration comment matches the trailing one-liner form its
neighbours already use, instead of a block above the line.
@thalida
thalida merged commit 71fe3a1 into main Jul 25, 2026
1 check passed
@thalida
thalida deleted the feat/issue-118-roof-reference-color branch July 25, 2026 18:03
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.

Building roofs: border shows the un-aged reference color (aging reference point)

1 participant