Skip to content

hue — Feature Requirements (all rendering modes)

Status: living inventory · Date: 2026-07-23 · Scope: apps/hue features common to every rendering mode — invocation, source acquisition, language detection, the highlight engine, themes, color depth, output-mode dispatch, the ANSI / HTML / terminal-previewer sinks, degradation, and non-functional requirements. The raylib GUI is specified separately in gui.md.

See the overview for the status scheme (not started / researched / partial / full (<sha>)), the ID scheme, and the rendering-mode map. Requirement statements use lowercase must / should with the repo's usual force. "Traces to" names the implementing source and, for full rows, the primary commit is in the Status cell.

Invocation & CLI (CLI)

Parsed by sparkles.core_cli.args.parseCliArgs!CliParams in app.d.

IDRequirementStatusTraces to
CLI1hue [options] [target] must render target — a file path, an HTTP(S) URL (SRC3), or a directory (SRC4, a multi-document set); with no target it highlights hue's own bundled source.partial (74d8f6a3)app.main; sourcePath/source; directory via SRC4 (URL pending)
CLI2--html must select HTML output instead of ANSI.full (74d8f6a3)CliParams.html
CLI3--theme <name> must select a built-in theme (default catppuccin-mocha).full (74d8f6a3)CliParams.theme
CLI4--gui must force the raylib window and --no-gui (alias --tui) must force terminal output; with neither, hue must autodetect (see MOD6). On a no-gui build, --gui must error out cleanly.full (cdc813f6)CliParams.gui/noGui/tui; wantGui
CLI5--font, --font-size, --window-width, --window-height must configure the GUI window (see gui.md).full (c2b49e99)CliParams.font*/window*
CLI6--line-numbers / --code-line-numbers (both default on, disableable with =false) must configure the GUI gutters.full (5b862346)CliParams.lineNumbers/codeLineNumbers
CLI7--help must print a usage/description header for the program and every option.full (d87397b3)HelpInfo in app.main
CLI8--background <no-background|spans|full> must select the terminal background mode (BGM); the default is full.full (d404dc8c)CliParams.background; parseBackgroundMode
CLI9--raw must force the highlighted-source view instead of the markdown preview, in every sink (GUI, TUI, ANSI, HTML). Without it a markdown file renders the decorated preview by default (MOD8); non-markdown files are always source.full (af6ebe95)CliParams.raw; preview-vs-raw branch in app.main
CLI10--ansi-copy=raw|strip (default raw) must set how a GUI text-regime selection over a ```ansi block copies — verbatim source (escapes) or stripSgr-cleaned (gui.md SEL7); runtime-toggleable.full (debfd92d)CliParams.ansiCopy
CLI11--table-copy=tsv|markdown (default tsv) must set how a GUI table grid selection copies — tab-separated cells or re-emitted | … | markdown (gui.md TBL2); runtime-toggleable.full (debfd92d)CliParams.tableCopy
CLI12--out <dir> must select the output directory for the static HTML gallery (HTM6) a directory target renders into; with --out omitted it must default to <target>/html.full (b61f4701)CliParams.outDir; gallery.md GAL2
CLI13The --diff family must select and configure the diff content kind: --diff [<a> <b> | <rev>[..<rev>]], --patch (force stdin-patch), --diff-layout unified|split, --diff-structural=on|off, --diff-preview, the whitespace/noise toggles, and --diff-copy=text|patch — registered here, specified in diff-view.md.partial (a2b634e8)--diff/--patch/--staged ship (DVS1DVS3); the layout, noise and copy flags await their milestones
CLI14--pr <number|url> must open a pull/merge-request session through the forge seam.not starteddiff-view.md DPR1/DPR7

Source acquisition (SRC)

IDRequirementStatusTraces to
SRC1With a path argument the whole file must be read into memory as the highlight input.full (74d8f6a3)readText(sourcePath)
SRC2With no path, hue must highlight its own app.d, embedded at compile time via import() so it works from any install.full (1c7398a0)import("app.d"); stringImportPaths
SRC3An http(s):// URL target must be fetched over the network and rendered like a file; the language is derived from the URL path extension, falling back to the response Content-Type. A fetch failure must report an error, not crash. (This is the user's explicit request — unlike the opt-in auto-loaded remote media of media.md IMG3.)not startedproposed URL fetch in app.main
SRC4A directory target must open a multi-document session (SRC5) over the files it contains: interactively, the gallery index (gallery.md GAL5) — superseded by the richer file-tree explorer (tree-view.md TVU1) when that lands; with --html, the static gallery (HTM6). A directory in a piped non---html mode must degrade to a static listing or a reported error, not a crash.full (6d86054e)gallery.md GAL1; tree-view.md TVU1; dir detection in app.main
SRC5A directory target must resolve to an ordered, filtered file list — sorted by path, restricted to renderable files: *.twoslash.json under --twoslash, else any file with an extension that is not obviously binary. The filter must be a deny-list, since hue renders unknown text as plain text (DEG2) and canonicalLanguage normalizes a label without deciding membership — an allow-list would drop the .toml/.txt files a directory legitimately holds. Extensionless files, recursive descent and .gitignore awareness are deferred to tree-view.md TVU1.full (77a476f3)source_set.collectSources/isRenderable
SRC6That file list must be the one multi-document session every rendering mode consumes — the HTML gallery iterates it, and the interactive backends navigate it (GAL3) — so a document set is acquired once and rendered many ways. It is the substrate the tab view (TBU1) and navigation (LNK3) later build on, not a parallel mechanism.full (6d86054e)source_set.SourceSet — the gallery iterates it, the GUI/TUI navigate it
SRC7Diff-pair acquisition: a diff target acquires pairs of sources through this same layer — two files (DVS1), a stdin patch plus worktree re-reads (DVS2), git show <rev>:<path> old sides (DVS3) — so source acquisition stays one subsystem. A rename pairs sources whose paths (and so LNG1 languages) differ; the language is resolved per side.full (a2b634e8)all three acquisition shapes ship (DVS1DVS3); DiffSides carries the per-side language
SRC8Forge acquisition: a PR/MR is an acquirable session source — a network fetch through the forge seam (DPR7) sharing SRC3's URL-fetch machinery once that lands, producing a SRC6-style multi-document session (DVS4).not starteddiff-view.md DPR1/DPR7; SRC3

Language detection (LNG)

IDRequirementStatusTraces to
LNG1The grammar language must be derived from the file extension, canonicalized through sparkles:syntax aliases.full (74d8f6a3)canonicalLanguage(extension)

Highlight engine (ENG)

hue drives the sparkles:syntax precise pipeline; the engine internals are specified in docs/specs/syntax.

IDRequirementStatusTraces to
ENG1Highlighting must use the injection-aware path so markdown (and other languages with injections.scm) get fenced/inline content highlighted by nested grammars.full (9b0a4b50)highlightInjected(cache, lang, source, events)
ENG2Grammars must be loaded from the nix bundle via $SPARKLES_TS_GRAMMAR_PATH; a GrammarRegistry/TsConfigCache is built once.full (74d8f6a3)GrammarRegistry.fromEnvironment; TsConfigCache.create
ENG3Highlighting must produce a HighlightEvent stream over the source, consumed identically by every rendering mode.full (74d8f6a3)SmallBuffer!HighlightEvent events
ENG4On any engine failure (no grammar, parse error) hue must fall back to a single plain-text span covering the whole source.full (74d8f6a3)res.hasErrorHighlightEvent.sourceSpan

Themes (THM)

IDRequirementStatusTraces to
THM1The named theme must be resolved from builtinThemes; an unknown name must warn and fall back to builtinDark.full (74d8f6a3)builtinThemes.get(themeName, …)
THM2The full sorted built-in theme set must be materialized once (names + parallel Theme values) for the live previewer and GUI.full (74d8f6a3)names/themes in app.main
THM3A theme must be resolved against the standard LabelSet before rendering (ResolvedTheme).full (74d8f6a3)resolveTheme(theme, labels)

Color depth (CLR)

IDRequirementStatusTraces to
CLR1ANSI output (non-interactive and previewer) must adapt to the terminal's detected color depth.full (74d8f6a3)detectColorDepth()

Output-mode dispatch (MOD)

Exactly one mode runs per invocation; see the mode map.

NOTE

These requirements are scheduled to be reshaped, not merely re-implemented. hue is moving to a single behavior with three backend flavors: the target (file · directory · URL) selects a content kind, the flags select a backend, and content kinds compose — a markdown document may embed a twoslash block, whose documentation popups render through the same markdown view. --markdown, --raw and --twoslash therefore stop selecting code paths and become content kinds and overlays (OVL4), and a directory target opens the file explorer (TVU1) rather than a bespoke index view. The dispatch collapse shipped (a75f1fc9): document.d owns one Document value with a content-detected kind (code / markdown / twoslash — a *.twoslash.json target needs no flag), one DocumentPipeline.load replaces the four load-pipeline copies, and app.main picks a backend once (pickBackend) then dispatches to one of four sinks, each a final switch over the kind. --twoslash/--markdown/--raw are now detection inputs (--overlay twoslash=… is the OVL4 spelling). Content-kind composition (a markdown document embedding a twoslash block) is the remaining piece — see ui-architecture.mdUIA6 and pipeline.md XFM3.

IDRequirementStatusTraces to
MOD1--gui (explicit or autodetected) on a GUI-enabled build must dispatch to the raylib window and return its exit code.full (e6063309)if (cli.gui) version(HueGui)
MOD2--gui on a no-gui build must print a rebuild hint to stderr and exit non-zero.full (e6063309)else stderr.writeln(…); return 1
MOD3Non-interactive (stdout not a tty) must emit the whole file once (HTML if --html, else ANSI) and exit.full (74d8f6a3)!interactive branch
MOD4An interactive tty (no --html) must open the live terminal previewer.full (74d8f6a3)interactive branch → runLoop
MOD5If a raw-key session can't be acquired in an otherwise-interactive tty, hue must degrade to emitting the whole file as ANSI.full (74d8f6a3)sessFactory is nullemitAnsiWholeFile
MOD6With no explicit mode flag (--gui/--no-gui/--html) on a GUI-enabled build, hue must default to the GUI window when a graphical display is available (Linux/BSD: $DISPLAY or $WAYLAND_DISPLAY set; macOS/Windows: a local, non-SSH session) and stdout is a tty, and otherwise fall through to the terminal dispatch (MOD3MOD5). On a no-gui build it always falls through.full (cdc813f6)displayAvailable; wantGui in app.main
MOD7The mode flags must override autodetection: --no-gui/--tui forces the terminal path even with a display present; --gui forces the window even with no display detected (raylib surfaces any failure).full (cdc813f6)wantGui flag precedence in app.main
MOD8A markdown file must render the render-markdown decorated preview by default in every sink — GUI (MDP), interactive TUI (MDP-T), non-interactive ANSI (ANS3), and HTML (HTM5) — reusing the shared MdDoc model and the one viewMarkdown widget view. --raw (CLI9) forces the highlighted-source view.full (241e8052)the ContentKind dispatch across sinks; buildPreviewModel + viewMarkdown
MOD9A diff or PR session is a content kind like code/markdown/twoslash (the dispatch-collapse doctrine): produced once by the pipeline, dispatched through the same backend pick, and rendered by every sink (DVL4) — no new modes.full (8b4f9797)ContentKind.diff dispatched by every sink (ANSI/HTML arms; TUI/GUI via the Document transport + ViewerModel)

ANSI terminal output (ANS)

IDRequirementStatusTraces to
ANS1Non-interactive/piped output must render the whole file to ANSI with italics and background emission enabled.full (74d8f6a3)emitAnsiWholeFile; renderAnsi
ANS2```ansi fenced blocks embedded in a doc are passed through as literal SGR (the tty renders them) in ANSI mode.full (74d8f6a3)(renderer pass-through)
ANS3For a markdown file the non-interactive ANSI emit must render the decorated preview by default — the shared viewMarkdown widget view painted to SGR cells via CellGrid.writeAnsi — not highlighted source; box-drawing / quote / rule glyphs emit natively and ```ansi fences pass through (ANS2). --raw (CLI9) reverts to ANS1.full (c3a5b2af)the ANSI sink's widget path in app.d
ANS4A diff session in non-interactive ANSI must emit the unified layout whole — the pager use-case (git diff | hue) — composing with the background modes (BGM*) like any theme background.full (31fdab59)runAnsiSink case diff:; verified via git diff | hue

Background mode (BGM)

How the theme background is applied in terminal rendering — the whole-file ANSI emit and the interactive previewer — selected by --background (CLI8). The three modes; full is the default (the prior fixed behaviour was spans).

IDRequirementStatusTraces to
BGM1no-background — emit foreground colors only; the terminal's own background shows through (the theme background is ignored). Useful for piped output over a themed terminal.full (d404dc8c)AnsiOptions.emitBackground: false; previewer chrome bg + backdrop gated
BGM2spans — emit a background only where the theme sets a span background (today's fixed whole-file behaviour, AnsiOptions(emitBackground: true)); selectable via the flag.full (d404dc8c)emitAnsiWholeFile; backgroundOptions
BGM3full (the new default) — fill every line with the theme's default background edge-to-edge, matching the previewer's back-color-erase look (PRV7). Fills each line via sparkles:syntax renderAnsi's fillLine.full (d404dc8c)renderAnsi fillLine (3e3d9cb4); backgroundOptions; previewer PRV7

HTML output (HTM)

IDRequirementStatusTraces to
HTM1--html must emit a self-contained <style> + <pre class="syn-root"><code> document with CSS-class highlighting.full (74d8f6a3)HTML branch; renderHtml(cssClasses)
HTM2The emitted stylesheet must carry the theme's default fg/bg on .syn-root (no duplicate pre{} color rule).full (74d8f6a3)writeThemeStylesheet

The GUI's interactive features apply best-effort to HTML output too — HTML selection is the browser's, so parity means emitting markup that copies cleanly and (optionally) a preview/gutter:

IDRequirementStatusTraces to
HTM3Best-effort SEL parity: the markup must be selectable so a browser copy yields the original source; any gutter / line-number / decoration content must be non-selectable (user-select: none) so it is excluded.partialplain <pre><code> copies to source today; the twoslash overlay realizes the decoration-excluded half on branch (TWH6TWH8); a plain---html gutter awaits HTM4
HTM4Best-effort NUM parity: HTML output must render an optional line-number gutter numbering physical (source) lines — each line wrapped in a .ln span whose number is a CSS ::before counter, so it is never selected or copied (HTM3); below-line overlay annotations must carry no number and must not advance the counter, and blank lines must keep their height and survive a copied selection.full (b61f4701)gallery.relayoutGutter; gallery.md GAL4
HTM5MDP parity: for a markdown file --html must render a rich HTML preview by default via the shared sparkles:syntax MdDoc → HTML emitter (renderMarkdownHtml) — with theme-derived CSS (writeThemeStylesheet), syntax-highlighted fences (a fenceRenderer hook reusing renderHtml), GitHub callouts, and column-aligned tables — not highlighted source. --raw (CLI9) emits highlighted source (HTM1).full (af6ebe95)renderMarkdownHtml (exists; enrichment + default wiring pending); app.main HTML markdown branch
HTM6A directory target with --html must render a static gallery into --out (CLI12): one standalone page per file in the set (SRC5) plus an index.html linking every page with its name and summary. Single-file --html (stdout fragment) must be unchanged.full (b61f4701)gallery.writeGallery; gallery.md GAL1/GAL2
HTM7Each gallery page must wrap hue's content fragment in a page shell: a header (name · summary · prev/next/index nav), a full-height single scroll container (exactly one scrollbar, no nested body+pre scrollbars), and a page background matched to the theme's .syn-root background.full (b61f4701)gallery.pageShell; gallery.md GAL2/GAL3/GAL6
HTM8Gallery pages must implement selection domains: a drag must be confined to the domain it starts in — the code, or one overlay annotation — so a copy never mixes the two. This layers on the pure-CSS code-only default (TWH6) and is hue's own output, not a consumer's responsibility.full (b61f4701)gallery.pageShell (selection CSS/JS); gallery.md GAL7; supersedes the JS harness (TWD3)
HTM9A diff/PR session with --html must render the static review site — the gallery analog: an index of changed files with per-file ± stats, one diff page per file with prev/next navigation, the dual old/new gutter (HTM4 generalized), and split-pane selection domains (HTM8).not starteddiff-view.md DVL4; gallery.md GAL10

Interactive terminal previewer (PRV)

IMPORTANT

Retired (D6, M9): previewer.d is deleted. Everything it did is subsumed by the full TUI (tui.md) — live theme cycling is ←/→ there — and the non-Posix tty path degrades to the whole-file ANSI emit (sparkles:tui's input reader is Posix-only). The rows below are kept as the historical record of what the TUI absorbed; none traces to live code.

previewer.d — the live theme browser (the baseline the full TUI (tui.md) extends). Its render/output core was @nogc nothrow.

IDRequirementStatusTraces to
PRV1The previewer must repaint a full frame, flush, read one key, and repeat until quit/select.full (74d8f6a3)runLoop
PRV2↑/↓ must cycle the selected theme (wrapping) and repaint live.full (74d8f6a3)runLoop Key.up/Key.down
PRV3Enter must select the theme: leave the alt screen and print the whole file highlighted in that theme onto the primary screen.full (d1c4e159)LoopResult.selected; renderFull
PRV4Any other key / cancel must quit and print nothing.full (74d8f6a3)Key.cancel/Key.other
PRV5A frame must show a header (title · theme name · index), a hint line, separators, the highlighted viewport slice, and a scrolling theme-list window around the selection.full (844680a3)Previewer.buildFrame
PRV6The viewport must show only the top maxCode lines that fit (height-derived), not the whole file, keeping the fold O(visible).full (fd22c112)firstLines; buildFrame maxCode
PRV7The theme backdrop must fill the viewport via back-color-erase (open theme bg, then erase), with begin/end synchronized-output markers.full (844680a3)CtlSeq.syncBegin/eraseDisplay/syncEnd
PRV8The alt screen must be entered on start and restored (show cursor, exit alt screen) on exit; its contents are discarded.full (74d8f6a3)enterAltScreen/exitAltScreen

Degradation & diagnostics (DEG)

IDRequirementStatusTraces to
DEG1Only degradation warnings are logged (logger level = warning); normal operation is silent.full (d87397b3)initLogger(LogLevel.warning)
DEG2A missing grammar must warn (no grammar for '<lang>') and render plain text, not fail.full (74d8f6a3)warning(i"no grammar …")
DEG3An unknown --theme must warn and use the default dark theme.full (74d8f6a3)builtinThemes.get fallback
DEG4Without $SPARKLES_TS_GRAMMAR_PATH, hue must still run — degrading to plain text for grammar-requiring languages.full (74d8f6a3)GrammarRegistry.fromEnvironment

Build and packaging (BLD)

How hue is compiled and shipped. The GUI backend is included in the default build; a raylib-/ghostty-free variant stays available for terminal-only use and minimal dependency closures.

IDRequirementStatusTraces to
BLD1The default dub configuration (application) must compile the GUI backend in (pulling sparkles:raylib-text + sparkles:ghostty), so a stock dub build :hue and the installed binary have --gui and the markdown preview with no special build.full (29bf1a65)apps/hue/dub.sdl configuration "application"
BLD2A no-gui dub configuration must build the raylib-/ghostty-free variant (the pre-flip application behaviour) for terminal-only installs and minimal closures.full (29bf1a65)apps/hue/dub.sdl configuration "no-gui"
BLD3The nix packages.hue must build the GUI-enabled default; a packages.hue-no-gui must build the headless variant with no raylib/GL in its closure. (GUI-enabled packages.hue done; the separate hue-no-gui package pending.)partial (29bf1a65)nix/packages/hue.nix
BLD4dub test :hue must stay headless — linking no window/GL — regardless of the default flip; gui.d stays excluded from the unittest config.full (e6063309)apps/hue/dub.sdl configuration "unittest"

Non-functional (NFR)

IDRequirementStatusTraces to
NFR1Startup (file read, parse, theme-list build) may allocate on the GC; the previewer's per-frame render/output core must be @nogc nothrow (a theme switch triggers no GC pause).full (0657c94a)Previewer @nogc methods; TermOut
NFR2Each previewer repaint must assemble into one reused SmallBuffer and flush with a single write; the resolved theme table is reused and only rebuilt on change.full (0657c94a)Previewer.frame/styleBuf; themeView
NFR3A raylib-/ghostty-free build of hue must remain available (the no-gui config, BLD2); the GUI + preview modules compile into the default application build and the unittest build (minus gui.d), and are excluded by no-gui.full (29bf1a65)apps/hue/dub.sdl no-gui excludedSourceFiles
NFR4GUI/TUI startup (process launch → first paint) should be fast: a provisional target of ≤ 100 ms (optimal ≤ 50 ms). TODO: calibrate against the window-system-integration research and empirical measurement.researched/not-startedprovisional target; no benchmark gate yet
NFR5GUI window resize must stay within the frame budget — the reflow (WIN3/WRP4 relayout on a width change) must not cause noticeable stutter.not startedrelayout; gui.md WIN3/WRP4
NFR6Large files must scroll instantly — a provisional target of up to 1 MB / 20k lines with no per-frame cost growth. Viewport culling (RND1) already makes scroll O(visible); load/relayout cost is the open question. TODO: calibrate against third-party editors + benchmarks.partialgui.md RND1 (culled scroll); load/relayout unbenchmarked
NFR7All logging must route through sparkles.base.logger; raylib's TraceLog output must be encapsulated (a SetTraceLogCallback bridge) and emitted at trace level, so it is silent under hue's default warning level (DEG1).full (c497d99d)gui.raylibTraceLog installed via SetTraceLogCallback before InitWindow; hue logging via sparkles.base.logger (DEG1/DEG2)
NFR8Diff interactivity targets: live re-diff under inline editing (DST5) must fit the debounce budget (provisional ≤ 50 ms for typical files); large-PR sessions (hundreds of files) must stay viewport-culled (DVG5) with lazy per-file diff computation — a file's diff/refinement is computed when it first scrolls into view or is opened, not up front.not starteddiff-view.md DVG5/DST5/DVM6

Deferred, researched & branch-only (DEF)

Roadmap items — planned/researched features, and modes that exist on another branch. Library-engine roadmap (TextMate second engine, locals, injection combined, incremental editor loop, UTF-16 sources) lives in the sparkles:syntax spec; the rows below are the ones that surface as hue capabilities.

IDRequirementStatusTraces to
DEF1--twoslash <nodes.json> mode (ANSI default / --html / --gui) — D-native Twoslash rendering.planned/branch-onlytwoslash.md TWM1TWM3
DEF2--markdown <file.md> mode — treat the input as Markdown and render the preview. Shipped as a standalone HTML emit on main (runMarkdownMode); being folded into the unified preview-by-default HTML path (HTM5) with theme CSS + highlighted fences.full (af6ebe95)app.runMarkdownMode; HTM5
DEF3The MdDoc → HTML emitter (sparkles:syntax md/render_html.d) that the --markdown/twoslash-docs paths need.fulllibs/syntax md/render_html.d; syntax spec J1
DEF4Runtime theme-file parsing (load user themes: native JSON, TextMate/VSCode JSON, Helix TOML) so --theme can name a file, not just a built-in.researched/not-startedsyntax spec D6
DEF5CSS-variable multi-theme HTML output mode (one document, theme switched via :root[data-theme] / prefers-color-scheme).researched/not-startedsyntax spec F6; render/html.d
DEF6Content-based language detection (a Linguist-style cascade) — today the language is only the file extension / fence label.not startedsyntax spec §deferred (canonicalLanguage only)
DEF7A grapheme/east-asian width table so wide/CJK/combining/tab characters occupy their true cell count (replacing the v1 one-column-per-codepoint metric).researched/not-startedgui.md FNT6
DEF8Color-emoji rendering in the GUI (a separate rasterizer for CBDT/COLR) — raylib/stb_truetype cannot.not startedgui.md FNT7
DEF9Pluggable overlays — a backend-agnostic overlay seam generalized from twoslash, plus new overlay kinds (source map, coverage, tracing, tree-sitter inspector, code size).researched/not-startedoverlays.md OVL*
DEF10Notifier / interactive popups — a cross-backend (GUI/TUI/HTML) snacks.nvim-style popup component (collapse-to-icon, expand, buttons, expandable items) with startup-info and file-info popups.researched/not-startednotifier.md NTF*/NSI*/NFI*
DEF11Full-screen TUI — grow the minimal theme-selection previewer into a terminal port of the GUI viewer: scrolling, a cell scrollbar, SGR mouse, selection → source offsets + OSC 52 copy, wrapping, line numbers, and the markdown preview (reusing the raylib-free widget views).full (8b1d2aac)tui.md TIN*/TSF*/TSB*/TSL*/MDP-T*/TCP*
DEF12UI component librarysparkles:ui ships: canvas-first, no native widgets, three levels, and immediate/retained/SSG interpreters. Its requirements live in docs/specs/ui; hue's port onto it is UIA4.partialsparkles:ui; ui-architecture.md UIA*
DEF13@sparkles/hue web integration — a JS/TS npm package that swaps Shiki for sparkles:syntax in web frameworks (VitePress/Next/Solid Start) across SSG/SSR (process shell-out first) and a future wasm client-side backend.not startedweb-integration.md PKG*/SHL*/WSM*/FWK*
DEF14Content folding — expand/collapse of code structures, markdown sections/lists, and any tree-sitter CST node (a cross-backend fold-range model + presentation-free fold-state machine, elided from the wrapped-line render).not startedfolding.md FLD*/FSR*
DEF15Tree / DAG view — an interactive tree + DAG component (snacks.nvim-explorer-style) across GUI/TUI/HTML: file explorer, tree-sitter inspector, file outline, git graph, dependency graph; a sparkles:ui widget.not startedtree-view.md TRV*/DAG*/TVU*
DEF16Navigation — 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.not startednavigation.md LNK*/REF*/LNB*
DEF17Images & diagrams — render raster images (![](…)), diagram fences (mermaid/graphviz), and LaTeX math via one media-block mechanism; GUI texture · terminal graphics protocol · HTML <img>/<svg>.not startedmedia.md MDB*/IMG*/DGM*/MTH*
DEF18Tab view — a tab-bar + active-tab-state-machine component across GUI/TUI/HTML; initial use cases: open files as tabs, and VitePress-style code groups.not startedtab-view.md TAB*/TBU*/TBB*
DEF19Transformer pipeline (architecture) — a pluggable parse→transform→compile pipeline (à la unified.js/markdown-it/babel) where highlighting/overlays/folding/navigation/media are transform plugins and the renderers are compilers.researched/not-startedpipeline.md PIP*/PRS*/XFM*/CMP*
DEF20Gallery & multi-document navigation — a directory of files rendered as a static HTML gallery (index + per-file pages with a prev/next header, a physical-line gutter, and selection domains) and navigated interactively in the GUI/TUI. Replaces the branch-only JS preview harness.full (6d86054e)gallery.md GAL*
DEF21Diff, PR & review — render diffs (two files, piped unified patch, git revisions) and pull requests (behind a DbI forge seam: GitHub first; GitLab/Gitea/Forgejo/Codeberg as adapters) across all four sinks: unified + side-by-side layouts over a new sparkles:diff engine, layered formatting-noise handling (word-level refinement, formatting-only hunk classification, structural tree-sitter diff incl. commutative-container equivalence, rendered markdown-preview diff), then a write surface — hunk/line staging, inline editing, content-anchored comments with two-target suggestions, and 3-way conflict viewing/resolution.not starteddiff-view.md DVM*/DVS*/DVL*/DVN*/DVG*/DPR*/DST*/DCM*/CFV*
DEF22Lantern — a which-key-inspired key guide: press a prefix, wait a beat, and a panel lists every key that can follow it. Built on hue's one binding table, which replaced three divergent copies of the keyboard policy and is what makes the keymap enumerable at all (and so is CFG6's prerequisite). Includes the <space> leader map.partial (c19bb926)lantern.md KEY*/LTN*/LMP*
DEF23Picker — a fuzzy finder behind <leader>f / <leader>s / <leader>g / <leader>/: a query constraint language (git:modified src/**/*.rs !mod.rs name), frecency-aware composite ranking, budgeted cancellable searches over the sparkles:event-horizon work-stealing pool, and sources for files, grep, recent, open documents, git, themes, lines and the keymap itself.not startedpicker.md PIK*/PKQ*/PKR*/PKS*/PKL*
DEF24sparkles:fuzzy — the matcher the picker drives, as its own library: a typo-resistant scorer with match positions, the query/constraint parser, the composite ranking formula, exponential-decay frecency, and a glob matcher. 100% @safe pure nothrow @nogc, benchmarked from the first commit.not startedpicker.md PKM*

Module coverage (general spec)

Every non-GUI source file maps to the requirements above:

SourceKey symbolsRequirements
apps/hue/src/app.dCliParams, main, emitAnsiWholeFile, mode dispatchCLI*, SRC*, LNG1, ENG*, THM*, CLR1, MOD*, ANS*, HTM*, DEG*
apps/hue/src/source_set.dSourceEntry, SourceSet, collectSources, twoslashTally, plainTallySRC4SRC6, gallery.md GAL1
apps/hue/src/gallery.drelayoutGutter, pageShell, galleryIndex, writeGalleryHTM4, HTM6HTM8, gallery.md GAL2/GAL4/GAL6/GAL7
apps/hue/src/previewer.ddeleted (D6, M9) — theme cycling lives in the TUI; BackgroundMode moved to ansi_model.dPRV* (retired)
apps/hue/dub.sdlbuild configurations (application [GUI] / no-gui / unittest)CLI4, MOD1/2, BLD1/2/4, NFR3
nix/packages/hue.nixpackages.hue, packages.hue-no-guiBLD3

GUI requirements · Overview