fix(plan): key room shapes by space and id so a floor switch never repaints a stranger (#742)

The flat room list was a bare map(), so Lit reused room nodes by position.
On a floor switch the previous floor's room node became the new floor's room
and `.room { transition: 0.12s }` drew its fill and stroke in from the old
computed values: one paper-white frame, then two or three frames darker than
the final fill (alpha rises while fill-opacity falls), then the fill. Between
two filled floors the fill bled in from the other floor's colour.

The list is now keyed(space.id, repeat(rooms, (r, i) => r.id || i, ...)), the
shape #534 settled on for openings and markers. The outer key handles the
floor switch, including room ids repeated on two floors (ids are unique only
within a space); the inner key keeps a node bound to its room inside a space,
where inserts, merges, splits and the editor filter shift positions. An
id-less room keys by its numeric index, which never equals a string id. The
transition itself stays: it smooths hover and a real fill change on the same
floor.

Witness: a new section of smoke_space_switch_transitions, before physicalize
(after it the first room changes template branch and the node is recreated
anyway). Red on dev: five transitions on g1, node r1 reused for g1, computed
fill rgba(0, 0, 0, 0) / 1; room nodes swapped by an insert; same-id case
reuses r1. A real custom_fill change still runs a fill transition (catches
`transition: none`). Two mutants: inner key removed, outer key removed.

Issue: #742
User-Visible: yes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
This commit is contained in:
Claude
2026-10-01 10:13:50 +00:00
committed by claude[bot]
parent 88985d2e4c
commit a0f72280ee
7 changed files with 185 additions and 9 deletions
+5
View File
@@ -15,6 +15,11 @@
- General settings restored after the card reloads — for example on returning
to the tab — now show the moon's "Now: …" line too, worked out afresh at that
moment ([#731](https://github.com/Matysh/houseplan-card/issues/731)).
- Switching floors no longer flashes rooms white and then darker than their
fill: the new floor appears in its own colours at once, with the usual short
slide. A real colour change on the same floor — a light turning on, a new
temperature, hover — still fades smoothly
([#742](https://github.com/Matysh/houseplan-card/issues/742)).
## v1.79.0-beta.1 — 2026-09-30
+5
View File
@@ -22,6 +22,11 @@
возврате на вкладку, — тоже показывают строку луны «Сейчас: …», рассчитанную
заново на этот момент
([#731](https://github.com/Matysh/houseplan-card/issues/731)).
- При переключении этажа комнаты больше не мигают белым и затем темнее своего
цвета: новый этаж сразу появляется в своих цветах, с обычным коротким
сдвигом плана. Настоящая смена цвета на том же этаже — включился свет,
сменилась температура, наведение — по-прежнему идёт плавно
([#742](https://github.com/Matysh/houseplan-card/issues/742)).
## v1.79.0-beta.1 — 2026-09-30
@@ -16,8 +16,8 @@ to prove that the Node witness actually kills it.
| Paint, cascade and layer composition | 26 | The invariant depends on computed CSS, SVG paint, clipping, stacking or pixels produced by Chromium. |
| Pointer geometry and trusted interaction | 45 | The invariant depends on hit testing, pointer capture, touch/keyboard dispatch or live DOM geometry. |
| Responsive DOM layout | 36 | The invariant depends on measured element boxes, responsive breakpoints, native/HA dialog shells or focusable target size. |
| Custom-element and HA browser lifecycle | 86 | The invariant crosses Lit/custom-element lifecycle, browser storage/events, lazy loading or a complete HA-card state transition. |
| **Total** | **201 / 200** | Growth above the cap fails `mutation-gate --check`. |
| Custom-element and HA browser lifecycle | 88 | The invariant crosses Lit/custom-element lifecycle, browser storage/events, lazy loading or a complete HA-card state transition. |
| **Total** | **203 / 200** | Growth above the cap fails `mutation-gate --check`. |
## Measured effect
@@ -261,6 +261,8 @@ The invariant crosses Lit/custom-element lifecycle, browser storage/events, lazy
- `room-gear-second-touch-keeps-drag`
- `room-settings-click-does-not-open`
- `room-tooltip-off-skips-pointer-modality`
- `rooms-rendered-without-keys`
- `rooms-rendered-without-space-key`
- `same-space-room-change-recenters`
- `space-create-hidden-display-override`
- `stairs-view-pan-opens-target-floor`