snap

module
v0.2.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 25, 2026 License: MIT

README

Snap

CI OpenSSF Best Practices OpenSSF Scorecard Go Reference

Jarvis Friends Snap — ready-to-use, production-minded Bubble Tea v2 components ("snaps"): navigation, tables, pickers, calendars, charts, and status surfaces with first-class keyboard and mouse support.

Every snap is theme-free with injected style hooks, so it drops into any Charm-stack app and adopts that app's look. Where a snap has multiple implementations (navigation styles, scrollbar presets, pill shapes), it exposes the choice through a small interface or preset list an app can surface to its users at runtime.

Every demo below lives in examples/ and is a VHS tape rendered in the official vhs container. Regenerate them all with go -C tools/rendertapes run . (Docker or Podman; the tool cross-compiles each example, runs every *.tape in parallel, and drops gifs next to tapes).

The examples also work as script-friendly input tools: each one renders its TUI on stderr and writes only the selected value to stdout, exiting 1 on cancel.

date=$(go run ./examples/datepicker)   # -> 2026-07-12
when=$(go run ./examples/timepicker)   # -> 08:30:45
svc=$(go run ./examples/table)         # -> api

Every example shows the same snap status bar with key bindings; pass --no-help to hide it.

Prebuilt binaries for every example ship as their own signed, per-OS/arch release archive (snap_<example>_<os>_<arch>) on the Releases page — no Go toolchain required to use one as a scripting tool. See examples/USAGE.md for the full calling convention.

Date picker

Calendar date picker with click-to-confirm days, header month/year focus, and keyboard/wheel paging.

Date picker demo

Time picker

HH:MM(:SS) time field with per-column dropdowns, type-ahead, and validation.

Time picker demo

Charts

Sparklines, horizontal bars, pie, and sankey charts rendered as ID-routed tea models with stretch-to-fit sizing.

Charts demo

Line chart

Braille line chart showing rolling streams with compact terminal-cell rendering.

Line chart demo

Cell canvas

Whole-cell canvas and gradient helpers for animated truecolor effects.

Cell canvas demo

Pickers

Drive-aware directory picker and related path-editing interactions.

Pickers demo

Context menu

Right-click menu with keyboard parity and terminal-edge clamping.

Context menu demo

Scrollbar

Scrollbar presets with click/drag mapping through OffsetAt.

Scrollbar demo

Table

Sortable/filterable table with row activation and keyboard/mouse support.

Table demo

Dependencies modal

Build info and dependency reader rendered through the status info modal.

Dependencies demo

Forms helpers

Parser-backed form validation for required fields, durations, ISO dates, and list splitting.

Forms demo

Pills and breadcrumbs

Segmented pills, shape variants, and breadcrumb styling helpers from the shared style contract.

Pills demo

Navigation

Tabs, Sidebar, and MinimalTopNav behind one navigator contract.

Navigation demo

Status and notifications

Status bar surfaces plus notification toast/history flows.

Status demo

Supporting packages (no standalone GIF)
  • gate/: feature-gate registry with env overrides for settings-exposed flags.
  • geom/: rect/point geometry helpers for hit-testing and layout math.
  • keys/: rebindable common key map shared by snaps and apps.
  • layout/: lipgloss frame arithmetic helpers.
  • logging/: reserved placeholder.
  • osc/: OSC 9;4 taskbar/tab progress integration.
  • page/: shared page base for sizing and colors.
  • rendercheck/: golden/layout/code-standard test helpers.
  • uifx/: mouse handlers, named zones, and effect tiers.
  • winterm/: Windows default-terminal detection and repair helpers.

The three navigation styles live side by side because they satisfy the same navigator contract; an app can swap between them at runtime.

