Display
The [display] block describes your panel’s physical geometry: pixel dimensions per panel, chain length, and scaling. These values flow into every layout calculation, so a mismatch between config and hardware clips content or centers it on the wrong axis.
The two reference builds
Section titled “The two reference builds”Two hardware configurations ship as ready-to-use examples — the maintainer’s day-to-day rigs that the demos and example configs are written against. You can match them, scale them, or build something different; the engine only cares about what [display] declares. The smallsign is a Raspberry Pi 4 with five 32×16 panels chained horizontally for a 160×16 canvas. The bigsign is a Raspberry Pi 5 with eight P3 32×64 panels arranged in a 2×4 vertical-serpentine layout for a 256×64 canvas.
Smallsign — Pi 4 + 5× 32×16 panels = 160×16 logical
[display]rows = 16cols = 32chain_length = 5default_scale = 1brightness = 60gpio_slowdown = 2Bigsign — Pi 5 + 8× P3 32×64 vertical-serpentine 2×4 = 256×64 logical
[display]rows = 32cols = 64chain_length = 8parallel = 1pixel_mapper_config = "Remap:256,64|192,32n|192,0n|128,32n|128,0n|64,32n|64,0n|0,32n|0,0n"default_scale = 4brightness = 60gpio_slowdown = 3pwm_bits = 8Logical canvas vs real panel
Section titled “Logical canvas vs real panel”When default_scale > 1, the engine wraps the real panel in a ScaledCanvas — the layer that expands logical pixels onto a big / scaled sign. All drawing logic stays at “16-tall logical content,” so widgets never need to know what scale they are running at; the wrapper expands each logical pixel to a scale×scale block on the real canvas and centers the content vertically. For developers and plugin authors: that expansion happens per SetPixel call.
There is one hard ceiling you must respect: content_height × scale ≤ panel_h_real. For the bigsign at scale = 4, this means content_height ≤ 16. Push above the ceiling and the logical canvas is taller than the real panel; content placed near the top or bottom edges silently clips. If you need per-section breathing room, use text_y_offset on the widget rather than over-specifying content_height.
Per-section overrides
Section titled “Per-section overrides”scale and content_height can also be set per section, overriding the display-level defaults. The classic case is a two_row widget: its two text rows need more horizontal room to fit handles like @firebird.demo, so it typically runs at scale = 2, giving 128 logical pixels of width instead of the default 64.
[[playlist.section]]mode = "slideshow"scale = 2content_height = 24hold_time = 4.0Scheduling
Section titled “Scheduling”[display.schedule] lets you automatically dim or darken the sign during certain hours — useful for not blasting full brightness at 3 a.m. The schedule is driven by a lightweight background task that wakes every ~30 seconds and adjusts matrix.brightness to match whichever window is active right now.
Windows
Section titled “Windows”A schedule is a list of [[display.schedule.windows]] entries. Each window covers a time range and specifies a brightness:
[display.schedule]enabled = truetimezone = "America/New_York" # set this — fresh Pis are often UTC
[[display.schedule.windows]]start = "07:00"end = "18:00"brightness = 100
[[display.schedule.windows]]start = "18:00"end = "23:00"brightness = 40
[[display.schedule.windows]]start = "23:00" # wraps past midnightend = "07:00"brightness = 0 # dark — panel off overnightbrightness = 0 makes the LEDs go dark (≈ zero panel power draw). This is not a power or sleep mode — the Pi keeps rendering at full cadence; only the LED brightness output goes to zero.
Window resolution
Section titled “Window resolution”At each check the scheduler finds the last matching window in the list whose time range includes the current wall-clock time. “Last” means highest index, so place more-specific or higher-priority windows after the general ones.
Because the last matching window wins, place a more specific window after a general one to override it. For example, a normal day with a dimmer lunch hour:
[[display.schedule.windows]]start = "07:00"end = "23:00"brightness = 100
[[display.schedule.windows]]start = "12:00" # overrides the window above during lunchend = "13:00"brightness = 40A window wraps past midnight when end < start (e.g. start = "23:00", end = "07:00"). That window is active from 23:00 until 06:59.
Day filtering
Section titled “Day filtering”Add a days list to a window to restrict it to specific weekdays:
[[display.schedule.windows]]start = "08:00"end = "18:00"brightness = 100days = ["mon", "tue", "wed", "thu", "fri"] # weekdays only
[[display.schedule.windows]]start = "10:00"end = "22:00"brightness = 60days = ["sat", "sun"] # weekends on a gentler settingAn empty days list (the default) matches every day of the week.
Timing and behavior
Section titled “Timing and behavior”- Boundary latency: brightness changes land within approximately 30 seconds of the scheduled time, not instantly at the second.
- Step, not fade: brightness jumps in one step when a window becomes active — there is no fade animation.
- Schedule changes need a restart: the schedule is read at startup; there is no live-reload. Restart the display process after editing
[display.schedule]. - Timezone:
timezoneaccepts any IANA name (e.g."America/New_York","Europe/London"). Leave it empty to use the Pi’s system time — but set it explicitly if you can; freshly imaged Pis default to UTC, which will shift your windows by several hours.
Viewing the resolved schedule
Section titled “Viewing the resolved schedule”Run led-ticker validate config.toml to see the resolved schedule printed alongside the usual validation output. This is useful for confirming window coverage and catching gaps before deploying.
[display] reference
Section titled “[display] reference”The full field reference — every knob, default value, and
Pi-version note — lives at
Reference: Config options.
The most-touched fields are above (rows, cols, chain_length,
default_scale, pixel_mapper_config, gpio_slowdown); see the
reference page when you need pwm_bits, pwm_lsb_nanoseconds,
rp1_pio, or the other Pi-tuning options.