Files
app/docs/interface/dashboards.md
T
stroblmeandClaude Opus 5.5 4ae8535cbb Draw each dashboard on a round panel's track in its own look
The canvas states the look of the dashboard shown, so a neighbour beside it
and the one a turn leaves wore that look too. Each page now restates its own
look, theme and palette. The ring's paint moves from rules under
[data-look] to variables each look sets on its root, which stop at the
nearer root where a descendant rule reached into both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WgBfkm4rCmtd1T4vHWjEPx
2026-10-15 16:00:10 +02:00

27 KiB
Raw Blame History

Dashboards and panels

A dashboard is a grid of widgets bound to message names. It can show values and send controls across several flows. A panel assigns published dashboards to a paired screen, such as a wall tablet.

Building one

  1. Open Dashboards → New dashboard.
  2. Enter edit mode, choose Add widget and select a type.
  3. Bind the widget to a message in its settings. On desktop, drag and resize tiles on the grid.
  4. Publish when the dashboard is ready.

Edits stay in a draft; paired screens show the published version. On phones, tiles stack in one column and dragging is disabled, but settings remain editable. In edit mode, ⌘Z / Ctrl-Z undoes an edit and ⌘⇧Z / Ctrl-Shift-Z redoes it.

Controls can publish real values while you edit, so choose their targets with care. Your new Switch may already be flipping something!

The widgets

Display

Widget Binds to Shows
Value anything formatted reading, unit and precision
Gauge float, int reading within a min/max range
Chart numeric messages, a query response or run metrics up to five lines
Bar float, int up to eight readings with separate scales
Icon numbers, booleans or strings a glyph selected from the value
Text — Markdown
Agenda list upcoming items
Forecast list an outlook strip
Notification record title, body and severity
Media image, audio, video, artifact image, audio or video
Player record playback status and transport controls
Clock — current time
Website — embedded page or image

Every widget has a title. Show title controls its visibility; the title still names the widget for accessibility and published values.

Input

Widget Publishes Settings
Button fixed value one-shot action
Buttons a value per button grid of actions
Switch bool on/off
Slider float, int min, max, step; horizontal or vertical; a reading beside it
Input text or number free entry
Selector selected value menu or row of choices
Colour list or string HSV, RGB or hex

Colour defaults to [h, s, v]: hue 0–360°, saturation and brightness 0–100%. Sends can select RGB ([r, g, b], 0–255) or hex ("#rrggbb"). HSV and RGB bind to list; hex binds to str.

Controls publish to their bound messages. The flow canvas shows them as endpoints feeding the nodes that consume those messages.

Bindings are checked in the editor and on the server. See Payload types.

A slider's reading

A Slider can also show what it sets against, such as the room's temperature beside a setpoint: Beside it binds reading: {message, dtype, label} to a float or int. The reading is only shown, never published. It is written in the slider's unit and to its step's decimals (a step of 0.5 writes 21 as 21.0), as the slider writes its own value, so the two always match; — stands in for the value until one arrives. On a round face it takes the middle (see Round dashboards); in a tile it is a line under the slider's value.

It is also marked where it sits on the slider's scale, as a thermostat marks the room's temperature: the handle is what is set, the dot what is. The dot is at the reading's fraction of the scale, (reading − min) / (max − min) held to 0–1, so a reading outside the range sits at that end. It takes no pointer, and there is none until a value arrives. See Dots on the track.

Sizes are CSS pixels of the canvas, as in the round geometry below. The slider's own value is at the tile's text size (14; 16 on a touch-friendly panel), centred on a line as tall as the control (32; 48 touch-friendly).

Part Value
Line 16 high, text 12: the label (muted, at most 96 wide, cut with an ellipsis), 6, the value (text colour), 6, the unit (muted). Without a label, the value and unit alone
Row directly under the slider's value, right-aligned with it, in the column right of the track (12 apart). With ticks the line shares the ticks' row, so the tile grows no taller; without them it adds 16
Row width the value column is as wide as its wider line, but at most half the row; the track takes the rest. What does not fit is cut from the label; the value and unit never are
Fader directly under the slider's value, both centred under the track, 8 below it; the line no wider than the tile inside its padding, cut from the label first