Design rules

  • Theme-free with style hooks. Components take injected styles (the datepicker/timepicker pattern) instead of importing an app theme, so any Bubble Tea app can adopt them. Hosts map their live theme onto the hooks.
  • Keyboard and mouse. Every interactive element works keyboard-only, mouse-only, and mixed.
  • Settings-ready interfaces. Where multiple implementations exist (e.g. navigation), a snap exposes an interface so an app can offer the choice to users at runtime.
  • Dependencies stay down to charm.land/{bubbletea,bubbles,lipgloss}/v2 plus small helpers that move with the component. One deliberate exception: charts plots braille through ntcharts rather than duplicating its canvas — snap only keeps the chart shapes ntcharts lacks.
  • Every component folder eventually gets a VHS .tape demo and its own README.

Development

bash tools/local_verify.sh is the gate: gofmt, golangci-lint on windows+linux, shellcheck, markdownlint, go vet, go test -race, and a dependency review (module-level vulnerability scan plus OpenSSF Scorecards on direct dependencies).

For color-audit passes, force a loud demo background at runtime with SNAP_DEMO_DEBUG_BG=#ff0066 before running an example or rendering tapes. Any unthemed background holes become obvious immediately.

The test suite also runs rendercheck.CheckCodeStandards over the whole module: display text is measured and padded in terminal cells, never bytes. Concretely — no len() on display strings (use lipgloss.Width), no printf width-padding of string verbs like %-9s (use lipgloss.PlaceHorizontal / Style.Width), no strings.Join(rows, "\n") (use lipgloss.JoinVertical), and no space-run gaps concatenated for alignment (use PlaceHorizontal or a Width/padded style).

Consumers pin tagged releases; for cross-repo development against an application, use a go.work file locally and keep replace directives out of committed go.mod files.

Input contract (mouse + keyboard)

