HP-1543: editor-exit zoom after cross-floor switch; motion flash restart on rapid retrip

HP-1543-01 (medium): exiting an editor AFTER switching floors inside it left
the editor working zoom on screen in view mode — the snapshot guard
(snap.space) dropped the restore and nothing else put the viewport back.
A space-mismatched exit now falls back to _restoreZoom() of the current
floor's saved view zoom (per-space store/LS_ZOOM were never polluted, the
view-only _saveZoom guard is untouched). Regression: crossFloor* asserts in
demo/smoke_zoom_out.mjs — red on v1.54.3, green now.

HP-1543-02 (low): a rapid off->on retrip before the current flash ended did
not restart the CSS animation: the senseflash class and animation-name never
changed, so the browser kept the old timeline and the second detection played
nothing once the first one-shot had finished (base opacity 0). Every
witnessed trip now bumps a generation counter; its parity alternates the
identical keyframes hp-sense / hp-sense-b via the .sf2 marker — a new
animation identity forces a fresh timeline per detection. flashTs and the
window timer re-arm as before; prefers-reduced-motion keeps the static ring
(retrip only extends the window). Regression: rapid* asserts in
demo/smoke_motion_sense.mjs — red on v1.54.3, green now.
This commit is contained in:
Matysh
2026-08-01 13:09:55 +03:00
parent adaed9be7c
commit fa32afa9f3
7 changed files with 178 additions and 15 deletions
+16 -1
View File
@@ -907,6 +907,13 @@ export const cardStyles = css`
animation: hp-sense 1.1s ease-in-out 3;
pointer-events: none;
}
/* HP-1543-02: a rapid off→on retrip must RESTART the flash. The card
flips the .sf2 marker on every trip (_senseTick generation parity);
hp-sense-b duplicates hp-sense exactly — switching the animation-name
is what makes the browser abandon the old timeline and start a fresh
one on the same pseudo-element (a same-name animation never restarts
while the class stays on). */
.dev.senseflash.sf2::after { animation-name: hp-sense-b; }
/* OCCUPANCY/PRESENCE while 'on': a calm STATIC ring, no animation —
«комната обитаема» is a state, not an event, so it must not blink.
Brightness matches the reduced-motion variant of the flash. */
@@ -924,6 +931,13 @@ export const cardStyles = css`
60% { transform: scale(1.12); opacity: 0.12; }
100% { transform: scale(1.12); opacity: 0; }
}
/* identical twin of hp-sense — exists ONLY as the alternate animation
identity for the retrip restart (HP-1543-02), keep the two in sync */
@keyframes hp-sense-b {
0% { transform: scale(0.9); opacity: 0.5; }
60% { transform: scale(1.12); opacity: 0.12; }
100% { transform: scale(1.12); opacity: 0; }
}
/* alarms pulse red over everything */
.dev.alarm::after {
content: '';
@@ -943,7 +957,8 @@ export const cardStyles = css`
/* the motion flash becomes a static ring for the same ~3.3s class
window — consistent with alarm's treatment; sensehold is static
by design already */
.dev.senseflash::after { animation: none; opacity: 0.4; }
.dev.senseflash::after,
.dev.senseflash.sf2::after { animation: none; opacity: 0.4; } /* HP-1543-02: retrip re-arms the window, ring stays static */
}
.dev .newdot {
position: absolute;