Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

102 changes: 102 additions & 0 deletions docs/design/board-diagrams.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Board diagram design language

Vocabulary for LightPlayer board diagrams. Every board drawing renders from
metadata (`boards/<vendor>/<product>.display.json` sidecars, see
`lp-app/lpa-boards/`) through one SVG renderer: the `BoardDiagram` Dioxus
component (`lpa-boards/src/diagram.rs`), whose geometry lives entirely in
`lpa-boards/src/geometry.rs`. There are no hand-drawn board images.

Ported from the approved UX spike (`spikes/hardware-boards/DESIGN-LANGUAGE.md`
rev 5, PR #222, two visual gates).

## Layout vocabulary

| Term | Meaning |
|---|---|
| **Unit** `u` | Pin pitch = row height. THE scaling factor — every other dimension derives from it. |
| **Row** | One pin's horizontal band, `u` tall. All annotation for a pin lives in its row, so every pin can be annotated simultaneously. |
| **Cell** | A typed chip inside a row. Width fits content; height is fixed (`0.78u`). |
| **Rail** | The stack of rows on a left/right board edge. Rails extend outward from the pads. |
| **Band** | Horizontal strip above/below the rails holding rows for top/bottom-edge pins (screw terminals etc.), which can't have vertical rows. |
| **Leader** | Elbow line connecting a top/bottom pad to its band row. |
| **Pad** | The pin's physical marker on the board edge, colored by role. |
| **Label** | The pin's name, silkscreen-style *inside* the board edge, colored by role. Keeps outside cells left-aligned into columns. |

The annotated-anatomy story (`studio/boards/board-diagram/anatomy` in the
story book) draws this vocabulary on a real board; its callout anchors are
computed from the same `BoardLayout` the renderer draws, so the figure tracks
the engine.

## Derived geometry (all from `u`)

Constants live in `lpa-boards/src/geometry.rs` — that module is the single
home for these numbers.

| Element | Size |
|---|---|
| Row height / pin pitch | `1.00u` |
| Cell height | `0.78u` |
| Pad | `0.62u × 0.45u` |
| Cell font | `0.50u` |
| Cell gap | `0.22u` |

The spike settled on `u = 12` for compact contexts (device card, discovery)
and `u = 13` for detail contexts (boards page pinout). `scale` multiplies the
rendered SVG size only — geometry never changes with it.

## Cell types

Colors ride `lpb-cell--*` classes in the studio stylesheet
(`lpa-studio-web/src/style.css`), mapped onto studio palette families where
one exists.

| Type | Color family | Used for |
|---|---|---|
| `name` | slate | Pin name (band rows only; rails put names inside the board) |
| `pwr` / `gnd` | red (status-error) / dim | Power and ground |
| `adc` `dac` `touch` | green (status-good) / blue (status-live) / orange (status-attention) | Analog capabilities |
| `spi` `i2c` `uart` `usb` | violet / cyan / brown / amber | Buses |
| `strap` | amber | Boot-strap pins — usable, with care |
| `warn` | dim orange | Caution: input-only, XTAL, PSRAM-reserved, JTAG |
| `conn` | **violet** (status-bound) | A bound connection (studio convention: bound = violet, never green) |
| swatch | — | Discovery color code (n solid squares) |

## Pin roles (pad + label color, drives eligibility)

`pwr5` `pwr3` `gnd` `io` `ioin` (input-only) `strap` `usb` `ctl` (EN/RST)
`nc` `rsvd` (in-package flash/PSRAM — present but never claimable)

Output-eligible for LEDs: `io`, `strap` (`PinRole::output_eligible()`).
Never: `ioin`, `usb` (e.g. C6 IO12/13 USB-JTAG), `nc`, `rsvd`, power/ctl,
and pins already bound or reserved (onboard RGB).

## Renderer modes

| Mode | Question it answers | Where |
|---|---|---|
| `plain` | what does the board look like? | catalog / picker thumbnails |
| `caps` | what's *supported* on each pin? | boards page detail |
| `wired` | what's *connected*? | device card hardware pane |
| `swatch` | which pin are my LEDs on? | pin discovery |

## Discovery language

- **Order test**: the 9-pixel palindrome `K-R-G-B-W-B-G-R-K`, repeated on every
free pin. K bounds each repeat, W marks the center; palindrome ⇒ direction
doesn't matter; K/W are permutation-invariant ⇒ the perceived row uniquely
identifies the strip's color order (RGB/GRB/…).
- **Code**: a pin's steady color sequence. Codes are **palindromes** — data
direction is unknown, so a code and its reverse are indistinguishable; a
palindrome reads the same from either end. Displayed with **K (off) pixels
between digits** so color runs read unambiguously, but no leading/trailing K —
short strips (even 3 LEDs) must still show 1-digit codes. A `d`-digit code
occupies `2d−1` physical pixels.
- **Code plan**: smallest `d digits × c colors` with `c^ceil(d/2) ≥ free pins`
(a length-`d` palindrome has `ceil(d/2)` free digits), colors drawn in order
from the palette `R G B C M Y W` (K is reserved as the separator). Even digit
counts are never optimal, so the ladder is 1 digit (1 px) → 3 digits (5 px) →
5 digits (9 px). E.g. 20 pins → `3 digits × 5 colors` = 25 `X·Y·X` codes on
5 pixels.

The discovery *mechanics* (driver rotation, channel budgets) are M7's plan;
this section defines only the visual language the `swatch` mode renders.
6 changes: 6 additions & 0 deletions lp-app/lpa-boards/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@ rust-version.workspace = true
default = []
# JSON Schema derives for the board display sidecar types (host-side tooling).
schema-gen = ["dep:schemars"]
# The BoardDiagram Dioxus component. Off by default so data-only consumers
# (lp-cli) never pull a UI framework.
diagram = ["dep:dioxus"]

[dependencies]
# Component-library feature set (no renderer, no launch): the consuming app
# picks the platform.
dioxus = { version = "0.7", default-features = false, features = ["lib"], optional = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
schemars = { workspace = true, optional = true }
Expand Down
39 changes: 35 additions & 4 deletions lp-app/lpa-boards/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,39 @@ is enforced by `tests/manifest_drift.rs`, not code coupling. Rationale:

Authoring guide and tier definitions: `lp-core/lpc-hardware/boards/README.md`.
Schema: `schemas/board-display.schema.json` (generated by `just schema-gen`).
Drawing vocabulary: `spikes/hardware-boards/DESIGN-LANGUAGE.md` until the
renderer milestone moves it into `docs/design/`.
Drawing vocabulary: `docs/design/board-diagrams.md`.

Coming milestones add the row-engine `BoardDiagram` component and the
`#/boards` catalog page here.
## The `BoardDiagram` component

The row-engine SVG renderer, behind the `diagram` cargo feature (off by
default so data-only consumers never pull a UI framework):

```toml
lpa-boards = { path = "../lpa-boards", features = ["diagram"] }
```

```rust
use lpa_boards::{BoardDiagram, DiagramMode, WiredConnection, board_by_id};

rsx! {
BoardDiagram {
board: board_by_id("espressif/esp32-s3-devkitc-1").unwrap().clone(),
mode: DiagramMode::Wired, // plain | caps | wired | swatch
u: 12.0, // pin pitch — the design language's unit
scale: 1.05, // on-screen size only; geometry is u-driven
wired: vec![WiredConnection {
gpio: 16,
title: "porch strip".into(),
extra: Some("WS2812 ×300".into()),
}],
}
}
```

Colors ride `lpb-*` classes; the class block lives in the consuming app's
stylesheet (`lpa-studio-web/src/style.css`), mapped onto the studio palette
(bound = violet). All geometry — rails, band rows, leader lines, viewBox —
comes from `geometry::BoardLayout`, which is public and deterministic:
stories compute annotation anchors from the same layout the renderer draws.

A coming milestone adds the `#/boards` catalog page.
4 changes: 4 additions & 0 deletions lp-app/lpa-boards/src/catalog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ pub const DISPLAY_MANIFEST_SOURCES: &[(&str, &str)] = &[
"quinled/dig-uno",
include_str!("../../../lp-core/lpc-hardware/boards/quinled/dig-uno.display.json"),
),
(
"domraem/dom-z-102",
include_str!("../../../lp-core/lpc-hardware/boards/domraem/dom-z-102.display.json"),
),
];

/// Every checked-in board, parsed once. Panics on malformed embedded data —
Expand Down
Loading
Loading