85 lines
4.5 KiB
Markdown
85 lines
4.5 KiB
Markdown
# render/ — shared frontend surfaces
|
|
|
|
Two pages that every endpoint can show, kept here rather than inside one component
|
|
because they belong to no single service: the now-playing screen reads Home Assistant,
|
|
the floorplan reads `identity`, and both are shown on thin clients, touch panels, the
|
|
kitchen and door panels alike.
|
|
|
|
Same rules as `digest-canvas-sdk` and `canvas-sdk`: **vendored, dependency-free, no
|
|
build step**, config from `?query=params` so nothing here holds a secret. Copy the
|
|
directory into a host's image; do not serve it from one place, or a kiosk that cannot
|
|
reach the container host shows nothing.
|
|
|
|
| | What | Reads |
|
|
|---|---|---|
|
|
| `media-visualiser/` | now-playing: circular spectrum, album-art colours, lyrics | HA `media_player` state |
|
|
| `floorplan-3d/` | who is in which room, extruded | `identity` `GET /floorplan/presence` |
|
|
|
|
## media-visualiser
|
|
|
|
```
|
|
nowplaying.html?ha=http://ha:8123&token=<HA token>&entity=media_player.living_room
|
|
```
|
|
|
|
**Two tiers, and the distinction is load-bearing.** CAVA reads an audio stream; most
|
|
endpoints do not have one — a kitchen panel showing what the *living room* is playing
|
|
has no audio to analyse and never will. So:
|
|
|
|
- **reactive** — audio is local. Real FFT via WebAudio (`attachAudio(el)`), or levels
|
|
pushed from `cava -r` by the host's agent (`pushLevels([...])`).
|
|
- **synthetic** — everywhere else. The ring breathes from track position and tempo.
|
|
|
|
The synthetic tier **says so on screen** ("visual rhythm — not an audio analysis") and
|
|
sets `data-tier` on the canvas. That matters: the moment somebody believes it is a
|
|
spectrum, every bass drop it misses becomes a bug report.
|
|
|
|
Palette extraction rejects near-greys and near-blacks *before* ranking (album art is
|
|
full of both, and a naive palette off a dark cover is four indistinguishable greys),
|
|
then lifts each colour until it clears the background — the step that gets skipped, and
|
|
why so many art-coloured visualisers are invisible on dark covers.
|
|
|
|
Lyrics: synced LRC highlights and scrolls; **plain text is shown but never
|
|
auto-scrolled at a guessed rate**, which is wrong within ten seconds and stays wrong.
|
|
Most tracks have none, so the layout treats absent as the normal case.
|
|
|
|
## floorplan-3d
|
|
|
|
```
|
|
floorplan.html?api=http://identity:8097&token=<identity token>[&level=<id>]
|
|
```
|
|
|
|
**Canvas 2D, not three.js** — a change from what `docs/endpoint-surfaces.md` planned,
|
|
made while building it. The scene is prisms on a plane: no lighting model, no textures,
|
|
no model import. An isometric projection with painter's-algorithm sorting draws exactly
|
|
that in ~200 lines, runs predictably on the small panels (where a WebGL context is much
|
|
less predictable), and keeps the frontend at zero dependencies. If this ever needs real
|
|
lighting or an imported model, three.js becomes right and this becomes the fallback.
|
|
|
|
Inherited from the Pebble watchapp deliberately, because they render the same payload
|
|
and divergence would mean one of them is lying:
|
|
|
|
- Occupied rooms **lit**, empty rooms **dark** — carried in lightness, not hue, because
|
|
colour already means *who*.
|
|
- A **third state**, dashed, for rooms HA never reports on. Drawing "no data" as
|
|
"empty" is a quiet lie.
|
|
- Occupants as **colour + initial**, upgraded to their photo where there is room, with
|
|
the colour ring kept either way — it is what ties this marker to the same person on
|
|
the watch and in the admin panel.
|
|
- `unplaced` people get a **visible shelf**. They are who you are most often looking for.
|
|
|
|
**Exact positions**, when the level has a metre scale and mmWave sensors placed on it:
|
|
a person fused to a single radar target is drawn *at* that coordinate with a footprint
|
|
dot on the floor (without it, a marker floated above the floor reads as further back in
|
|
the room). An unattributed target is a **hollow dashed puck with a question mark** — no
|
|
colour, no initial, because every visual language here for a *person* is reserved for
|
|
people the system can name. A radar target lights the room even with nobody named:
|
|
somebody is in there, and that the house can't say who is a fact about the house.
|
|
|
|
Drag to orbit; pitch is clamped and there is no free-fly, because an unconstrained
|
|
camera on a wall panel is something people knock askew and cannot get back.
|
|
|
|
**The caveat no rendering fixes:** this is only as right as room-level presence, which
|
|
has never been measured in this house. A beautiful 3D house with everybody on the
|
|
unplaced shelf is a beautiful picture of nothing — test that first with the admin
|
|
panel's floorplan tab, **Live** ticked.
|