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, language detection, the highlight engine, themes, color depth, output-mode dispatch, the ANSI/HTML/previewer sinks, degradation, non-functional
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
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
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

Rendering modes

hue dispatches to exactly one mode per invocation (MOD1MOD7):

ModeWhenEntry codeSpec
ANSIstdout is not a tty, or no key session (piped/redirected)app.emitAnsiWholeFileANS*
HTML--htmlapp.main (HTML branch)HTM*
Previewerinteractive tty with no display (e.g. SSH), or --no-gui/--tuipreviewer.runLooptui.md · PRV*
GUIdefault on a GUI-enabled build when a display is detected, or forced with --guigui.runGuigui.md
Twoslash--twoslash <nodes.json> (ANSI / --html / --gui) · --markdown <file.md>planned/branch-onlyapp.runTwoslashMode / runMarkdownModetwoslash.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.

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/LNG/ENG/THM/CLR/MOD/ANS/HTM/PRV/DEG/NFR; 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 and the picker spec PIK/PKQ/PKR/PKS/PKL/PKM. 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)