Skip to content

sparkles:docs SSG surface — Feature Requirements

Status: shipped (extraction) + two open rows · Date: 2026-08-21 · Scope: the library surface extracted from hue's gallery — one module per concern under libs/docs/src/sparkles/docs/.

NOTE

Most rows here absorb by reference: the normative text lives in the shipped gallery.md / hue feature-requirements rows each cites, and this table records which sparkles:docs module owns it now. New normative content appears only in DOC8 and DOC10.

Design & rationale

The extraction (milestone D0) moved code, not behavior: hue gallery output is byte-identical before and after, which is the property that let the move happen as one reviewable refactor. What the library adds over the app-internal version is shareabilityci reads the sidebar schema from it, hue renders with it, and the discovery and apidoc efforts build on it — plus a real package, which finally gives the shared helpers (escapeInto, the options vocabulary) a home that isn't "public because root-level modules have no package visibility".

The module split follows the import graph: options at the bottom (plain data

  • pure builders), fragment/breadcrumbs/site_tree above it, page_shell on top, source_set and sidebar beside them, assets for the stylesheet files.

SSG surface (DOC)

IDRequirementStatusTraces to
DOC1Content fragments. One document renders to a <style> + <pre class="syn-root"><code> fragment (plain or twoslash), with the physical-line gutter available fragment-side for shell-less pages. Owns HTM1's fragment half, HTM4, GAL4.fullfragment.plainFragment/twoslashFragment/relayoutGutter/withLineNumbers
DOC2Page shell. The full page around a fragment: nav header (prev/next disabled-not-omitted, index link), one scroll container, selection domains. Owns GAL3, GAL6, GAL7, HTM7, HTM8.fullpage_shell.pageShell
DOC3Dual themes + appearance toggle. Light and dark from one rendering, the toggle writing VitePress's own localStorage['vitepress-theme-appearance'] key, a no-flash <head> script, everything gated on a two-theme run. Owns HTM10.fullpage_shell.pageShell (toggle + script); assets.themeStylesheet
DOC4Chrome palette. The whole surround (page, header, rule, nav, gutter) derives from the rendering theme's default bg/fg — themeChrome — so pane and chrome are one surface by construction; the palette is a parameter (GalleryOptions.chrome), so a site can substitute its own (--chrome=site, DSC5). Owns GAL6's theme-sourcing half.fulloptions.ChromePalette/themeChrome/themeBackground
DOC5Mirrored site tree. A recursive set renders <out>/<rel-path>.html plus an index.html in every directory, page-relative hrefs throughout, depth-rebased asset hrefs; a flat set keeps the flat layout byte for byte. Owns GAL12, HTM6's mirrored half.fullsite_tree.buildSiteTree/directoryIndex; page_shell.writeGallery/pageHref/depthAdjustedHref
DOC6Breadcrumbs. Per-segment directory-index links that work from file://, copy-path controls, forge links under --repo-url/--repo-prefix, VitePress Breadcrumbs.vue markup/class parity. Owns GAL14.fullbreadcrumbs.breadcrumbsFor/renderBreadcrumbs/breadcrumbCss
DOC7Stylesheet assets. A page set leaves theme rules to one shared stylesheet — self-hosted assets/hue.css, --stylesheet link, --emit-stylesheet write — carrying both theme scopes and the chrome/twoslash/markdown blocks. Owns GAL11, HTM1's shared-sheet half.fullassets.themeStylesheet/writeStylesheetAsset/writeStylesheetFile
DOC8Sidebar. The docs-site sidebar/srcExclude data (docs/.vitepress/sidebar.json, docs-config.json) has one D schema, in this library, consumed by the site config, by ci --check-docs-sidebar / --audit-fences, and by generated pages: a listing page must be able to render the same sidebar tree the docs site shows, its links resolved against the site base URL, so a reader crossing between a VitePress page and a listing keeps the same navigation. hue gallery --sidebar <sidebar.json> --site-base <url> supplies the tree and the base the routes resolve against; on hue site pages the docs nav renders inside the explorer's docs/ node (DOC11) rather than as the whole aside; --chrome=site (DSC5) will later bundle the base with the site palette.full (100a10b1)sidebar.SidebarItem/loadSidebar/loadSidebarFile/sidebarLinks; sidebar.sidebarNav/sidebarCss; GalleryOptions.sidebarHtml
DOC9Document set. The ordered, filtered, summarized file list every mode consumes, with the recursive .gitignore-aware descent delegated to sparkles:build-primitives' glob walk. Owns GAL1/GAL8 and the library half of SRC5/SRC6/SRC9.fullsource_set.SourceSet/collectSources/isRenderable; sparkles.build_primitives.glob_walk
DOC11Explorer sidebar + unified directory pages. On a generated site, the sidebar is the site's own file explorer, built per page: directories as collapsibles open along the current page's path, each name a link to its own index inside the summary, pages as page-relative links (the file:// discipline) with the current one highlighted, and the docs nav rendered inline as the docs/ node's children — no wrapper, no parallel copy of the raw docs/ file subtree, and a listing-route nav entry rendered as that directory's real file subtree with relative hrefs. A directory page is the same shell as a file page — title, header, appearance toggle, breadcrumbs in directory mode — around an intentionally empty pane: the explorer is the listing, so moving between a file and a directory keeps the tree and clears the pane (the VSCode "no file open" state). The explorer is built from what was actually written, so it never links a hole. Born from PR #371 UAT: bare list indexes and a docs sidebar redundant with them read as two different sites.fullpage_shell.explorerNav/directoryPage/writeExplorerGallery; GalleryOptions.explorerSidebar/siteBase; sidebar.sidebarItemsHtml; breadcrumbs.breadcrumbsFor(isDirectory)
DOC10Escaping unification. options.escapeInto (4 entities) must fold into sparkles.base.text.html.writeHtmlEscaped (5 entities — it also escapes '), so the repository has one HTML-escaping implementation. This is a deliberate byte change for any name/summary containing an apostrophe: it lands with a golden update, after the D0 byte-identity guarantee has served its purpose — never silently.full (36e7225b)options.escapeInto (a forwarder); sparkles.base.text.html.writeHtmlEscaped

Non-goals

  • Interactive navigation (GAL5, GNV*) stays hue's: the library renders static pages; sessions are the app's concern.
  • Serving. The library writes files. Dev servers, deployment, and CI wiring are the consumer's (discovery.md DSC4 and the docs-site build scripts).