Dots on the track

A slider's ticks, a selector's options on a round face and a slider's reading are dots inside the track, on its midline — on a round face the ring's centre line, radius c − 20. Each is drawn in the colour that reads on what covers it: the track, the value's fill, or the handle.

Dot Size, tile / ring On the track On the fill On the handle
Stop: a tick, an option half the track's thickness (4 on the 8 track) / 6 --muted-foreground --primary-foreground at 70 % hidden under it
Reading the track's thickness (8) / 12 --foreground --primary-foreground Fluksio --foreground, Material --primary-foreground, Glass black at 75 %

The reading is a filled circle like the handle, smaller and in the text colour rather than the handle's paint, so it reads as what the room is beside what it is set to. It is larger than a stop and stronger in colour, and it is the one dot that shows on the handle, so a reading at the setpoint is still visible.

Part Value
Place (tile) the dot's centre on the handle's travel: handle ÷ 2 + fraction × (track length − handle) from the track's left end (from its bottom end on a fader), so a dot and the handle line up at the same value
Place (ring) the dot's centre at the fraction of the sweep, as the handle
Ticks with ticks on (the default), n intervals of the scale — the steps when there are 5 or fewer, else the first of 4, 3 or 2 that divides the steps evenly, else 4 — and a dot at each i/n, both ends included. A row keeps its labels under the track; a fader has none
Options a dot per option at i/(n − 1) of the sweep (one option: the middle). The selector's ring has a value arc from the start to the selected option, so the options up to it are on the fill
Colour change where the fill or the handle covers a dot, that part of it takes the colour for the fill or the handle, so a dot changes colour as the fill's end or the handle passes over it, and follows them while they move. A device may instead switch a whole dot when the fill's end or the handle's centre passes the dot's centre
Order track, dots, fill, the dots again over the fill, handle, the reading again over the handle
Locked in a tile, the dots at 0.45 opacity, as the handle; on the ring, the whole ring at 0.45

Charts

Choose the chart's data source:

  • Live: recent numeric message history, updated as values arrive.
  • Query: publishes a record request containing range_s and interval_s, then draws a flow's series response. Include those fields in the answer so the chart can reject responses for a different window.
  • Runs: compares a numeric metric from named runs, a sweep or the latest runs of a flow. See Runs.

Multi-line charts show a legend as well as different colours.

!!! tip "Skip the unfinished bucket"

If your query aggregates into time buckets, leave out the bucket still
filling. Otherwise an incomplete total can look like a sudden drop.

Media tiles

Media messages contain artifact references; the widget loads the bytes they name. Crop or fit controls image sizing. Play as it arrives enables autoplay, subject to the browser's rules for sound.

For local streams, volatile=True artifacts can be pushed over the websocket with their message. Stored artifacts are fetched individually, as are frames viewed through a portal. Use occasional snapshots for remote screens.

For continuous video, set Live stream to a browser-compatible camera URL. The browser must be able to reach that URL; enrollment does not expose the camera itself. See Media payloads.

Player tiles

A Player reads a status record and publishes commands to a separate str message.

Status field Meaning
title, artist, album track details
status play, pause, stop, load or off
position, duration seconds

Controls send toggle, next, prev and seek:<seconds>. Your receiving node translates those into device actions. The position advances in the browser between readings and resets to each fresh reading.

Website tiles

Set Address to a page to embed, or choose Image for a snapshot or MJPEG URL. A website may refuse embedding.

Embedded pages run in a sandbox without cookies or storage by default. Trusted site permits the site's own origin, cookies and storage. Use it only for a trusted destination. The app blocks trusted embeds of its own origin, including the portal origin, to protect your session.

