feat(booth): blink the Entry/Exit lights on radar presence (mirror relay 3)
The on-screen Hyrje/Dalje barrier lights were 2-state (green=free / red=busy)
off the camera lane-status only — they couldn't show the radar-only "detected,
not yet confirmed" state that makes the physical button lamp (relay 3) blink.
Now they mirror the lamp's 3-state rule per lane:
radar present + camera not busy → BLINK green↔red (~1 Hz)
camera busy → SOLID red
otherwise → SOLID green
End-to-end:
- LanePresence (lane-presence.ts): subscribes to deviceEvents.onInput, resolves
each presence edge to its lane via the new direction-agnostic presenceLaneOf()
(device-resolve.ts) — entry AND exit, unlike the entry-gated relayForPresence
the one-car-one-ticket gate uses — and emits a lane-presence {entry,exit} bus
event on change. Wired in server.ts (start + onClose).
- WS forwards it (hello snapshot + push) into live-store.radar.
- BarrierLight (BoothScreen.tsx) is now 3-state; blinks via the .lane-blink
keyframe (index.css), which holds solid-red under prefers-reduced-motion.
Same input + same rule as the lamp, so the screen and the post never disagree.
A new test (lane-presence.test.ts) caught a real bug: the first cut reused
relayForPresence, so the EXIT lane never resolved (it's entry-gated) and never
blinked — presenceLaneOf fixes it. Covers entry/exit independence, de-dupe
across several radars on one lane, and ignoring non-presence inputs.
Full workspace build/lint/test green (185 server tests). Updated the
button-light-indicator wiki page ("On-screen twin").
Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -428,3 +428,30 @@ html.theme-light .btn:hover:not(:disabled) {
|
||||
html.theme-light .btn-primary {
|
||||
color: #fafaf7;
|
||||
}
|
||||
|
||||
/* ── Barrier-light blink ────────────────────────────────────────────────────
|
||||
The booth Entry/Exit indicator blinks green↔red (~1 Hz) when the radar/presence
|
||||
input is active but the camera hasn't confirmed a vehicle yet — mirroring the
|
||||
physical button lamp (relay 3). Toggles a CSS var the component maps onto its
|
||||
border / tint / glyph, so green and red alternate every 500 ms. */
|
||||
@keyframes lane-blink {
|
||||
0%, 49% { --lane-c: var(--color-term-green); --lane-tint: color-mix(in srgb, var(--color-term-green) 10%, transparent); }
|
||||
50%, 100% { --lane-c: var(--color-term-red); --lane-tint: color-mix(in srgb, var(--color-term-red) 10%, transparent); }
|
||||
}
|
||||
.lane-blink {
|
||||
animation: lane-blink 1s steps(1, end) infinite;
|
||||
border-color: var(--lane-c);
|
||||
background: var(--lane-tint);
|
||||
color: var(--lane-c);
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
/* No flashing for motion-sensitive users — hold the "attention" (red) state. */
|
||||
.lane-blink {
|
||||
animation: none;
|
||||
--lane-c: var(--color-term-red);
|
||||
--lane-tint: color-mix(in srgb, var(--color-term-red) 10%, transparent);
|
||||
border-color: var(--lane-c);
|
||||
background: var(--lane-tint);
|
||||
color: var(--lane-c);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user