Wallboard mode Read from ten feet away, with no mouse and nobody watching most of the time. Type goes up several steps and interaction goes to zero. The only thing that should change unprompted is state someone needs to walk over for. Tokens this needs: --card, --card-foreground, --muted, --muted-foreground, --border, --status-critical, --status-warn, --status-unknown The status, chart, scale, state and direction names are an extension, not a rename. shadcn has --destructive and five --chart-* and nothing else in this territory. ──────────────────────────────────────────────────────────────────────── // Wallboard.tsx ──────────────────────────────────────────────────────────────────────── import { cn } from "@/lib/utils"; import { freshness } from "../freshness-indicator/freshness"; import type { Status } from "../semantic-status-color/status"; export type Tile = { label: string; value: string; status: Status }; /** Four at most, and the type says so. Twelve panels at three metres is * twelve panels nobody can read. */ export type Tiles = [Tile] | [Tile, Tile] | [Tile, Tile, Tile] | [Tile, Tile, Tile, Tile]; type Props = { tiles: Tiles; /** When the newest sample arrived and how often one should. A frozen page * looks fine from ten feet, so stale has to be a state the board draws. */ lastArrival: Date | null; expectedEveryMs: number; now?: Date; }; /** Grey at rest. A nominal value is the same ink as its label; colour is * spent only on a state someone should walk over for. */ const VALUE: Record = { nominal: "text-card-foreground", warn: "text-status-warn", critical: "text-status-critical", unknown: "text-status-unknown", }; const clock = (d: Date) => `${String(d.getUTCHours()).padStart(2, "0")}:${String(d.getUTCMinutes()).padStart(2, "0")}`; export function Wallboard({ tiles, lastArrival, expectedEveryMs, now = new Date() }: Props) { const { state } = freshness(lastArrival, expectedEveryMs, now); const frozen = state === "stale" || state === "unknown"; return (
{tiles.map((t) => (
{/* No hover, no legend, no chrome: the label is on the tile. */}

{t.label}

{t.value}

))} {frozen && (

{lastArrival ? `stale since ${clock(lastArrival)}` : "no data"}

)}
); } ──────────────────────────────────────────────────────────────────────── // demo.tsx ──────────────────────────────────────────────────────────────────────── import { Wallboard } from "./Wallboard"; /** * Four numbers for a screen across the room. Three are at rest and drawn in * the same ink as their labels; errors has crossed its threshold and is the * only colour on the wall. The clock is fixed so the board renders the same * on the server and in the browser. */ const NOW = new Date("2026-09-15T09:00:00Z"); export default function Demo() { return (
); }