Dashboard settings

Open Dashboard settings from the dock. Each setting can hold a fixed value or follow a message chosen in Driven by. The fixed value is the fallback when no usable message value is available.

Setting Choices Message type
Look fluksio, material, glass str
Theme system, light, dark str
Palette ordered hex colours list
Background image URL str
Lock read-only on/off bool

To change one on a schedule, have a scheduled node publish its bound message.

Look and theme

Fluksio is the default look. Material uses flat tonal cards; Glass uses translucent tiles. Widgets work the same in all three.

Theme follows the chosen preference unless a palette sets the background colour.

Palette

Paste a colour list or a Coolors palette link. Colours have roles by position:

Position Role
1 background
2 widget surface
3 primary controls and first chart line
4 accent
5 text
6+ additional chart lines

Missing roles are derived, so three colours are enough to get started. Rotate shifts their order. Text contrast is corrected automatically; failure and success indicators keep their status colours.

Background and lock

Background draws an image beneath the widgets. Lock disables publishing from controls and shows Read-only when viewing the dashboard. It does not restrict API permissions and does not disable controls in edit mode.

Round dashboards

For a round screen such as a rotary knob, set the canvas to Round in the dashboard settings, or pick the Knob preset (360×360). A round canvas is square (shape: "round" forces canvas_height to canvas_width), and nothing outside its circle is drawn. It fills the screen at any width: a phone neither stacks nor pads it.

A round dashboard has no grid. It shows one widget at a time, each drawn as the whole face, in the order of widgets; layout is not read. In the editor, the faces are a row above the dock: press one to show it and open its settings, drag it along the row (or Alt+←/→) to move it, and add more with Add widget.

A Slider, Selector, Colour or Gauge draws on the ring along the edge, which a knob's own ring turns. In a browser, drag along the ring or use the mouse wheel (or the arrow keys once it has focus): one notch is one step, one option (no wrap) or one hue step (hue_step, default 5°, wrapping). The value moves at once and is published once, 300 ms after the last notch or when the pointer is released. A Gauge only shows. On any other face, turning a knob only wakes the screen.

A Slider's reading (Beside it) is written large in the middle, under its label; the slider's own title and value move to the line in the ring's gap.

Value, Bar, Switch, Button, Clock, Icon, Notification and Text have faces of their own. Every other type is drawn as its rectangular body in the middle of the face, and the editor marks it Poor fit for round.

Moving between faces

Gesture Effect
Swipe left / right next / previous face of this dashboard; stops at either end
Swipe up / down next / previous dashboard of the panel (/panel/{id} only); stops at either end
Page dot that face
PageDown / PageUp next / previous face
Shift+PageDown / Shift+PageUp next / previous dashboard of the panel
Arrow keys turn the ring, not the page

A swipe carries the page with the finger (Swiping); a drag that starts on the ring turns the ring instead. A dashboard reopens on the face it was last left on in this session, otherwise on its first. Landing on another dashboard shows its title and icon in the middle of the face for one second; a round panel has no rail.

Geometry

Devices that draw dashboards natively use these numbers. They are canvas pixels, scaled with the canvas; S is the canvas width and c = S/2. Angles are degrees clockwise from three o'clock. Text sizes are font sizes; muted is the look's muted text colour.

