Sections and modes
The [[playlist.section]] block is the fundamental unit of a led-ticker program. Each section groups one or more widgets and tells the engine how to run them. Three modes are available: slideshow, ticker, and one_at_a_time.
A playlist is just an ordered list of sections. The engine runs them in sequence, firing a section-to-section transition at each boundary, and loops back to the start when the last section finishes.
ticker — side-by-side continuous stream
Section titled “ticker — side-by-side continuous stream”All widgets in the section are joined into a single continuous stream that scrolls left across the panel without stopping. Each widget follows immediately after the last, separated by a • bullet character. The stream loops: when the last widget exits the left edge, the first re-enters from the right. This is the classic news ticker or stock crawl — one unbroken ribbon of content.
ticker suits short-text widgets that the reader can absorb at a glance: a weather condition, a price update, a brief announcement. Combine several short widgets and the stream stays lively without any pauses. Transitions are not used between widgets in this mode — the bullet separator is the only break.
The separator is customizable per section. Set separator to any string — " * " or " | " are common alternatives — or "" for a minimal two-space gap with no glyph. separator_color accepts the same shapes as widget font_color (constant [r, g, b], "rainbow", or a gradient table). separator_font and separator_font_size let you match the separator’s typeface to the rest of the section. All four fields are rejected on non-ticker modes. separator_size shrinks or grows the bigsign separator circle (default 8; radius = size ÷ 2); it does not affect the smallsign BDF •.

[[playlist.section]]mode = "ticker"loop_count = 1scroll_step_ms = 35
[[playlist.section.widget]]type = "message"text = "Open 9-5"font_color = [225, 48, 108]
[[playlist.section.widget]]type = "countdown"text = "Summer Camps"countdown_date = 2026-06-20font_color = [120, 220, 255]
[[playlist.section.widget]]type = "message"text = "Free coffee Friday"font_color = [255, 220, 0]
[[playlist.section.widget]]type = "message"text = "All ages welcome"font_color = [180, 220, 180]one_at_a_time — sequential scroll
Section titled “one_at_a_time — sequential scroll”Each widget scrolls all the way across the panel and fully off the left edge before the next widget enters from the right. Widgets never appear on screen at the same time. Each message gets its own clean moment without a held pause.
one_at_a_time suits medium-length messages that should read as distinct items — enrollment announcements, sale callouts, or any set of messages where you want each one to complete before the next begins. Unlike ticker, there is never any overlap between consecutive messages; unlike slideshow, there is no hold and no transition animation. The effect is a clean sequence of individual scrolls.

[[playlist.section]]mode = "one_at_a_time"loop_count = 1scroll_step_ms = 35
[[playlist.section.widget]]type = "message"text = "Now Enrolling"font_color = [225, 48, 108]
[[playlist.section.widget]]type = "countdown"text = "Summer Camps"countdown_date = 2026-06-20font_color = [120, 220, 255]
[[playlist.section.widget]]type = "message"text = "Spring Classes Open"font_color = [255, 220, 0]
[[playlist.section.widget]]type = "message"text = "Drop-ins welcome"font_color = [180, 220, 180]slideshow — held with transitions
Section titled “slideshow — held with transitions”Each widget is displayed for hold_time seconds (default 3.0). If the widget’s text overflows the panel width, it scrolls once before stopping; otherwise it holds stationary. When the hold expires a transition animation runs, and the next widget appears. slideshow is the natural fit for a storefront window display or information board where each item needs to be readable on its own.
The transition used between widgets in the section is configured via the transition field. If you omit transition, the global [transitions] default applies. When a section explicitly sets transition = "...", that transition is also used when the section appears — overriding the global between_sections setting for that section’s entry.

[transitions]default = "push_left"duration = 0.5
[[playlist.section]]mode = "slideshow"loop_count = 1hold_time = 2.5
[[playlist.section.widget]]type = "message"text = "Open daily"font_color = [120, 220, 255]
[[playlist.section.widget]]type = "message"text = "10am - 8pm"font_color = [225, 48, 108]
[[playlist.section.widget]]type = "image"path = "config/assets/phoenix_transparent.png"fit = "pillarbox"image_align = "center"hold_time = 3.0
[[playlist.section.widget]]type = "message"text = "All ages"font_color = [255, 220, 0]For gif widgets in slideshow mode, play_count = 0 plays the gif through the section’s hold_time — the engine computes how many complete loops fit and plays at least one. See gif widget — play_count = 0.
loop_count and section progression
Section titled “loop_count and section progression”loop_count controls how many times the engine runs through all of the section’s widgets before moving on to the next section. A loop_count of 1 (the default) means the engine plays each widget once and then moves on. A value of 2 plays the whole set twice, and so on. Section-to-section transitions fire once when the engine leaves the section — they are not repeated on each loop.
The global [transitions] between_sections setting controls what transition plays at section boundaries. A section can override this by setting transition explicitly — when it does, that transition is used both for inter-widget swaps within the section AND for the entry transition when the section first appears.
Tuning scroll cadence with scroll_step_ms
Section titled “Tuning scroll cadence with scroll_step_ms”Both ticker and one_at_a_time advance one logical pixel per engine tick by default — 50 ms per pixel, or about 20 logical pixels per second. Set scroll_step_ms on a section to override that cadence. Lower values (30-40 ms) speed the marquee up for dense content like RSS headlines or rapid stock tickers; higher values (70-100 ms) slow it down for messages that need a deliberate read. The same value also drives the post-hold scroll on slideshow mode for widgets whose content overflows the panel width.
[[playlist.section]]mode = "one_at_a_time"loop_count = 1scroll_step_ms = 30 # snappier than the 50 ms default
[[playlist.section.widget]]type = "rss.feed"feed_url = "https://example.com/feed"The section-level scroll_step_ms is distinct from the per-widget scroll_speed_ms on gif and image widgets — the section knob controls how fast the engine’s cursor advances across widgets in scroll modes; the widget knob controls how fast text scrolls inside a single widget’s text overlay. Different layers, different code paths; both can be set in the same config.
Section backgrounds with bg_color
Section titled “Section backgrounds with bg_color”Setting bg_color on a section paints a solid RGB color across the panel before any widget draws. Widgets in the section inherit that background unless they set their own bg_color — one line at the section level instead of repeating it on every widget.
[[playlist.section]]mode = "slideshow"hold_time = 4.0bg_color = [255, 244, 214] # brand cream — warm neutral behind all widgets in this section
[[playlist.section.widget]]type = "message"text = "Now Enrolling"
[[playlist.section.widget]]type = "message"text = "Spring Classes"When a section has a bg_color and the next section has a different one, transitions paint the right color throughout — the engine forwards outgoing_bg_color and incoming_bg_color to the active transition so the panel never flashes through black at the cut-over. Widget-level bg_color works the same way for inter-widget transitions within a section.
A widget setting its own bg_color overrides the section default for that widget only. Use a section-level color as the base and only set widget-level bg_color when one widget needs a different tint.
default vs transition
Section titled “default vs transition”The [transitions] block uses default = "wipe_left" for the playlist-wide default. Inside a [[playlist.section]] the equivalent is transition = "wipe_left" — writing default = inside a section block has no effect (the key is silently dropped).
Which mode to use
Section titled “Which mode to use”| Mode | What it looks like |
|---|---|
ticker | All widgets joined in one continuous stream, looping endlessly — the classic news ticker |
one_at_a_time | Each widget scrolls fully across and off before the next enters — clean sequential scrolls, no overlap |
slideshow | Each widget holds on screen for hold_time, then a transition reveals the next — storefront / info-board style |