Every visual snap splits input by concern:

  • OnMouse owns the pointer. Clicks, wheel (all four directions), drag, and hover are handled in View().OnMouse (dispatched by uifx.MouseHandlers to the component's handler methods) — never in Update. Keeping the two paths separate isolates pointer logic from state transitions and leaves room to process them independently later.
  • Update owns keys and messages. Component Updates contain no tea.MouseMsg cases; a host that feeds one raw mouse anyway hits dead code, not a second handler.
  • Hit zones are named layers, not hand-kept rectangles. Components build uifx.Zones from the same lipgloss.NewLayer(content).ID(name) blocks the frame is composed of, and handlers ask zones.Hit(x, y) which zone the pointer landed in — powered by lipgloss v2's Compositor.Hit, so zones track layout changes and resolve overlap by z-order (the timepicker package is the reference; the datepicker's uniform grid and the pickers' list rows still use direct arithmetic where that is simpler).
  • Parents translate and call the child's OnMouse. Bubble Tea v2 only invokes the root view's OnMouse (absolute coordinates) and does not translate for children — a parent adjusts x/y itself and calls the child's View().OnMouse. Never forward mouse into a child's Update — the runtime hands the raw event to both the root OnMouse and Update, so two doors means every click processed twice.
Effect tiers (uifx.Level)
Tier Feedback Root mouse mode
LevelMinimal interactions only — no hover/drag cosmetics, minimal redraw churn (thin links) CellMotion
LevelMedium (default) + wheel everywhere, drag tracking while a button is held CellMotion
LevelHigh + hover highlighting of the element under the pointer AllMotion

Set a component's Effects field and give your root view Effects.MouseMode(). Hover is a motion-event firehose — that is why it is opt-in.

Testing input without false failures

Input tests assert semantic state (the highlighted day, the focused column, the cursor row) after events aimed at the component's own recorded hit zones — never hardcoded screen coordinates and never styled output (styles vary by color profile; where rendering must be checked, an injected Transform marker keeps it profile-independent). That keeps every failure a real behavior change.

Directories

Path Synopsis
Package charts holds terminal chart primitives: sparklines (block and directional braille), horizontal bars, pie charts, sankey flows, multi-series braille line charts, and a whole-cell CellCanvas with color gradients.
Package charts holds terminal chart primitives: sparklines (block and directional braille), horizontal bars, pie charts, sankey flows, multi-series braille line charts, and a whole-cell CellCanvas with color gradients.
Package datepicker provides a Bubble Tea v2 component for viewing and selecting a date from a monthly view.
Package datepicker provides a Bubble Tea v2 component for viewing and selecting a date from a monthly view.
Package dependencies reads the running binary's build info (module path, version, VCS state, and dependency list) for display in about/info views.
Package dependencies reads the running binary's build info (module path, version, VCS state, and dependency list) for display in about/info views.
examples
cellcanvas command
Command cellcanvas demos snap/charts' whole-cell canvas and color gradients: a classic plasma field animates over a truecolor palette built from chained charts.Gradient blends.
Command cellcanvas demos snap/charts' whole-cell canvas and color gradients: a classic plasma field animates over a truecolor palette built from chained charts.Gradient blends.
charts command
Command charts is the canonical multi-chart wiring example: several chart models of the same and different types live in one app, every data message carries the ID of the chart it belongs to, and the window is split between charts on resize via SetSize with layout driven by Used().
Command charts is the canonical multi-chart wiring example: several chart models of the same and different types live in one app, every data message carries the ID of the chart it belongs to, and the window is split between charts on resize via SetSize with layout driven by Used().
datepicker command
Command datepicker is a script-usable date prompt built on snap/datepicker: pick a day and the ISO date is written to stdout (the TUI itself renders on stderr), so a shell can capture it:
Command datepicker is a script-usable date prompt built on snap/datepicker: pick a day and the ISO date is written to stdout (the TUI itself renders on stderr), so a shell can capture it:
dependencies command
Command dependencies demos snap/dependencies rendered by snap/status's InfoModal: the running binary's build info (Go version, OS, VCS revision) above a scrollable dependency list read via dependencies.ExpandedBuildInfo.
Command dependencies demos snap/dependencies rendered by snap/status's InfoModal: the running binary's build info (Go version, OS, VCS revision) above a scrollable dependency list read via dependencies.ExpandedBuildInfo.
forms command
Command forms is a script-usable task form proving snap/forms extends huh rather than replacing it: a plain huh.Form whose fields validate through forms.HuhValidate(ParseRequired/ParseDuration/ParseISODate), with SplitAndClean cleaning the tags on submit.
Command forms is a script-usable task form proving snap/forms extends huh rather than replacing it: a plain huh.Form whose fields validate through forms.HuhValidate(ParseRequired/ParseDuration/ParseISODate), with SplitAndClean cleaning the tags on submit.
internal/exui
Package exui is the shared chrome for snap's example programs, so every example reads the same way and doubles as a script-friendly input tool:
Package exui is the shared chrome for snap's example programs, so every example reads the same way and doubles as a script-friendly input tool:
linechart command
Command linechart demos snap/charts' braille line chart model: two live series (a sine sweep and its noisy echo) stream through ID-routed LineDataMsgs into a LineChartModel that stretches to fill the window — braille dots give 2x4 sub-cell resolution, and overlapping series blend their colors per cell.
Command linechart demos snap/charts' braille line chart model: two live series (a sine sweep and its noisy echo) stream through ID-routed LineDataMsgs into a LineChartModel that stretches to fill the window — braille dots give 2x4 sub-cell resolution, and overlapping series blend their colors per cell.
menu command
Command menu is a script-usable context-menu picker built on snap/menu: right-click anywhere (or press m) to pop the menu, choose an item, and the chosen item's ID is written to stdout (the TUI itself renders on stderr):
Command menu is a script-usable context-menu picker built on snap/menu: right-click anywhere (or press m) to pop the menu, choose an item, and the chosen item's ID is written to stdout (the TUI itself renders on stderr):
navigation command
Command navigation is a script-usable page picker that shows all three snap/navigation styles behind the one Navigator contract: n swaps between Sidebar, Tabs, and MinimalTopNav at runtime (the swap the contract exists for), arrows/clicks/wheel move between pages, and Enter writes the active page's ID to stdout (the TUI itself renders on stderr):
Command navigation is a script-usable page picker that shows all three snap/navigation styles behind the one Navigator contract: n swaps between Sidebar, Tabs, and MinimalTopNav at runtime (the swap the contract exists for), arrows/clicks/wheel move between pages, and Enter writes the active page's ID to stdout (the TUI itself renders on stderr):
pickers command
Command pickers is a script-usable directory prompt built on snap/pickers' DirPicker: walk the tree, Space selects, Ctrl+S picks the browsed folder, and the chosen path (relative to the demo tree) is written to stdout (the TUI itself renders on stderr):
Command pickers is a script-usable directory prompt built on snap/pickers' DirPicker: walk the tree, Space selects, Ctrl+S picks the browsed folder, and the chosen path (relative to the demo tree) is written to stdout (the TUI itself renders on stderr):
pills command
Command pills is a script-usable PillShape picker built on snap/styles: every shape is previewed as pills, a segmented pill, a nav strip, and breadcrumbs; Enter writes the selected shape's config value to stdout (the TUI itself renders on stderr):
Command pills is a script-usable PillShape picker built on snap/styles: every shape is previewed as pills, a segmented pill, a nav strip, and breadcrumbs; Enter writes the selected shape's config value to stdout (the TUI itself renders on stderr):
scrollbar command
Command scrollbar demos snap/scrollbar's three presets side by side over the same scrolling text: Smooth (sub-cell glide), Line (thin default), and Classic (retro blocks).
Command scrollbar demos snap/scrollbar's three presets side by side over the same scrolling text: Smooth (sub-cell glide), Line (thin default), and Classic (retro blocks).
status command
Command status demos snap/status + snap/notifications end to end: the status bar (key help on the left, live segments and a summary on the right) with notification toasts, a progress notification that fills as a fake download runs, and the ctrl+n history panel with severity badges.
Command status demos snap/status + snap/notifications end to end: the status bar (key help on the left, live segments and a summary on the right) with notification toasts, a progress notification that fills as a fake download runs, and the ctrl+n history panel with severity badges.
table command
Command table is a script-usable row picker built on snap/table: browse, sort, and filter, then Enter (or double-click) writes the chosen row's key to stdout (the TUI itself renders on stderr), so a shell can capture it:
Command table is a script-usable row picker built on snap/table: browse, sort, and filter, then Enter (or double-click) writes the chosen row's key to stdout (the TUI itself renders on stderr), so a shell can capture it:
timepicker command
Command timepicker is a script-usable time prompt built on snap/timepicker: confirm a time and HH:MM:SS is written to stdout (the TUI itself renders on stderr), so a shell can capture it:
Command timepicker is a script-usable time prompt built on snap/timepicker: confirm a time and HH:MM:SS is written to stdout (the TUI itself renders on stderr), so a shell can capture it:
Package forms provides small input-parsing helpers for text fields: trim-and-validate parsers that return user-facing error messages naming the field, so every form page doesn't re-invent "required", duration, and date validation with slightly different wording.
Package forms provides small input-parsing helpers for text fields: trim-and-validate parsers that return user-facing error messages naming the field, so every form page doesn't re-invent "required", duration, and date validation with slightly different wording.
Package gate provides named boolean feature gates with defaults, environment-variable overrides, and optional persistence, letting apps and pages toggle functionality at runtime (surfaced in the Settings page via a GateRegistry passed through settings.Options).
Package gate provides named boolean feature gates with defaults, environment-variable overrides, and optional persistence, letting apps and pages toggle functionality at runtime (surfaced in the Settings page via a GateRegistry passed through settings.Options).
Package geom provides small screen-geometry primitives shared across the framework and its consumers.
Package geom provides small screen-geometry primitives shared across the framework and its consumers.
Package keys defines AppKeyMap, the application-wide key bindings (quit, page cycling, settings, nav/status toggles) with bubbles/help integration and user rebinding support.
Package keys defines AppKeyMap, the application-wide key bindings (quit, page cycling, settings, nav/status toggles) with bubbles/help integration and user rebinding support.
Package layout provides lipgloss-frame arithmetic helpers: where content starts inside a bordered/padded style, how much room it has, and rendering content into a fixed outer box.
Package layout provides lipgloss-frame arithmetic helpers: where content starts inside a bordered/padded style, how much room it has, and rendering content into a fixed outer box.
Package menu provides a right-click context menu: a small pop-up action list opened at the pointer position, clamped to the terminal, and driven by mouse or keyboard.
Package menu provides a right-click context menu: a small pop-up action list opened at the pointer position, clamped to the terminal, and driven by mouse or keyboard.
Package navigation defines the Navigator interface and the built-in navigators: Sidebar (left-docked list), Tabs (top-docked bordered tab bar with overflow paging), and MinimalTopNav (compact top row with optional number prefixes).
Package navigation defines the Navigator interface and the built-in navigators: Sidebar (left-docked list), Tabs (top-docked bordered tab bar with overflow paging), and MinimalTopNav (compact top row with optional number prefixes).
Package notifications provides a severity-aware notification manager with toast display, history, and optional JSON persistence.
Package notifications provides a severity-aware notification manager with toast display, history, and optional JSON persistence.
Package osc emits terminal OSC escape sequences for taskbar / tab progress (the ConEmu OSC 9;4 protocol, honored by Windows Terminal and others).
Package osc emits terminal OSC escape sequences for taskbar / tab progress (the ConEmu OSC 9;4 protocol, honored by Windows Terminal and others).
Package page provides a small embeddable base for app pages, removing the colors/size boilerplate every page would otherwise repeat.
Package page provides a small embeddable base for app pages, removing the colors/size boilerplate every page would otherwise repeat.
Package pickers holds directory/file selection components: a drive-aware directory browser (DirPicker) and a multi-path editor (MultiFileEditor) whose rows open per-row pickers.
Package pickers holds directory/file selection components: a drive-aware directory browser (DirPicker) and a multi-path editor (MultiFileEditor) whose rows open per-row pickers.
Package rendercheck holds test helpers that catch rendered-string building mistakes in Bubble Tea v2 apps: layout math that guesses frame sizes, borders that lose their edges, lines that overflow the viewport, display- width errors around emoji/CJK, golden-file comparisons, and key-binding hygiene (CheckCodeStandards) — shared so every consumer gates on the same checks.
Package rendercheck holds test helpers that catch rendered-string building mistakes in Bubble Tea v2 apps: layout math that guesses frame sizes, borders that lose their edges, lines that overflow the viewport, display- width errors around emoji/CJK, golden-file comparisons, and key-binding hygiene (CheckCodeStandards) — shared so every consumer gates on the same checks.
Package scrollbar renders minimal scroll indicators for scrolling regions.
Package scrollbar renders minimal scroll indicators for scrolling regions.
Package status renders the bottom status bar and its attached surfaces: key-binding help (short and expanded), the settings/notification/info icon cluster with click regions, the notification history panel, and the centered app-info modal.
Package status renders the bottom status bar and its attached surfaces: key-binding help (short and expanded), the settings/notification/info icon cluster with click regions, the notification history panel, and the centered app-info modal.
Package theme builds the application's visual styling by combining three orthogonal axes that the end user can choose independently:
Package theme builds the application's visual styling by combining three orthogonal axes that the end user can choose independently:
Package table is a themed, interactive data table widget for Bubble Tea apps.
Package table is a themed, interactive data table widget for Bubble Tea apps.
Package timepicker is a small Bubble Tea component for editing a time.Duration as hours/minutes/seconds segments.
Package timepicker is a small Bubble Tea component for editing a time.Duration as hours/minutes/seconds segments.
Package uifx defines the shared interaction-effect tiers for snap components.
Package uifx defines the shared interaction-effect tiers for snap components.
Package winterm reads and writes the Windows *default terminal* delegation — the per-user setting that decides whether console applications open in the legacy console host (conhost) or in Windows Terminal.
Package winterm reads and writes the Windows *default terminal* delegation — the per-user setting that decides whether console applications open in the legacy console host (conhost) or in Windows Terminal.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL