Use cases
Sample home / project dashboards one curation tier below the bundled
presets — they assume a specific city, account, RSS
feed, or other environment-specific bit, so they aren't shipped as
splashboard install --template choices. Drop a TOML in
examples/usecases/
to add one.
User-submitted dashboards live on the Community page, under a looser curation bar.
Companions home_companions
Clock figlet + date + greeting at the top; a random cat and a random dog stand side-by-side beneath as a paired visual hero; fortune cookie + daily quote form the soft typographic body; almanac strip anchors the bottom. Each refresh rotates the pets via `random_cat` / `random_dog`. Showcase preview shows a camera-icon placeholder; the live splash downloads real photos.
Requires: network access for cataas.com / dog.ceo
Show config
# Companions — desk-pet ambient splash. A clock figlet sits at the top
# with date + greeting underneath; a random cat and a random dog stand
# side-by-side beneath as a paired visual hero. A fortune cookie + daily
# quote form the soft typographic body, and the almanac strip
# (moon · zodiac · day-of-year) anchors the bottom for a touch of
# cosmic texture. Refresh cycles rotate the pet portraits — each `cd`
# brings new companions.
# ── Widgets ────────────────────────────────────────────────────────
# Pet bookends. `max_width` / `max_height` cap the rendered box so the
# `align = "center"` offset has room to take effect — without the caps,
# the image fills the whole cell and centring becomes a no-op.
[[widget]]
id = "cat"
fetcher = "random_cat"
render = { type = "media_image", fit = "contain", align = "center", max_width = 18, max_height = 9 }
[[widget]]
id = "dog"
fetcher = "random_dog"
render = { type = "media_image", fit = "contain", align = "center", max_width = 18, max_height = 9 }
# Clock — small figlet so the pets can share the band.
[[widget]]
id = "clock_hero"
fetcher = "clock"
format = "%H:%M"
render = { type = "text_ascii", style = "figlet", font = "slant", color = "panel_title", align = "center" }
[[widget]]
id = "date"
fetcher = "clock"
format = "%A · %e %B %Y"
render = { type = "text_plain", align = "center", color = "text_secondary" }
[[widget]]
id = "greeting"
fetcher = "clock_derived"
render = { type = "text_plain", align = "center", color = "text_secondary" }
[widget.options]
kind = "time_of_day"
# Soft typography centre — fortune cookie + daily quote.
[[widget]]
id = "fortune"
fetcher = "random_fortune"
render = { type = "list_plain", align = "center" }
[[widget]]
id = "quote"
fetcher = "random_quote"
shape = "text"
render = { type = "text_plain", align = "center", color = "panel_title" }
# Almanac strip.
[[widget]]
id = "moon"
fetcher = "clock_derived"
render = { type = "text_plain", align = "right" }
[widget.options]
kind = "moon_phase"
[[widget]]
id = "sep1"
fetcher = "basic_static"
format = " · "
render = { type = "text_plain", align = "center" }
[[widget]]
id = "zodiac"
fetcher = "clock_derived"
render = { type = "text_plain", align = "center" }
[widget.options]
kind = "zodiac"
[[widget]]
id = "sep2"
fetcher = "basic_static"
format = " · "
render = { type = "text_plain", align = "center" }
[[widget]]
id = "doy"
fetcher = "clock_derived"
render = { type = "text_plain", align = "left" }
[widget.options]
kind = "day_of_year"
# ── Layout ─────────────────────────────────────────────────────────
[[row]]
height = { length = 1 }
# Hero clock — full figlet, centred.
[[row]]
height = { length = 6 }
[[row.child]]
widget = "clock_hero"
[[row]]
height = { length = 1 }
[[row.child]]
widget = "date"
[[row]]
height = { length = 1 }
[[row.child]]
widget = "greeting"
[[row]]
height = { length = 1 }
# Pets, side-by-side as the visual companion pair beneath the clock.
[[row]]
height = { length = 11 }
flex = "center"
gap = 8
[[row.child]]
widget = "cat"
width = { length = 26 }
border = "top"
title = " cat "
title_align = "center"
[[row.child]]
widget = "dog"
width = { length = 26 }
border = "top"
title = " dog "
title_align = "center"
[[row]]
height = { length = 1 }
# Fortune cookie — wraps freely.
[[row]]
height = { length = 3 }
flex = "center"
[[row.child]]
widget = "fortune"
width = { length = 90 }
[[row]]
height = { length = 1 }
# Daily quote, centred single line.
[[row]]
height = { length = 1 }
flex = "center"
[[row.child]]
widget = "quote"
width = { length = 100 }
[[row]]
height = { length = 1 }
# Almanac strip.
[[row]]
height = { length = 1 }
flex = "center"
[[row.child]]
widget = "moon"
width = { length = 4 }
[[row.child]]
widget = "sep1"
width = { length = 5 }
[[row.child]]
widget = "zodiac"
width = { length = 14 }
[[row.child]]
widget = "sep2"
width = { length = 5 }
[[row.child]]
widget = "doy"
width = { length = 14 }
[[row]]
height = { fill = 1 }
______ _____ ____ < < /|__ /( __ ) / // (_)/_ </ __ | / // / ___/ / /_/ / /_//_(_)____/\____/ Thursday · 11 June 2026 morning ───────── cat ────────── ───────── dog ────────── ▄▄▄▄▄▄ ▄▄▄▄▄▄ ▄▄▄▄▄▄▀▀▀▀▄▄▄▄▄▄ ▄▄▄▄▄▄▀▀▀▀▄▄▄▄▄▄ ▄▄ ▀▀▀▀▀▀▀▄▄▄▄▄ ▄▄ ▀▀▀▀▀▀▀▄▄▄▄▄ ▀▀▄▄▀▀▀▄▀▀▀▀ ▀▀▄▄▀▀▀▄▀▀▀▀ ▀ ▀ ▀ ▀ ▄▄▀▀▄▄▄▀▄▄ ▄▄▀▀▄▄▄▀▄▄ ▀▀ ▄▄▄▄▄▄▄▄ ▀▀ ▀▀ ▄▄▄▄▄▄▄▄ ▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ A man with one watch knows what time it is. A man with two watches is never sure. If you can't make it good, at least make it look good. — Bill Gates 🌓 F · ♊ Gemini · day 162
GitHub inbox home_github_inbox
Contributions heatmap as a wide masthead band, avatar identity card to its left, then a 2×2 grid of notifications / my PRs / review queue / assigned-issues. The year-at-a-glance heatmap is the visual hero, the queues the operational body.
Requires: GitHub auth (gh login or `GH_TOKEN` / `GITHUB_TOKEN`)
Show config
# GitHub triage inbox — designed around a single visual move: the
# contributions heatmap fills the masthead band as a wide horizontal strip,
# anchoring the splash with "here's what your year of GitHub looks like".
# Avatar + identity card sit to its left as a sidebar; the four inbox
# queues stack as a 2×2 grid below, each with a small count badge in the
# title so heaviness reads at a glance.
# ── Widgets ────────────────────────────────────────────────────────
# Avatar.
[[widget]]
id = "avatar"
fetcher = "github_avatar"
render = { type = "media_image", fit = "contain", max_width = 14, max_height = 7, align = "center" }
# Identity lines.
[[widget]]
id = "user"
fetcher = "github_user"
shape = "text_block"
render = { type = "list_plain" }
# Hero — contributions heatmap, full year, fills the masthead band.
[[widget]]
id = "heatmap"
fetcher = "github_contributions"
shape = "heatmap"
render = "grid_heatmap"
# Four inbox queues.
[[widget]]
id = "notifications"
fetcher = "github_notifications"
render = { type = "list_links", max_items = 5 }
[[widget]]
id = "my_prs"
fetcher = "github_my_prs"
render = { type = "list_links", max_items = 5 }
[[widget]]
id = "review_queue"
fetcher = "github_review_requests"
render = { type = "list_links", max_items = 5 }
[[widget]]
id = "assigned"
fetcher = "github_assigned_issues"
render = { type = "list_links", max_items = 5 }
# ── Layout ─────────────────────────────────────────────────────────
[[row]]
height = { length = 1 }
bg = "subtle"
# Masthead: avatar (14) | identity (24) | heatmap (76). Asymmetric.
[[row]]
height = { length = 7 }
bg = "subtle"
gap = 2
[[row.child]]
widget = "avatar"
width = { length = 14 }
[[row.child]]
widget = "user"
width = { length = 24 }
[[row.child]]
widget = "heatmap"
width = { length = 78 }
[[row]]
height = { length = 1 }
bg = "subtle"
[[row]]
height = { length = 1 }
# Inbox 2×2 grid, equal cells.
[[row]]
height = { length = 7 }
flex = "center"
gap = 2
[[row.child]]
widget = "notifications"
width = { length = 56 }
border = "top"
title = " notifications "
title_align = "left"
[[row.child]]
widget = "my_prs"
width = { length = 56 }
border = "top"
title = " my PRs "
title_align = "left"
[[row]]
height = { length = 1 }
[[row]]
height = { length = 7 }
flex = "center"
gap = 2
[[row.child]]
widget = "review_queue"
width = { length = 56 }
border = "top"
title = " review queue "
title_align = "left"
[[row.child]]
widget = "assigned"
width = { length = 56 }
border = "top"
title = " assigned "
title_align = "left"
[[row]]
height = { fill = 1 }
Yuji Ueki ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ▄▄▄▄▄ Terminal splash renderer ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ▄▄▄▄▄▀▀▀▀▄▄▄▄▄ Tokyo, Japan · member si ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ▀▄▄▀▀▄▄▀▀▀ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ▄▀▄▄▄▄▀▄ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ▀▀ ▄▄▀▀▀▀▄▄ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ▀▀▀▀▀▀▀▀▀▀▀▀ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ notifications ─────────────────────────────────────── my PRs ────────────────────────────────────────────── splashboard review_requested: feat: heatmap unhappychoice/splashboard#54 feat(docs): generate widget ratatui mention: rfc: themes unhappychoice/splashboard#51 feat(fetcher): split clock review queue ──────────────────────────────────────── assigned ──────────────────────────────────────────── ratatui/ratatui#1234 feat: add pie chart unhappychoice/splashboard#41 meta: widget catalog & road tokio-rs/tokio#5678 fix: race in spawn unhappychoice/splashboard#17 theme system
Linear sprint board home_linear
Cycle overview as three panels — stats, state breakdown bars, burndown sparkline — all derived from the same `linear_cycle` fetcher in different shapes. Active issues and notifications sit below; cycle calendar + personal priority breakdown anchor the bottom.
Requires: Linear API token (`LINEAR_TOKEN`)
Show config
# Linear sprint dashboard — no hero, just three Overview panels (cycle
# stats / state breakdown / burndown sparkline) drawn from the same
# `linear_cycle` read in three different shapes. Active issues +
# notifications sit below; the cycle calendar carries the time axis at
# the bottom alongside a personal priority breakdown.
# ── Widgets ────────────────────────────────────────────────────────
# Overview row — three views of the same cycle.
[[widget]]
id = "cycle_stats"
fetcher = "linear_cycle"
shape = "entries"
render = "grid_table"
[[widget]]
id = "state_bars"
fetcher = "linear_cycle"
shape = "bars"
render = { type = "chart_bar", horizontal = true }
[[widget]]
id = "burndown"
fetcher = "linear_cycle"
shape = "number_series"
render = { type = "chart_sparkline", label = "completed" }
# Operations row — what's open and what needs attention.
[[widget]]
id = "active_issues"
fetcher = "linear_issues"
render = "list_timeline"
[widget.options]
filter_state = "started"
filter_assignee = "me"
limit = 4
[[widget]]
id = "notifications"
fetcher = "linear_notifications"
render = "list_timeline"
[widget.options]
filter_read = "unread"
limit = 4
# Bottom row — time axis + personal priority distribution.
[[widget]]
id = "cycle_calendar"
fetcher = "linear_cycle"
shape = "calendar"
render = "grid_calendar"
[[widget]]
id = "priority"
fetcher = "linear_issues"
shape = "bars"
render = { type = "chart_bar", horizontal = true }
[widget.options]
filter_assignee = "me"
# ── Layout ─────────────────────────────────────────────────────────
[[row]]
height = { length = 1 }
# Overview: cycle stats / state bars / burndown sparkline.
[[row]]
height = { length = 9 }
flex = "center"
gap = 2
[[row.child]]
widget = "cycle_stats"
width = { length = 38 }
border = "top"
title = " cycle stats "
title_align = "left"
[[row.child]]
widget = "state_bars"
width = { length = 38 }
border = "top"
title = " state breakdown "
title_align = "left"
[[row.child]]
widget = "burndown"
width = { length = 38 }
border = "top"
title = " burndown "
title_align = "left"
[[row]]
height = { length = 1 }
# Operations: active issues + unread notifications.
[[row]]
height = { length = 9 }
flex = "center"
gap = 2
[[row.child]]
widget = "active_issues"
width = { length = 56 }
border = "top"
title = " active · me "
title_align = "left"
[[row.child]]
widget = "notifications"
width = { length = 60 }
border = "top"
title = " notifications "
title_align = "left"
[[row]]
height = { length = 1 }
# Time axis + personal priority distribution.
[[row]]
height = { length = 10 }
flex = "center"
gap = 2
[[row.child]]
widget = "cycle_calendar"
width = { length = 30 }
border = "top"
title = " cycle days "
title_align = "left"
[[row.child]]
widget = "priority"
width = { length = 86 }
border = "top"
title = " by priority · me "
title_align = "left"
[[row]]
height = { fill = 1 }
cycle stats ─────────────────────── state breakdown ─────────────────── burndown ────────────────────────── Cycle 24 Completed 17████████████████████████ completed █ Started 2026-04-22 In Progress 8███████████ ██ Ends 2026-05-06 Todo 12████████████████ ▅██ Completed 17 / 40 Canceled 3███ ▅███ Days left 5 ▂████ ▂█████ ▃██████ ·▃███████ active · me ───────────────────────────────────────── notifications ─────────────────────────────────────────── 2025-04-29 │ ENG-123 Fix login flow 2025-04-29 │ ENG-123 mention by @sarah │ In Progress · P1 │ Fix login flow 2025-04-28 │ ENG-118 Polish dashboard layout 2025-04-28 │ ENG-118 assigned by @max │ Todo · P3 │ Polish dashboard cycle days ──────────────── by priority · me ────────────────────────────────────────────────────────────────── April 2026 Urgent 1█████████████████████████ Su Mo Tu We Th Fr Sa High 3██████████████████████████████████████████████████████████████████████████████ 1 2 3 4 Medium 2███████████████████████████████████████████████████ 5 6 7 8 9 10 11 Low 1█████████████████████████ 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Laptop mission control home_system_monitor
Tight grid of vertical thermometer gauges and small tables: battery / cpu / memory / disk thermometers across the top, uptime / load / memory details / mounts tables below, and a full-width processes table at the bottom.
Requires: local system access (no auth)
Show config
# Mission-control style laptop monitor — every panel is a gauge or a small
# table, packed into a tight grid that reads as one continuous control
# board. No figlet, no decorative bands. The visual signature is "lots of
# small panes with their own borders, all aligned to the same column grid".
#
# All four gauges (battery / cpu / memory / disk) use vertical
# `gauge_thermometer` so the top row reads as a row of dial-style indicators.
# Panel heights match the thermometer column so nothing leaves dead space.
# ── Widgets ────────────────────────────────────────────────────────
# Top row — four vertical thermometers, identical style.
[[widget]]
id = "battery"
fetcher = "system_monitor_battery"
shape = "ratio"
render = { type = "gauge_thermometer", tone = "drain", label = "bat" }
[[widget]]
id = "cpu_gauge"
fetcher = "system_monitor_cpu"
shape = "ratio"
render = { type = "gauge_thermometer", tone = "drain", label = "cpu" }
[[widget]]
id = "memory_gauge"
fetcher = "system_monitor_memory"
shape = "ratio"
render = { type = "gauge_thermometer", tone = "drain", label = "ram" }
[[widget]]
id = "disk_gauge"
fetcher = "system_monitor_disk"
shape = "ratio"
render = { type = "gauge_thermometer", tone = "drain", label = "dsk" }
# Middle / bottom row tables.
[[widget]]
id = "uptime"
fetcher = "system_monitor_uptime"
shape = "text"
render = { type = "text_plain", align = "left" }
[[widget]]
id = "load_table"
fetcher = "system_monitor_load"
shape = "entries"
render = "grid_table"
[[widget]]
id = "memory_details"
fetcher = "system_monitor_memory"
shape = "entries"
render = "grid_table"
[[widget]]
id = "disk_bars"
fetcher = "system_monitor_disk"
shape = "bars"
render = { type = "chart_bar", horizontal = true }
[[widget]]
id = "processes"
fetcher = "system_monitor_processes"
shape = "entries"
render = "grid_table"
[widget.options]
count = 8
# ── Layout ─────────────────────────────────────────────────────────
# Four 28-cell columns: 28 × 4 + 2 × 3 = 118.
[[row]]
height = { length = 1 }
# Top row — four thermometers on the left, uptime stacked over load-avg
# in a single right-side column. 11 rows tall so the thermometer columns
# have enough vertical resolution to show partial fill steps; the right
# column splits 5/6 between uptime (only 1 line of content) and load avg
# (3 entries) so neither panel feels empty.
[[row]]
height = { length = 11 }
flex = "center"
gap = 2
[[row.child]]
widget = "battery"
width = { length = 13 }
border = "top"
title = " bat "
title_align = "center"
[[row.child]]
widget = "cpu_gauge"
width = { length = 13 }
border = "top"
title = " cpu "
title_align = "center"
[[row.child]]
widget = "memory_gauge"
width = { length = 13 }
border = "top"
title = " ram "
title_align = "center"
[[row.child]]
widget = "disk_gauge"
width = { length = 13 }
border = "top"
title = " dsk "
title_align = "center"
[[row.child]]
width = { length = 56 }
[[row.child.row]]
height = { length = 5 }
[[row.child.row.child]]
widget = "uptime"
border = "top"
title = " uptime "
title_align = "left"
[[row.child.row]]
height = { length = 6 }
[[row.child.row.child]]
widget = "load_table"
border = "top"
title = " load avg "
title_align = "left"
[[row]]
height = { length = 1 }
# Middle row — memory details + mounts + top processes, three columns.
# Sized at 11 rows so processes (8 entries + title) fits without padding.
[[row]]
height = { length = 11 }
flex = "center"
gap = 2
[[row.child]]
widget = "memory_details"
width = { length = 38 }
border = "top"
title = " memory "
title_align = "left"
[[row.child]]
widget = "disk_bars"
width = { length = 38 }
border = "top"
title = " mounts "
title_align = "left"
[[row.child]]
widget = "processes"
width = { length = 38 }
border = "top"
title = " top processes "
title_align = "left"
[[row]]
height = { fill = 1 }
─── bat ─── ─── cpu ─── ─── ram ─── ─── dsk ─── uptime ────────────────────────────────────────────── ╭─╮ ╭─╮ ╭─╮ ╭─╮ 2m │█│ │░│ │░│ │░│ │█│ │░│ │░│ │░│ │█│ │░│ │░│ │░│ │█│ │░│ │░│ │█│ load avg ──────────────────────────────────────────── bat │█│ 100% cpu │░│ 16% ram │░│ 8% dsk │█│ 58% 1min 0.89 │█│ │░│ │░│ │█│ 5min 0.27 │█│ │░│ │░│ │█│ 15min 0.09 │█│ │█│ │█│ │█│ ╰●╯ ╰●╯ ╰●╯ ╰●╯ memory ──────────────────────────── mounts ──────────────────────────── top processes ───────────────────── used 1.3 GB / 42████ xtask 0.0% total 15.6 GB /home 110██████████████ multipathd 0.0% free 14.3 GB /data 200█████████████████████████████ kworker/0:2-events 0.0% probing-thread 0.0% python3 0.0%
Todoist GTD home_todoist
Three-column kanban (overdue / today / upcoming), each a `todoist_tasks` list filtered by `filter_due`. Three count badges as a header strip summarise the day's pulse. No figlet, no quote — task columns are the dashboard.
Requires: Todoist API token (`TODOIST_TOKEN`)
Show config
# Todoist GTD dashboard — three-column kanban: overdue / today /
# upcoming, each one a `todoist_tasks` list filtered by `filter_due`.
# Three count badges in a subtle band header summarise the day's pulse,
# then the columns themselves take up the body. No figlet hero, no
# bottom quote — just task columns, all business.
#
# Showcase note: `todoist_tasks.sample_body` is options-blind, so all
# three count badges and all three list columns render identical sample
# content in the preview. In live use each column shows its own
# filtered set.
# ── Widgets ────────────────────────────────────────────────────────
# Three count badges — same fetcher with different `filter_due`. Tone
# follows the badge sample's Status (Error/Warn/Ok) so overdue reads red
# in live use.
[[widget]]
id = "count_overdue"
fetcher = "todoist_tasks"
shape = "badge"
render = { type = "status_badge", padding = 2, align = "center" }
[widget.options]
filter_due = "overdue"
[[widget]]
id = "count_today"
fetcher = "todoist_tasks"
shape = "badge"
render = { type = "status_badge", padding = 2, align = "center" }
[widget.options]
filter_due = "today"
[[widget]]
id = "count_upcoming"
fetcher = "todoist_tasks"
shape = "badge"
render = { type = "status_badge", padding = 2, align = "center" }
[widget.options]
filter_due = "upcoming"
# Three task columns — same fetcher, different `filter_due`.
[[widget]]
id = "list_overdue"
fetcher = "todoist_tasks"
shape = "linked_text_block"
render = { type = "list_links", max_items = 12 }
[widget.options]
filter_due = "overdue"
[[widget]]
id = "list_today"
fetcher = "todoist_tasks"
shape = "linked_text_block"
render = { type = "list_links", max_items = 12 }
[widget.options]
filter_due = "today"
[[widget]]
id = "list_upcoming"
fetcher = "todoist_tasks"
shape = "linked_text_block"
render = { type = "list_links", max_items = 12 }
[widget.options]
filter_due = "upcoming"
# ── Layout ─────────────────────────────────────────────────────────
# Header strip: three count badges as the day's pulse.
[[row]]
height = { length = 1 }
[[row]]
height = { length = 1 }
flex = "center"
gap = 4
[[row.child]]
widget = "count_overdue"
width = { length = 32 }
[[row.child]]
widget = "count_today"
width = { length = 32 }
[[row.child]]
widget = "count_upcoming"
width = { length = 32 }
[[row]]
height = { length = 1 }
# Three task columns — the dashboard body. 36 + 36 + 36 + 4 + 4 = 116.
[[row]]
height = { length = 30 }
flex = "center"
gap = 4
[[row.child]]
widget = "list_overdue"
width = { length = 36 }
border = "top"
title = " overdue "
title_align = "left"
[[row.child]]
widget = "list_today"
width = { length = 36 }
border = "top"
title = " today "
title_align = "left"
[[row.child]]
widget = "list_upcoming"
width = { length = 36 }
border = "top"
title = " upcoming "
title_align = "left"
[[row]]
height = { fill = 1 }
● todo 9 (2 overdue) ● todo 9 (2 overdue) ● todo 9 (2 overdue) overdue ───────────────────────── today ─────────────────────────── upcoming ──────────────────────── overdue · P4 Fix flaky CI on macOS r overdue · P4 Fix flaky CI on macOS r overdue · P4 Fix flaky CI on macOS r overdue · P3 Reply to design review overdue · P3 Reply to design review overdue · P3 Reply to design review today · P1 Ship v2.3 release notes today · P1 Ship v2.3 release notes today · P1 Ship v2.3 release notes today · P2 Pair with @sam on auth re today · P2 Pair with @sam on auth re today · P2 Pair with @sam on auth re today · P3 Review @lin's PR #482 today · P3 Review @lin's PR #482 today · P3 Review @lin's PR #482 today · P4 Update onboarding doc scr today · P4 Update onboarding doc scr today · P4 Update onboarding doc scr tomorrow · P2 1:1 prep — quarterly g tomorrow · P2 1:1 prep — quarterly g tomorrow · P2 1:1 prep — quarterly g wed · P3 Draft proposal for caching wed · P3 Draft proposal for caching wed · P3 Draft proposal for caching fri · P3 Migrate flaky integration t fri · P3 Migrate flaky integration t fri · P3 Migrate flaky integration t
Manuscript project_book
Slim figlet title centred above a wide deadline gauge, a writing-pace sparkline below, and totals / chapters / recent-edits tables along the bottom. Manuscript front-matter aesthetic.
Requires: local git repo with prose content
Show config
# Book project splash — manuscript cover. Slim figlet title centred at the
# top, then a wide deadline gauge that spans the page like a chapter
# divider, the writing-pace sparkline below, and three small tables (LOC
# totals, chapters, recent edits) at the bottom. Reads as a book front
# matter page rather than a code dashboard.
# ── Widgets ────────────────────────────────────────────────────────
# Slim figlet title.
[[widget]]
id = "name"
fetcher = "git_repo_name"
render = { type = "text_ascii", style = "figlet", font = "small", color = "panel_title", align = "center" }
# Edition / age subtitle — version tag and how long the project has run,
# laid out side-by-side as a single byline for the manuscript cover.
[[widget]]
id = "byline"
fetcher = "git_latest_tag"
shape = "text"
render = { type = "text_plain", align = "right", color = "text_secondary" }
[[widget]]
id = "byline_sep"
fetcher = "basic_static"
format = " · "
render = { type = "text_plain", align = "center", color = "text_secondary" }
[[widget]]
id = "age"
fetcher = "git_age"
shape = "text"
render = { type = "text_plain", align = "left", color = "text_secondary" }
# Wide deadline gauge — spans the page. 30 segments so the bar actually
# fills the canvas band instead of being a tiny 5-LED nub.
[[widget]]
id = "deadline"
fetcher = "clock_countdown"
shape = "ratio"
render = { type = "gauge_segment", tone = "drain", segments = 30 }
[widget.options]
target = "2026-12-31"
target_label = "ship"
window_days = 365
# Writing pace sparkline.
[[widget]]
id = "pace"
fetcher = "git_commits_activity"
shape = "number_series"
render = { type = "chart_sparkline", style = "bars" }
# LOC totals.
[[widget]]
id = "totals"
fetcher = "code_loc"
shape = "entries"
render = "grid_table"
# Longest chapters — `code_largest_files` reads as "chapter X — N words"
# in a manuscript repo (the largest .md files are the longest chapters).
[[widget]]
id = "chapters"
fetcher = "code_largest_files"
shape = "entries"
render = "grid_table"
[widget.options]
count = 6
# Recent edits.
[[widget]]
id = "edits"
fetcher = "git_recent_commits"
render = "list_timeline"
[widget.options]
count = 4
# ── Layout ─────────────────────────────────────────────────────────
[[row]]
height = { length = 2 }
# Cover band — slim figlet centred.
[[row]]
height = { length = 5 }
[[row.child]]
widget = "name"
[[row]]
height = { length = 1 }
flex = "center"
[[row.child]]
widget = "byline"
width = { length = 8 }
[[row.child]]
widget = "byline_sep"
width = { length = 5 }
[[row.child]]
widget = "age"
width = { length = 8 }
[[row]]
height = { length = 2 }
# Deadline gauge — segmented bar centred under the cover band.
[[row]]
height = { length = 3 }
flex = "center"
[[row.child]]
widget = "deadline"
width = { length = 49 }
[[row]]
height = { length = 1 }
# Writing-pace sparkline — full-width band.
[[row]]
height = { length = 5 }
flex = "center"
[[row.child]]
widget = "pace"
width = { length = 100 }
border = "top"
title = " writing pace · commits/week "
title_align = "left"
[[row]]
height = { length = 1 }
# Bottom: totals (left, narrow) | chapters (centre) | recent edits (right).
[[row]]
height = { length = 8 }
flex = "center"
gap = 2
[[row.child]]
widget = "totals"
width = { length = 26 }
border = "top"
title = " totals "
title_align = "left"
[[row.child]]
widget = "chapters"
width = { length = 34 }
border = "top"
title = " longest chapters "
title_align = "left"
[[row.child]]
widget = "edits"
width = { length = 38 }
border = "top"
title = " recent edits "
title_align = "left"
[[row]]
height = { fill = 1 }
_ _ _ _ ____ __| |__ _ __| |_ | |__ ___ __ _ _ _ __| | (_-< '_ \ / _` (_-< ' \| '_ \/ _ \/ _` | '_/ _` | /__/ .__/_\__,_/__/_||_|_.__/\___/\__,_|_| \__,_| |_| v1.2.3 · 2y 3m ship · 202d 12h ▰▰▰▰▰▰▰▰▰▰▰▰▰▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱▱ 45 writing pace · commits/week ───────────────────────────────────────────────────────────────────── ▂ █ ▅ ▂ ▇ █▁█▄ ▁ ▇█▄ █▁ ▆ █▃████ ▃█ ▆███▃██ ▅███████████▅███████ totals ──────────────── longest chapters ────────────── recent edits ────────────────────── Rust 8,234 src/render/mod.rs 1,234 2023-11-14 │ feat(render): add heatmap TypeScript 2,111 src/fetcher/git/mod.rs 812 │ a1b2c3d Markdown 820 src/payload.rs 640 2023-11-14 │ fix(fetcher): tz fallback TOML 560 │ d4e5f6a 2023-11-13 │ chore: bump ratatui │ e7f8a9b
CI status project_ci
Layered CI dashboard: tone-coloured status hero, per-branch status row (main / develop / feat / hotfix), then a 2-column band of pass/fail sparkline + duration scatter, with the recent runs timeline as the operational footer. All four data-rich panels are different shapes of the same `github_action_history` and `github_action_status` reads.
Requires: GitHub auth (gh login or `GH_TOKEN`), local git repo on GitHub
Show config
# CI status splash — answers "is CI happy?" in layers, drilling down:
# 1. Hero badge: overall status of the active branch
# 2. Per-branch status row: which branches are healthy
# 3. History sparkline + duration scatter: pass/fail and timing trends
# 4. Recent runs timeline: what specifically just ran
#
# Skips a branch / dirty / ahead-behind panel — that's prompt territory.
# ── Widgets ────────────────────────────────────────────────────────
# Slim repo header.
[[widget]]
id = "repo"
fetcher = "git_repo_name"
render = { type = "text_plain", align = "center", color = "text_secondary" }
[[widget]]
id = "commit"
fetcher = "git_recent_commits"
shape = "text_block"
format = "1"
render = { type = "list_plain", align = "center", color = "text_secondary" }
# Hero — fat status badge centred on the canvas.
[[widget]]
id = "status"
fetcher = "github_action_status"
shape = "badge"
render = { type = "status_badge", padding = 8, align = "center" }
# Status text line — branch · result · duration.
[[widget]]
id = "status_text"
fetcher = "github_action_status"
shape = "text"
render = { type = "text_plain", align = "center" }
# Per-branch status badges — same fetcher, different `branch` option. In
# the live splash these read distinct (each branch's own status); the
# showcase preview shows them as identical sample data because
# `github_action_status.sample_body` is options-blind.
[[widget]]
id = "branch_main"
fetcher = "github_action_status"
shape = "badge"
render = { type = "status_badge", padding = 1, align = "center" }
[widget.options]
branch = "main"
[[widget]]
id = "branch_develop"
fetcher = "github_action_status"
shape = "badge"
render = { type = "status_badge", padding = 1, align = "center" }
[widget.options]
branch = "develop"
[[widget]]
id = "branch_feat"
fetcher = "github_action_status"
shape = "badge"
render = { type = "status_badge", padding = 1, align = "center" }
[widget.options]
branch = "feat/foo"
[[widget]]
id = "branch_hotfix"
fetcher = "github_action_status"
shape = "badge"
render = { type = "status_badge", padding = 1, align = "center" }
[widget.options]
branch = "hotfix"
# Pass/fail count over the last 30 runs — clearer than a NumberSeries
# sparkline (which can't differentiate values, only positions). Bars
# shape gives explicit "passed N · failed M" headline.
[[widget]]
id = "history"
fetcher = "github_action_history"
shape = "bars"
render = { type = "chart_bar", horizontal = true }
# Run-duration trend — PointSeries connected by a line.
[[widget]]
id = "duration"
fetcher = "github_action_history"
shape = "point_series"
render = "chart_line"
# Recent runs timeline.
[[widget]]
id = "runs"
fetcher = "github_action_history"
shape = "timeline"
render = "list_timeline"
# Open PRs awaiting CI — what's queued up downstream of the runs panel.
[[widget]]
id = "open_prs"
fetcher = "github_repo_prs"
shape = "linked_text_block"
render = { type = "list_links", max_items = 6 }
# ── Layout ─────────────────────────────────────────────────────────
[[row]]
height = { length = 1 }
[[row]]
height = { length = 1 }
[[row.child]]
widget = "repo"
[[row]]
height = { length = 1 }
[[row.child]]
widget = "commit"
[[row]]
height = { length = 1 }
# Hero badge — wide centred band.
[[row]]
height = { length = 3 }
flex = "center"
[[row.child]]
widget = "status"
width = { length = 100 }
[[row]]
height = { length = 1 }
flex = "center"
[[row.child]]
widget = "status_text"
width = { length = 90 }
[[row]]
height = { length = 1 }
# Per-branch status row — four small badges spanning the canvas, each
# panel titled with the branch name so the live (and showcase) reader
# can tell them apart.
[[row]]
height = { length = 3 }
flex = "center"
gap = 2
[[row.child]]
widget = "branch_main"
width = { length = 28 }
border = "top"
title = " main "
title_align = "center"
[[row.child]]
widget = "branch_develop"
width = { length = 28 }
border = "top"
title = " develop "
title_align = "center"
[[row.child]]
widget = "branch_feat"
width = { length = 28 }
border = "top"
title = " feat/foo "
title_align = "center"
[[row.child]]
widget = "branch_hotfix"
width = { length = 28 }
border = "top"
title = " hotfix "
title_align = "center"
[[row]]
height = { length = 1 }
# 2-col band: pass/fail sparkline | duration scatter.
[[row]]
height = { length = 6 }
flex = "center"
gap = 2
[[row.child]]
widget = "history"
width = { length = 58 }
border = "top"
title = " pass / fail (last 30) "
title_align = "left"
[[row.child]]
widget = "duration"
width = { length = 58 }
border = "top"
title = " duration "
title_align = "left"
[[row]]
height = { length = 1 }
# Recent runs (left) + open PRs feeding CI (right).
[[row]]
height = { length = 8 }
flex = "center"
gap = 2
[[row.child]]
widget = "runs"
width = { length = 58 }
border = "top"
title = " recent runs "
title_align = "left"
[[row.child]]
widget = "open_prs"
width = { length = 58 }
border = "top"
title = " open PRs "
title_align = "left"
[[row]]
height = { fill = 1 }
splashboard a1b2c3d feat(render): add heatmap ● ci passing main · passing ────────── main ────────── ──────── develop ───────── ──────── feat/foo ──────── ───────── hotfix ───────── ● ci passing ● ci passing ● ci passing ● ci passing pass / fail (last 30) ───────────────────────────────── duration ────────────────────────────────────────────── passed 25█████████████████████████████████████████████████ ⢠⠓⢄ ⢠⢣ failed 5█████████ ⢠⠃ ⠑⢄ ⢀⠎ ⢇ ⢀⡠⢄⣀ ⢠⠃ ⠈⢢ ⡜ ⠈⢆ ⢀⡠⠔⠒⠢⠤⠔⠊⠁ ⠉⠢⣀ ⣠⠃ ⠣⡀ ⢀⡠⠊⠢⡀ ⡰⠁ ⠘⡄ ⣀⠤⠤⠒⠒⠊⠉⠉⠉⠒⠊⠁ ⠑⠤⠒⠉ ⠑⠒⠢⠤⠔⠁ ⠑⢤⠃ ⠘ recent runs ─────────────────────────────────────────── open PRs ────────────────────────────────────────────── Apr 12 │ #4235 main #54 feat(docs): generate widget catalogue │ passing #51 feat(fetcher): split clock options Apr 10 │ #4234 feat/auth-refactor │ failing Apr 7 │ #4233 main │ passing Apr 5 │ #4232 main
Welcome card project_welcome
Welcome splash for newcomers cloning the repo. Repo-name figlet hero, tagline / mission line, two-column body (getting-started commands and what-this-is description), then a links band and a maintainer footer. Almost entirely static content — meant to be customised by the repo maintainer and committed to the repo so cloners see a curated welcome on their first `cd`.
Show config
# Welcome card — for the "other / project" context: when someone
# clones this repo and cd's in for the first time, this is the splash
# they see. Big logo, tagline, getting-started commands, "what is
# this", and where-to-go-next links. Mostly static content authored
# by the maintainer; the only live fetcher is `git_repo_name` for the
# figlet header. Designed to ship inside the repo as
# `.splashboard/dashboard.toml` so cloners get a curated welcome.
# ── Widgets ────────────────────────────────────────────────────────
# Repo name as the visual hero — figlet quadrant blocks like the
# project_codebase preset, but uncluttered (no metadata band beside it).
[[widget]]
id = "logo"
fetcher = "git_repo_name"
render = { type = "text_ascii", style = "blocks", pixel_size = "quadrant", color = "panel_title", align = "center" }
# Tagline — two-line mission statement. Maintainer edits this to taste.
[[widget]]
id = "tagline"
fetcher = "basic_static"
shape = "text_block"
format = """
Customizable terminal splash, configured per directory.
One-line install, TOML config, fast cached first-paint.
"""
render = { type = "list_plain", align = "center", color = "text_secondary" }
# Getting-started commands — the four-line incantation a cloner runs
# after `git clone` to actually try the project. List rendered plain.
[[widget]]
id = "quickstart"
fetcher = "basic_static"
shape = "text_block"
format = """
$ cargo build --release
$ ./target/release/splashboard install
$ source ~/.zshrc
$ cd any-project # splash appears
"""
render = { type = "list_plain" }
# "What is this" — a few sentences expanding on the tagline so a
# cloner knows whether to keep reading. Static text.
[[widget]]
id = "what_is"
fetcher = "basic_static"
shape = "text_block"
format = """
A terminal splash you control with TOML.
The killer feature is per-directory walk-up:
each repo can ship its own dashboard, so
different projects greet you differently
when you cd in.
"""
render = { type = "list_plain" }
# Where-to-go-next links — handover to docs / contributing / issues.
[[widget]]
id = "next_steps"
fetcher = "basic_static"
shape = "text_block"
format = """
• Read AGENTS.md for the architecture overview
• See CONTRIBUTING.md to ship a new fetcher or renderer
• Catalog issue: github.com/unhappychoice/splashboard/issues/41
• Open an issue: github.com/unhappychoice/splashboard/issues
"""
render = { type = "list_plain" }
# Maintainer footer — contact + license + sponsor link.
[[widget]]
id = "footer"
fetcher = "basic_static"
shape = "text"
format = "Maintained by @unhappychoice · MIT licensed · github.com/unhappychoice/splashboard"
render = { type = "text_plain", align = "center", color = "text_secondary" }
# ── Layout ─────────────────────────────────────────────────────────
[[row]]
height = { length = 2 }
# Hero logo.
[[row]]
height = { length = 5 }
[[row.child]]
widget = "logo"
[[row]]
height = { length = 1 }
# Tagline.
[[row]]
height = { length = 2 }
flex = "center"
[[row.child]]
widget = "tagline"
width = { length = 100 }
[[row]]
height = { length = 1 }
# Two-column body: quickstart | what is this.
[[row]]
height = { length = 8 }
flex = "center"
gap = 4
[[row.child]]
widget = "quickstart"
width = { length = 50 }
border = "top"
title = " getting started "
title_align = "left"
[[row.child]]
widget = "what_is"
width = { length = 50 }
border = "top"
title = " what is this "
title_align = "left"
[[row]]
height = { length = 1 }
# Where to go next — full-width links band.
[[row]]
height = { length = 6 }
flex = "center"
[[row.child]]
widget = "next_steps"
width = { length = 100 }
border = "top"
title = " where to go next "
title_align = "left"
[[row]]
height = { length = 1 }
# Footer.
[[row]]
height = { length = 1 }
[[row.child]]
widget = "footer"
[[row]]
height = { fill = 1 }
▝█ ▜▌ ▜▌ ▝█ ▟▀▀ ▜▞▜▖ █ ▝▀▙ ▟▀▀ ▐▙▜▖▐▙▄ ▟▀▙ ▝▀▙ ▜▟▜▖▗▄█ ▝▀▙ ▐▙▟▘ █ ▟▀█ ▝▀▙ ▐▌▐▌▐▌▐▌█ █ ▟▀█ ▐▌▝▘█ █ ▀▀▘ ▟▙ ▝▀▘ ▝▀▝▘▀▀▘ ▀▘▝▘▀▝▀ ▝▀▘ ▝▀▝▘▀▀ ▝▀▝▘ Customizable terminal splash, configured per directory. One-line install, TOML config, fast cached first-paint. getting started ─────────────────────────────── what is this ────────────────────────────────── $ cargo build --release A terminal splash you control with TOML. $ ./target/release/splashboard install $ source ~/.zshrc The killer feature is per-directory walk-up: $ cd any-project # splash appears each repo can ship its own dashboard, so different projects greet you differently when you cd in. where to go next ──────────────────────────────────────────────────────────────────────────────── • Read AGENTS.md for the architecture overview • See CONTRIBUTING.md to ship a new fetcher or renderer • Catalog issue: github.com/unhappychoice/splashboard/issues/41 • Open an issue: github.com/unhappychoice/splashboard/issues Maintained by @unhappychoice · MIT licensed · github.com/unhappychoice/splashboard