Dot Matrix Display

dot-matrix-displayViewers

The other half of the panel from the segment display. A segment readout can say a number; this is what says C:Small Plate on the top line and Mix=99 Volume=99 on the bottom, and it does it the way the hardware does — a fixed field of dots, five columns by seven or eight rows per character, ink moving across dots that never move. Which kind of screen it is comes from the preset, and the two are genuinely different objects: an LED marquee makes light at the dot, so it is round, bright, haloed, on black glass; a backlit character LCD lights the pane and the dots are shadows on it, so the ink is square and dark on yellow-green, with no halo at all and a spill that comes from the backlight rather than from the characters. Text wider than the panel is cut off as a real module cuts it, or scrolls on a clock derived from elapsed time so a dropped frame cannot make it drift. A bitmap prop drives the dots directly for meters, waveforms and boot logos, and a blinking block cursor marks the field being edited. The unlit grid is one tiled pattern and each line of ink is one path, so a 20x2 screen is a handful of nodes rather than 1,600.

bitmap
99
99
Scroll long text
OFF
5x8 (descenders)
ON

Install

Copies the source into your project. Anything it depends on comes with it.

$ npx shadcn add @syntho-ui/dot-matrix-display

Pulls in

dot-matrix-fontdisplay-chromecontrol-theme

First time? Add the registry to your components.json once:

components.json
{
  "registries": {
    "@syntho-ui": "https://engine.syntho.app/r/{name}.json"
  }
}

Usage

Controlled or uncontrolled, whichever suits the surrounding state.

example.tsx
import { DotMatrixDisplay } from "@/components/ui/dot-matrix-display"
import { themeVars } from "@/lib/theme"

// The backlit character module: dark square ink on yellow-green.
<DotMatrixDisplay
  preset="lcd-green"
  columns={16}
  rows={8}
  text={["C:Small Plate", "Mix=99 Volume=99"]}
/>

// The marquee: round lit dots on black glass, scrolling.
<DotMatrixDisplay preset="led-red" columns={12} scroll text="NOW PLAYING — SIDE TWO" />

// Straight to the dots, for anything the character generator cannot say.
<DotMatrixDisplay preset="vfd" bitmap={levels} />

// Re-skin every display in a surface from one style block.
<div style={themeVars({ displayInk: "#ff9f1a", displaySpill: "#ff9f1a" })}>
  <DotMatrixDisplay columns={12} text="SYNTHO 128" />
</div>

Props

PropTypeDefaultDescription
textstring | string[]A line, or one per array entry. Newlines split too.
bitmapboolean[][]Drive the dots directly, [row][column], ignoring the font — meters, waveforms, logos, anything the character generator has no glyph for.
columnsnumberCharacter cells across — the panel's physical width. Defaults to the widest line. Text past it is cut off unless scroll is set.
rows7 | 87Dot rows per cell. Seven is the classic 5x7 module and clips descenders exactly as one does; eight draws them.
presetDisplayPresetId | DisplayPreset"led-red"Panel skin. The reflective ones (lcd-green, lcd-blue, lcd-grey) turn the screen into a backlit module: square ink, no bloom, spill from the backlight.
shape"square" | "round"The dot itself. Defaults to square on reflective skins and round on emissive ones, which is how the two kinds of screen are actually built.
pitchnumber4Dot spacing in pixels, centre to centre — the display's whole scale.
fillnumber0.74Dot size as a fraction of the pitch. Under 1 is what leaves the grid visible.
scrollbooleanfalseMarquee lines that do not fit. Stops entirely under prefers-reduced-motion; a line that already fits never moves.
speednumber18Marquee speed in dot columns per second.
cursorDotMatrixCursorThe block a module leaves where you are typing: { line?, column, style?: "block" | "underline", blink? }.
colorstringOverride the ink colour. The unlit dots are derived from it and follow.
ghostnumberHow visible the unlit dots are, 0..1. Defaults to the skin's.
bloomnumberHalo around the lit dots, 0..1. Defaults to the skin's — zero on the reflective ones.
spillnumberHow far light escapes the window onto the panel, 0..1.
brightnessnumber1Overall drive on the ink.
labelstringSilkscreen caption above the display.
— theme--uikit-display-ink / --uikit-display-spillNot props: the two CSS custom properties (displayInk / displaySpill via themeVars) that re-skin every display under a wrapper, resolved in CSS with no re-render. Precedence is instance color, then these, then the skin.
framebooleantrueDraw the panel around the pane.

Interaction

  • Drag with pointer capture, so the gesture keeps tracking past the edge of the control.
  • Shift while dragging for a fine pass; release it mid-gesture and coarse tracking resumes.
  • Double-click resets to defaultValue.
  • Arrow keys step normally, Shift+arrow steps finely, PageUp/PageDown jump by ten, Home/End go to the extremes.
  • Proper slider and switch roles with live aria-valuetext, so a screen reader announces the formatted value rather than the raw number.
  • The scroll wheel adjusts the value while the pointer is over the control; stepped ranges move at least one declared step per notch by default.