Part Value
Face circle of diameter S at (c, c)
Title one line centred at y = c − 80, 18, muted, at most 200 wide; the widget's title, or the label of a slider's reading
Middle a 240 × 128 box centred at (c, c); what a face draws in its middle is centred in it and clipped to it
Centre reading centred at (c, c), line height 1, its unit after it at 0.4 em, muted. Size: 72, or 240 ÷ (0.6 × the characters written) rounded down where that is smaller, never below 24
Ring band 40 along the edge
Ring arc start 120°, sweep 300° (ends at 60°), centre-line radius c − 20, stroke 16 with round caps
Slider track over the sweep, value arc from the start to the value (none at the minimum), handle 28 across, its ticks as dots; the value as the centre reading
Slider with a reading the reading as the centre reading; the gap line holds the title (muted) and the slider's value. The reading as a dot 12 across on the centre line at its fraction of the sweep (Dots on the track)
Selector a value arc from the start to the selected option (none at the first), a dot 6 across per option at i/(n−1) of the sweep (one option: the middle), the selected one under the handle; its label as the centre reading, at most 36
Colour hue h at h/360 of the sweep in 150 strokes of 2°, red at both ends; the handle filled with the colour; a swatch 96 across in the middle, with a hairline border
Gauge track and value arc, no handle; the value as the centre reading
Gap line centred at y = S − 28, 15, at most 140 wide, clear of the ring's end caps
Value the reading as the centre reading, to its precision; a word shrinks like any other
Bar an arc per row, the first outermost, each over the ring's sweep (start 120°, 300°) with round caps: a track in the look's track paint and the row's value arc in its data colour, on its own scale (none at the minimum). n rows share a band 64 thick inward from c − 12, 3 apart: stroke s = min(16, (64 − 3(n − 1)) / n), centre-line radius rᵢ = c − 12 − s/2 − i(s + 3), so up to three rows are 16 thick and the first is on the ring (c − 20). The middle is the legend, a line per row in order: a dot 8 across in the row's colour, 8, the label (muted, cut with an ellipsis), 8, the value and unit to the row's precision (— for none). Lines of 22 at 17 for up to 5 rows, 18 at 15 for 6–7, 16 at 13 for 8; the block centred at (c, c), as wide as its widest line but at most 240 and at most the width of the disc inside the innermost arc (radius c − 12 − n·s − 3(n − 1)) at the block's top and bottom, less 16. The title is at most that disc's width at the title's line (y = c − 89), less 8
Switch a disc 128 across centred at (c, c): the look's button, filled when on and tonal when off, with a power glyph 40 over the word On or Off at 17; a press toggles
Button a disc 128 across centred at (c, c), tonal, its label at 17 over at most three lines; a press sends its value
Clock the time (hours and minutes, the device's locale) sized as a centre reading, over the date (weekday, day, month) at 17, muted, 4 apart; the pair centred at (c, c)
Icon the glyph 96 across over its label at 17, muted, 4 apart; the pair centred at (c, c). Nothing matched: a dash at 72, muted
Notification the title at 17, medium (an error in the destructive colour, led by ⚠), over the body at 17, muted; centred lines in the middle
Text centred lines at 17: # at 1.35 em and ## medium, ### muted, list items led by a bullet; in the middle
Not wired the problem, at 17, muted, in the middle; a ring type draws no ring
Any other type its rectangular body, without a card, from y = c − 64 to c + S/(2√2), x = c ± S/(2√2) (Knob: 53–307 × 116–307)
Page dots one per face, from two faces: dots 6 across on targets 16 apart (closer when more than 128 wide would be needed), centred at y = S − 12; the current one in the text colour, the others muted at half opacity
Dashboard name a pill centred at (c, c), 56 high and fully round, 20 padding either side: the icon 24, 10, and the title at 24, medium, cut with an ellipsis; at most 280 wide, on the look's card colour, opaque, with a hairline border in --border (no blur), the face visible around it; for 1000 ms
Paging faces slide sideways, dashboards up and down; see Motion
Locked controls do nothing and read as disabled; the ring at 0.45 opacity. Read-only in the gap line's place (centred at y = S − 28): a lock glyph 15 and the word at 15, 6 apart, muted. A face whose gap line is in use leads that line with the lock glyph instead. Nothing is drawn outside the circle

Paint follows the look: Fluksio draws a muted track, a primary value and a handle of the ground colour ringed in primary; Material a tonal track and a primary handle; Glass a translucent track, a glowing value and a white handle. A Switch or Button face wears the look's own button.

Motion

How a dashboard moves, for devices that draw it natively. Distances are canvas pixels. Each look moves at its own spring; a device without springs runs the spring's closed form for the duration given and then sets the end value, or uses the cubic-bezier that stands in for it.

Look Spring (stiffness, damping, mass) ζ, ω₀ Duration (within 1 %) Overshoot Cubic-bezier stand-in
Fluksio 420, 34, 1 0.830, 20.49 s⁻¹ 210 ms 0.9 % (0.26, 0.12, 0.25, 1.01) over 250 ms, at most 1.5 % off
Material 550, 38, 1 0.810, 23.45 s⁻¹ 270 ms 1.3 % (0.20, 0.11, 0.27, 1.19) over 260 ms, at most 1.7 % off
Glass 320, 22, 0.8 0.688, 20.00 s⁻¹ 330 ms 5.1 % (0.26, 0.20, 0.20, 1.33) over 320 ms, at most 1.7 % off

From rest, a spring's progress is p(t) = 1 − e^(−ζω₀t)·(cos ω_d t + (ζω₀/ω_d)·sin ω_d t), with ω_d = ω₀·√(1 − ζ²). "Spring" below is the dashboard's look's.

What Moves From → to Timing Input during it
Face paging (round) the faces, side by side on a track the track slides one face width S, the new face coming in from the side it lies on (the next from the right). A dot that skips faces brings its face in beside the one shown, so a turn is always one width spring, from where the track is (a swipe's release speed carried on) a new turn while one runs: the running one lands at once and the next starts
Dashboard paging (round panel) the dashboard, and beside it the next one slides S up (the next, from below) or down (the previous, from above), the next one drawn on the face it opens on; once landed, it is the dashboard shown, and its name pill shows for a moment. Each one on the track wears its own look, theme and palette. The ground is the dashboard shown's and changes over as the turn begins, without a fade. One opened by its address replaces the last at once spring further paging waits for the turn to land
Page dot the current dot and the last muted at 0.5 opacity ↔ text colour at 1 200 ms, cubic-bezier(0.4, 0, 0.2, 1) retargets
Dashboard name the pill, on landing on another dashboard opacity 0 → 1, held 1000 ms, 1 → 0 in 200 ms, out 150 ms, cubic-bezier(0.4, 0, 0.2, 1) —
Ring value set by a notch, a key or the engine the value arc's end, the handle (slider, selector, colour) from where it is drawn to the new fraction of the sweep spring each notch retargets from where it is, at the speed it has
Ring value set by a drag the same follows the pointer exactly none —
Hue across red the colour handle a change of more than half the sweep jumps to the other end none —
Slider's reading on the ring, gauge on the ring the reading's dot; the value arc from where it is drawn to the new fraction; a dot's colour follows the fill and the handle as they pass spring retargets
Numbers on the ring centre reading, gap line switch at once, with the notch none —
Value face, Value and Gauge tiles the number counts to the new value, written to its precision spring retargets
Slider tile set elsewhere the fill's end, the handle, the reading's dot from where it is drawn to the new fraction spring a drag or a key moves it at once
Gauge and Bar tiles the value arc, each bar's fill from where it is drawn to the new fraction spring retargets
Dashboard change (rectangular panel) every tile the old dashboard goes at once; each new tile opacity 0 → 1, y +8 → 0 spring —
Rail the current entry's marker slides to the new entry spring retargets

With reduced motion asked for, nothing travels on its own: a page under the finger still follows it, but every turn, return and value lands at once. The dot and the name pill, which only change colour or opacity, keep their timing.

A device may simplify where its hardware is slow, keeping the direction and the end state: a turn a key or a dot asked for may cut; a retarget may restart the curve from where it is without carrying the speed; a counting number may switch; and the value arc may be redrawn each frame as an arc to the eased angle, which is what the browser's reveal amounts to.

Swiping

Faces are swiped sideways and a panel's dashboards up and down, with the page under the finger, as a tile view moves.

Part Value
Start a press anywhere on the face but the ring band, which turns the ring instead
Axis none until the drag has gone 8 from where it began along either axis; then the longer of the two, kept until release
Follow the page moves with the drag one to one, and the page that way is drawn beside it, edge to edge, S away: the next face, or the next dashboard on the face it would open on (the one last shown there, else its first), with its live values
Neighbours the dashboards before and after the one shown are built in advance — loaded, drawn and fed live values — so the one a swipe reaches is complete from the first move. They take no input until they are the one shown
Past the last nothing beside it; the page moves 0.3 of the drag, at most 48
Release turns if the drag went at least S/4 (90 on the Knob), or went at least 8 and was moving at least 500 a second towards the next page over its last 80 ms; otherwise goes back
Turn, go back the look's spring from where the page is, carrying the release speed; a device may use the look's cubic-bezier over its duration from where it is
Press during a turn lands the turn at once; the new drag starts from a page at rest
A swipe that began on a control is not a press of it

Showing one

Open /view/{name} for a dashboard-only view with your normal session. For a dedicated screen, pair a panel.

Panels: hanging a screen on a wall

As a superuser:

  1. Open Dashboards → Panels, add a panel and select its dashboards.
  2. Enable Touch friendly for larger controls.
  3. Open the displayed pairing link on the device. It shows a six-character code.
  4. Enter that code for the panel, check the device description, then press Pair device.

The screen collects its credential and shows the assigned published dashboards. Several dashboards get a navigation rail.

A panel credential reads its assigned dashboards, their bound messages and the artifacts they show. It writes only the targets of their controls and query charts, and the in ports of its own I/O. A message its tiles only draw, or a dashboard setting is bound to, stays read only. On a locked dashboard only the query charts may still publish.

Unpair screen revokes a locally paired credential and keeps the panel's dashboard assignments. Deleting the panel removes the assignment and its access.

A screen without a browser

The openpanel firmware, kept in its own repository, draws dashboards as native widgets on an ESP32-P4 wall panel (Waveshare ESP32-P4-WIFI6-Touch-LCD-7B, 1024×600). Once its config page points it at this instance, it shows the pairing code itself; enter it as in step 4. It reads the same published dashboards and live values and draws every widget type with two exceptions, both shown as a placeholder: a website tile that embeds a page (image tiles work), and a chart of runs, which a panel credential may not read. Media tiles play MJPEG streams, pushed frames, images, and H.264 Baseline or MJPEG clips up to 640×360. Re-encode other clips with the clip recipe.

The device decides what the panel's I/O port names mean. openpanel serves gpio.<n>, backlight, touch, mic and speaker, lists each one's config in its README and ignores any other name. A browser screen serves none of them.

The device's own I/O

A panel can also act as a node. Under I/O, wire a port on the device to a message:

Field Meaning
port The device's name for it, such as gpio.4, backlight, touch, mic or speaker. Lowercase letters, digits, _ and .
direction in: the device publishes to the message. out: the device follows it
message A qualified flow.name. A flow must declare it, as for a control
config A JSON object passed to the device unread, such as {"pull": "up", "debounce_ms": 50}

The credential may publish to its in messages even when a dashboard is locked, and may upload an artifact named after one (PUT /artifacts?name=<message>), which is how a microphone sends a recording. out messages are read only.

!!! note "If the local link is wrong"

Pairing links use `FRONTEND_HOST`. Set it to the app address reachable
from the screen's network.

A screen somewhere you cannot reach

An enrolled instance also shows a portal pairing link. Use that link on the remote screen, then approve its code in the same dialog. The device description says via portal.

The instance enforces the same dashboard and message limits. Remote credentials are issued by the portal, so Unpair screen does not revoke them; revoke them at the portal. Deleting the panel removes access on the instance.

See also