Skip to content

hue — Feature Specification

Status: living inventory · Date: 2026-08-05 · Scope: apps/hue (apps/hue/src/*.d) plus the sparkles libraries it drives (sparkles:syntax, sparkles:core-cli, sparkles:raylib-text, sparkles:ghostty).

hue is an interactive syntax-highlighting file viewer and live theme previewer over sparkles:syntax. It reads a source file (or its own source), highlights it with the precise tree-sitter pipeline, and renders it in one of four rendering modes: non-interactive ANSI, HTML, an interactive terminal previewer, and an optional raylib GUI window with a render-markdown.nvim-style markdown preview.

This spec is a traceable feature inventory and the source of truth for hue: every requirement carries an ID, a status, and a link to the code that implements it, so every part of the codebase maps to a requirement (see Traceability below).

Design sources

The design and rationale for the two large hue efforts live in GitHub issues, whose normative requirements are folded into these specs (the specs supersede the issues as the requirement of record):

IssueTitleFolded into
#121hue: raylib GPU rendering backend (--gui) — styled runs as data on sparkles:syntax + the shared sparkles:raylib-textgui.md (§ Design & scope, milestones)
#120sparkles:twoslash — D-native Twoslash (umbrella)twoslash.md
#122Render-side 1/2 — sparkles:syntax as a Shiki replacement (SSG HTML, playground, VitePress)twoslash.md RS1*
#123Render-side 2/2 — twoslash × sparkles:syntax via apps/hue (HTML + ANSI)twoslash.md TWM*/TWO*/TWH*

hue's visuals are built on the canvas-first UI toolkit, which has its own requirement tree:

SpecOwns
sparkles:uithe toolkit — state machines (STM), layout (LAY), widgets (WGT/VMD), backends (TGT), theme (THM), input (INP)
ui/layout.mdthe layout-model decision record
ui/migration.mdthe sequencing of hue's port onto the toolkit

hue-side requirements referencing those areas live in ui-architecture.md.

Documentation map

PageWhat it covers
Overview (this page)what hue is · the rendering modes · the status/ID/traceability scheme · module coverage
Feature requirementsapp-wide requirements common to all rendering modes: invocation & CLI, source acquisition, concatenation & stdin, line ranges, text normalization & safety, language detection, the highlight engine, themes, color policy, output-mode dispatch, width & wrapping, the ANSI/HTML/previewer sinks, degradation, non-functional
Document chrome (design)the decorations drawn around the content — header, grid, rule, snip, the line-number gutter and the git change column — as one composable --style set implemented as sparkles:ui widgets, so the same set renders in ANSI, HTML, TUI and GUI. Replaces the three private gutters hue paints today
Pager & streaming (design)hue's place in the shell: when it pages (and why its own TUI is the pager rather than a spawned less), rendering pre-formatted input so $MANPAGER / git core.pager work, and following input that has not finished arriving (tail -f, less +F)
GUI (--gui) requirementsthe raylib GPU window: window/font, the wrapped-line render model, the raw & markdown-preview views, navigation, scrollbar, live theme cycling, search/goto, every markdown construct, code blocks, mouse selection & clipboard (incl. ANSI-block selection, table grid selection — sub-cell / row / column / rectangular — and copy modes: ANSI raw/strip, table TSV/markdown), fullscreen, debug hooks
TUI requirements (full viewer shipped: T1–T4)the full-screen terminal viewer — the GUI viewer painted in cells: scrolling, a cell scrollbar, SGR mouse, incremental search, wrapping, line numbers, the markdown preview, and drag-selection → OSC 52 copy (all shipped). A GUI→TUI parity map. Extends the shipped PRV previewer
Android (shipped v0: AND1–AND10)the GUI sink as a NativeActivity APK: raylib PLATFORM_ANDROID, the nix-native dual-ABI build (no Gradle), fontconfig-free fonts, soname-dlopen'd grammars, the asset bundle, touch interaction (drag/fling, tap, long-press, pinch, toolbar), lifecycle, on-device goldens, and the honest desktop-parity checklist
Configuration (design: CFG1–CFG12)a persistent, user-editable JSON configuration for the whole app — appearance, panes, behaviour, and a rebindable keymap over keymap.Command — layered defaults → user file → project file → environment → CLI, each layer a sparse overlay. The only route to preferences on Android, where no command line exists.
Content folding (planned)expand/collapse of code structures, markdown sections/lists, and any tree-sitter CST node — a cross-backend fold-range model + fold-state machine, elided from the wrapped-line render
Format preview (shipped v1: FP0–FP6)a toggle-able format preview: in-memory reformatting through pluggable formatters (in-process sparkles:dmd-fmt for D, opt-in external shell-outs) driven by a draggable column ruler that sets the soft max line length and reformats live — read-only, backend-neutral interaction machine, coalesced off-thread formatting
Tree / DAG view (planned)an interactive tree and DAG component (snacks.nvim-explorer-style): file explorer, tree-sitter inspector, file outline, git graph, dependency graph — a sparkles:ui widget across GUI/TUI/HTML
Tab view (planned)a tab view component (tab bar + active-tab state machine) — open files as tabs, and VitePress-style code groups — a sparkles:ui widget across GUI/TUI/HTML
Gallery & multi-document nav (shipped: G0–G3)rendering a set of documents: the static HTML gallery (index + per-file pages, prev/next header, physical-line gutter, selection domains) and interactive prev/next + index view in the GUI/TUI. Superseded in part by the file explorer, whose HTML flavor the gallery becomes
Diff & PR view (planned)viewing diffs (two files, piped unified patch, git revisions) and pull requests (via a DbI forge seam — GitHub first, then GitLab/Gitea/Forgejo/Codeberg) across all four sinks: a sparkles:diff engine library, unified + side-by-side layouts, layered formatting-noise handling (word-level, formatting-only hunks, structural tree-sitter diff, commutative-container equivalence, rendered-preview diff), hunk/file navigation — then a write surface: hunk/line staging, inline editing, content-anchored comments with proposed suggestions, and 3-way conflict viewing/resolution
DSV preview (design)Delimiter-Separated Values (CSV/TSV/PSV) as a content kind: the dialect sniffer (delimiter · quote · header, incl. stdin/.txt content detection), the sparkles:dsv engine (RFC 4180 identity-channel parser, typed columns, projection compute), the grid preview in every sink, the data-browser tier (multi-key sort, filter bar + header menus, column hide/reorder), the copy deltas (source dialect re-emit, pristine byte reproduction), and a 100 MB / 1M-row scale target — phased around the table-rendering unification (CHK)
Navigation (planned)link following & go-to — markdown anchors + local-file links, module/import & relative paths, doc-comment ($(REF …)/@see) references, and LSP go-to-definition; intra- and inter-document, cross-backend
Images & diagrams (planned)media rendering — raster images (![](…)), diagram fences (mermaid, graphviz), and LaTeX math via one media-block mechanism; GUI texture · terminal graphics protocol · HTML <img>/<svg>
Twoslash requirements (planned/branch-only)the --twoslash / --markdown modes and the raylib twoslash overlay — the first overlay of hue's pluggable overlay layer; implemented on feat/syntax-twoslash, not yet on this branch
Overlay requirements (planned)the pluggable overlay framework generalized from twoslash, plus the additional overlay kinds: source map, code coverage, tracing, tree-sitter inspector, function code size
Lantern (shipped: LT0–LT3)the key guide — a which-key-inspired panel that lights up after a prefix and lists what can follow it — over hue's one binding table (KEY) and the <space> leader map (LMP). The table is what makes the keymap enumerable, and so is also CFG6's prerequisite
Picker (design)the fuzzy finder behind <leader>f / <leader>s / <leader>g / <leader>/ — a query constraint language, frecency-aware composite ranking, budgeted searches over the sparkles:event-horizon work-stealing pool, and the sources (files, grep, recent, git, themes, lines, keymaps) — on a new sparkles:fuzzy engine
Notifier requirements (planned)the cross-backend interactive popup component (snacks.nvim-style: collapse to a floating icon, expand back, buttons, expandable items) and the startup-info / file-info popups
UI architecture (architecture)how hue consumes the canvas-first toolkit sparkles:ui — the port inventory (which visuals are widgets, which are still per-backend) and hue's own consumption requirements. The toolkit's own STM/LAY/WGT/TGT requirements now live in docs/specs/ui
Transformer pipeline (architecture)the pluggable pipeline (parse → transform → compile, à la unified.js/markdown-it/babel) that unifies hue's processing: highlighting/overlays/folding/navigation/media as transform plugins, the renderers as compilers
Open implementation issuesconcrete hue gaps deferred from the normative specs: GUI-state ownership, app-owned duplicate painters, and the native pointer-grab blocker
Web integration (planned)the @sparkles/hue npm package — a Shiki drop-in for JS frameworks (VitePress/Next/Solid Start) via SSG/SSR process shell-out, then a future wasm client-side backend

CLI & Subcommands

hue provides a clean subcommand hierarchy built on sparkles:core-cli with @Flatten composition:

SubcommandDescriptionKey Options
view (default)View and syntax-highlight a file, directory, or twoslash overlay[paths], --markdown, --raw, --patch, @Flatten("Output Sinks")
diffDiff two files or git revisions with structural awareness[targets], --staged, @Flatten("Diff Options"), @Flatten("Output Sinks")
prOpen a GitHub/GitLab pull request as a diff session<pr>, @Flatten("Diff Options"), @Flatten("Output Sinks")
galleryBatch render a directory into a static HTML syntax/theme gallery[dir], --out, --markdown, --raw
themeInspect and list built-in color themes--list, [name]
overlayInspect registered document overlays (twoslash, coverage, trace)--list, [kind]
configDisplay resolved configuration, fonts, and theme settings--show

Universal options (--log-level, --theme, --background) live on the root command alongside flattened GUI and overlay options.

Rendering modes & Sinks

Rendering subcommands (view, diff, pr) resolve to exactly one active backend sink per invocation (MOD1MOD7):

ModeFlagWhenEntry codeSpec
ANSI--backend=ansistdout is not a tty or piped/redirectedapp.runAnsiSinkANS*
HTML--html / --backend=html--html passed or html backend requestedapp.runHtmlSinkHTM*
TUI--tui / --no-gui / --backend=tuiInteractive tty with no display or explicit terminal requestapp.runTuiSinktui.md · PRV*
GUI--gui / --backend=guiDisplay available on GUI-enabled build, or forced with --guiapp.runGuiSinkgui.md

NOTE

For a markdown file every sink renders the render-markdown decorated preview by default (general MOD8) — ANSI (ANS3), HTML (HTM5), the terminal previewer (MDP-T), and the GUI (MDP) — over the shared MdDoc model and widget view; --raw forces highlighted source. A DSV file (CSV/TSV/…) likewise renders the grid preview by default in every sink (dsv-preview.mdDSK3, general MOD10).

Status scheme

Every requirement row carries one Status:

StatusMeaning
not startedno implementation yet.
researcheddesign/notes exist (in code comments or a sibling doc), but no implementation.
partialimplemented with a documented limitation or missing sub-case (the row's notes say what is missing).
full (<sha>)fully implemented; <sha> is the primary commit (the "commit hash evidence"). Where several commits contributed, the earliest feature commit is cited and later refinements are noted.

NOTE

The cited SHAs are pre-merge branch commits on feat/hue-preview-polish and a few earlier merges. Some are fixup! targets that fold into their base commit on autosquash — the base commit is cited. Hashes will be finalized when the branch is squashed/rebased and merged; treat them as evidence-of-work, not permanently stable identifiers.

ID scheme

Requirement IDs are <AREA><n> — a short area mnemonic plus a number, unique within a document (e.g. ENG3, MDP7, SEL2). The general spec uses CLI/SRC/CAT/RNG/TXT/LNG/ENG/THM/CLR/MOD/CHR/WID/PGR/BGM/ANS/HTM/PRV/DEG/NFR; the chrome spec uses STY/CHW/CHG and the pager spec PAG/PIN/STR; the GUI spec uses WIN/FNT/RND/VIW/WRP/NUM/NAV/SCB/THG/FND/MDP/COD/SEL/FSC/DBG/BOX; the lantern spec uses KEY/LTN/LMP, the picker spec PIK/PKQ/PKR/PKS/PKL/PKM, and the DSV spec DSK/DSD/DSM/DSG/DSB/DSS/DSF/DSC/DSN/DSZ. Each area's mnemonic is expanded at its section heading.

Traceability

Every source file under apps/hue/src/ is covered by at least one requirement. The Module coverage table at the foot of each spec lists each file (and its key symbols) against the requirement IDs that own it, so coverage is auditable in both directions: requirement → code (the "Traces to" column of every row) and code → requirement (the coverage tables). The shared libraries hue drives are traced at the boundary — the requirement names the sparkles library and the concrete entry point hue calls; the library's own internals are specified in its own docs.

Source filePrimary spec + areas
apps/hue/src/app.dgeneral — CLI, SRC, LNG, ENG, THM, CLR, MOD, ANS, HTM, DEG
apps/hue/src/source_set.dgeneral — SRC4SRC6; galleryGAL1, GAL8
apps/hue/src/gallery.dgeneral — HTM4, HTM6HTM8; galleryGAL2GAL4, GAL6, GAL7
apps/hue/src/previewer.dgeneral — PRV, NFR
apps/hue/src/gui.dGUI — WIN, FNT, RND, VIW, NUM, NAV, SCB, THG, FND, COD, SEL, FSC, DBG
apps/hue/src/gui_preview.dGUI — VIW, MDP (the document model; rendering is the shared widget views)
apps/hue/src/viewer_model.dGUI/TUI — RND, WRP, NUM, FND (the shared document-pipeline Whole; ui/migration MIG9)
apps/hue/src/gui_ansi.dGUI — MDP (the ```ansi fence decoder)
apps/hue/src/gui_text.dGUI — WRP, FND, NUM (pure metrics/search)
apps/hue/src/table_select.dGUI — TBL1, TBL2, TBL5 (presentation-free smart-drag + serializers)
apps/hue/src/tui.dTUITIN, TSF, TSB, TSL, MDP-T; general — PRV (the shipped viewer)
apps/hue/src/ansi_model.dGUI — MDP12; general — NFR3 (ghostty-free presentation types shared by both painters)
apps/hue/src/gui_canvas.dui/backendsTGT6 (the raylib canvas adapter)
apps/hue/src/tui_canvas.dui/backendsTGT6 (the cell-grid canvas adapter)
apps/hue/src/twoslash_tui.dtwoslashTWM/TWO/TWH; galleryGNV1, GNV2
apps/hue/src/android_glue.dAndroidAND2, AND4, AND9 (the NDK surface: logcat sink, asset extraction, debug env, clipboard entry)
apps/hue/src/android_clipboard.dAndroidAND6 (the JNI ClipboardManager bridge, over an ImportC'd <jni.h>)
apps/hue/src/android_paths.dAndroidAND2, AND9 (pure, host-tested: the extracted-asset layout, manifest-entry safety, hue-debug.env)
apps/hue/src/gui_touch.dAndroidAND6 (TouchScroller: tap / drag+fling / long-press / gesture cancel)
apps/hue/src/keymap.dlanternKEY (the one binding table every backend resolves through), LMP (the map it holds)
apps/hue/src/lantern.dlanternLTN1LTN4, LTN9LTN12 (the prefix state machine and its wall-clock delay)
apps/hue/src/lantern_view.dlanternLTN5LTN8, LTN14 (the panel as one widget tree, both backends)
apps/hue/tools/capture-modes.dui/backendsTGT10 (the cross-backend parity harness)