Presentation Turn a technical specification into an interactive, persuasive web deck — the kind at iii.dev/roadmap/. The output is a content layer inside the repo's roadmap base (the shared component library, gallery, and markdown spec viewer that build every deck into one static site — Astro routes of the site package in iii, a standalone Vite project in other repos): 1. helps engineers understand the spec — the architecture is a navigable map, not prose; 2. is interactive — steppable diagrams, a selectable system map, live toggles; interactivity is what makes it stick; 3. reads like marketi…

, className, children }: PromptProps) {\n return (\n \u003cspan className={cn('font-mono text-accent', className)}>\n {symbol}\n {children !== undefined ? \u003cspan className=\"text-ink ml-2\">{children}\u003c/span> : null}\n \u003c/span>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":441,"content_sha256":"1607a920f3fd61db08d9625b69637192f2e1ff35942e79311fcae41d20292b16"},{"filename":"base/src/components/schematic/Sheet.tsx","content":"import { cn } from '@lib/lib/utils'\nimport type * as React from 'react'\n\ninterface SheetProps {\n children: React.ReactNode\n className?: string\n}\n\nexport function Sheet({ children, className }: SheetProps) {\n return (\n \u003cdiv className={cn('mx-auto w-full max-w-[1200px] border-x border-rule min-h-screen bg-bg', className)}>\n {children}\n \u003c/div>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":363,"content_sha256":"6d1c58244a5dbe27839d8723ad1bf0c5232319174832ab35f461eb60fbd62927"},{"filename":"base/src/components/schematic/StatusDot.tsx","content":"import { cn } from '@lib/lib/utils'\nimport type * as React from 'react'\n\ntype DotTone = 'accent' | 'alert' | 'warn' | 'ink' | 'ghost'\n\nconst dotTone: Record\u003cDotTone, string> = {\n accent: 'bg-accent',\n alert: 'bg-alert',\n warn: 'bg-warn',\n ink: 'bg-ink',\n ghost: 'bg-ink-ghost',\n}\n\ninterface StatusDotProps extends React.HTMLAttributes\u003cHTMLSpanElement> {\n tone?: DotTone\n pulse?: boolean\n}\n\nexport function StatusDot({ tone = 'accent', pulse, className, ...props }: StatusDotProps) {\n return (\n \u003cspan\n aria-hidden\n className={cn('inline-block size-1.5 rounded-full shrink-0', dotTone[tone], pulse && 'pulse-dot', className)}\n {...props}\n />\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":675,"content_sha256":"04e3a1b74f8b6ed21d762d55a977bd9c4c0fb1b656ba13deedfea36a67d40f52"},{"filename":"base/src/components/schematic/StatusPanel.tsx","content":"import { cn } from '@lib/lib/utils'\nimport type * as React from 'react'\n\nexport type StatusVariant = 'info' | 'success' | 'warn' | 'alert'\n\nconst variantTone: Record\u003cStatusVariant, { border: string; icon: string; headline: string }> = {\n info: {\n border: 'border-rule',\n icon: 'text-ink',\n headline: 'text-ink',\n },\n success: {\n border: 'border-accent',\n icon: 'text-accent',\n headline: 'text-accent',\n },\n warn: {\n border: 'border-warn',\n icon: 'text-warn',\n headline: 'text-warn',\n },\n alert: {\n border: 'border-alert',\n icon: 'text-alert',\n headline: 'text-alert',\n },\n}\n\ninterface StatusPanelProps {\n variant?: StatusVariant\n icon?: React.ReactNode\n headline: React.ReactNode\n detail?: React.ReactNode\n className?: string\n}\n\nexport function StatusPanel({ variant = 'info', icon, headline, detail, className }: StatusPanelProps) {\n const tone = variantTone[variant]\n return (\n \u003cdiv className={cn('flex items-start gap-x-3 border bg-bg px-3.5 py-3', tone.border, className)}>\n {icon ? (\n \u003cspan aria-hidden className={cn('size-[18px] shrink-0', tone.icon)}>\n {icon}\n \u003c/span>\n ) : null}\n \u003cdiv className=\"min-w-0 flex flex-col gap-y-0.5\">\n \u003cdiv className={cn('font-mono text-[13px] font-semibold lowercase', tone.headline)}>{headline}\u003c/div>\n {detail ? \u003cdiv className=\"font-mono text-[12px] text-ink-faint lowercase\">{detail}\u003c/div> : null}\n \u003c/div>\n \u003c/div>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":1474,"content_sha256":"1731d9fc23b18bf3b25818546e685555d8837c08440f9ba7c8cdfca5c508ca91"},{"filename":"base/src/components/schematic/Terminal.tsx","content":"import { cn } from '@lib/lib/utils'\nimport type * as React from 'react'\nimport { Caret } from './Caret'\nimport { Prompt } from './Prompt'\n\ninterface TerminalProps {\n title?: React.ReactNode\n children: React.ReactNode\n className?: string\n}\n\nexport function Terminal({ title, children, className }: TerminalProps) {\n return (\n \u003cdiv className={cn('border border-rule bg-bg', className)}>\n {title ? (\n \u003cdiv className=\"bg-panel px-3.5 py-2 border-b border-rule font-mono text-[11px] font-medium uppercase tracking-[0.06em] text-ink-faint\">\n {title}\n \u003c/div>\n ) : null}\n \u003cdiv className=\"p-4 font-mono text-[13px] text-ink\">{children}\u003c/div>\n \u003c/div>\n )\n}\n\ninterface TerminalRowProps {\n command: React.ReactNode\n output?: React.ReactNode\n showCaret?: boolean\n className?: string\n}\n\nexport function TerminalRow({ command, output, showCaret, className }: TerminalRowProps) {\n return (\n \u003cdiv className={cn('flex flex-col gap-y-1', className)}>\n \u003cdiv className=\"flex items-center gap-x-2\">\n \u003cPrompt symbol=\"$\" />\n \u003cspan className=\"text-ink\">{command}\u003c/span>\n {showCaret ? \u003cCaret /> : null}\n \u003c/div>\n {output ? \u003cdiv className=\"pl-4 text-[12.5px] text-ink-faint\">{output}\u003c/div> : null}\n \u003c/div>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":1279,"content_sha256":"e92ebe5edac480967e3999960cd49ad1801de5d23d5e15ae6b9ce6249d84f6f9"},{"filename":"base/src/components/schematic/Wordmark.tsx","content":"import { cn } from '@lib/lib/utils'\n\n/**\n * the iii wordmark: three \"i\"s, each a stem + a tittle, six rectangles total,\n * all sharing the same square unit, all in ink. Gaps are half a unit; stems are\n * two and a half units tall, so the mark is a square.\n */\nexport function Wordmark({ className }: { className?: string }) {\n const unit = 4\n const stems = [0, 6, 12]\n return (\n \u003csvg aria-label=\"iii\" role=\"img\" viewBox=\"0 0 16 16\" className={cn('h-[18px] w-auto', className)}>\n {stems.map((x) => (\n \u003cg key={x} className=\"fill-ink\">\n \u003crect x={x} y={0} width={unit} height={unit} />\n \u003crect x={x} y={6} width={unit} height={10} />\n \u003c/g>\n ))}\n \u003c/svg>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":705,"content_sha256":"513f6c3ef3346aea744227d309af2396bb9b828ca0e26a23d9b9f33e36bba88d"},{"filename":"base/src/components/schematic/WorkerCard.tsx","content":"import { cn } from '@lib/lib/utils'\nimport type * as React from 'react'\n\ninterface WorkerCardProps {\n name: string\n version?: string\n description: React.ReactNode\n command: React.ReactNode\n kind: string\n focused?: boolean\n className?: string\n}\n\nexport function WorkerCard({ name, version, description, command, kind, focused, className }: WorkerCardProps) {\n return (\n \u003carticle\n className={cn(\n 'border border-rule transition-colors',\n focused ? 'bg-panel border-l-2 border-l-accent' : 'bg-bg',\n className,\n )}\n >\n \u003cheader className=\"flex items-center justify-between px-4 py-3 border-b border-rule-2\">\n \u003cdiv className=\"font-mono text-[16px] font-semibold lowercase text-ink\">{name}\u003c/div>\n {version ? (\n \u003cdiv className=\"font-mono text-[11px] uppercase tracking-[0.06em] text-ink-ghost tabular-nums\">\n v{version}\n \u003c/div>\n ) : null}\n \u003c/header>\n \u003cdiv className=\"px-4 py-3 font-mono text-[13px] leading-[1.7] text-ink-faint\">{description}\u003c/div>\n \u003cdiv className=\"bg-panel font-mono text-[12.5px] text-ink px-4 py-2 border-t border-rule-2\">{command}\u003c/div>\n \u003cfooter className=\"flex items-center justify-between px-4 py-2 border-t border-rule-2\">\n \u003cspan className=\"font-mono text-[11px] uppercase tracking-[0.06em] text-ink-faint\">{kind}\u003c/span>\n \u003cspan aria-hidden className=\"text-accent\">\n ✓\n \u003c/span>\n \u003c/footer>\n \u003c/article>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":1482,"content_sha256":"bb4b2cc441a8d54987d00992b7f6e479ab7075ead20d7c6aea08a2445c86d407"},{"filename":"base/src/components/Section.tsx","content":"import { cn } from '@lib/lib/utils'\nimport type * as React from 'react'\nimport { useEffect, useRef, useState } from 'react'\n\ninterface SectionProps {\n id: string\n index: string // drafting-sheet section number, e.g. \"01\"\n eyebrow: string\n title: React.ReactNode\n lede?: React.ReactNode\n children: React.ReactNode\n className?: string\n}\n\n/**\n * a numbered drafting-sheet section: full-width top rule, label-caps eyebrow\n * with the sheet number on the right, headline-section title, ink-faint lede.\n * content reveals on first scroll into view.\n */\nexport function Section({ id, index, eyebrow, title, lede, children, className }: SectionProps) {\n const ref = useRef\u003cHTMLElement>(null)\n const [shown, setShown] = useState(false)\n\n useEffect(() => {\n const el = ref.current\n if (!el) return\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n setShown(true)\n observer.disconnect()\n }\n }\n },\n { rootMargin: '0px 0px -10% 0px' },\n )\n observer.observe(el)\n return () => observer.disconnect()\n }, [])\n\n return (\n \u003csection id={id} ref={ref} className={cn('border-t border-rule scroll-mt-[64px]', className)}>\n \u003cdiv className=\"flex items-center justify-between px-4 py-2.5 border-b border-rule-2 @3xl:px-9\">\n \u003cspan className=\"font-mono text-[12px] font-medium uppercase tracking-[0.18em] text-ink-faint\">{eyebrow}\u003c/span>\n \u003cspan className=\"font-mono text-[12px] font-medium uppercase tracking-[0.14em] text-ink-ghost tabular-nums\">\n {index}\n \u003c/span>\n \u003c/div>\n \u003cdiv className={cn('px-4 py-12 @3xl:px-9 @3xl:py-16 reveal', shown && 'reveal-in')}>\n \u003ch2 className=\"font-mono text-[28px] font-medium leading-[1.25] tracking-[-0.01em] text-ink lowercase max-w-[28ch]\">\n {title}\n \u003c/h2>\n {lede ? (\n \u003cp className=\"mt-4 font-mono text-[14px] leading-[1.7] text-ink-faint lowercase max-w-[62ch]\">{lede}\u003c/p>\n ) : null}\n \u003cdiv className=\"mt-10\">{children}\u003c/div>\n \u003c/div>\n \u003c/section>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":2141,"content_sha256":"75a739a190c1eea7bad54b0976c3cf3b61a99b3c67f30ddf3ce41bd290aeec4e"},{"filename":"base/src/components/SpecSheet.tsx","content":"import { cn } from '@lib/lib/utils'\nimport type * as React from 'react'\n\ninterface SpecSheetProps {\n title: React.ReactNode\n meta?: React.ReactNode\n children: React.ReactNode\n defaultOpen?: boolean\n className?: string\n}\n\n/**\n * the expandable technical layer: a native \u003cdetails> datasheet with a\n * panel-tinted head strip. closed by default so the page stays a story;\n * the spec is one click away.\n */\nexport function SpecSheet({ title, meta, children, defaultOpen, className }: SpecSheetProps) {\n return (\n \u003cdetails className={cn('group border border-rule bg-bg', className)} open={defaultOpen}>\n \u003csummary className=\"flex cursor-pointer select-none items-center justify-between gap-x-3 bg-panel px-3.5 py-2.5 border-b border-transparent group-open:border-rule list-none [&::-webkit-details-marker]:hidden\">\n \u003cspan className=\"flex items-center gap-x-2.5 min-w-0\">\n \u003cspan aria-hidden className=\"font-mono text-[13px] text-accent w-3 shrink-0\">\n \u003cspan className=\"group-open:hidden\">+\u003c/span>\n \u003cspan className=\"hidden group-open:inline\">−\u003c/span>\n \u003c/span>\n \u003cspan className=\"font-mono text-[12px] font-medium uppercase tracking-[0.14em] text-ink-faint truncate\">\n {title}\n \u003c/span>\n \u003c/span>\n {meta ? (\n \u003cspan className=\"font-mono text-[11px] uppercase tracking-[0.06em] text-ink-ghost shrink-0\">{meta}\u003c/span>\n ) : null}\n \u003c/summary>\n \u003cdiv className=\"p-5\">{children}\u003c/div>\n \u003c/details>\n )\n}\n\ninterface SpecRowProps {\n name: string\n type?: string\n children?: React.ReactNode\n required?: boolean\n indent?: boolean\n}\n\n/** one row of a type-table: `name type required-marker` + faint description */\nexport function SpecRow({ name, type, children, required, indent }: SpecRowProps) {\n return (\n \u003cdiv className={cn('py-1.5 border-b border-rule-2 last:border-b-0', indent && 'pl-4 border-l border-rule-2')}>\n \u003cdiv className=\"flex flex-wrap items-baseline gap-x-3\">\n \u003cspan className=\"font-mono text-[12.5px] text-ink\">\n {name}\n {required ? \u003cspan className=\"text-accent\">*\u003c/span> : null}\n \u003c/span>\n {type ? \u003cspan className=\"font-mono text-[11.5px] text-ink-ghost\">{type}\u003c/span> : null}\n \u003c/div>\n {children ? (\n \u003cdiv className=\"mt-0.5 font-mono text-[12px] leading-[1.6] text-ink-faint lowercase\">{children}\u003c/div>\n ) : null}\n \u003c/div>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":2435,"content_sha256":"7408b5beafc22a122583bad7a40fe8a0c1737631dbbdb7e25c1af3d1ffd62b19"},{"filename":"base/src/components/TopNav.tsx","content":"import { ModeToggle } from '@lib/components/schematic/ModeToggle'\nimport { Wordmark } from '@lib/components/schematic/Wordmark'\nimport type { Route } from '@lib/hooks/useHashRoute'\nimport { useTheme } from '@lib/hooks/useTheme'\nimport type { DeckMeta, NavItem } from '@lib/lib/deck-types'\nimport { cn } from '@lib/lib/utils'\nimport { useEffect, useState } from 'react'\n\nexport function TopNav({\n route,\n meta,\n nav,\n specHref = '#/spec',\n}: {\n route: Route\n meta: DeckMeta\n nav: NavItem[]\n /** set to null to hide the spec link (e.g. in the md-only viewer) */\n specHref?: string | null\n}) {\n const [theme, setTheme] = useTheme()\n const [active, setActive] = useState\u003cstring | null>(null)\n\n // scroll-spy: highlight the section currently in view (home page only)\n useEffect(() => {\n if (route.kind !== 'home') return\n const sections = nav.map((l) => document.getElementById(l.id)).filter((el): el is HTMLElement => el !== null)\n if (sections.length === 0) return\n const observer = new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) setActive(entry.target.id)\n }\n },\n { rootMargin: '-20% 0px -70% 0px' },\n )\n for (const el of sections) observer.observe(el)\n return () => observer.disconnect()\n }, [route, nav])\n\n return (\n \u003cheader className=\"sticky top-0 z-50 border-b border-rule bg-bg\">\n \u003cdiv className=\"flex items-center gap-x-5 px-4 py-2.5 @3xl:px-9\">\n \u003ca href=\"#/\" className=\"flex items-center gap-x-2.5 shrink-0\" aria-label=\"iii — back to overview\">\n \u003cWordmark />\n \u003cspan className=\"font-mono text-[13px] font-semibold lowercase text-ink hidden @lg:inline\">\n {meta.wordmarkLabel}\n \u003c/span>\n \u003c/a>\n\n {route.kind === 'home' ? (\n \u003cnav className=\"hidden @3xl:flex items-center gap-x-4 min-w-0 overflow-x-auto\">\n {nav.map((link) => (\n \u003ca\n key={link.id}\n href={`#${link.id}`}\n className={cn(\n 'font-mono text-[12px] lowercase py-1.5 transition-colors whitespace-nowrap',\n active === link.id ? 'text-accent' : 'text-ink-faint hover:text-ink',\n )}\n >\n {link.label}\n \u003c/a>\n ))}\n \u003c/nav>\n ) : (\n \u003ca href=\"#/\" className=\"font-mono text-[12px] lowercase text-ink-faint hover:text-ink transition-colors\">\n ← back to the overview\n \u003c/a>\n )}\n\n \u003cdiv className=\"ml-auto flex items-center gap-x-4 shrink-0\">\n {specHref ? (\n \u003ca\n href={specHref}\n className={cn(\n 'font-mono text-[12px] lowercase whitespace-nowrap transition-colors',\n route.kind === 'page' && route.slug === 'spec' ? 'text-accent' : 'text-ink-faint hover:text-ink',\n )}\n >\n spec\n \u003c/a>\n ) : null}\n \u003cModeToggle\n value={theme}\n onChange={setTheme}\n options={[\n { value: 'light', label: 'light' },\n { value: 'dark', label: 'dark' },\n ]}\n />\n \u003c/div>\n \u003c/div>\n \u003c/header>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":3284,"content_sha256":"8fc9e2833de04cef033d071caed41baa6a7e25638cc30fb2cf198b0ea6fe91a8"},{"filename":"base/src/content/highlight.tsx","content":"import { type CSSProperties, Fragment, type ReactNode } from 'react'\n\n/**\n * A dependency-free, multi-color (\"rainbow\") syntax highlighter for the four\n * languages codegen emits. It classifies tokens into keyword / string / comment\n * / type / function / number / operator / plain and colors each from a\n * dedicated syntax palette (see HighlightStyles). The palette is theme-aware: a\n * darker saturated set on the light sheet, a brighter One-Dark-style set under\n * [data-theme=\"dark\"]. This intentionally overrides the deck's rationed-accent\n * rule for code blocks.\n */\nexport type HlLang = 'typescript' | 'javascript' | 'rust' | 'python' | 'yaml'\n\nconst KEYWORDS: Record\u003cHlLang, Set\u003cstring>> = {\n typescript: new Set([\n 'export',\n 'import',\n 'from',\n 'interface',\n 'type',\n 'async',\n 'function',\n 'return',\n 'const',\n 'let',\n 'await',\n 'new',\n 'class',\n 'extends',\n 'implements',\n 'as',\n 'void',\n 'in',\n 'of',\n 'typeof',\n 'keyof',\n 'string',\n 'number',\n 'boolean',\n ]),\n javascript: new Set([\n 'export',\n 'import',\n 'from',\n 'async',\n 'function',\n 'return',\n 'const',\n 'let',\n 'await',\n 'new',\n 'class',\n 'extends',\n 'as',\n 'in',\n 'of',\n 'typeof',\n ]),\n rust: new Set([\n 'use',\n 'pub',\n 'type',\n 'struct',\n 'fn',\n 'async',\n 'let',\n 'await',\n 'crate',\n 'mut',\n 'match',\n 'impl',\n 'mod',\n 'as',\n 'return',\n 'self',\n 'Self',\n 'where',\n 'dyn',\n 'move',\n 'enum',\n 'trait',\n 'const',\n 'static',\n 'ref',\n ]),\n python: new Set([\n 'from',\n 'import',\n 'class',\n 'def',\n 'return',\n 'None',\n 'True',\n 'False',\n 'and',\n 'or',\n 'not',\n 'in',\n 'is',\n 'if',\n 'else',\n 'elif',\n 'for',\n 'while',\n 'await',\n 'async',\n 'with',\n 'as',\n 'pass',\n 'lambda',\n 'yield',\n 'try',\n 'except',\n 'raise',\n 'str',\n 'int',\n 'float',\n 'bool',\n ]),\n yaml: new Set(['true', 'false', 'null', 'yes', 'no', 'on', 'off']),\n}\n\ntype TokKind = 'ws' | 'comment' | 'string' | 'number' | 'keyword' | 'type' | 'function' | 'punct' | 'plain'\ninterface Tok {\n kind: TokKind\n value: string\n}\n\nconst isSpace = (c: string) => c === ' ' || c === '\\t' || c === '\\n' || c === '\\r'\nconst isWordStart = (c: string) => /[A-Za-z_$]/.test(c)\nconst isWord = (c: string) => /[A-Za-z0-9_$]/.test(c)\nconst isDigit = (c: string) => c >= '0' && c \u003c= '9'\n\nfunction tokenize(code: string, lang: HlLang): Tok[] {\n const kw = KEYWORDS[lang]\n const hashComments = lang === 'python'\n const slashComments = lang !== 'python'\n const toks: Tok[] = []\n const n = code.length\n let i = 0\n\n while (i \u003c n) {\n const c = code[i]\n\n if (isSpace(c)) {\n let j = i + 1\n while (j \u003c n && isSpace(code[j])) j++\n toks.push({ kind: 'ws', value: code.slice(i, j) })\n i = j\n continue\n }\n\n if (hashComments && c === '#') {\n let j = i + 1\n while (j \u003c n && code[j] !== '\\n') j++\n toks.push({ kind: 'comment', value: code.slice(i, j) })\n i = j\n continue\n }\n\n if (slashComments && c === '/' && code[i + 1] === '/') {\n let j = i + 2\n while (j \u003c n && code[j] !== '\\n') j++\n toks.push({ kind: 'comment', value: code.slice(i, j) })\n i = j\n continue\n }\n\n if (slashComments && c === '/' && code[i + 1] === '*') {\n let j = i + 2\n while (j \u003c n && !(code[j] === '*' && code[j + 1] === '/')) j++\n j = Math.min(n, j + 2)\n toks.push({ kind: 'comment', value: code.slice(i, j) })\n i = j\n continue\n }\n\n if (c === '\"' || c === \"'\") {\n let j = i + 1\n while (j \u003c n && code[j] !== c) {\n if (code[j] === '\\\\') j++\n j++\n }\n j = Math.min(n, j + 1)\n toks.push({ kind: 'string', value: code.slice(i, j) })\n i = j\n continue\n }\n\n if (isDigit(c)) {\n let j = i + 1\n while (j \u003c n && (isWord(code[j]) || code[j] === '.')) j++\n toks.push({ kind: 'number', value: code.slice(i, j) })\n i = j\n continue\n }\n\n if (isWordStart(c)) {\n let j = i + 1\n while (j \u003c n && isWord(code[j])) j++\n const word = code.slice(i, j)\n const next = code[j]\n let kind: TokKind\n if (kw.has(word)) kind = 'keyword'\n else if (next === '(' || next === '\u003c') kind = 'function'\n else if (/^[A-Z]/.test(word)) kind = 'type'\n else kind = 'plain'\n toks.push({ kind, value: word })\n i = j\n continue\n }\n\n // a run of operator / punctuation chars, stopping before tokens a later\n // pass should own\n let j = i + 1\n while (\n j \u003c n &&\n !isSpace(code[j]) &&\n !isWordStart(code[j]) &&\n !isDigit(code[j]) &&\n code[j] !== '\"' &&\n code[j] !== \"'\" &&\n code[j] !== '/'\n ) {\n j++\n }\n toks.push({ kind: 'punct', value: code.slice(i, j) })\n i = j\n }\n\n return toks\n}\n\nfunction tokenizeYamlValue(text: string, toks: Tok[]) {\n const consts = KEYWORDS.yaml\n const n = text.length\n let i = 0\n while (i \u003c n) {\n const c = text[i]\n if (isSpace(c)) {\n let j = i + 1\n while (j \u003c n && isSpace(text[j])) j++\n toks.push({ kind: 'ws', value: text.slice(i, j) })\n i = j\n continue\n }\n if (c === '#') {\n toks.push({ kind: 'comment', value: text.slice(i) })\n i = n\n continue\n }\n if (c === '\"' || c === \"'\") {\n let j = i + 1\n while (j \u003c n && text[j] !== c) {\n if (text[j] === '\\\\') j++\n j++\n }\n j = Math.min(n, j + 1)\n toks.push({ kind: 'string', value: text.slice(i, j) })\n i = j\n continue\n }\n if (isDigit(c)) {\n let j = i + 1\n while (j \u003c n && (isWord(text[j]) || text[j] === '.')) j++\n toks.push({ kind: 'number', value: text.slice(i, j) })\n i = j\n continue\n }\n if (isWordStart(c)) {\n let j = i + 1\n while (j \u003c n && isWord(text[j])) j++\n const w = text.slice(i, j)\n toks.push({ kind: consts.has(w) ? 'keyword' : 'plain', value: w })\n i = j\n continue\n }\n let j = i + 1\n while (\n j \u003c n &&\n !isSpace(text[j]) &&\n !isWordStart(text[j]) &&\n !isDigit(text[j]) &&\n text[j] !== '\"' &&\n text[j] !== \"'\" &&\n text[j] !== '#'\n ) {\n j++\n }\n toks.push({ kind: 'punct', value: text.slice(i, j) })\n i = j\n }\n}\n\nfunction tokenizeYaml(code: string): Tok[] {\n const toks: Tok[] = []\n const lines = code.split('\\n')\n lines.forEach((line, idx) => {\n if (idx > 0) toks.push({ kind: 'ws', value: '\\n' })\n const indent = (line.match(/^\\s*/) as RegExpMatchArray)[0]\n if (indent) toks.push({ kind: 'ws', value: indent })\n let rest = line.slice(indent.length)\n if (rest === '') return\n if (rest[0] === '#') {\n toks.push({ kind: 'comment', value: rest })\n return\n }\n if (rest[0] === '-' && (rest[1] === ' ' || rest.length === 1)) {\n toks.push({ kind: 'punct', value: '-' })\n rest = rest.slice(1)\n }\n const keyMatch = rest.match(/^([\\w./@-]+)(:)(?=\\s|$)/)\n if (keyMatch) {\n toks.push({ kind: 'keyword', value: keyMatch[1] })\n toks.push({ kind: 'punct', value: ':' })\n rest = rest.slice(keyMatch[0].length)\n }\n tokenizeYamlValue(rest, toks)\n })\n return toks\n}\n\nconst COLOR: Partial\u003cRecord\u003cTokKind, string>> = {\n comment: 'var(--cg-comment)',\n string: 'var(--cg-string)',\n number: 'var(--cg-number)',\n keyword: 'var(--cg-keyword)',\n type: 'var(--cg-type)',\n function: 'var(--cg-function)',\n punct: 'var(--cg-punct)',\n}\n\n/** The syntax palette. Render once per page. */\nexport function HighlightStyles() {\n const css = `\n.cg-hl {\n --cg-plain: #0a0a0a;\n --cg-comment: #9a948c;\n --cg-keyword: #9333ea;\n --cg-string: #15803d;\n --cg-number: #b45309;\n --cg-type: #0e7490;\n --cg-function: #1d4ed8;\n --cg-punct: #6b6865;\n color: var(--cg-plain);\n}\n[data-theme=\"dark\"] .cg-hl {\n --cg-plain: #e6e6e6;\n --cg-comment: #7f848e;\n --cg-keyword: #c678dd;\n --cg-string: #98c379;\n --cg-number: #d19a66;\n --cg-type: #e5c07b;\n --cg-function: #61afef;\n --cg-punct: #abb2bf;\n}`\n return \u003cstyle>{css}\u003c/style>\n}\n\nexport function Highlight({ code, lang }: { code: string; lang: HlLang }): ReactNode {\n const toks = lang === 'yaml' ? tokenizeYaml(code) : tokenize(code, lang)\n return (\n \u003cspan className=\"cg-hl\">\n {toks.map((tok, idx) => {\n const color = COLOR[tok.kind]\n if (!color) return \u003cFragment key={idx}>{tok.value}\u003c/Fragment>\n const style: CSSProperties = { color }\n if (tok.kind === 'comment') style.fontStyle = 'italic'\n return (\n \u003cspan key={idx} style={style}>\n {tok.value}\n \u003c/span>\n )\n })}\n \u003c/span>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":8760,"content_sha256":"3653fd809d4e7c06f431fc34fbee84c33ff86fe337f46c9c1963dfd2c485772b"},{"filename":"base/src/content/markdown.tsx","content":"import { CodeBlock } from '@lib/components/schematic/CodeBlock'\nimport { Highlight, type HlLang } from '@lib/content/highlight'\nimport { Mermaid } from '@lib/content/mermaid'\nimport { cn } from '@lib/lib/utils'\nimport { marked } from 'marked'\nimport { Fragment, type MouseEvent, type ReactNode } from 'react'\n\n/**\n * Renders a markdown string as React, styled in the deck's drafting-sheet\n * system. Fenced code reuses the deck's syntax highlighter where the language\n * is supported (monochrome otherwise); ```mermaid fences render as live,\n * themed diagrams. Spec content keeps its original casing (the deck's lowercase\n * rule applies to chrome copy, not rendered docs).\n *\n * Input is locally-authored, trusted spec markdown (not user input).\n */\n\nconst LANG_MAP: Record\u003cstring, HlLang> = {\n ts: 'typescript',\n typescript: 'typescript',\n tsx: 'typescript',\n js: 'javascript',\n jsx: 'javascript',\n javascript: 'javascript',\n mjs: 'javascript',\n rs: 'rust',\n rust: 'rust',\n py: 'python',\n python: 'python',\n yml: 'yaml',\n yaml: 'yaml',\n}\n\n/** GitHub-style heading slug (matches the anchors the specs link to). */\nexport function slugify(text: string): string {\n return text\n .trim()\n .toLowerCase()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/\\s+/g, '-')\n}\n\n/** Rewrite a markdown href: sibling `*.md` links point into the spec viewer. */\nfunction rewriteHref(href: string): string {\n if (!href) return '#'\n if (href.startsWith('#')) return href\n const m = href.match(/^\\.?\\/?([\\w./-]+?)\\.md(?:#.*)?$/)\n if (m) {\n const base = m[1].split('/').pop() ?? m[1]\n return `#/spec/${base.toLowerCase()}`\n }\n return href\n}\n\n// marked's Token union is broad; this renderer reads a known subset of fields.\ntype Tok = { type: string; [k: string]: unknown }\n\nfunction renderInline(tokens: Tok[] = [], keyPrefix = 'i'): ReactNode[] {\n return tokens.map((t, i) => {\n const key = `${keyPrefix}-${i}`\n const sub = (t.tokens as Tok[] | undefined) ?? []\n switch (t.type) {\n case 'text':\n return sub.length ? (\n \u003cFragment key={key}>{renderInline(sub, key)}\u003c/Fragment>\n ) : (\n \u003cFragment key={key}>{t.text as string}\u003c/Fragment>\n )\n case 'strong':\n return (\n \u003cstrong key={key} className=\"font-semibold text-ink\">\n {renderInline(sub, key)}\n \u003c/strong>\n )\n case 'em':\n return (\n \u003cem key={key} className=\"italic\">\n {renderInline(sub, key)}\n \u003c/em>\n )\n case 'del':\n return (\n \u003cdel key={key} className=\"text-ink-ghost line-through\">\n {renderInline(sub, key)}\n \u003c/del>\n )\n case 'codespan':\n return (\n \u003ccode key={key} className=\"font-mono text-[0.88em] text-ink bg-panel px-1 py-0.5 border border-rule\">\n {t.text as string}\n \u003c/code>\n )\n case 'link': {\n const href = rewriteHref(t.href as string)\n const external = /^https?:/.test(href)\n // a same-page anchor (`#section`) must scroll in place, not change the\n // hash to a bare `#…` (which the router would read as \"go home\")\n const anchor = href.startsWith('#') && !href.startsWith('#/')\n return (\n \u003ca\n key={key}\n href={href}\n className=\"text-accent hover:underline underline-offset-2\"\n {...(external ? { target: '_blank', rel: 'noreferrer' } : {})}\n {...(anchor\n ? {\n onClick: (e: MouseEvent) => {\n e.preventDefault()\n document.getElementById(decodeURIComponent(href.slice(1)))?.scrollIntoView({ behavior: 'smooth' })\n },\n }\n : {})}\n >\n {renderInline(sub, key)}\n \u003c/a>\n )\n }\n case 'br':\n return \u003cbr key={key} />\n case 'escape':\n return \u003cFragment key={key}>{t.text as string}\u003c/Fragment>\n default:\n return \u003cFragment key={key}>{(t.text as string) ?? ''}\u003c/Fragment>\n }\n })\n}\n\nfunction renderTokens(tokens: Tok[] = [], keyPrefix = 'b'): ReactNode[] {\n return tokens.map((t, i) => {\n const key = `${keyPrefix}-${i}`\n const sub = (t.tokens as Tok[] | undefined) ?? []\n switch (t.type) {\n case 'heading': {\n const id = slugify(t.text as string)\n const inner = renderInline(sub, key)\n const depth = t.depth as number\n if (depth \u003c= 1)\n return (\n \u003ch1\n key={key}\n id={id}\n className=\"font-mono font-semibold text-ink text-[24px] @3xl:text-[28px] leading-tight mt-0 mb-4 scroll-mt-20\"\n >\n {inner}\n \u003c/h1>\n )\n if (depth === 2)\n return (\n \u003ch2\n key={key}\n id={id}\n className=\"font-mono font-medium text-ink text-[18px] leading-snug mt-10 mb-3 pt-5 border-t border-rule scroll-mt-20\"\n >\n {inner}\n \u003c/h2>\n )\n if (depth === 3)\n return (\n \u003ch3 key={key} id={id} className=\"font-mono font-semibold text-ink text-[14px] mt-6 mb-2 scroll-mt-20\">\n {inner}\n \u003c/h3>\n )\n return (\n \u003ch4\n key={key}\n id={id}\n className=\"font-mono font-semibold text-ink-faint text-[11px] uppercase tracking-[0.08em] mt-5 mb-2 scroll-mt-20\"\n >\n {inner}\n \u003c/h4>\n )\n }\n case 'paragraph':\n return (\n \u003cp key={key} className=\"font-mono text-[13px] @3xl:text-[14px] leading-[1.7] text-ink-faint my-3\">\n {renderInline(sub, key)}\n \u003c/p>\n )\n case 'text':\n return sub.length ? (\n \u003cFragment key={key}>{renderInline(sub, key)}\u003c/Fragment>\n ) : (\n \u003cFragment key={key}>{t.text as string}\u003c/Fragment>\n )\n case 'code': {\n const code = (t.text as string) ?? ''\n const lang = ((t.lang as string) ?? '').trim().toLowerCase().split(/\\s+/)[0]\n if (lang === 'mermaid') return \u003cMermaid key={key} chart={code} />\n const hl = LANG_MAP[lang]\n return (\n \u003cdiv key={key} className=\"my-4\">\n \u003cCodeBlock title={lang || undefined}>{hl ? \u003cHighlight code={code} lang={hl} /> : code}\u003c/CodeBlock>\n \u003c/div>\n )\n }\n case 'blockquote':\n return (\n \u003cblockquote key={key} className=\"border-l-2 border-rule pl-4 my-4 [&>p]:text-ink-faint [&>p]:my-2\">\n {renderTokens(sub, key)}\n \u003c/blockquote>\n )\n case 'list': {\n const ordered = Boolean(t.ordered)\n const items = (t.items as Tok[]) ?? []\n const className = cn(\n 'my-3 pl-5 font-mono text-[13px] @3xl:text-[14px] leading-[1.7] text-ink-faint space-y-1.5 marker:text-ink-ghost',\n ordered ? 'list-decimal' : 'list-disc',\n )\n const lis = items.map((it, j) => (\n \u003cli key={`${key}-${j}`} className=\"pl-1\">\n {renderTokens((it.tokens as Tok[]) ?? [], `${key}-${j}`)}\n \u003c/li>\n ))\n return ordered ? (\n \u003col key={key} className={className}>\n {lis}\n \u003c/ol>\n ) : (\n \u003cul key={key} className={className}>\n {lis}\n \u003c/ul>\n )\n }\n case 'table': {\n const header = (t.header as Tok[]) ?? []\n const rows = (t.rows as Tok[][]) ?? []\n return (\n \u003cdiv key={key} className=\"my-4 overflow-x-auto\">\n \u003ctable className=\"w-full border-collapse text-[13px] min-w-[480px]\">\n \u003cthead>\n \u003ctr>\n {header.map((cell, c) => (\n \u003cth\n key={c}\n className=\"border border-rule bg-panel px-3 py-2 text-left font-mono text-[10px] uppercase tracking-[0.06em] text-ink-faint\"\n >\n {renderInline((cell.tokens as Tok[]) ?? [], `${key}-h-${c}`)}\n \u003c/th>\n ))}\n \u003c/tr>\n \u003c/thead>\n \u003ctbody>\n {rows.map((row, r) => (\n \u003ctr key={r}>\n {row.map((cell, c) => (\n \u003ctd\n key={c}\n className=\"border border-rule px-3 py-2 align-top font-mono text-ink-faint leading-[1.6]\"\n >\n {renderInline((cell.tokens as Tok[]) ?? [], `${key}-${r}-${c}`)}\n \u003c/td>\n ))}\n \u003c/tr>\n ))}\n \u003c/tbody>\n \u003c/table>\n \u003c/div>\n )\n }\n case 'hr':\n return \u003chr key={key} className=\"my-8 border-0 border-t border-rule\" />\n case 'space':\n return null\n case 'html':\n return (\n \u003cdiv\n key={key}\n className=\"contents\"\n // biome-ignore lint/security/noDangerouslySetInnerHtml: trusted local spec markdown\n dangerouslySetInnerHTML={{ __html: t.text as string }}\n />\n )\n default:\n return null\n }\n })\n}\n\n// spec READMEs open with a YAML frontmatter block (site metadata, parsed by\n// scripts/manifest.mjs) — never render it as prose\nconst FRONTMATTER_RE = /^---\\r?\\n[\\s\\S]*?\\r?\\n---\\r?\\n?/\n\nexport function Markdown({ source }: { source: string }) {\n const tokens = marked.lexer(source.replace(FRONTMATTER_RE, '')) as unknown as Tok[]\n return \u003cdiv className=\"min-w-0\">{renderTokens(tokens)}\u003c/div>\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":9602,"content_sha256":"2cb9ebd81ae9abac52bca41df814c3f2613ecc5c17d504da610c25ad0a67bb31"},{"filename":"base/src/content/mermaid.tsx","content":"import { CodeBlock } from '@lib/components/schematic/CodeBlock'\nimport { useEffect, useId, useState } from 'react'\n\n/**\n * A mermaid diagram themed to the drafting sheet (mono font, ink borders, panel\n * fills, light/dark aware). Renders the SVG client-side and re-renders when the\n * deck's data-theme flips. Falls back to the diagram source while rendering or\n * if mermaid throws.\n */\n\nfunction themeVariables(dark: boolean) {\n return dark\n ? {\n background: '#111110',\n mainBkg: '#1a1916',\n primaryColor: '#1a1916',\n primaryBorderColor: '#f2f0ed',\n primaryTextColor: '#f2f0ed',\n secondaryColor: '#1f1e1c',\n tertiaryColor: '#1f1e1c',\n lineColor: '#9c9893',\n textColor: '#f2f0ed',\n nodeBorder: '#f2f0ed',\n clusterBkg: '#1f1e1c',\n clusterBorder: '#2a2926',\n titleColor: '#f2f0ed',\n edgeLabelBackground: '#111110',\n actorBkg: '#1a1916',\n actorBorder: '#f2f0ed',\n actorTextColor: '#f2f0ed',\n signalColor: '#9c9893',\n signalTextColor: '#f2f0ed',\n labelBoxBkgColor: '#1a1916',\n labelBoxBorderColor: '#2a2926',\n }\n : {\n background: '#f2f0ed',\n mainBkg: '#e9e6e2',\n primaryColor: '#e9e6e2',\n primaryBorderColor: '#0a0a0a',\n primaryTextColor: '#0a0a0a',\n secondaryColor: '#ebe8e3',\n tertiaryColor: '#f2f0ed',\n lineColor: '#6b6865',\n textColor: '#0a0a0a',\n nodeBorder: '#0a0a0a',\n clusterBkg: '#ebe8e3',\n clusterBorder: '#d8d5d0',\n titleColor: '#0a0a0a',\n edgeLabelBackground: '#f2f0ed',\n actorBkg: '#e9e6e2',\n actorBorder: '#0a0a0a',\n actorTextColor: '#0a0a0a',\n signalColor: '#6b6865',\n signalTextColor: '#0a0a0a',\n labelBoxBkgColor: '#e9e6e2',\n labelBoxBorderColor: '#d8d5d0',\n }\n}\n\nexport function Mermaid({ chart }: { chart: string }) {\n const rawId = useId()\n const id = `mmd-${rawId.replace(/[^a-zA-Z0-9]/g, '')}`\n const [svg, setSvg] = useState\u003cstring | null>(null)\n\n useEffect(() => {\n let cancelled = false\n\n const render = async () => {\n // lazy-load mermaid (~1.5MB) so decks without mermaid fences never ship it\n const { default: mermaid } = await import('mermaid')\n const dark = document.documentElement.dataset.theme === 'dark'\n mermaid.initialize({\n startOnLoad: false,\n securityLevel: 'strict',\n theme: 'base',\n fontFamily: '\"Chivo Mono\", ui-monospace, monospace',\n themeVariables: themeVariables(dark),\n })\n try {\n const { svg } = await mermaid.render(id, chart)\n if (!cancelled) setSvg(svg)\n } catch {\n if (!cancelled) setSvg(null)\n }\n }\n\n void render()\n const observer = new MutationObserver(() => void render())\n observer.observe(document.documentElement, {\n attributes: true,\n attributeFilter: ['data-theme'],\n })\n return () => {\n cancelled = true\n observer.disconnect()\n }\n }, [chart, id])\n\n if (!svg) {\n return \u003cCodeBlock title=\"mermaid\">{chart}\u003c/CodeBlock>\n }\n\n return (\n \u003cdiv className=\"my-5 overflow-x-auto border border-rule bg-bg p-4\">\n \u003cdiv\n className=\"flex justify-center [&_svg]:max-w-full [&_svg]:h-auto\"\n // biome-ignore lint/security/noDangerouslySetInnerHtml: trusted, locally-authored spec diagram rendered by mermaid\n dangerouslySetInnerHTML={{ __html: svg }}\n />\n \u003c/div>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":3510,"content_sha256":"9d9b80ae54ae5d2857f7ece9edbf031ef8773120782c1a4f5b9e29eec49679cb"},{"filename":"base/src/gallery/App.tsx","content":"import { SPECS } from 'virtual:spec-manifest'\nimport { Prompt } from '@lib/components/schematic/Prompt'\nimport { Sheet } from '@lib/components/schematic/Sheet'\nimport { Gallery } from './Gallery'\nimport { SiteFooter } from './SiteFooter'\nimport { SiteHeader } from './SiteHeader'\nimport { SITE } from './site'\n\nfunction Hero() {\n const live = SPECS.filter((s) => s.status !== 'draft')\n const decks = SPECS.filter((s) => s.hasDeck).length\n const draft = SPECS.length - live.length\n // the newest shipped spec — the \"where the roadmap is right now\" stat\n const latest = [...live].sort((a, b) => b.date.localeCompare(a.date))[0]\n\n const stats = [\n { value: String(SPECS.length), label: SPECS.length === 1 ? 'spec' : 'specs' },\n { value: String(decks), label: 'interactive' },\n ...(latest ? [{ value: latest.dayLabel ?? latest.month, label: 'latest' }] : []),\n ...(draft > 0 ? [{ value: String(draft), label: 'in draft' }] : []),\n ]\n\n return (\n \u003csection className=\"border-b border-rule px-4 py-16 @3xl:px-9 @3xl:py-20\">\n \u003cdiv className=\"font-mono text-[11px] uppercase tracking-[0.18em] text-ink-faint mb-6\">\n \u003cPrompt symbol=\"//\">{SITE.heroEyebrow}\u003c/Prompt>\n \u003c/div>\n \u003ch1 className=\"font-mono text-[34px] @3xl:text-[52px] font-semibold lowercase leading-[1.05] tracking-[-0.03em] text-ink max-w-[20ch]\">\n {SITE.heroTitle}\n \u003c/h1>\n \u003cp className=\"mt-6 font-mono text-[14px] @3xl:text-[15px] leading-[1.7] text-ink-faint max-w-[64ch]\">\n {SITE.heroLead}\n \u003c/p>\n\n \u003cdiv className=\"mt-10 flex flex-wrap items-stretch border border-rule w-fit\">\n {stats.map((s, i) => (\n \u003cdiv key={s.label} className={`px-5 py-4 ${i > 0 ? 'border-l border-rule' : ''}`}>\n \u003cdiv className=\"font-mono text-[24px] @3xl:text-[28px] font-semibold leading-none text-ink\">{s.value}\u003c/div>\n \u003cdiv className=\"mt-1.5 font-mono text-[11px] uppercase tracking-[0.06em] text-ink-faint\">{s.label}\u003c/div>\n \u003c/div>\n ))}\n \u003c/div>\n \u003c/section>\n )\n}\n\nexport default function App() {\n return (\n \u003cdiv className=\"@container min-h-screen\">\n \u003cSheet>\n \u003cSiteHeader />\n \u003cmain>\n \u003cHero />\n \u003csection id=\"roadmap\" className=\"px-4 py-12 @3xl:px-9 @3xl:py-16\">\n \u003cdiv className=\"font-mono text-[11px] uppercase tracking-[0.14em] text-ink-ghost mb-8\">the roadmap\u003c/div>\n \u003cGallery />\n \u003c/section>\n \u003c/main>\n \u003cSiteFooter />\n \u003c/Sheet>\n \u003c/div>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":2506,"content_sha256":"ab18f45f80b756c879a1dcc51bed6e8a29b6a0676cbcf97faa5fcfaa21452b2b"},{"filename":"base/src/gallery/Gallery.tsx","content":"import { SPECS } from 'virtual:spec-manifest'\nimport type { SpecEntry } from 'virtual:spec-manifest'\nimport { PresentationCard } from './PresentationCard'\n\ninterface TimelineItem {\n spec: SpecEntry\n index: number\n}\n\ninterface MonthGroup {\n month: string\n items: TimelineItem[]\n}\n\n/**\n * the roadmap: one column, strictly newest first, grouped under month\n * markers on a vertical rule. the manifest pre-sorts featured-first for the\n * landing feed (dist/index.json); a timeline is chronological by definition,\n * so it re-sorts by date here and ignores pinning.\n */\nexport function Gallery() {\n if (SPECS.length === 0) {\n return (\n \u003cdiv className=\"border border-rule bg-bg px-6 py-16 text-center font-mono text-[13px] lowercase text-ink-faint\">\n no specs yet. add \u003cspan className=\"text-ink\">tech-specs/<yyyy-mm-dd-slug>/README.md\u003c/span> with a\n frontmatter block to list the first one.\n \u003c/div>\n )\n }\n\n const ordered = [...SPECS].sort((a, b) => b.date.localeCompare(a.date))\n const groups: MonthGroup[] = []\n ordered.forEach((spec, index) => {\n const last = groups[groups.length - 1]\n const item = { spec, index }\n if (last && last.month === spec.month) last.items.push(item)\n else groups.push({ month: spec.month, items: [item] })\n })\n\n return (\n \u003col className=\"relative max-w-[860px] border-l border-rule\">\n {groups.map((group, g) => (\n \u003cli key={group.month} className={g > 0 ? 'pt-12' : ''}>\n \u003cdiv className=\"relative pl-6 @3xl:pl-9\">\n \u003cspan\n aria-hidden\n className=\"absolute left-0 top-[3px] size-[9px] -translate-x-1/2 border border-rule bg-panel\"\n />\n \u003ch3 className=\"font-mono text-[11px] uppercase tracking-[0.18em] leading-none text-ink-ghost\">\n {group.month}\n \u003c/h3>\n \u003c/div>\n \u003col>\n {group.items.map(({ spec, index }) => (\n \u003cli key={spec.slug} className=\"relative mt-7 pl-6 @3xl:pl-9\">\n \u003cspan\n aria-hidden\n className={`absolute left-0 top-[4px] size-[7px] -translate-x-1/2 rounded-full ${\n index === 0 ? 'bg-accent pulse-dot' : 'bg-ink-ghost'\n }`}\n />\n \u003cdiv className=\"font-mono text-[11px] uppercase tracking-[0.14em] leading-none text-ink-faint\">\n {spec.dayLabel ?? spec.month}\n {index === 0 ? \u003cspan className=\"text-accent\"> · latest\u003c/span> : null}\n \u003c/div>\n \u003cdiv className=\"mt-3\">\n \u003cPresentationCard spec={spec} index={index} />\n \u003c/div>\n \u003c/li>\n ))}\n \u003c/ol>\n \u003c/li>\n ))}\n \u003c/ol>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":2757,"content_sha256":"e75244cea447518e6cc0a7d7444e935daf318429e1c812e68060ba9a303567fc"},{"filename":"base/src/gallery/main.tsx","content":"import { StrictMode } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport '@lib/index.css'\nimport App from './App'\n\ncreateRoot(document.getElementById('root')!).render(\n \u003cStrictMode>\n \u003cApp />\n \u003c/StrictMode>,\n)\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":229,"content_sha256":"798a566ad195d7ca6c79109597bdaa28fb1cfefbacbad4cfd2ca5964f1269124"},{"filename":"base/src/gallery/PresentationCard.tsx","content":"import type { SpecEntry } from 'virtual:spec-manifest'\nimport { StatusDot } from '@lib/components/schematic/StatusDot'\n\n/**\n * one spec on the roadmap. a plain anchor to `\u003cslug>/` (a real navigation\n * into the built deck — or the markdown viewer when no deck exists). the\n * timeline gutter owns the date, so the card carries only sequence number and\n * status; the single accent appears only on hover — border, title, arrow.\n */\nexport function PresentationCard({ spec, index }: { spec: SpecEntry; index: number }) {\n const { slug, title, tagline, tags, status, hasDeck } = spec\n const isDraft = status === 'draft'\n const num = String(index + 1).padStart(2, '0')\n\n return (\n \u003ca\n href={`${slug}/`}\n aria-label={`${title}. ${tagline}${isDraft ? ' (draft)' : ''}`}\n style={{ animationDelay: `${Math.min(index, 8) * 60}ms` }}\n className=\"group flex flex-col border border-rule bg-bg p-6 @3xl:p-7 transition-colors hover:border-accent card-rise\"\n >\n \u003cdiv className=\"flex items-center justify-between gap-x-3\">\n \u003cspan className=\"font-mono text-[11px] uppercase tracking-[0.14em] text-ink-ghost\">{num}\u003c/span>\n \u003cspan className=\"flex items-center gap-x-3 font-mono text-[11px] uppercase tracking-[0.06em] text-ink-faint\">\n {isDraft ? (\n \u003cspan className=\"flex items-center gap-x-1.5 text-warn\">\n \u003cStatusDot tone=\"warn\" />\n draft\n \u003c/span>\n ) : null}\n \u003cspan>{hasDeck ? 'interactive deck' : 'spec'}\u003c/span>\n \u003c/span>\n \u003c/div>\n\n \u003ch3 className=\"mt-4 font-mono text-[18px] @3xl:text-[20px] font-semibold lowercase tracking-[-0.01em] leading-[1.25] text-ink transition-colors group-hover:text-accent\">\n {title}\n \u003c/h3>\n \u003cp className=\"mt-2.5 font-mono text-[13px] leading-[1.6] text-ink-faint\">{tagline}\u003c/p>\n\n \u003cdiv className=\"mt-auto pt-6 flex items-end justify-between gap-x-3\">\n \u003cspan className=\"flex flex-wrap gap-1.5\">\n {tags.slice(0, 4).map((t) => (\n \u003cspan\n key={t}\n className=\"border border-rule px-1.5 py-0.5 font-mono text-[10px] uppercase tracking-[0.08em] text-ink-faint\"\n >\n {t}\n \u003c/span>\n ))}\n \u003c/span>\n \u003cspan\n aria-hidden\n className=\"font-mono text-[12px] lowercase whitespace-nowrap text-ink-faint transition-colors group-hover:text-accent\"\n >\n open →\n \u003c/span>\n \u003c/div>\n\n \u003cdiv className=\"mt-4 border-t border-rule-2 pt-3 font-mono text-[10px] lowercase text-ink-ghost truncate\">\n tech-specs/{slug}\n \u003c/div>\n \u003c/a>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":2658,"content_sha256":"b54f61d07b5dbf9bcf511800c866f276f562e18411afee513eba1bb655c11a8d"},{"filename":"base/src/gallery/site.ts","content":"/**\n * site.ts — the gallery's repo identity, set once. Everything listed on the\n * page itself comes from `virtual:spec-manifest` (each spec README's\n * frontmatter); nothing per-spec ever lands in this file. `heroLead` is the\n * one hand-curated line: it speaks in roadmap voice (what's next, what\n * landed) without naming specs, so it never drifts as entries are added.\n */\n\nexport const SITE = {\n /** text next to the wordmark in the header */\n wordmarkLabel: '__WORDMARK_LABEL__',\n /** small-caps eyebrow above the hero title */\n heroEyebrow: 'tech-specs / roadmap',\n /** the big hero line — the roadmap framing, e.g. \"what we're working on\" */\n heroTitle: '__HERO_TITLE__',\n heroLead: '__HERO_LEAD__',\n /** left attribution in the footer bar */\n attribution: '__ATTRIBUTION__',\n /** right \"source of truth\" line in the footer bar */\n source: 'source of truth: __REPO__/tech-specs',\n}\n","content_type":"application/typescript; charset=utf-8","language":"typescript","size":906,"content_sha256":"df9629ce085ee3e4240b517d586a21cf1b240ae7842bdff80c75cd99ba35213f"},{"filename":"base/src/gallery/SiteFooter.tsx","content":"import { Wordmark } from '@lib/components/schematic/Wordmark'\nimport { SITE } from './site'\n\nexport function SiteFooter() {\n return (\n \u003cfooter className=\"border-t border-rule\">\n \u003cdiv className=\"flex flex-wrap items-center justify-between gap-y-3 px-4 py-4 @3xl:px-9\">\n \u003cspan className=\"flex items-center gap-x-2.5\">\n \u003cWordmark className=\"h-[14px]\" />\n \u003cspan className=\"font-mono text-[11px] uppercase tracking-[0.06em] text-ink-faint\">{SITE.attribution}\u003c/span>\n \u003c/span>\n \u003cspan className=\"font-mono text-[11px] uppercase tracking-[0.06em] text-ink-ghost\">{SITE.source}\u003c/span>\n \u003c/div>\n \u003c/footer>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":656,"content_sha256":"d0700205e20b925f7e72b8acb28cc5c1fdbc4aea4c87c96157c7a70cc00b913b"},{"filename":"base/src/gallery/SiteHeader.tsx","content":"import { ModeToggle } from '@lib/components/schematic/ModeToggle'\nimport { Wordmark } from '@lib/components/schematic/Wordmark'\nimport { useTheme } from '@lib/hooks/useTheme'\nimport { SITE } from './site'\n\nexport function SiteHeader() {\n const [theme, setTheme] = useTheme()\n\n return (\n \u003cheader className=\"sticky top-0 z-50 border-b border-rule bg-bg\">\n \u003cdiv className=\"flex items-center gap-x-5 px-4 py-2.5 @3xl:px-9\">\n \u003ca href=\"./\" className=\"flex items-center gap-x-2.5 shrink-0\" aria-label=\"back to the index\">\n \u003cWordmark />\n \u003cspan className=\"font-mono text-[13px] font-semibold lowercase text-ink hidden @lg:inline\">\n {SITE.wordmarkLabel}\n \u003c/span>\n \u003c/a>\n\n \u003cspan className=\"hidden @3xl:inline font-mono text-[12px] lowercase text-ink-ghost\">\n the roadmap, spec by spec\n \u003c/span>\n\n \u003cdiv className=\"ml-auto shrink-0\">\n \u003cModeToggle\n value={theme}\n onChange={setTheme}\n options={[\n { value: 'light', label: 'light' },\n { value: 'dark', label: 'dark' },\n ]}\n />\n \u003c/div>\n \u003c/div>\n \u003c/header>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":1188,"content_sha256":"1dc7751de21e9be88526e07cbe4e6b3f6a1272a84e6d5cd4e79575919e24e76c"},{"filename":"base/src/hooks/useHashRoute.ts","content":"import { useEffect, useState } from 'react'\n\nexport type Route = { kind: 'home' } | { kind: 'page'; slug: string; rest: string[] }\n\nfunction parse(hash: string): Route {\n // `#/\u003cslug>` (and `#/\u003cslug>/\u003csub>/...`) are page routes; the slug is the\n // FIRST segment, matched against the PAGES registry in App.tsx, and any\n // further segments are exposed as `rest` (e.g. the spec viewer's file).\n const m = hash.match(/^#\\/(.+)$/)\n if (m) {\n const segments = m[1].split('/').filter(Boolean)\n const [slug, ...rest] = segments\n if (slug) return { kind: 'page', slug, rest }\n }\n return { kind: 'home' }\n}\n\n/**\n * hash routing with two namespaces: `#/...` paths are routes (deep-dive\n * pages); bare `#section-id` hashes stay native anchor scrolls on the home\n * page. unknown page slugs fall back to home (App renders a not-found note).\n */\nexport function useHashRoute(): Route {\n const [route, setRoute] = useState\u003cRoute>(() => parse(window.location.hash))\n\n useEffect(() => {\n const onChange = () => setRoute(parse(window.location.hash))\n window.addEventListener('hashchange', onChange)\n return () => window.removeEventListener('hashchange', onChange)\n }, [])\n\n useEffect(() => {\n // deep-dive pages and the explicit \"#/\" home link start at the top;\n // bare \"#section\" hashes keep native anchor behaviour.\n if (route.kind === 'page' || window.location.hash === '#/') {\n window.scrollTo({ top: 0, behavior: 'instant' })\n }\n }, [route])\n\n return route\n}\n","content_type":"application/typescript; charset=utf-8","language":"typescript","size":1498,"content_sha256":"da8f808692f65b79d495741259c773731b151dce1f4925159adc502a2700be4c"},{"filename":"base/src/hooks/useStepper.ts","content":"import { useCallback, useEffect, useRef, useState } from 'react'\n\nexport interface Stepper {\n step: number\n playing: boolean\n atEnd: boolean\n play: () => void\n pause: () => void\n toggle: () => void\n next: () => void\n prev: () => void\n reset: () => void\n goTo: (step: number) => void\n}\n\n/**\n * shared driver for the step-through diagrams: `step` walks 0..total-1,\n * auto-advancing every `intervalMs` while playing; pauses at the end.\n */\nexport function useStepper(total: number, intervalMs = 2400, autoPlay = false): Stepper {\n const [step, setStep] = useState(0)\n const [playing, setPlaying] = useState(autoPlay)\n const timer = useRef\u003cReturnType\u003ctypeof setInterval> | null>(null)\n\n const atEnd = step >= total - 1\n\n useEffect(() => {\n if (!playing) return\n timer.current = setInterval(() => {\n setStep((s) => {\n if (s >= total - 1) {\n setPlaying(false)\n return s\n }\n return s + 1\n })\n }, intervalMs)\n return () => {\n if (timer.current) clearInterval(timer.current)\n }\n }, [playing, intervalMs, total])\n\n const play = useCallback(() => {\n setStep((s) => (s >= total - 1 ? 0 : s))\n setPlaying(true)\n }, [total])\n const pause = useCallback(() => setPlaying(false), [])\n const toggle = useCallback(() => {\n setPlaying((p) => {\n if (!p) setStep((s) => (s >= total - 1 ? 0 : s))\n return !p\n })\n }, [total])\n const next = useCallback(() => {\n setPlaying(false)\n setStep((s) => Math.min(total - 1, s + 1))\n }, [total])\n const prev = useCallback(() => {\n setPlaying(false)\n setStep((s) => Math.max(0, s - 1))\n }, [])\n const reset = useCallback(() => {\n setPlaying(false)\n setStep(0)\n }, [])\n const goTo = useCallback(\n (s: number) => {\n setPlaying(false)\n setStep(Math.max(0, Math.min(total - 1, s)))\n },\n [total],\n )\n\n return { step, playing, atEnd, play, pause, toggle, next, prev, reset, goTo }\n}\n","content_type":"application/typescript; charset=utf-8","language":"typescript","size":1951,"content_sha256":"2d1e838f37438a69acac768303ab9a2a9c9bc26e72cfa64969ced269b5d8aa9e"},{"filename":"base/src/hooks/useTheme.ts","content":"import { useCallback, useEffect, useState } from 'react'\n\nexport type Theme = 'light' | 'dark'\n\nfunction readTheme(): Theme {\n try {\n const t = localStorage.getItem('iii-theme')\n return t === 'dark' ? 'dark' : 'light'\n } catch {\n return 'light'\n }\n}\n\nexport function useTheme(): [Theme, (next: Theme) => void] {\n const [theme, setTheme] = useState\u003cTheme>(readTheme)\n\n useEffect(() => {\n document.documentElement.dataset.theme = theme\n }, [theme])\n\n const set = useCallback((next: Theme) => {\n setTheme(next)\n try {\n localStorage.setItem('iii-theme', next)\n } catch {\n /* private mode — theme just won't persist */\n }\n }, [])\n\n return [theme, set]\n}\n","content_type":"application/typescript; charset=utf-8","language":"typescript","size":694,"content_sha256":"3dc4a7a647f57cb51956d6f7d047f62747307bd43779ef78c661dc9b5160f8e3"},{"filename":"base/src/index.css","content":"/* scan the whole presentations project (shared src + every deck + the viewer)\n for utility classes, regardless of which app is the vite root per build */\n@import \"tailwindcss\" source(\"../\");\n\n@theme {\n --font-sans: \"Chivo Mono\", ui-monospace, SFMono-Regular, Menlo, Monaco,\n Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n --font-mono: \"Chivo Mono\", ui-monospace, SFMono-Regular, Menlo, Monaco,\n Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n\n /* paper / surface ramp (3-step) */\n --color-bg: #f2f0ed;\n --color-panel: #e9e6e2;\n --color-paper-2: #ebe8e3;\n\n /* ink ramp (3-step) */\n --color-ink: #0a0a0a;\n --color-ink-faint: #6b6865;\n --color-ink-ghost: #a3a09c;\n\n /* structural lines */\n --color-rule: #d8d5d0;\n --color-rule-2: #e6e3df;\n\n /* accent (single hero — hot orange) */\n --color-accent: #ff5a1f;\n --color-accent-fg: #f2f0ed;\n\n /* status */\n --color-alert: #c43e1c;\n --color-warn: #a87a00;\n\n /* radii — only two are allowed */\n --radius-none: 0px;\n --radius-full: 9999px;\n\n /* spacing scale */\n --spacing-gutter: 24px;\n --spacing-section-x: 36px;\n --spacing-section-y: 80px;\n --spacing-sheet-max: 1200px;\n --spacing-content-max: 1216px;\n}\n\n/* dark theme: invert paper/ink and swap accent to electric blue */\n[data-theme=\"dark\"] {\n --color-bg: #111110;\n --color-panel: #1a1916;\n --color-paper-2: #1f1e1c;\n --color-ink: #f2f0ed;\n --color-ink-faint: #9c9893;\n --color-ink-ghost: #5d5a55;\n --color-rule: #2a2926;\n --color-rule-2: #1f1e1c;\n --color-accent: #3ea8ff;\n --color-accent-fg: #111110;\n}\n\n@layer base {\n html,\n body,\n #root {\n height: 100%;\n }\n\n html,\n body {\n scrollbar-gutter: stable;\n }\n\n html {\n overflow-y: scroll;\n scroll-behavior: smooth;\n }\n\n body {\n background-color: var(--color-bg);\n color: var(--color-ink);\n /* explicitly disable decorative ligatures — the schematic feel relies on\n monospace columns, not typographic flourishes */\n font-feature-settings: \"liga\" 0, \"clig\" 0, \"calt\" 0, \"dlig\" 0;\n }\n\n ::selection {\n background-color: var(--color-accent);\n color: var(--color-accent-fg);\n }\n\n ::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n }\n ::-webkit-scrollbar-track {\n background: transparent;\n }\n ::-webkit-scrollbar-thumb {\n background: var(--color-rule);\n }\n ::-webkit-scrollbar-thumb:hover {\n background: var(--color-ink-ghost);\n }\n}\n\n@keyframes pulse-dot {\n 0% {\n box-shadow: 0 0 0 0 var(--color-accent);\n }\n 100% {\n box-shadow: 0 0 0 8px transparent;\n }\n}\n\n@utility pulse-dot {\n animation: pulse-dot 1.6s ease-out infinite;\n}\n\n@keyframes blink {\n 0%, 49% { opacity: 1; }\n 50%, 100% { opacity: 0; }\n}\n\n@utility blink {\n animation: blink 1s steps(1) infinite;\n}\n\n@keyframes wiggle {\n 0%, 90%, 100% { transform: rotate(0deg); }\n 93% { transform: rotate(-3deg); }\n 96% { transform: rotate(3deg); }\n}\n\n@utility wiggle {\n animation: wiggle 3s ease-in-out infinite;\n}\n\n/* the one sanctioned shadow stack — used only for stacked \"deal\" cards */\n@utility deal-shadow {\n box-shadow: -2px 0 0 var(--color-rule),\n -16px 4px 36px -10px rgba(0, 0, 0, 0.22);\n}\n\n/* ---- schematic diagram utilities (same 1px-grid spirit) ---- */\n\n/* marching dashes along an SVG edge — signal in motion on a wire */\n@keyframes flow-dash {\n to {\n stroke-dashoffset: -16;\n }\n}\n\n@utility flow-dash {\n stroke-dasharray: 6 10;\n animation: flow-dash 0.9s linear infinite;\n}\n\n/* a slower, fainter version for ambient wires */\n@utility flow-dash-slow {\n stroke-dasharray: 2 10;\n animation: flow-dash 2.4s linear infinite;\n}\n\n/* event ripple — an expanding 1px ring, the fan-out cue */\n@keyframes ripple-ring {\n 0% {\n opacity: 0.9;\n r: 4;\n }\n 100% {\n opacity: 0;\n r: 26;\n }\n}\n\n@utility ripple-ring {\n animation: ripple-ring 1.6s ease-out infinite;\n}\n\n/* terminal output: each line fades + rises in, staggered by animation-delay */\n@keyframes fade-rise {\n from {\n opacity: 0;\n transform: translateY(3px);\n }\n to {\n opacity: 1;\n transform: none;\n }\n}\n\n@utility fade-rise {\n animation: fade-rise 0.4s ease-out both;\n}\n\n/* scroll-reveal: sections rise 8px and fade in once observed */\n@utility reveal {\n opacity: 0;\n transform: translateY(8px);\n transition: opacity 0.55s ease-out, transform 0.55s ease-out;\n}\n\n@utility reveal-in {\n opacity: 1;\n transform: translateY(0);\n}\n\n/* gallery cards stagger in on load; fill-mode `both` holds opacity:0 through\n the stagger delay so cards appear in order */\n@keyframes card-rise {\n from {\n opacity: 0;\n transform: translateY(8px);\n }\n to {\n opacity: 1;\n transform: none;\n }\n}\n\n@utility card-rise {\n animation: card-rise 0.5s ease-out both;\n}\n\n@media (prefers-reduced-motion: reduce) {\n html {\n scroll-behavior: auto;\n }\n .flow-dash,\n .flow-dash-slow,\n .ripple-ring,\n .pulse-dot,\n .wiggle,\n .card-rise,\n .fade-rise {\n animation: none;\n }\n .reveal {\n opacity: 1;\n transform: none;\n transition: none;\n }\n}\n","content_type":"text/css; charset=utf-8","language":"css","size":5001,"content_sha256":"aca3adb7dffafe5b99058a4b2157297e27fbbb7cc298add4d31fce26525a7b27"},{"filename":"base/src/lib/deck-types.ts","content":"/**\n * deck-types.ts — the shapes a deck's content layer feeds into the shared\n * chrome (TopNav, Footer). Each deck defines its values in its own\n * `src/content/deck.ts` and passes them as props from its App.tsx; the shared\n * components never reach into deck content.\n */\n\nexport interface NavItem {\n /** must match a section's DOM id so scroll-spy + anchor links work */\n id: string\n label: string\n}\n\nexport interface FooterSpec {\n /** small caps eyebrow above the closing line, e.g. \"get started\" */\n eyebrow: string\n /** the big closing line — the one-command payoff */\n headline: string\n /** the command shown in the bordered chip */\n command: string\n /** left attribution line in the bottom bar */\n attribution: string\n /** right \"source of truth\" line in the bottom bar */\n source: string\n}\n\nexport interface DeckMeta {\n /** wordmark text next to the logo in the top nav */\n wordmarkLabel: string\n}\n","content_type":"application/typescript; charset=utf-8","language":"typescript","size":927,"content_sha256":"b1bf431146af80970f5e353b4ae51e1735ac1962a24ce3711d639830ec4672f5"},{"filename":"base/src/lib/utils.ts","content":"import { type ClassValue, clsx } from 'clsx'\nimport { twMerge } from 'tailwind-merge'\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}\n","content_type":"application/typescript; charset=utf-8","language":"typescript","size":166,"content_sha256":"746e4d9beb1a5b6f0e047ec19d5f1c542c9f8117f4ea7c80d7b9bd0fe2128e91"},{"filename":"base/src/pages/SpecPage.tsx","content":"import { HighlightStyles } from '@lib/content/highlight'\nimport { Markdown } from '@lib/content/markdown'\nimport { useHashRoute } from '@lib/hooks/useHashRoute'\nimport { cn } from '@lib/lib/utils'\nimport { useMemo } from 'react'\n\n/**\n * A15 - the spec viewer. A separate hash-route page (`#/spec/\u003cfile>`) that\n * renders every markdown file of the tech-spec, with a sidebar listing the\n * files and the rendered doc beside it.\n *\n * The markdown arrives via the `docs` prop: each deck ships a tiny\n * `src/spec-docs.ts` whose `import.meta.glob` bundles its own spec's md at\n * build time (the glob must live deck-side — it resolves relative to the\n * importing file). Frontmatter in README.md is stripped by \u003cMarkdown>.\n */\n\ninterface Doc {\n slug: string\n file: string\n label: string\n source: string\n}\n\nfunction firstHeading(src: string): string | null {\n const m = src.match(/^#\\s+(.+?)\\s*$/m)\n return m ? m[1].replace(/`/g, '').trim() : null\n}\n\nfunction toDocs(raw: Record\u003cstring, string>): Doc[] {\n return Object.entries(raw)\n .map(([path, source]) => {\n const file = path.split('/').pop() ?? path\n const base = file.replace(/\\.md$/, '')\n return { slug: base.toLowerCase(), file, label: firstHeading(source) ?? base, source }\n })\n .filter((d) => !/-review-|^_/.test(d.file))\n .sort((a, b) => {\n if (a.slug === 'readme') return -1\n if (b.slug === 'readme') return 1\n return a.file.localeCompare(b.file)\n })\n}\n\nexport function SpecPage({ docs }: { docs: Record\u003cstring, string> }) {\n const route = useHashRoute()\n const items = useMemo(() => toDocs(docs), [docs])\n const wanted = route.kind === 'page' ? route.rest[0] : undefined\n const active = items.find((d) => d.slug === wanted) ?? items[0]\n\n if (!active) {\n return (\n \u003cmain className=\"px-4 py-24 @3xl:px-9\">\n \u003cp className=\"font-mono text-[14px] lowercase text-ink-faint\">no spec markdown found beside this deck.\u003c/p>\n \u003c/main>\n )\n }\n\n return (\n \u003cmain className=\"px-4 @3xl:px-9 py-8 @3xl:py-10\">\n \u003cHighlightStyles />\n \u003cdiv className=\"grid grid-cols-1 @3xl:grid-cols-[210px_minmax(0,1fr)] gap-6 @3xl:gap-10\">\n \u003cnav\n aria-label=\"spec files\"\n className=\"@3xl:sticky @3xl:top-20 @3xl:self-start min-w-0 border-b border-rule pb-3 @3xl:border-b-0 @3xl:pb-0 @3xl:border-r @3xl:border-rule @3xl:pr-6\"\n >\n \u003cdiv className=\"font-mono text-[10px] uppercase tracking-[0.14em] text-ink-ghost mb-3\">spec\u003c/div>\n \u003cul className=\"flex @3xl:flex-col gap-x-1 gap-y-0.5 overflow-x-auto @3xl:overflow-visible\">\n {items.map((d) => {\n const on = d.slug === active.slug\n return (\n \u003cli key={d.slug} className=\"shrink-0 @3xl:shrink\">\n \u003ca\n href={`#/spec/${d.slug}`}\n aria-current={on ? 'page' : undefined}\n className={cn(\n 'block whitespace-nowrap @3xl:whitespace-normal font-mono text-[12px] leading-[1.45] py-1.5 px-3 @3xl:pl-3 @3xl:-ml-px @3xl:border-l-2 transition-colors',\n on ? 'text-ink @3xl:border-accent' : 'text-ink-faint hover:text-ink @3xl:border-transparent',\n )}\n >\n {d.label}\n \u003c/a>\n \u003c/li>\n )\n })}\n \u003c/ul>\n \u003c/nav>\n\n \u003carticle className=\"min-w-0 max-w-[80ch]\">\n \u003cMarkdown source={active.source} />\n \u003c/article>\n \u003c/div>\n \u003c/main>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":3540,"content_sha256":"cf65ef7168954dfc5c866b98decec1d1db59736be58d484287a5e84e47607f10"},{"filename":"base/src/vite-env.d.ts","content":"/// \u003creference types=\"vite/client\" />\n\ndeclare module 'virtual:spec-manifest' {\n export interface SpecEntry {\n slug: string\n title: string\n tagline: string\n /** \"YYYY-MM-DD\" (legacy specs may carry month-only \"YYYY-MM\") */\n date: string\n /** the timeline's month group, e.g. \"2026 · june\" */\n month: string\n /** e.g. \"jun 29\" — null when the date has no day component */\n dayLabel: string | null\n tags: string[]\n status: 'live' | 'draft'\n featured: boolean\n hasDeck: boolean\n }\n export const SPECS: SpecEntry[]\n}\n","content_type":"application/typescript; charset=utf-8","language":"typescript","size":558,"content_sha256":"36980fb726324ccb553b0e0f515b0550a85f40df29d051c99d89c22627edd31e"},{"filename":"base/tsconfig.app.json","content":"{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"useDefineForClassFields\": true,\n \"lib\": [\"ES2022\", \"DOM\", \"DOM.Iterable\"],\n \"module\": \"ESNext\",\n \"skipLibCheck\": true,\n\n \"moduleResolution\": \"bundler\",\n \"allowImportingTsExtensions\": true,\n \"resolveJsonModule\": true,\n \"isolatedModules\": true,\n \"moduleDetection\": \"force\",\n \"noEmit\": true,\n \"jsx\": \"react-jsx\",\n\n \"strict\": true,\n \"noUnusedLocals\": true,\n \"noUnusedParameters\": true,\n \"noFallthroughCasesInSwitch\": true,\n \"noUncheckedSideEffectImports\": true,\n\n \"paths\": {\n \"@lib/*\": [\"./src/*\"]\n }\n },\n \"include\": [\"src\", \"*/src\", \"_viewer/src\"],\n \"exclude\": [\"dist\", \"node_modules\"]\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":698,"content_sha256":"6e148f5c6bc51bca4043d498733d39836fc2f72bdc60715d510241271633ee4f"},{"filename":"base/tsconfig.json","content":"{\n \"files\": [],\n \"references\": [{ \"path\": \"./tsconfig.app.json\" }, { \"path\": \"./tsconfig.node.json\" }]\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":107,"content_sha256":"e8d6f7b50828db3953e21c7e92584f9206b3cd2551b4012507372afbb7fe9ce3"},{"filename":"base/tsconfig.node.json","content":"{\n \"compilerOptions\": {\n \"target\": \"ES2023\",\n \"lib\": [\"ES2023\"],\n \"module\": \"ESNext\",\n \"skipLibCheck\": true,\n\n \"moduleResolution\": \"bundler\",\n \"allowImportingTsExtensions\": true,\n \"allowJs\": true,\n \"isolatedModules\": true,\n \"moduleDetection\": \"force\",\n \"noEmit\": true,\n\n \"types\": [\"node\"],\n\n \"strict\": true,\n \"noUnusedLocals\": true,\n \"noUnusedParameters\": true,\n \"noFallthroughCasesInSwitch\": true,\n \"noUncheckedSideEffectImports\": true\n },\n \"include\": [\"vite.config.ts\", \"build.mjs\", \"scripts\"]\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":549,"content_sha256":"be40d8e1f903fcaa72c0af2d1c8183f11c8bfacdc847045b0e0207dd1daf4a16"},{"filename":"base/vite.config.ts","content":"import { fileURLToPath, URL } from 'node:url'\nimport tailwindcss from '@tailwindcss/vite'\nimport react from '@vitejs/plugin-react'\nimport { defineConfig } from 'vite'\nimport { specManifestPlugin } from './scripts/manifest.mjs'\n\n// One config for every app in this project. `vite` (dev) serves the gallery at\n// `/` and every deck at `/\u003cslug>/` from a single server; `build.mjs` reuses\n// this file programmatically with a per-deck `root`/`outDir`, so each deck\n// ships as a self-contained, relative-path static site that works under any\n// URL prefix (deployed at iii.dev/roadmap/\u003cslug>/).\nexport default defineConfig({\n base: './',\n plugins: [react(), tailwindcss(), specManifestPlugin()],\n resolve: {\n alias: {\n '@lib': fileURLToPath(new URL('./src', import.meta.url)),\n },\n },\n // Deck spec pages bundle `../../../../tech-specs/\u003cslug>/*.md`, which sits\n // outside the per-deck root — allow the dev server to read from the repo root.\n server: { fs: { allow: [fileURLToPath(new URL('../..', import.meta.url))] } },\n})\n","content_type":"application/typescript; charset=utf-8","language":"typescript","size":1041,"content_sha256":"c938e6105c9c1937eff369b8c5e9f332fa646791bdc758eaea1993a1de17fae5"},{"filename":"README.md","content":"# /presentation\n\nTurn a tech-spec directory into an interactive, marketing-grade web\npresentation — the kind at [iii.dev/roadmap/](https://iii.dev/roadmap/).\n\nThe deck is built to: help engineers **understand** the design (the\narchitecture is a navigable map, not prose), be **interactive** (steppable\ndiagrams, a selectable system map, live toggles), read like **marketing**\n(it argues the *why*), and be **build-in-public ready** (each deck builds to a\nportable static `dist/\u003cslug>/`).\n\n## Use it\n\nFrom a Claude Code session in this workspace:\n\n```\n/presentation tech-specs/2026-06-devexp\n```\n\nIt reads the spec, reads the repo's component registry, proposes a\nslide-by-slide narrative outline for your approval, scaffolds the deck's\n**content layer** at `\u003cbase>/\u003cslug>/` (in iii: `website/roadmap/\u003cslug>/`),\ngenerates the content against the shared `@lib` component library, writes the\nspec's registration frontmatter, and verifies with a typecheck, a build, and a\nbrowser pass.\n\n## Hosting — one Vite project per repo, no per-deck deploys\n\nSpecs are markdown-only at `tech-specs/\u003cslug>/`; decks are content layers\ninside the repo's single presentations site (the \"base\"). The base owns the\none `package.json`, the shared component library + design tokens, the gallery,\na markdown viewer for specs without decks, and `build.mjs`. In iii, merging to\nmain deploys everything to `iii.dev/roadmap/` via the website workflow —\nno Vercel, no manual step. See `reference/hosting.md`.\n\n## What's in here\n\n- `SKILL.md` — the operating instructions (the brain).\n- `reference/` — the design system, the interactive archetype library, the\n component standards + registry format, the narrative framework, the quality\n bar, and the hosting/layout rules. The skill loads these first.\n- `template/` — one deck's content-layer starter (~13 files: App, deck.ts,\n spec-docs glob, three worked-example sections, a deep-dive page). No\n package.json, no config — everything visual imports from `@lib`.\n- `base/` — the full per-repo presentations site scaffold: shared `src/`\n (primitives, diagram archetypes, hooks, markdown machinery, gallery,\n viewer), `build.mjs`, `vite.config.ts`, tsconfigs, the `COMPONENTS.md`\n registry seed, and the SOP README seed. Copied once per repo, identity\n tokens filled, then only ever extended by component promotions.\n\n## Extending the design\n\nThe live visual system for iii is `website/roadmap/src/` (tokens in\n`src/index.css`, components under `src/components/`); every promoted component\ngets a `COMPONENTS.md` entry per `reference/component-standards.md`.\n**Maintenance note:** `base/` is a snapshot of that live `src/` — re-seed it\nfrom `website/roadmap/` periodically (copy `src/`, `scripts/manifest.mjs`,\n`vite.config.ts`, tsconfigs, `_viewer/`, `COMPONENTS.md`; take `build.mjs`\nbut restore the standalone `DIST = join(ROOT, 'dist')` — iii's copy emits\ninto `website/dist/roadmap/`; keep base's own `package.json`, since iii folds\nthose deps into the `iii-website` package; re-tokenize the `package.json`\nname, `src/gallery/site.ts`, `index.html`, `README.md`) so fresh repos start\nwith the newest archetypes. The template imports only the\ncore `@lib` surface (Section, TopNav, Footer, Sheet, SpecSheet, PageShell,\nhooks, SpecPage), which every base version guarantees.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":3323,"content_sha256":"cf74a123ec5c681e9761a264b2269d70b43670f7e86b81ee8e22eb6302642cf0"},{"filename":"reference/archetypes.md","content":"# Archetype library\n\nThe deck is assembled from a fixed catalog of proven slide archetypes. For\nevery slide: **match the spec content to an archetype, then supply data.** Do\nnot invent a new diagram when one fits. Hand-build a bespoke SVG only when no\narchetype matches and the concept is load-bearing — and then follow\n`SequencePlayer.tsx`'s conventions.\n\nTwo kinds:\n- **Diagram archetypes** — shared, props-driven components in\n `@lib/components/diagrams/` (the base project's library). You import them\n and pass data from the deck's `content/`.\n- **Compositional archetypes** — patterns you build inline in a section from\n primitives (`Cell`, `SpecSheet`, `CodeBlock`, `ModeToggle`, `Button`, …).\n The starter `Hero.tsx` and `PayoffSection.tsx` are worked examples.\n\n**The repo registry wins.** This catalog documents the bundled baseline; the\nlive inventory is `\u003cbase>/COMPONENTS.md`, which grows as decks promote new\narchetypes (per `reference/component-standards.md`). Read it in Phase 1b —\nwhen it and this file disagree, the registry is the truth.\n\n## Selection heuristics\n\n| The spec has… | Use |\n|---|---|\n| a thesis / one-line promise | A1 Hero |\n| a \"today's pain\" enumeration | A2 Problem + A11 |\n| a command / install / golden path | A3 CLI Playground |\n| a component/responsibility map, planes, \"owns / never does\" | A4 System Map |\n| a temporal protocol, a \"turn\", a handshake, numbered steps | A5 Sequence |\n| a lifecycle whose state evolves (boot, durability, readiness) | A6 Step Reveal |\n| one event → many handlers; reactive/triggers | A7 Fan-Out |\n| many cases collapse to one mechanism (or one forks) | A8 Funnel |\n| a mode/policy that changes what's allowed | A9 Toggle Explorer |\n| a human-in-the-loop / approval / branching outcome | A10 Decision Flow |\n| before/after, removed, renamed, metrics | A11 Scorecard + Solves |\n| any field-level schema (the depth layer of any slide) | A12 Spec Datasheet |\n| a config file, pseudocode, an API skeleton | A13 Code Walkthrough |\n| a distinct consumer/scenario worth a full page | A14 Deep-dive Page |\n\nEvery interactive archetype is keyboard-operable, disables controls at bounds,\nrespects `prefers-reduced-motion`, and degrades to a readable static state.\n\n---\n\n## Diagram archetypes (bundled)\n\n### A4 — System Map · `diagrams/SystemMap.tsx`\n\nThe signature visual: the whole architecture in one interactive diagram. Click\na node → its edges highlight and its datasheet updates. Author node `x/y/w/h`\nand edge `d` paths in the same coordinate space (default `1030×600`).\n\n```ts\ntype MapNodeKind = 'primary' | 'secondary' | 'optional' | 'external'\ninterface MapNode { id; x; y; w; h; title; sub?; kind; tag? }\ninterface MapEdge { id; from; to; d; label?; lx?; ly?; anchor?; dashed?; dur? }\ninterface MapNodeInfo { id; kindLabel; role; sections?; note?; bullets?; install? }\ninterface InfoSection { heading; items: { name; desc? }[]; dotted? }\n```\n\nUse in a section with the paired-layout pattern from\n`sections/SystemMapSection.tsx` (ResizeObserver sticks the datasheet beside the\nmap ≥1024px, stacks below it narrower). `MapDatasheet` takes a resolved\n`info` object — look it up from a `Record\u003cstring, MapNodeInfo>` by `selected`.\nMaps from: the spec's architecture/component-responsibility section. One node\nper component; `sections` from each component's surface/emits; `dotted: true`\nfor event lists.\n\n### A5 — Sequence · `diagrams/SequencePlayer.tsx`\n\nA step-through sequence diagram: lifelines per lane, one arrow per step, the\nactive step in accent with a travelling pulse and a narration line.\n\n```ts\ninterface SeqLane { id; label; x }\ninterface SeqStep { from; to; label; title; desc; event? } // from===to => self-loop\n\u003cSequencePlayer title lanes={SEQ_LANES} steps={SEQ_STEPS} />\n```\n\nMaps from: any protocol / turn loop / handshake. One lane per participant; one\nstep per message. Set `event` when a step emits a trigger.\n\n### A6 — Step Reveal · `diagrams/StepReveal.tsx`\n\nA lifecycle/timeline walker: a strip of ordered stages; the stepper walks them;\na panel shows the active stage's evolving record.\n\n```ts\ninterface RevealStage { label; tone?: 'ink'|'accent'|'alert'|'warn'; caption?; rows?: {k;v}[]; note? }\n\u003cStepReveal title stages={STAGES} />\n```\n\nMaps from: boot sequences, durability/crash-resume timelines, readiness\nbring-up. Use `tone: 'alert'` for a crash/failure stage, `'accent'` for the\nresolved one. `rows` is the state object that changes per stage.\n\n### A3 — CLI Playground · `diagrams/CliPlayground.tsx`\n\nAn interactive terminal: lines reveal one at a time (staggered `fade-rise`);\nswitch tracks (golden path vs day-2) with a toggle.\n\n```ts\ninterface CliLine { cmd?; out?: string[]; fn?; exit? } // out tinted by ✓/✗/! glyph\ninterface CliTrack { id; label; lines: CliLine[] }\n\u003cCliPlayground tracks={TRACKS} title=\"run it\" />\n```\n\nMaps from: install/quickstart, the golden command path, day-2 ops. Put verbatim\ncommands + output in. `fn` shows the backing function id; prefix output lines\nwith `✓`/`✗`/`!` to tint them.\n\n### A7 — Fan-Out · `diagrams/FanOut.tsx`\n\nOne write/emit fans out to many bound handlers — ambient ripple + marching\nedges. No stepper; it just breathes.\n\n```ts\ninterface FanHandler { id; label; desc? }\n\u003cFanOut source={{ label, sub? }} trigger=\"store::written\" handlers={HANDLERS} />\n```\n\nMaps from: a reactive/event model. The `trigger` keeps its casing; handlers are\nthe functions bound to it.\n\n### A8 — Funnel · `diagrams/Funnel.tsx`\n\nMany paths converge into one guaranteed mechanism, with an optional dashed\nrejected path.\n\n```ts\ninterface FunnelPath { id; label; desc? }\n\u003cFunnel paths={PATHS} target={{ label, sub? }} reject={{ label, desc? }} />\n```\n\nMaps from: \"many spawn paths → one owned spawn\", \"many inputs → one reaper\".\nUse `reject` to show the eliminated/forbidden path (rendered alert + dashed).\n\n---\n\n## Compositional archetypes (build inline from primitives)\n\n### A1 — Hero (`sections/Hero.tsx` is the template)\n\nStates the **win** in one line + a three-value subhead — never the mechanism.\nA stat strip quantifies it; a small `\u003cTerminal>` makes it concrete; two CTAs\njump to the map and the payoff.\n\n### A2 — Problem / Tangle\n\nA grid of `\u003cCell>` cards naming today's failures, optionally `alert`-tinted, or\na `\u003cStatusPanel variant=\"alert\">` per failure. Make the reader feel the tangle\nbefore the solution. Pull from the spec's pain points / motivation.\n\n### A9 — Toggle Explorer\n\n`useState` for the mode + `\u003cModeToggle>` + a grid of `\u003cFnChip>`. On change,\nre-filter the chips (opacity/strikethrough for blocked) and update a counter.\nFor policy/allow-list/capability slides.\n\n### A10 — Decision Flow\n\n`useState\u003c'pending'|'approved'|'denied'>` + `\u003cButton>` approve/deny. Borders,\n`\u003cStatusDot>`, and the output block change per state; a replay resets. For\nhuman-in-the-loop / governance.\n\n### A11 — Before/After Scorecard + Solves table (`sections/PayoffSection.tsx`)\n\nA `gap-px bg-rule` metric grid (`before → after`, accent on the after) plus a\ntwo-column problem (alert) / answer (accent) table. The closing argument.\n\n### A12 — Spec Datasheet (`components/SpecSheet.tsx`)\n\n`\u003cSpecSheet>` + `\u003cSpecRow>` — a `\u003cdetails>` closed by default. This is the\n**depth layer of every slide**: keep the narrative skimmable, put field-level\ndetail one click away.\n\n### A13 — Code Walkthrough (`components/schematic/CodeBlock.tsx`)\n\n`\u003cCodeBlock>` with `\u003cK>` keyword / `\u003cS>` string / `\u003cC>` comment / `\u003cM>` muted.\nThe accent stays rationed to string literals. For config files, pseudocode,\nAPI skeletons.\n\n### A14 — Deep-dive Page (`components/PageShell.tsx`)\n\nA full `#/\u003cslug>` page via `\u003cPageShell>` (cross-links siblings with `related`).\nRegister it in `App.tsx`'s `PAGES` map. Give one to each distinct\nconsumer/scenario worth the full walkthrough.\n\n### A15 — Spec Viewer (`@lib/pages/SpecPage.tsx`, built-in)\n\nThe source-of-truth reading mode: a separate `#/spec/\u003cfile>` page that renders\nevery markdown file of the paired `tech-specs/\u003cslug>/` directory with a file\n**sidebar**. The shared `SpecPage` takes `{ docs }`; the deck's tiny\n`src/spec-docs.ts` supplies them (an `import.meta.glob` whose literal the\nskill substitutes at scaffold — see `reference/hosting.md`). The template\nwires it (`spec: Spec` in `PAGES`; the shared `TopNav` renders the `spec`\nlink). You do not generate or edit it beyond that wiring.\n\n- Markdown → React via `@lib/content/markdown.tsx`, styled in the\n drafting-sheet system; the leading frontmatter block is stripped; fenced\n code reuses `Highlight` where the language is supported\n (`ts/js/rust/python/yaml`), monochrome otherwise.\n- ` ```mermaid ` fences render as **live, theme-aware diagrams** via\n `@lib/content/mermaid.tsx` (lazy-loaded; mono font, ink borders, light/dark).\n- Sidebar labels come from each file's first H1; README sorts first. Sibling\n `*.md` links rewrite into the viewer; in-page `#anchors` scroll.\n\nIt complements the narrative deck: the deck argues the *why* and makes the\narchitecture interactive; the spec viewer is the *complete text* one click\naway. (Specs with no deck get the same reading mode from the base's\n`_viewer/` app — every spec URL works either way.)\n\n### A16 — Durability Timeline (`diagrams/DurabilityTimeline.tsx`)\n\nA lifecycle told as a steppable timeline of stages, each pairing a narration\nwith an **evolving state record** beside it (status / step / calls / note).\nBuilt for \"a durable thing survives crashes and waits\" stories.\n`{ stages, heading, headingNote?, recordHeading }` — a stage can mark\n`gapAfter` to render a dashed pause connector.\n**vs A6 Step Reveal:** reach for A16 when the record-beside-narration density\nis the point; A6 when state simply accumulates.\n\n### A17 — Event Fan-Out (`diagrams/EventFanOut.tsx`)\n\nOne **concrete, named write** → trigger type → N named subscribers, with\nambient always-on motion (ripples + traveling dots). Denser and more literal\nthan A7. `{ heading, source, sourceSub?, trigger, handlers, edges, footnote?,\nariaLabel }`.\n**vs A7 Fan-Out:** A17 narrates one specific write with real handler names;\nA7 is the abstract reactive-surface shape.\n\n### A18 — Spawn Tree (`diagrams/SpawnTree.tsx`)\n\nA parent spawns N parallel children and joins their results: fan out, run\nconcurrently, join back, one answer — with steppable narrative states driving\nwhich children exist/run/deliver, and a parked-parent visual state.\n`{ heading, chips?, parentTitle, parentLabels, parentCallLine, nodes, states,\nariaLabel }`. Use for sub-agent / fan-out-join concurrency claims.\n\n### Primitive: WorkerCard (`schematic/WorkerCard.tsx`)\n\nOne worker as a product card — name, version, description, install command,\nkind badge. Use when cataloguing installable workers/components in a grid.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":10855,"content_sha256":"36c2ee6805c4521f250dc525995870c0b9a2e9554fd916346e280fe031218844"},{"filename":"reference/component-standards.md","content":"# component standards — deck-local vs promoted, and the registry\n\nThe shared library (`\u003cbase>/src/`) is the single copy of every reusable\nvisual. Decks never duplicate it and never reach into each other. This file\ndefines when a new component may join it, what it must satisfy, and how the\nregistry stays truthful.\n\n## The decision rule\n\n**Default: deck-local.** A new visual lives at\n`\u003cbase>/\u003cslug>/src/diagrams/\u003cName>.tsx`, imported relatively. It can bake in\nits spec's copy and topology — it ships with one deck only.\n\n**Promote to `\u003cbase>/src/components/{diagrams,schematic}/` only when ALL\nthree hold:**\n\n1. **Generic over its data** — nothing spec-specific inside; every label,\n node, stage, and copy string arrives via typed props (the deck keeps the\n data in its `content/`).\n2. **Recurring shape** — it maps to a spec shape future decks will plausibly\n need (a lifecycle, a tree, a timeline, a fan-out, a funnel…), not this\n spec's particular topology.\n3. **Passes the checklist below** without deck-specific hacks.\n\nA second deck needing a deck-local diagram is the natural promotion trigger:\npromote it then (props-decouple first), never copy it.\n\n**Never fork.** Don't copy a shared component into a deck to tweak it —\nextend it with additive, non-breaking props, or build a genuinely different\ndeck-local one. **Changing an existing shared component's behavior or API\nrequires explicit user approval and a full `node build.mjs`** — it re-renders\nevery deck on the site.\n\n## The promotion checklist\n\n1. Props-driven; zero content/data inside the component.\n2. Design tokens only (`bg-bg`, `text-ink-faint`, `stroke-rule`, …) — never\n hardcoded hex; light/dark comes free.\n3. Any auto/infinite animation gated behind a runtime\n `prefers-reduced-motion` check; the static fallback reads complete.\n4. Keyboard operable; controls disable at bounds; visible active state.\n5. `aria-label` on the interactive figure; sensible roles.\n6. Container queries (`@3xl:` …), never viewport breakpoints.\n7. Wide content wrapped in `overflow-x-auto` with an inner `min-w-[…]`; the\n page body never scrolls horizontally.\n8. No shadows, no gradients (`deal-shadow` is the sole exception); radii 0.\n9. Exported prop types + a one-line JSDoc header stating purpose (the source\n of the registry entry's `purpose` line).\n10. Its `COMPONENTS.md` entry lands **in the same change**.\n\n## The registry (`\u003cbase>/COMPONENTS.md`)\n\nOne entry per file; the `### \u003cheading>` equals the file's basename — that 1:1\nrule is what makes the parity check trivial (`node build.mjs` warns on files\nwithout entries and entries without files; `--strict-registry` fails).\n\nSix sections in fixed order — **layout · primitive · archetype · hook · util ·\ngallery** — alphabetical within each. Append at the right position; never\nreword other entries in a deck PR; delete an entry only when deleting its file.\n\nEntry template:\n\n```markdown\n### SequencePlayer\n- kind: archetype\n- import: `import { SequencePlayer } from '@lib/components/diagrams/SequencePlayer'`\n- purpose: step-through sequence diagram — lifelines per lane, one arrow per step, narrated\n- props: `{ title: string; lanes: SeqLane[]; steps: SeqStep[] }`\n- use when: the spec has a temporal protocol, a turn loop, a handshake, numbered steps\n- not when: state evolves in place with no message passing (use StepReveal)\n- used by: 2026-06-08-agentic, 2026-06-29-codegen\n```\n\n`props` is a compact sketch (the file is the type truth); `use when` speaks\nthe archetype-selection voice; `not when` disambiguates near-siblings\n(DurabilityTimeline vs StepReveal, EventFanOut vs FanOut); `used by` is\ninformative, maintained by the skill when it wires a deck.\n\n## Worked precedents\n\n- **WorkerCard** — already props-driven when promoted from the agentic deck:\n the model promotion (zero refactor).\n- **DurabilityTimeline / EventFanOut / SpawnTree** — promoted from the agentic\n deck by moving their baked STAGES/HANDLERS/STATES arrays into the deck's\n `content/{durability,fanout,spawn}.ts` and threading them as props.\n- **agentic's SystemMap fork** — NOT promoted: 483 lines diverged from the\n shared SystemMap with deck content baked in. It stays at\n `2026-06-08-agentic/src/diagrams/SystemMap.tsx`, the canonical props-driven\n `@lib` SystemMap serves everyone else.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":4351,"content_sha256":"4bca5f521cfa5fc9cabb45d2abcde1502f6fa587f6e85dc5a56bb47796b8d475"},{"filename":"reference/design-system.md","content":"# Design system — the law\n\nThis is the locked visual system. It lives in the base project's\n`src/index.css` (in iii: `website/roadmap/src/index.css`; seeded from\nthis skill's `base/`) as Tailwind v4 `@theme` tokens. **Do not change the\ntokens in a deck run.** This file is the reference for *using* them correctly\nin generated content.\n\nThe feel: a monospace drafting sheet. Emphasis comes from 1px borders and a\nsingle rationed accent — never from gradients, shadows, or saturation. It\nshould read like a system you trust.\n\n## Color tokens\n\nUsed as Tailwind utilities: `bg-bg`, `text-ink`, `border-rule`, `fill-accent`,\n`stroke-ink-faint`, etc. Dark mode swaps automatically via\n`[data-theme=\"dark\"]`; never hardcode hex in components.\n\n| Token | Light | Dark | Use for |\n|---|---|---|---|\n| `bg` | `#f2f0ed` | `#111110` | page / card background |\n| `panel` | `#e9e6e2` | `#1a1916` | header strips, toggles |\n| `paper-2` | `#ebe8e3` | `#1f1e1c` | a second, subtler surface |\n| `ink` | `#0a0a0a` | `#f2f0ed` | primary text, strong borders |\n| `ink-faint` | `#6b6865` | `#9c9893` | body copy, secondary text |\n| `ink-ghost` | `#a3a09c` | `#5d5a55` | tertiary text, section numbers |\n| `rule` | `#d8d5d0` | `#2a2926` | structural 1px lines |\n| `rule-2` | `#e6e3df` | `#1f1e1c` | softer inner dividers |\n| `accent` | `#ff5a1f` | `#3ea8ff` | success / active / CTA only |\n| `accent-fg` | `#f2f0ed` | `#111110` | text on an accent fill |\n| `alert` | `#c43e1c` | `#c43e1c` | errors, removed/rejected paths |\n| `warn` | `#a87a00` | `#a87a00` | warnings, held states |\n\n**Accent discipline.** The accent is the most powerful tool here precisely\nbecause it is rare: ✓ success, the active nav link / map edge / step, a primary\nCTA, a string literal in code. If it is on more than ~5% of the screen, it has\nlost its meaning. Active states use an accent *border + text*, not a fill — the\nonly fill is the primary button.\n\n## Radii\n\nOnly two exist: `rounded-none` (0) and `rounded-full` (pills/dots). Nothing in\nbetween. No `rounded-lg`, no `rounded-2xl`.\n\n## Typography\n\n- **Font:** Chivo Mono (400/500/600), loaded in `index.html`. Set as both\n `--font-sans` and `--font-mono`. Everything is monospace.\n- **Ligatures are hard-disabled** (`font-feature-settings: 'liga' 0 …`). The\n schematic look depends on monospace column alignment — do not re-enable them.\n- **Scale:** hero h1 44/64px semibold, tracking `-0.02em`; section h2 28px\n medium; label-caps 11–12px uppercase, tracking `0.06–0.18em`; body/code\n 12–14px, leading 1.6–1.7.\n- **Case:** all copy is **lowercase** by default. The *only* exceptions are\n identifiers, function ids, type names, and code — they keep their original\n casing (use `\u003cFnChip>` / `\u003cCodeBlock>`). No Title Case headlines.\n\n## Layout\n\n- The whole deck sits in one centered `\u003cSheet>`: `max-w-[1200px]` with\n `border-x border-rule`.\n- Responsive via **container queries** (`@2xl @3xl @4xl @5xl`), because the\n sheet — not the viewport — is the layout context. Use `@3xl:` etc., not `md:`.\n- Gutters `px-4` → `@3xl:px-9`. Section verticals `py-12` → `@3xl:py-16`.\n- **Visual grids are built with `gap-px bg-rule`**: lay cells in a grid with a\n 1px gap over a `rule`-colored background so the rule shows through as\n hairlines. Do not draw a border on every cell.\n- Wide content (SVG diagrams, tables, code) must scroll inside its own\n `overflow-x-auto` container with a `min-w-[...]`. The page body must never\n scroll horizontally.\n\n## Motion\n\nAll keyframes live in `index.css` and are **disabled under\n`prefers-reduced-motion`** centrally. Any *infinite/auto* animation a component\nstarts must also gate behind a runtime check:\n\n```ts\nconst reducedMotion = useMemo(\n () => typeof window !== 'undefined' &&\n window.matchMedia('(prefers-reduced-motion: reduce)').matches,\n [],\n)\n```\n\n| Utility | What | Where |\n|---|---|---|\n| `reveal` / `reveal-in` | fade + 8px rise on scroll-in | every `\u003cSection>` |\n| `pulse-dot` | expanding ring on a dot | active status indicators |\n| `flow-dash` / `flow-dash-slow` | marching dashes on an edge | active wires |\n| `ripple-ring` | expanding 1px ring | event fan-out source |\n| `fade-rise` | line fades + rises | staggered terminal output |\n| `blink` | cursor | terminal caret |\n| SVG `\u003canimateMotion>` | a 2.6px circle travels a path | the active edge/arrow |\n\nStagger terminal lines with inline `animationDelay: i * 70ms` (cap ~700ms).\nMotion should feel calm and purposeful — one thing moves to draw the eye, never\na carousel.\n\n## The one shadow\n\n`deal-shadow` exists for stacked \"card deck\" effects only. No other shadows.\nNo glows. No gradients except the tiny scroll-fade masks already in\n`SystemMap`'s datasheet.\n\n## Anti-slop guardrails\n\nThe drafting-sheet system exists to prevent generic AI-site slop. Treat any\nurge toward these as a bug: hero gradients; emoji as iconography; everything\ncentered; three identical rounded-2xl drop-shadow feature cards; purple→blue\ngradients; \"Empower / Seamless / Unlock\" copy; an accent on every element.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5053,"content_sha256":"81a19b03e7d3233b376df4ff5463650a3b370db336ddc497782861cdfa029b51"},{"filename":"reference/hosting.md","content":"# hosting — the two-tree layout, one site\n\nEvery repo hosts its spec presentations as **one Vite project** (the \"base\") —\nno per-deck projects, no per-deck installs, no separate deploys. This file is\nthe law for that layer — do not re-derive it.\n\n## The two trees\n\n```\n\u003crepo>/tech-specs/\u003cslug>/*.md the spec — MARKDOWN ONLY\n (frontmatter in README.md = registration)\n\u003cbase>/\u003cslug>/ the deck's content layer (optional)\n\u003cbase>/src/ the shared component library + tokens\n```\n\nIn iii, `\u003cbase>` = `website/roadmap/`. The pointer file\n`tech-specs/README.md` names the base dir — that is how Phase 0 finds it in\nany repo.\n\n**The pairing contract.** `slug` = the spec directory's basename, used\nidentically in three places: `tech-specs/\u003cslug>/` (the md), `\u003cbase>/\u003cslug>/`\n(the deck), and the URL `/roadmap/\u003cslug>/`. The build fails on an orphan\ndeck dir (no matching spec) and never needs a manifest — the folder is the\nidentity, so the old \"manifest slug ≠ dirname → 404\" bug class cannot exist.\n\n## Registration = frontmatter (no central manifest)\n\nThe top of `tech-specs/\u003cslug>/README.md`:\n\n```yaml\n---\ntitle: the developer experience overhaul # fallback: the first H1\ntagline: one file, one command, zero zombies. # fallback: first paragraph\ndate: 2026-06-21 # YYYY-MM-DD; fallback: dirname\n # prefix. day precision drives\n # the roadmap order + labels\ntags: [dx, cli] # ≤ 4\nstatus: live # or draft — muted card, kept\n # out of index.json + sitemap\nfeatured: false # pin in the landing feed\n # (index.json); the roadmap\n # itself stays chronological\n---\n```\n\n- `slug` is NEVER a field — the build hard-errors if present.\n- Deck presence is derived (`\u003cbase>/\u003cslug>/index.html` exists), never declared.\n- A spec with no frontmatter still lists (the fallbacks apply); the build\n warns per derived field.\n- A new spec touches only its own folder → two spec PRs can never conflict.\n\n## What the build produces\n\n`node build.mjs` (at `\u003cbase>`; `--only=\u003cslug>` for a fast partial):\n\n```\ndist/index.html the roadmap (a one-column timeline, newest spec\n first, month-grouped; built from\n virtual:spec-manifest)\ndist/index.json machine-readable spec list (feeds the iii.dev\n landing timeline; drafts excluded)\ndist/\u003cslug>/index.html the deck — or the generic md viewer (_viewer/,\n built once + copied) when the spec has no deck\ndist/\u003cslug>/\u003cfile>.md the raw spec markdown, directly linkable\ndist/\u003cslug>/spec.json (viewer pages only) the file list the viewer fetches\n```\n\nEvery deck builds with `base: './'` and its own hashed assets, so\n`dist/\u003cslug>/` stays individually portable — any CDN, any prefix, or straight\nfrom disk.\n\n## The spec-docs glob (the one fragile coupling)\n\nEach deck's `src/spec-docs.ts` bundles its spec markdown at build time:\n\n```ts\nexport const SPEC_DOCS = import.meta.glob('../../../../tech-specs/\u003cslug>/*.md', {\n query: '?raw', import: 'default', eager: true,\n}) as Record\u003cstring, string>\n```\n\n`import.meta.glob` resolves relative to the importing file, so the literal\nencodes the depth from `\u003cbase>/\u003cslug>/src/` to the spec tree. The skill\nsubstitutes it at scaffold time (`__SPEC_MD_GLOB__`); if the base ever moves,\nevery deck's glob moves with it — `pnpm type-check`/`build` catch it.\n\n## Dev, verify, ship\n\n```\npnpm dev ONE server: gallery at /, every deck at /\u003cslug>/\npnpm type-check strict, shared lib + gallery + viewer + all decks\nnode build.mjs --only=\u003cslug> gallery + one spec (fast)\nnode build.mjs --strict-registry registry parity as a hard failure (CI)\npnpm build && pnpm preview the full site at :4173\n```\n\n**iii runs an integrated shape:** the decks build as Astro routes of the\n`iii-website` package — pages at `website/src/pages/roadmap/` mount each\ndeck's `src/App.tsx` as a React island (the base's `src/DeckHost.tsx`,\ncode-split per deck), contract checks live in\n`website/scripts/validate-roadmap.ts`, and the output lands at\n`website/dist/roadmap/` in the same shape as the standalone build (hashed\nassets under the site-level `/_astro/`). The base dir keeps no per-deck\n`index.html`, no `build.mjs`, and no package.json of its own.\n\n**Deploy (iii):** merging to main runs `.github/workflows/deploy-website.yml`,\nwhich builds the whole site (`pnpm --filter iii-website build`) and syncs\n`website/dist/` to S3 (immutable hashed assets; must-revalidate\nhtml/xml/json/md/txt), then invalidates CloudFront. The CloudFront\nviewer-request function rewrites `/roadmap/…/` directory URLs to\n`…/index.html` and 301s extensionless forms to the trailing-slash canonical —\nsame mechanism as `/blog/`. No Vercel, no manual deploy, no per-deck pipeline.\n\n**Deploy (other repos):** `dist/` is fully static with relative asset paths —\npublish it under any prefix with whatever CI the repo uses. The skill never\ncreates deploy config.\n\n## Porting a legacy layout\n\nA repo on the old model (standalone Vite project per deck +\n`tech-specs/build.mjs` + `_gallery/`) ports one deck at a time:\n\n1. Move the spec md to `tech-specs/\u003cslug>/` (md only) and add the frontmatter\n block (values from the old `_gallery/src/content/presentations.ts` entry).\n2. Move the deck's content layer (`index.html` → entry `./src/main.tsx`,\n `src/{App,sections,pages,content}`) to `\u003cbase>/\u003cslug>/`.\n3. Delete its duplicated machinery: package.json, lockfile, vite/tsconfigs,\n `src/{components,hooks,lib}`, `index.css`, markdown utils, SpecPage.\n4. Rewrite imports (shared → `@lib/…`; deck-local → relative), thread\n `meta`/`nav`/`footer` props from `content/deck.ts`, add `src/spec-docs.ts`\n + `PAGES.spec`.\n5. Truly spec-specific diagrams stay deck-local under `\u003cslug>/src/diagrams/`;\n generic ones promote per `reference/component-standards.md`.\n6. `pnpm type-check && node build.mjs --only=\u003cslug>` + `/browse`; delete the\n old per-deck project and, when the last deck is ported, the old\n `_gallery/` + root glue.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6542,"content_sha256":"2755ee436aa9ba1a8a1966db13744a64a5b6d12f626bbeb61fa8ed428b6555c6"},{"filename":"reference/narrative-framework.md","content":"# Narrative framework\n\nA tech spec is organized for completeness. A presentation is organized for\n**persuasion**. Do not mirror the spec's table of contents — re-sequence its\nmaterial into a story that makes a reader *want* the work to happen. This is\nwhat satisfies requirements 1 (understanding) and 3 (marketing) at once.\n\n## The arc (the default 8–12 slide spine)\n\n1. **Hero — the promise.** Compress the thesis into one line + a three-value\n subhead (simplicity / structure / correctness). Stat strip. Two CTAs. State\n the *win*, never the mechanism. This is the hook. (A1)\n2. **Why — the pain.** Name today's failures as concrete, cited cards. Make the\n reader feel the tangle before you offer the fix. (A2)\n3. **Show it — the demo.** An interactive proof, early: a CLI playground or a\n sequence. \"Run it, step through it\" beats \"read about it\" and converts\n skimmers fast. (A3 / A5)\n4. **The map — what exists.** The whole architecture in one navigable diagram.\n Orient the reader before any detail. (A4)\n5..N. **The mechanisms — how it works.** One slide per design pillar, each in\n the archetype that fits: sequence for protocols, step-reveal for lifecycles,\n fan-out for reactivity, funnel for \"many → one\", toggle for policy, decision\n flow for governance. One claim per slide; depth behind a `\u003cSpecSheet>`.\nN+1. **The transition — adoption.** Before/after, removed/renamed, a phased\n roadmap. Lower the perceived risk of doing the work. (A11)\nLast. **The payoff — why it holds.** A quantified scorecard + a problem→answer\n table. Close the persuasion loop. (A11)\n\nDeep-dive pages (A14) hang off the arc for distinct consumers/scenarios that\ndeserve a full walkthrough.\n\n## Techniques (apply throughout)\n\n- **Three-value hero framing.** Simplicity + structure + correctness in one\n breath. \"one file. one command. zero zombies.\"\n- **Problem → solution pairing.** Never assert a benefit without first naming\n the failure it cures.\n- **Before/after wherever available.** Two columns, today vs target. Contrast\n is the most legible form of argument.\n- **Ration the accent.** It lands on success / active / CTA only. Overuse kills\n persuasion; scarcity gives each accent moment weight.\n- **Progressive disclosure.** Big claim (headline) → supporting cards → deep\n spec (`\u003cSpecSheet>`, closed). One page serves both the exec who skims and the\n engineer who drills.\n- **Quantify the win.** Pull the spec's numbers verbatim (files, commands,\n workers, % reductions). If you compute one, say so. Numbers convince.\n- **Stay honest.** Ground every claim in the spec. Keep one trade-offs /\n open-questions beat — admitted limits read as credibility, which persuades\n more than a flawless pitch.\n- **Let the reader set the tempo.** Scroll-driven reveals, not an autoplay\n carousel. They advance; the deck responds.\n\n## The planning step (Phase 2)\n\nBefore writing any code, produce the outline and **show it to the user**:\n\n```\nslide | archetype | the one claim | source | data to pull\n-------+-----------+---------------------------------------+---------------+----------------------------\nhero | A1 | one file, one command, zero zombies | README §1 | thesis, 4 stats, 2 CTAs\nwhy | A2 | today: 6 ways processes leak | daemon §2 | 6 failure cards + citations\nrun-it | A3 | bring the whole stack up in one step | onboarding §1 | golden-path commands\nmap | A4 | four planes, three meeting points | README §3 | nodes, edges, per-node info\n... | ... | ... | ... | ...\npayoff | A11 | smaller surface, stronger guarantees | README §7 | 5 metrics, problem/answer rows\n```\n\nThis table is where a dry spec becomes a story, and it is far cheaper to revise\nhere than after scaffolding. Get sign-off, then build.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":3926,"content_sha256":"cc9b7bdbebcdca64d4daeb3fb95430dfbdf30a920ef64ffba640e720aa38fb1c"},{"filename":"reference/quality-bar.md","content":"# Quality bar\n\nRun this before declaring a deck done. It maps directly to the four\nrequirements. Anything red gets fixed, not noted.\n\n## Build integrity\n\n- [ ] `pnpm type-check` passes at the base (strict, zero errors — shared lib +\n every deck in one program).\n- [ ] `node build.mjs --only=\u003cslug>` succeeds with **zero frontmatter or\n registry warnings**; `dist/\u003cslug>/` uses relative paths (`base: './'`).\n- [ ] Dev server boots; **zero console errors/warnings** in `/browse`.\n- [ ] The write surface held: nothing outside `\u003cbase>/\u003cslug>/**` and the\n spec README's frontmatter block was modified — except a registered\n component promotion (new file under `\u003cbase>/src/components/` + its\n `COMPONENTS.md` entry in the same change).\n- [ ] If anything under `\u003cbase>/src/` changed, the **full** `node build.mjs`\n passes (a shared change must not break sibling decks).\n- [ ] The frontmatter block validates (title/tagline/date/status; no `slug`\n key; date is `YYYY-MM-DD`) and the spec lands on the roadmap timeline\n in date order, its card rendered from the frontmatter.\n- [ ] `#/spec` renders every spec md file with the frontmatter stripped.\n- [ ] `src/content/example.ts` and the starter example sections/pages were\n deleted or replaced — no placeholder content ships.\n\n## Req 1 — engineers understand the spec\n\n- [ ] Every major design pillar in the spec has a slide; nothing load-bearing\n is dropped.\n- [ ] Each slide makes exactly one claim, and its visual proves it.\n- [ ] The architecture is one navigable map (A4), not prose.\n- [ ] Field-level detail exists for skeptics, behind a `\u003cSpecSheet>`, closed.\n- [ ] Every claim is grounded in the spec; one honest trade-offs beat is kept.\n\n## Req 2 — interactive\n\n- [ ] At least three genuinely interactive archetypes are present (e.g. a\n stepper, the selectable map, a toggle or decision flow).\n- [ ] Every control is keyboard-operable, disables at its bounds, and shows a\n visible active state.\n- [ ] All motion respects `prefers-reduced-motion`; the static fallback is\n fully readable.\n- [ ] Scroll-spy nav + scroll-reveal work; deep-dive hash routes load and the\n back link returns home.\n\n## Req 3 — looks like marketing\n\n- [ ] The hero states the *win* in one line + three values — not the mechanism.\n- [ ] A problem→solution arc is present, with at least one before/after and one\n quantified scorecard.\n- [ ] The accent is rationed (success / active / CTA only); no gradient or\n shadow drift (only `deal-shadow`).\n- [ ] Light and dark are both correct; the accent swaps orange↔blue; there is\n no theme flash on load.\n- [ ] Typography law holds: Chivo Mono, ligatures off, lowercase copy,\n identifiers keep their casing, caps tracking on labels.\n- [ ] Voice: no em-dashes; no \"robust / comprehensive / crucial / seamless /\n unlock / delve\".\n\n## Req 4 — build-in-public ready\n\n- [ ] Responsive: no horizontal body scroll at 375px; wide diagrams scroll\n inside their own `overflow-x-auto` container.\n- [ ] `dist/\u003cslug>/` is individually portable (relative asset paths — any CDN,\n any prefix); the raw spec `.md` files sit beside its `index.html`.\n- [ ] Title + meta description set (`index.html` tokens substituted); the tab\n wordmark is coherent.\n- [ ] No secrets, no internal-only URLs, no broken links. Safe to share.\n\n## Anti-slop check\n\nNone of these slipped in: a gradient hero; emoji as iconography; everything\ncentered; three identical rounded-2xl drop-shadow feature cards; purple→blue\ngradients; \"Empower / Seamless / Unlock\" copy; the accent on every element.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":3658,"content_sha256":"7a83cdd5b5f491eade5a26694961f4810f42272592a10136fabda5503e3c0c43"},{"filename":"template/index.html","content":"\u003c!doctype html>\n\u003chtml lang=\"en\" class=\"antialiased\">\n \u003chead>\n \u003cmeta charset=\"UTF-8\" />\n \u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n \u003ctitle>__TITLE__\u003c/title>\n \u003cmeta name=\"description\" content=\"__DESCRIPTION__\" />\n \u003clink rel=\"preconnect\" href=\"https://fonts.googleapis.com\" />\n \u003clink rel=\"preconnect\" href=\"https://fonts.gstatic.com\" crossorigin />\n \u003clink\n rel=\"stylesheet\"\n href=\"https://fonts.googleapis.com/css2?family=Chivo+Mono:wght@400;500;600&display=swap\"\n />\n \u003cscript>\n try {\n const t = localStorage.getItem('iii-theme');\n document.documentElement.dataset.theme =\n t === 'dark' || t === 'light' ? t : 'light';\n } catch (_) {\n document.documentElement.dataset.theme = 'light';\n }\n \u003c/script>\n \u003c/head>\n \u003cbody class=\"bg-bg text-ink font-sans\">\n \u003cdiv id=\"root\">\u003c/div>\n \u003cscript type=\"module\" src=\"./src/main.tsx\">\u003c/script>\n \u003c/body>\n\u003c/html>\n","content_type":"text/html; charset=utf-8","language":"markup","size":966,"content_sha256":"d889a25f24bd92f1ce1e3c13ed824dc79b278f8a1d7a7d4aaf9b116343aa1f2a"},{"filename":"template/README.md","content":"# deck content layer\n\nThis is one presentation's content layer, scaffolded by the `/presentation`\nskill into `\u003cbase>/\u003cslug>/` (in iii: `website/roadmap/\u003cslug>/`). It has\nno package.json, no config, no lockfile — dependencies, build, and the shared\ncomponent library live in the base project one level up. Everything visual\nimports from `@lib`; see the base's `COMPONENTS.md` before building anything\nnew. Dev: `pnpm dev` from the base serves this deck at `/\u003cslug>/`.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":469,"content_sha256":"667f1b37ff1166677ad8c45938f3fc0a8ed1eb117689a4402fe660edccf49016"},{"filename":"template/src/App.tsx","content":"import { Footer } from '@lib/components/Footer'\nimport { Sheet } from '@lib/components/schematic/Sheet'\nimport { TopNav } from '@lib/components/TopNav'\nimport { useHashRoute } from '@lib/hooks/useHashRoute'\nimport { SpecPage } from '@lib/pages/SpecPage'\nimport type { ComponentType } from 'react'\nimport { DECK_META, FOOTER, NAV } from './content/deck'\nimport { ExamplePage } from './pages/ExamplePage'\nimport { Hero } from './sections/Hero'\nimport { PayoffSection } from './sections/PayoffSection'\nimport { SystemMapSection } from './sections/SystemMapSection'\nimport { SPEC_DOCS } from './spec-docs'\n\n/**\n * Ordered home-page sections. The first is the hero; the rest each carry a DOM\n * id matching a NAV entry in content/deck.ts for scroll-spy.\n */\nconst SECTIONS: ComponentType[] = [Hero, SystemMapSection, PayoffSection]\n\n// The built-in spec viewer — never remove. It renders every markdown file of\n// the paired tech-specs/\u003cslug>/ directory with a file sidebar.\nconst Spec = () => \u003cSpecPage docs={SPEC_DOCS} />\n\n/** deep-dive pages, keyed by the `#/\u003cslug>` route slug. */\nconst PAGES: Record\u003cstring, ComponentType> = {\n example: ExamplePage,\n spec: Spec,\n}\n\nfunction Home() {\n return (\n \u003cmain>\n {SECTIONS.map((Component, i) => (\n \u003cComponent key={i} />\n ))}\n \u003c/main>\n )\n}\n\nfunction NotFound() {\n return (\n \u003cmain className=\"px-4 py-24 @3xl:px-9\">\n \u003cp className=\"font-mono text-[14px] lowercase text-ink-faint\">\n nothing here.{' '}\n \u003ca href=\"#/\" className=\"text-ink hover:text-accent transition-colors\">\n ← back to the overview\n \u003c/a>\n \u003c/p>\n \u003c/main>\n )\n}\n\nexport default function App() {\n const route = useHashRoute()\n const Page = route.kind === 'page' ? PAGES[route.slug] : undefined\n\n return (\n \u003cdiv className=\"@container min-h-screen\">\n \u003cSheet>\n \u003cTopNav route={route} meta={DECK_META} nav={NAV} />\n {route.kind === 'home' ? \u003cHome /> : Page ? \u003cPage /> : \u003cNotFound />}\n \u003cFooter footer={FOOTER} />\n \u003c/Sheet>\n \u003c/div>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":2046,"content_sha256":"462bed028d80896a7da598cb5bd72ab2a0a1fb3c6cb7cdcb6f485d8e26bad105"},{"filename":"template/src/content/deck.ts","content":"/**\n * deck.ts — the one file that describes THIS presentation.\n *\n * The /presentation skill rewrites this per tech-spec. Everything here is pure\n * data (no JSX); the shared chrome (TopNav, Footer) receives it as props from\n * App.tsx — shared components never reach into deck content. The ordered list\n * of section COMPONENTS and the deep-dive PAGES map live in App.tsx.\n */\n\nimport type { DeckMeta, FooterSpec, NavItem } from '@lib/lib/deck-types'\n\nexport const DECK_META: DeckMeta = {\n wordmarkLabel: 'spec presentation',\n}\n\n/**\n * top-nav section links. each id must match the `id` passed to a \u003cSection>.\n * keep this short (6–9 items) — it is the reader's map of the whole deck.\n */\nexport const NAV: NavItem[] = [\n { id: 'map', label: 'map' },\n { id: 'payoff', label: 'payoff' },\n]\n\nexport const FOOTER: FooterSpec = {\n eyebrow: 'get started',\n headline: 'one file. one command.',\n command: 'iii up',\n attribution: 'spec presentation — architecture overview',\n source: 'source of truth: tech-specs/\u003cyour-spec>',\n}\n","content_type":"application/typescript; charset=utf-8","language":"typescript","size":1041,"content_sha256":"c01a81aef134d85083c4540503b3f283fe2ee8e22eb7cb0a8722dc1ca196a46c"},{"filename":"template/src/content/example.ts","content":"/**\n * example.ts — PLACEHOLDER DATA for the starter deck.\n *\n * The /presentation skill replaces this with data extracted from the tech-spec\n * (often split into per-topic modules). It exists so the template renders and\n * builds out of the box, and so there is a concrete, copyable example of the\n * shape each archetype expects. Delete it once you have real content.\n */\nimport type { CliTrack } from '@lib/components/diagrams/CliPlayground'\nimport type { FanHandler } from '@lib/components/diagrams/FanOut'\nimport type { FunnelPath } from '@lib/components/diagrams/Funnel'\nimport type { SeqLane, SeqStep } from '@lib/components/diagrams/SequencePlayer'\nimport type { RevealStage } from '@lib/components/diagrams/StepReveal'\nimport type { MapEdge, MapNode, MapNodeInfo } from '@lib/components/diagrams/SystemMap'\n\n/* ---- hero ---- */\n\nexport const HERO_STATS = [\n { value: '4', label: 'standalone parts' },\n { value: '1', label: 'declarative file' },\n { value: '0', label: 'manual steps' },\n { value: '100%', label: 'typed contracts' },\n] as const\n\nexport const HERO_CLAIMS = [\n {\n title: 'one file',\n body: 'the whole system is declared in one place. no scattered config, no second source of truth.',\n },\n {\n title: 'one command',\n body: 'bring the entire stack up with a single command. no two-terminal dance, no ordering races.',\n },\n {\n title: 'clean planes',\n body: 'each part owns exactly one job and talks only over typed contracts. no hidden coupling.',\n },\n {\n title: 'correct by construction',\n body: 'the failure modes that used to need discipline are now impossible by design.',\n },\n] as const\n\n/* ---- system map (A4) ---- */\n\nexport const MAP_NODES: MapNode[] = [\n { id: 'client', x: 40, y: 250, w: 170, h: 60, title: 'client', sub: 'any caller', kind: 'external' },\n { id: 'gateway', x: 320, y: 248, w: 200, h: 66, title: 'gateway', sub: 'routes calls', kind: 'primary' },\n { id: 'worker', x: 650, y: 120, w: 200, h: 66, title: 'worker', sub: 'runs the loop', kind: 'primary' },\n { id: 'store', x: 650, y: 376, w: 200, h: 66, title: 'store', sub: 'durable state', kind: 'secondary' },\n { id: 'watcher', x: 900, y: 248, w: 120, h: 66, title: 'watcher', sub: 'reacts', kind: 'optional' },\n]\n\nexport const MAP_EDGES: MapEdge[] = [\n {\n id: 'request',\n from: 'client',\n to: 'gateway',\n d: 'M 210 280 L 320 281',\n label: 'request',\n lx: 265,\n ly: 272,\n dur: 2,\n },\n {\n id: 'dispatch',\n from: 'gateway',\n to: 'worker',\n d: 'M 520 268 C 590 250, 600 158, 650 152',\n label: 'dispatch',\n lx: 600,\n ly: 196,\n anchor: 'start',\n dur: 1.8,\n },\n {\n id: 'persist',\n from: 'gateway',\n to: 'store',\n d: 'M 520 296 C 590 320, 600 404, 650 410',\n label: 'persist',\n lx: 600,\n ly: 372,\n anchor: 'start',\n dur: 1.8,\n },\n {\n id: 'write',\n from: 'worker',\n to: 'store',\n d: 'M 750 186 L 750 376',\n label: 'write result',\n lx: 758,\n ly: 290,\n anchor: 'start',\n dur: 1.6,\n },\n {\n id: 'emit',\n from: 'store',\n to: 'watcher',\n d: 'M 850 404 C 920 388, 960 332, 960 314',\n label: 'emit event',\n lx: 968,\n ly: 360,\n anchor: 'start',\n dur: 2.2,\n },\n]\n\nexport const MAP_INFO: Record\u003cstring, MapNodeInfo> = {\n client: {\n id: 'client',\n kindLabel: 'external',\n role: 'any caller — a web app, a cli, another service. it only knows the gateway contract.',\n sections: [\n {\n heading: 'calls',\n items: [{ name: 'gateway::request', desc: 'submit work and get an id back immediately.' }],\n },\n ],\n note: 'replace this node with the real entry points of your system.',\n },\n gateway: {\n id: 'gateway',\n kindLabel: 'core',\n role: 'the single front door: validates, routes, and hands work to the right plane.',\n sections: [\n {\n heading: 'surface',\n items: [\n { name: 'gateway::request', desc: 'accept work, enqueue it, return fast.' },\n { name: 'gateway::status', desc: 'point-in-time read of a request.' },\n ],\n },\n ],\n install: 'add gateway',\n },\n worker: {\n id: 'worker',\n kindLabel: 'core',\n role: 'runs the actual work loop — durable, resumable, one job at a time.',\n sections: [\n {\n heading: 'surface',\n items: [\n { name: 'worker::run', desc: 'execute one unit of work to completion.' },\n { name: 'compose::down', desc: 'stop a supervised worker graph.' },\n ],\n },\n ],\n bullets: ['every step is a durable entry — a crash resumes mid-run.'],\n install: 'add worker',\n },\n store: {\n id: 'store',\n kindLabel: 'supporting',\n role: 'the durable, reactive state — every write emits an event.',\n sections: [\n {\n heading: 'emits',\n dotted: true,\n items: [\n { name: 'store::written', desc: 'a record changed — bind and render live.' },\n { name: 'store::removed', desc: 'a record was deleted.' },\n ],\n },\n ],\n note: 'pure storage + notification. it runs no business logic of its own.',\n },\n watcher: {\n id: 'watcher',\n kindLabel: 'optional',\n role: 'an optional reactor: binds store events and does something useful — notify, index, escalate.',\n sections: [\n {\n heading: 'binds',\n items: [{ name: 'store::written', desc: 'the only thing it needs to know.' }],\n },\n ],\n note: 'optional by design — the core three run with or without it.',\n },\n}\n\n/* ---- sequence (A5) ---- */\n\nexport const SEQ_LANES: SeqLane[] = [\n { id: 'client', label: 'client', x: 110 },\n { id: 'gateway', label: 'gateway', x: 380 },\n { id: 'worker', label: 'worker', x: 640 },\n { id: 'store', label: 'store', x: 880 },\n]\n\nexport const SEQ_STEPS: SeqStep[] = [\n {\n from: 'client',\n to: 'gateway',\n label: 'gateway::request',\n title: 'submit work',\n desc: 'the client drops a request and gets a request id back immediately — no blocking.',\n },\n {\n from: 'gateway',\n to: 'store',\n label: 'store::write',\n title: 'record it',\n desc: 'the gateway persists the new request; the write fires an event.',\n event: 'store::written',\n },\n {\n from: 'gateway',\n to: 'worker',\n label: 'worker::run',\n title: 'dispatch',\n desc: 'the gateway hands the queued work to a worker to execute.',\n },\n {\n from: 'worker',\n to: 'worker',\n label: 'do the work',\n title: 'run the loop',\n desc: 'the worker runs durable steps; a crash resumes from the last committed step.',\n },\n {\n from: 'worker',\n to: 'store',\n label: 'store::write',\n title: 'write result',\n desc: 'the worker commits the typed result; the store fires another event.',\n event: 'store::written',\n },\n {\n from: 'store',\n to: 'client',\n label: 'live update',\n title: 'render live',\n desc: 'the client was subscribed all along — the result appears with no polling.',\n },\n]\n\n/* ---- payoff (A11) ---- */\n\nexport const PAYOFF_METRICS = [\n { label: 'files to edit', before: '7', after: '1' },\n { label: 'commands to boot', before: '5', after: '1' },\n { label: 'terminals open', before: '2', after: '1' },\n { label: 'startup races', before: 'many', after: '0' },\n] as const\n\nexport const PAYOFF_SOLVES = [\n {\n problem: 'config scattered across files',\n answer: 'one declarative file',\n detail: 'a single source of truth the whole stack reads from.',\n },\n {\n problem: 'manual, order-sensitive boot',\n answer: 'one command, topo-sorted',\n detail: 'dependencies bring up in the right order automatically.',\n },\n {\n problem: 'state changes you have to poll for',\n answer: 'events on every write',\n detail: 'bind once and render live — never chase status again.',\n },\n] as const\n\n/* ---- lifecycle / durability (A6) ---- */\n\nexport const REVEAL_STAGES: RevealStage[] = [\n {\n label: 'queued',\n tone: 'ink',\n caption: 'the request lands and is written as a durable entry before anything runs.',\n rows: [\n { k: 'status', v: 'queued' },\n { k: 'step', v: '0 / 3' },\n ],\n },\n {\n label: 'running',\n tone: 'ink',\n caption: 'a worker picks it up and commits each step as it goes.',\n rows: [\n { k: 'status', v: 'running' },\n { k: 'step', v: '2 / 3' },\n ],\n },\n {\n label: 'crash',\n tone: 'alert',\n caption: 'the worker dies mid-step. the in-flight step is lost — but the committed log is not.',\n rows: [\n { k: 'status', v: 'interrupted' },\n { k: 'step', v: '2 / 3' },\n ],\n note: 'a crash is a state transition, not lost work',\n },\n {\n label: 'resume',\n tone: 'warn',\n caption: 'a fresh worker reads the log and continues from the last committed step. nothing replays twice.',\n rows: [\n { k: 'status', v: 'resuming' },\n { k: 'step', v: '2 / 3' },\n ],\n },\n {\n label: 'done',\n tone: 'accent',\n caption: 'the final step commits and the typed result is written.',\n rows: [\n { k: 'status', v: 'done' },\n { k: 'step', v: '3 / 3' },\n ],\n note: 'work lost: none. steps replayed: zero.',\n },\n]\n\n/* ---- reactive fan-out (A7) ---- */\n\nexport const FAN_SOURCE = { label: 'store::write', sub: 'one commit, no publish step' }\nexport const FAN_TRIGGER = 'store::written'\nexport const FAN_HANDLERS: FanHandler[] = [\n { id: 'watcher', label: 'watcher::react', desc: 'escalate or act on the change' },\n { id: 'index', label: 'search::index', desc: 'keep the index current' },\n { id: 'metrics', label: 'metrics::count', desc: 'live dashboard tiles' },\n]\n\n/* ---- convergence funnel (A8) ---- */\n\nexport const FUNNEL_PATHS: FunnelPath[] = [\n { id: 'fire', label: 'fire and forget', desc: 'no record, no retry' },\n { id: 'thread', label: 'detached thread', desc: 'dies with the process' },\n { id: 'retry', label: 'naive retry', desc: 'duplicates on restart' },\n]\nexport const FUNNEL_TARGET = { label: 'durable queue entry', sub: 'committed before ack — exactly-once, resumable' }\nexport const FUNNEL_REJECT = { label: 'in-memory only', desc: 'lost on crash — removed by design' }\n\n/* ---- cli playground (A3) ---- */\n\nexport const CLI_TRACKS: CliTrack[] = [\n {\n id: 'first-run',\n label: 'first run',\n lines: [\n { cmd: 'your-cli up', out: ['→ reading your-spec.yml', '✓ stack up — gateway, worker, store'] },\n {\n cmd: 'your-cli request { input }',\n fn: 'gateway::request',\n out: ['→ { id: \"r_8c2\", accepted: true }'],\n exit: 0,\n },\n { cmd: 'your-cli status r_8c2', fn: 'gateway::status', out: ['✓ done — result ready'] },\n ],\n },\n {\n id: 'day-2',\n label: 'day-2 ops',\n lines: [\n { cmd: 'your-cli ps', out: ['ID STATUS UPTIME', 'worker-1 running 4h12m'] },\n {\n cmd: 'your-cli logs worker-1 --tail 2',\n fn: 'ops::logs',\n out: ['\"handled r_8c1 in 12ms\"', '\"handled r_8c2 in 9ms\"'],\n exit: 0,\n },\n ],\n },\n]\n","content_type":"application/typescript; charset=utf-8","language":"typescript","size":10992,"content_sha256":"1f2e52d50b7eab813cf0c9c719af519fc2883180a0a8db8582bc8783071536a6"},{"filename":"template/src/main.tsx","content":"import { StrictMode } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport '@lib/index.css'\nimport App from './App'\n\ncreateRoot(document.getElementById('root')!).render(\n \u003cStrictMode>\n \u003cApp />\n \u003c/StrictMode>,\n)\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":229,"content_sha256":"798a566ad195d7ca6c79109597bdaa28fb1cfefbacbad4cfd2ca5964f1269124"},{"filename":"template/src/pages/ExamplePage.tsx","content":"import { SequencePlayer } from '@lib/components/diagrams/SequencePlayer'\nimport { PageShell } from '@lib/components/PageShell'\nimport { C, CodeBlock, K, M, S } from '@lib/components/schematic/CodeBlock'\nimport { SEQ_LANES, SEQ_STEPS } from '../content/example'\n\n/**\n * A14 — a deep-dive page (`#/example` route). Use one per distinct\n * consumer/scenario worth its own full page: a focused sequence plus the code\n * a reader would actually write. Cross-link siblings via PageShell `related`.\n */\nexport function ExamplePage() {\n return (\n \u003cPageShell\n eyebrow=\"deep dive\"\n title=\"a worked example, end to end\"\n description=\"a deep-dive page lives at its own #/slug route. give one to each scenario that deserves the full walkthrough — a sequence, the real code, and the contracts behind it.\"\n >\n \u003cSequencePlayer title=\"the example flow\" lanes={SEQ_LANES} steps={SEQ_STEPS} />\n\n \u003cCodeBlock title=\"what the caller writes\">\n \u003cK>await\u003c/K> client.\u003cK>request\u003c/K>(\u003cM>{'{'}\u003c/M>\n {'\\n '}input: \u003cS>\"do the thing\"\u003c/S>,{'\\n '}on: \u003cM>{'{'}\u003c/M> done: (r) \u003cM>{'=>'}\u003c/M> render(r) \u003cM>{'}'}\u003c/M>,{' '}\n \u003cC>{'// bound once, fires live'}\u003c/C>\n {'\\n'}\n \u003cM>{'})'}\u003c/M>\n \u003c/CodeBlock>\n \u003c/PageShell>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":1259,"content_sha256":"ebac33690da73f1ce76715692972422a4500466a4f70da0055bcf07f6b3f4b1f"},{"filename":"template/src/sections/Hero.tsx","content":"import { Caret } from '@lib/components/schematic/Caret'\nimport { Cell } from '@lib/components/schematic/Cell'\nimport { Prompt } from '@lib/components/schematic/Prompt'\nimport { StatusDot } from '@lib/components/schematic/StatusDot'\nimport { Terminal, TerminalRow } from '@lib/components/schematic/Terminal'\nimport { HERO_CLAIMS, HERO_STATS } from '../content/example'\n\n/**\n * A1 — the hero. States the WIN in one line plus a three-value subhead; never\n * the mechanism. CTAs jump into the map and the payoff. A small terminal makes\n * the promise concrete; the stat strip quantifies it.\n */\nexport function Hero() {\n return (\n \u003csection id=\"hero\">\n \u003cdiv className=\"grid grid-cols-1 @4xl:grid-cols-2 gap-x-16 gap-y-12 px-4 pt-16 pb-14 @3xl:px-9 @3xl:pt-24 @3xl:pb-20\">\n \u003cdiv className=\"min-w-0\">\n \u003cdiv className=\"font-mono text-[11px] uppercase tracking-[0.06em] text-ink-faint mb-6\">\n \u003cPrompt symbol=\"$\">tech-specs / your-spec\u003c/Prompt>\n \u003c/div>\n \u003ch1 className=\"font-mono font-semibold lowercase text-ink text-[44px] leading-[1.05] tracking-[-0.02em] @3xl:text-[64px] @3xl:leading-[1.02]\">\n one file.\n \u003cbr />\n one command.\n \u003c/h1>\n \u003cp className=\"mt-6 font-mono text-[14px] leading-[1.7] text-ink-faint lowercase max-w-[56ch]\">\n the whole system, declared once and brought up in a single step — \u003cspan className=\"text-ink\">simple\u003c/span>{' '}\n to run, \u003cspan className=\"text-ink\">structured\u003c/span> by design, \u003cspan className=\"text-ink\">correct\u003c/span> by\n construction.\n \u003c/p>\n \u003cdiv className=\"mt-8 flex flex-wrap items-center gap-3\">\n \u003ca\n href=\"#map\"\n className=\"inline-flex h-11 items-center bg-ink text-bg border border-ink px-5 font-mono text-[14px] lowercase transition-colors hover:bg-bg hover:text-ink\"\n >\n walk the architecture →\n \u003c/a>\n \u003ca\n href=\"#payoff\"\n className=\"inline-flex h-11 items-center bg-bg text-ink border border-ink px-5 font-mono text-[14px] lowercase transition-colors hover:bg-ink hover:text-bg\"\n >\n skip to the payoff\n \u003c/a>\n \u003c/div>\n \u003c/div>\n\n \u003cdiv className=\"min-w-0 self-center\">\n \u003cTerminal title=\"from zero to running\">\n \u003cdiv className=\"flex flex-col gap-y-2.5\">\n \u003cTerminalRow\n command=\"your-cli up\"\n output={\n \u003cspan className=\"flex items-center gap-x-2\">\n \u003cStatusDot pulse />\n \u003cspan>stack up — gateway, worker, store connected\u003c/span>\n \u003c/span>\n }\n />\n \u003cTerminalRow\n command={\n \u003c>\n your-cli request \u003cspan className=\"text-ink-faint\">{'{ input }'}\u003c/span>\n \u003c/>\n }\n output={\u003cspan className=\"tabular-nums\">{'→ { id: \"r_8c2\", accepted: true }'}\u003c/span>}\n />\n \u003cdiv className=\"flex items-center gap-x-2\">\n \u003cPrompt symbol=\"$\" />\n \u003cCaret />\n \u003c/div>\n \u003c/div>\n \u003c/Terminal>\n\n \u003cdiv className=\"grid grid-cols-2 @lg:grid-cols-4 border-x border-b border-rule bg-rule gap-px\">\n {HERO_STATS.map((stat) => (\n \u003cdiv key={stat.label} className=\"bg-bg px-4 py-3.5 min-w-0\">\n \u003cdiv className=\"font-mono text-[20px] font-semibold text-ink tabular-nums leading-none\">\n {stat.value}\n \u003c/div>\n \u003cdiv className=\"mt-1.5 font-mono text-[10px] uppercase tracking-[0.06em] text-ink-faint leading-[1.4]\">\n {stat.label}\n \u003c/div>\n \u003c/div>\n ))}\n \u003c/div>\n \u003c/div>\n \u003c/div>\n\n \u003cdiv className=\"border-t border-rule\">\n \u003cdiv className=\"grid grid-cols-1 @2xl:grid-cols-2 @5xl:grid-cols-4 gap-px bg-rule\">\n {HERO_CLAIMS.map((claim, i) => (\n \u003cCell\n key={claim.title}\n title={\n \u003cspan className=\"flex items-center gap-x-2.5\">\n \u003cspan className=\"font-mono text-[11px] text-ink-ghost tabular-nums\">0{i + 1}\u003c/span>\n {claim.title}\n \u003c/span>\n }\n className=\"border-0\"\n bodyClassName=\"max-w-[36ch]\"\n >\n {claim.body}\n \u003c/Cell>\n ))}\n \u003c/div>\n \u003c/div>\n \u003c/section>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":4601,"content_sha256":"e8b83d081e9d366eeb326249e34e37656798a95fcc1975fbb006556dd5dadf71"},{"filename":"template/src/sections/PayoffSection.tsx","content":"import { Section } from '@lib/components/Section'\nimport { PAYOFF_METRICS, PAYOFF_SOLVES } from '../content/example'\n\n/**\n * A11 — the payoff. Closes the persuasion loop: a quantified before/after\n * scorecard, then a problem → answer table. The reader should leave convinced\n * the work is worth doing.\n */\nexport function PayoffSection() {\n return (\n \u003cSection\n id=\"payoff\"\n index=\"07\"\n eyebrow=\"the payoff\"\n title=\"smaller surface, stronger guarantees.\"\n lede=\"the same system, measured before and after. the failure modes that used to need discipline are now gone by construction.\"\n >\n {/* scorecard */}\n \u003cdiv className=\"grid grid-cols-2 @3xl:grid-cols-4 border-x border-t border-rule bg-rule gap-px\">\n {PAYOFF_METRICS.map((m) => (\n \u003cdiv key={m.label} className=\"bg-bg px-4 py-5 min-w-0\">\n \u003cdiv className=\"flex items-baseline gap-x-2\">\n \u003cspan className=\"font-mono text-[13px] text-ink-ghost line-through tabular-nums\">{m.before}\u003c/span>\n \u003cspan className=\"font-mono text-[12px] text-ink-ghost\">→\u003c/span>\n \u003cspan className=\"font-mono text-[24px] font-semibold text-accent tabular-nums leading-none\">\n {m.after}\n \u003c/span>\n \u003c/div>\n \u003cdiv className=\"mt-2 font-mono text-[10px] uppercase tracking-[0.06em] text-ink-faint\">{m.label}\u003c/div>\n \u003c/div>\n ))}\n \u003c/div>\n\n {/* problem → answer */}\n \u003cdiv className=\"mt-8 grid grid-cols-1 @3xl:grid-cols-2 border border-rule bg-rule gap-px\">\n \u003cdiv className=\"bg-panel px-4 py-2.5 font-mono text-[10px] uppercase tracking-[0.14em] text-ink-faint\">\n the problem\n \u003c/div>\n \u003cdiv className=\"bg-panel px-4 py-2.5 font-mono text-[10px] uppercase tracking-[0.14em] text-ink-faint hidden @3xl:block\">\n the answer\n \u003c/div>\n {PAYOFF_SOLVES.map((row) => (\n \u003cdiv key={row.problem} className=\"contents\">\n \u003cdiv className=\"bg-bg px-4 py-4 min-w-0\">\n \u003cdiv className=\"font-mono text-[13px] text-alert lowercase\">{row.problem}\u003c/div>\n \u003c/div>\n \u003cdiv className=\"bg-bg px-4 py-4 min-w-0\">\n \u003cdiv className=\"font-mono text-[13px] text-accent lowercase\">{row.answer}\u003c/div>\n \u003cdiv className=\"mt-1 font-mono text-[12px] leading-[1.6] text-ink-faint lowercase\">{row.detail}\u003c/div>\n \u003c/div>\n \u003c/div>\n ))}\n \u003c/div>\n \u003c/Section>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":2488,"content_sha256":"f66d31cb5963114c1c5992ae55517c326ba1e21286f934ca50ae74568ee6eb0b"},{"filename":"template/src/sections/SystemMapSection.tsx","content":"import { MapDatasheet, SystemMap } from '@lib/components/diagrams/SystemMap'\nimport { Section } from '@lib/components/Section'\nimport { SpecRow, SpecSheet } from '@lib/components/SpecSheet'\nimport { StatusDot } from '@lib/components/schematic/StatusDot'\nimport { useEffect, useRef, useState } from 'react'\nimport { MAP_EDGES, MAP_INFO, MAP_NODES } from '../content/example'\n\n/** matches tailwind @5xl container width (64rem) */\nconst PAIRED_LAYOUT_MIN_WIDTH = 1024\n\nconst LEGEND = [\n { swatch: \u003cspan className=\"inline-block size-3 border-[1.25px] border-ink bg-bg\" />, label: 'core' },\n { swatch: \u003cspan className=\"inline-block size-3 border border-ink-faint bg-bg\" />, label: 'supporting' },\n { swatch: \u003cspan className=\"inline-block size-3 border border-dashed border-ink-faint bg-bg\" />, label: 'optional' },\n { swatch: \u003cspan className=\"inline-block size-3 border border-rule bg-bg\" />, label: 'external' },\n { swatch: \u003cStatusDot pulse />, label: 'active flow' },\n] as const\n\nexport function SystemMapSection() {\n const [selected, setSelected] = useState('gateway')\n const layoutRef = useRef\u003cHTMLDivElement>(null)\n const mapRef = useRef\u003cHTMLDivElement>(null)\n const [pairedLayout, setPairedLayout] = useState(false)\n const [mapHeight, setMapHeight] = useState\u003cnumber | undefined>()\n\n useEffect(() => {\n const layoutEl = layoutRef.current\n const mapEl = mapRef.current\n if (!layoutEl || !mapEl) return\n\n const sync = () => {\n const paired = layoutEl.clientWidth >= PAIRED_LAYOUT_MIN_WIDTH\n setPairedLayout(paired)\n setMapHeight(paired ? mapEl.offsetHeight : undefined)\n }\n\n sync()\n const observer = new ResizeObserver(sync)\n observer.observe(layoutEl)\n observer.observe(mapEl)\n return () => observer.disconnect()\n }, [])\n\n const info = MAP_INFO[selected] ?? MAP_INFO.gateway\n\n return (\n \u003cSection\n id=\"map\"\n index=\"01\"\n eyebrow=\"system map\"\n title=\"a few parts, talking only over typed contracts.\"\n lede=\"every arrow below is a call or an event — no hidden in-process coupling anywhere. click any node to read its datasheet: each part is useful on its own, and together they are the whole system.\"\n >\n \u003cdiv className=\"flex flex-wrap items-center gap-x-5 gap-y-2 mb-5\">\n {LEGEND.map((item) => (\n \u003cspan key={item.label} className=\"flex items-center gap-x-2\">\n {item.swatch}\n \u003cspan className=\"font-mono text-[10px] uppercase tracking-[0.06em] text-ink-faint\">{item.label}\u003c/span>\n \u003c/span>\n ))}\n \u003c/div>\n\n \u003cdiv ref={layoutRef} className=\"grid grid-cols-1 @5xl:grid-cols-[minmax(0,1fr)_340px] gap-6 items-stretch\">\n \u003cdiv ref={mapRef} className=\"border border-rule bg-bg p-3 overflow-x-auto min-h-0 self-start\">\n \u003cdiv className=\"min-w-[760px]\">\n \u003cSystemMap nodes={MAP_NODES} edges={MAP_EDGES} selected={selected} onSelect={setSelected} />\n \u003c/div>\n \u003c/div>\n \u003cdiv\n className=\"@5xl:sticky @5xl:top-16 min-h-0 overflow-hidden\"\n style={pairedLayout && mapHeight ? { height: mapHeight } : undefined}\n >\n \u003cMapDatasheet\n info={info}\n className={pairedLayout ? 'h-full' : undefined}\n layoutKey={pairedLayout ? mapHeight : 'stack'}\n />\n \u003c/div>\n \u003c/div>\n\n \u003cdiv className=\"mt-6 grid grid-cols-1 @4xl:grid-cols-2 gap-4\">\n \u003cSpecSheet title=\"the wiring, in words\" meta={`${MAP_EDGES.length} edges`}>\n \u003cdiv className=\"flex flex-col\">\n \u003cSpecRow name=\"client → gateway::request\" type=\"work in\">\n any caller drops a request and gets an id back immediately.\n \u003c/SpecRow>\n \u003cSpecRow name=\"gateway → worker::run\" type=\"dispatch\">\n queued work is handed to a worker to execute, in order.\n \u003c/SpecRow>\n \u003cSpecRow name=\"gateway / worker → store\" type=\"persist + emit\">\n every write lands in the durable store and fires an event.\n \u003c/SpecRow>\n \u003cSpecRow name=\"store → watcher\" type=\"reactive surface\">\n optional reactors bind store events and render or act live.\n \u003c/SpecRow>\n \u003c/div>\n \u003c/SpecSheet>\n\n \u003cSpecSheet title=\"design principles\" meta=\"from the spec\">\n \u003cdiv className=\"flex flex-col\">\n \u003cSpecRow name=\"standalone first\">\n every part is independently installable and useful by itself. cross-part calls are explicit, never\n imports.\n \u003c/SpecRow>\n \u003cSpecRow name=\"one job each\">\n the gateway routes, the worker runs, the store remembers. anything that grows real logic becomes its own\n part.\n \u003c/SpecRow>\n \u003cSpecRow name=\"reactive by default\">\n state changes emit events; consumers bind once and render live.\n \u003c/SpecRow>\n \u003c/div>\n \u003c/SpecSheet>\n \u003c/div>\n \u003c/Section>\n )\n}\n","content_type":"application/typescript; charset=utf-8","language":"tsx","size":4979,"content_sha256":"08177b2bbb8e08dc10f5dd7e3b532a98cc5fc91e9348d5687e6602258688e703"},{"filename":"template/src/spec-docs.ts","content":"/**\n * Bundles this spec's markdown for the #/spec page. The glob MUST live\n * deck-side (import.meta.glob resolves relative to the importing file); its\n * literal is substituted at scaffold time because the relative depth from\n * \u003cbase>/\u003cslug>/src/ to \u003cspecs-dir>/\u003cslug>/ depends on where the base project\n * lives (in iii: '../../../../tech-specs/\u003cslug>/*.md').\n */\nexport const SPEC_DOCS = import.meta.glob('__SPEC_MD_GLOB__', {\n query: '?raw',\n import: 'default',\n eager: true,\n}) as Record\u003cstring, string>\n","content_type":"application/typescript; charset=utf-8","language":"typescript","size":514,"content_sha256":"dc0aa5618db0223debb2751c5d82920a29bd10d9569fd95078dfef4f1453b19d"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Presentation","type":"text"}]},{"type":"paragraph","content":[{"text":"Turn a technical specification into an interactive, persuasive web deck — the kind at iii.dev/roadmap/. The output is a ","type":"text"},{"text":"content layer","type":"text","marks":[{"type":"strong"}]},{"text":" inside the repo's roadmap base (the shared component library, gallery, and markdown spec viewer that build every deck into one static site — Astro routes of the site package in iii, a standalone Vite project in other repos):","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"helps engineers ","type":"text"},{"text":"understand","type":"text","marks":[{"type":"strong"}]},{"text":" the spec — the architecture is a navigable map, not prose;","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"is ","type":"text"},{"text":"interactive","type":"text","marks":[{"type":"strong"}]},{"text":" — steppable diagrams, a selectable system map, live toggles; interactivity is what makes it stick;","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"reads like ","type":"text"},{"text":"marketing","type":"text","marks":[{"type":"strong"}]},{"text":" — it argues the ","type":"text"},{"text":"why","type":"text","marks":[{"type":"em"}]},{"text":". if no one is convinced the work should happen, the spec has not done its job;","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"is ","type":"text"},{"text":"build-in-public ready","type":"text","marks":[{"type":"strong"}]},{"text":" — each deck ships as a static page at ","type":"text"},{"text":"/roadmap/\u003cslug>/","type":"text","marks":[{"type":"code_inline"}]},{"text":", safe to share.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Comparable to","type":"text"}]},{"type":"paragraph","content":[{"text":"A product launch microsite generated from an RFC. Stripe-doc clarity meets a keynote narrative, in a monospace drafting-sheet style.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Activation","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Use For","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"generating an interactive deck from a tech-spec directory","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"refreshing or extending a presentation already generated by this skill","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Do Not Use For","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"writing the spec itself — use ","type":"text"},{"text":"/tech-spec","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"static slide exports (pdf / keynote) — use a slide tool","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"general UI work unrelated to a spec — use ","type":"text"},{"text":"/design","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Load First","type":"text"}]},{"type":"paragraph","content":[{"text":"Read these before building (they are the law — do not re-derive them):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"reference/design-system.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — the locked tokens, type, motion, layout","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"reference/archetypes.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — the interactive slide library + how to pick one","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"reference/component-standards.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — deck-local vs promoted components, the promotion checklist, the registry format","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"reference/narrative-framework.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — the persuasive arc + outline rules","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"reference/quality-bar.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — the checklist to self-verify before finishing","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"reference/hosting.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — the two-tree layout, the pairing contract, frontmatter registration, and deploy","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"per repo:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"\u003cbase>/COMPONENTS.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — the live registry of that repo's shared components. It may exceed the bundled catalog; when it and ","type":"text"},{"text":"reference/archetypes.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" disagree, ","type":"text"},{"text":"the repo registry wins","type":"text","marks":[{"type":"strong"}]},{"text":".","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"The skill bundles two scaffolds:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"template/","type":"text","marks":[{"type":"code_inline"}]},{"text":" — one deck's ","type":"text"},{"text":"content layer","type":"text","marks":[{"type":"strong"}]},{"text":" (App, sections, pages, content data, the spec-docs glob). Copy it per spec; everything visual comes from the base's shared ","type":"text"},{"text":"src/","type":"text","marks":[{"type":"code_inline"}]},{"text":" via the ","type":"text"},{"text":"@lib","type":"text","marks":[{"type":"code_inline"}]},{"text":" alias. You generate only content.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"base/","type":"text","marks":[{"type":"code_inline"}]},{"text":" — the whole per-repo presentations site: the shared component library + design tokens, the gallery, the md-only spec viewer, and the build glue (","type":"text"},{"text":"build.mjs","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"vite.config.ts","type":"text","marks":[{"type":"code_inline"}]},{"text":", one ","type":"text"},{"text":"package.json","type":"text","marks":[{"type":"code_inline"}]},{"text":"). Copy once per repo (in iii it already lives at ","type":"text"},{"text":"website/roadmap/","type":"text","marks":[{"type":"code_inline"}]},{"text":"); per-deck runs never modify it except ","type":"text"},{"text":"additive component promotion","type":"text","marks":[{"type":"strong"}]},{"text":" per ","type":"text"},{"text":"reference/component-standards.md","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Progress Updates","type":"text"}]},{"type":"paragraph","content":[{"text":"Emit one short line before each phase: ","type":"text"},{"text":"ingesting spec","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"reading the component registry","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"proposing outline","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"scaffolding","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"generating slides (k/N)","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"registering spec frontmatter","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"verifying","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Workflow","type":"text"}]},{"type":"paragraph","content":[{"text":"Phases are gated. Do not skip Phase 2's approval or Phase 5's verification.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"0. Resolve inputs","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"The argument is a tech-spec directory: ","type":"text"},{"text":"\u003crepo>/tech-specs/\u003cslug>/","type":"text","marks":[{"type":"code_inline"}]},{"text":" — ","type":"text"},{"text":"markdown only","type":"text","marks":[{"type":"strong"}]},{"text":" (README.md + domain docs; frontmatter in README.md). If given a path elsewhere, resolve into the spec tree or ask.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"The ","type":"text"},{"text":"slug is the spec directory's basename","type":"text","marks":[{"type":"strong"}]},{"text":" (e.g. ","type":"text"},{"text":"2026-06-21-devexp","type":"text","marks":[{"type":"code_inline"}]},{"text":" — ","type":"text"},{"text":"YYYY-MM-DD-\u003cname>","type":"text","marks":[{"type":"code_inline"}]},{"text":"; the day prefix orders the roadmap timeline). It is the deck directory name AND the URL segment — the pairing contract in ","type":"text"},{"text":"reference/hosting.md","type":"text","marks":[{"type":"code_inline"}]},{"text":". Fix it now and use it everywhere; never prettify it.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Resolve the ","type":"text"},{"text":"base project","type":"text","marks":[{"type":"strong"}]},{"text":": read ","type":"text"},{"text":"\u003crepo>/tech-specs/README.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" — the pointer names the base dir (in iii: ","type":"text"},{"text":"website/roadmap/","type":"text","marks":[{"type":"code_inline"}]},{"text":"). Fallback: search for a dir containing both ","type":"text"},{"text":"COMPONENTS.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" and a shared ","type":"text"},{"text":"src/","type":"text","marks":[{"type":"code_inline"}]},{"text":". Detect its shape:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"integrated base","type":"text","marks":[{"type":"strong"}]},{"text":" (shared ","type":"text"},{"text":"src/","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"scripts/manifest.mjs","type":"text","marks":[{"type":"code_inline"}]},{"text":", no package.json or build.mjs of its own — iii's shape: the site's Astro pages at ","type":"text"},{"text":"website/src/pages/roadmap/","type":"text","marks":[{"type":"code_inline"}]},{"text":" render each deck's ","type":"text"},{"text":"src/App.tsx","type":"text","marks":[{"type":"code_inline"}]},{"text":" as a React island via the base's ","type":"text"},{"text":"src/DeckHost.tsx","type":"text","marks":[{"type":"code_inline"}]},{"text":"; deps live in the ","type":"text"},{"text":"iii-website","type":"text","marks":[{"type":"code_inline"}]},{"text":" package) → use it, and scaffold content layers only;","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"standalone base","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"build.mjs","type":"text","marks":[{"type":"code_inline"}]},{"text":" + own ","type":"text"},{"text":"package.json","type":"text","marks":[{"type":"code_inline"}]},{"text":", one ","type":"text"},{"text":"index.html","type":"text","marks":[{"type":"code_inline"}]},{"text":" per deck — the ","type":"text"},{"text":"base/","type":"text","marks":[{"type":"code_inline"}]},{"text":" snapshot's shape) → use it;","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"absent","type":"text","marks":[{"type":"strong"}]},{"text":" → first run in this repo: pick the location with the user (default ","type":"text"},{"text":"website/roadmap/","type":"text","marks":[{"type":"code_inline"}]},{"text":" when ","type":"text"},{"text":"website/","type":"text","marks":[{"type":"code_inline"}]},{"text":" exists, else ","type":"text"},{"text":"roadmap/","type":"text","marks":[{"type":"code_inline"}]},{"text":" at the repo root) and scaffold it in Phase 3;","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"legacy layout","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"tech-specs/build.mjs","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"_gallery/","type":"text","marks":[{"type":"code_inline"}]},{"text":" — per-deck standalone projects) → stop and offer the port procedure in ","type":"text"},{"text":"reference/hosting.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" before generating anything new.","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Output location is ","type":"text"},{"text":"\u003cbase>/\u003cslug>/","type":"text","marks":[{"type":"code_inline"}]},{"text":". If it exists and is non-empty, ask: overwrite, update in place, or abort. ","type":"text"},{"text":"Never write a non-markdown file under ","type":"text","marks":[{"type":"strong"}]},{"text":"tech-specs/","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":".","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Detect the install mode: workspace (repo ","type":"text"},{"text":"pnpm-workspace.yaml","type":"text","marks":[{"type":"code_inline"}]},{"text":" lists the base) vs standalone (","type":"text"},{"text":"pnpm install --ignore-workspace","type":"text","marks":[{"type":"code_inline"}]},{"text":" inside the base).","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"1. Deep ingest (read, do not skim)","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Read the spec ","type":"text"},{"text":"README.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" in full first: thesis, architecture, principles, cross-cutting contracts, migration overview. Note whether it already has a frontmatter block (title/tagline/date/tags/status).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Read every domain doc. For each, capture: the one load-bearing phrase, the pain it removes, the mechanism, any schema/fields, any sequence/lifecycle, any numbers, any honest trade-off.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Build a ","type":"text"},{"text":"content inventory","type":"text","marks":[{"type":"strong"}]},{"text":" (architecture, protocol/wire contract, lifecycle, state model, config schema, security, migration, …). This is the raw material for archetype matching.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"1b. Component awareness (before planning).","type":"text","marks":[{"type":"strong"}]},{"text":" Read ","type":"text"},{"text":"\u003cbase>/COMPONENTS.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" end to end and list ","type":"text"},{"text":"\u003cbase>/src/components/{schematic,diagrams}/","type":"text","marks":[{"type":"code_inline"}]},{"text":" + ","type":"text"},{"text":"src/hooks/","type":"text","marks":[{"type":"code_inline"}]},{"text":". The registry is the live catalog for this repo and supersedes the bundled ","type":"text"},{"text":"reference/archetypes.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" where they disagree. ","type":"text"},{"text":"Reuse-first mandate:","type":"text","marks":[{"type":"strong"}]},{"text":" a slide may get a bespoke visual only after the catalog demonstrably has no fit for its content shape. Name any planned new component in the Phase 2 outline, marked ","type":"text"},{"text":"local","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"promote","type":"text","marks":[{"type":"code_inline"}]},{"text":" (see ","type":"text"},{"text":"reference/component-standards.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"), so the user approves it at the same gate.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"2. Narrative plan — THE GATE","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Apply the arc in ","type":"text"},{"text":"reference/narrative-framework.md","type":"text","marks":[{"type":"code_inline"}]},{"text":". Produce a deck outline: an ordered slide list, each with ","type":"text"},{"text":"{ title, archetype (or reused registry component), the single claim, source section(s), the concrete data it pulls, interactivity, new component: \u003cName> (local|promote) — only when nothing fits }","type":"text","marks":[{"type":"code_inline"}]},{"text":". Include candidate deep-dive pages.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Derive the hero line + three-value subhead + stat strip. Choose the wordmark label.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Present the outline to the user for approval/edits before scaffolding.","type":"text","marks":[{"type":"strong"}]},{"text":" This is the cheapest place to turn a dry spec into a story. Skip only if the user explicitly says \"just build it\".","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"3. Scaffold (mechanical)","type":"text"}]},{"type":"paragraph","content":[{"text":"The deck:","type":"text","marks":[{"type":"strong"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"mkdir -p \u003cbase>/\u003cslug>/","type":"text","marks":[{"type":"code_inline"}]},{"text":" and copy ","type":"text"},{"text":"template/","type":"text","marks":[{"type":"code_inline"}]},{"text":" into it — in an ","type":"text"},{"text":"integrated base (iii)","type":"text","marks":[{"type":"strong"}]},{"text":" copy ","type":"text"},{"text":"template/src/","type":"text","marks":[{"type":"code_inline"}]},{"text":" only and skip ","type":"text"},{"text":"index.html","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"src/main.tsx","type":"text","marks":[{"type":"code_inline"}]},{"text":" (the site's ","type":"text"},{"text":"[slug]/index.astro","type":"text","marks":[{"type":"code_inline"}]},{"text":" route provides the document shell and mounts ","type":"text"},{"text":"src/App.tsx","type":"text","marks":[{"type":"code_inline"}]},{"text":"; the page title/description come from the spec frontmatter).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Substitute the ","type":"text"},{"text":"__SPEC_MD_GLOB__","type":"text","marks":[{"type":"code_inline"}]},{"text":" literal in ","type":"text"},{"text":"src/spec-docs.ts","type":"text","marks":[{"type":"code_inline"}]},{"text":" with the computed relative path from ","type":"text"},{"text":"\u003cbase>/\u003cslug>/src/","type":"text","marks":[{"type":"code_inline"}]},{"text":" to ","type":"text"},{"text":"\u003cspecs-dir>/\u003cslug>/*.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" (in iii: ","type":"text"},{"text":"../../../../tech-specs/\u003cslug>/*.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"); in a standalone base also ","type":"text"},{"text":"__TITLE__","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"__DESCRIPTION__","type":"text","marks":[{"type":"code_inline"}]},{"text":" in ","type":"text"},{"text":"index.html","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"No per-deck install, no per-deck config, no lockfile.","type":"text","marks":[{"type":"strong"}]},{"text":" Ensure deps once: workspace mode → ","type":"text"},{"text":"pnpm install","type":"text","marks":[{"type":"code_inline"}]},{"text":" at the repo root (only if the base's deps are missing); standalone mode → ","type":"text"},{"text":"pnpm install --ignore-workspace","type":"text","marks":[{"type":"code_inline"}]},{"text":" in ","type":"text"},{"text":"\u003cbase>","type":"text","marks":[{"type":"code_inline"}]},{"text":" (commit the generated lockfile).","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Registration:","type":"text","marks":[{"type":"strong"}]},{"text":" write or update the YAML frontmatter block at the top of ","type":"text"},{"text":"tech-specs/\u003cslug>/README.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" (schema in ","type":"text"},{"text":"reference/hosting.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"): title + tagline from the approved hero, ","type":"text"},{"text":"date: YYYY-MM-DD","type":"text","marks":[{"type":"code_inline"}]},{"text":" (day precision — the roadmap timeline orders and labels by it), 0–4 tags, ","type":"text"},{"text":"status: draft","type":"text","marks":[{"type":"code_inline"}]},{"text":". There is no central manifest — the build aggregates every spec's frontmatter, so this run touches nothing shared. If frontmatter already exists, update only the fields this run owns (tagline polish, status).","type":"text"}]},{"type":"paragraph","content":[{"text":"The base project","type":"text","marks":[{"type":"strong"}]},{"text":" (first run in a repo only): copy ","type":"text"},{"text":"base/","type":"text","marks":[{"type":"code_inline"}]},{"text":" into the chosen dir (never its ","type":"text"},{"text":"node_modules","type":"text","marks":[{"type":"code_inline"}]},{"text":"/","type":"text"},{"text":"dist","type":"text","marks":[{"type":"code_inline"}]},{"text":"). Fill the identity once: ","type":"text"},{"text":"__REPO__","type":"text","marks":[{"type":"code_inline"}]},{"text":" in ","type":"text"},{"text":"package.json","type":"text","marks":[{"type":"code_inline"}]},{"text":"; the ","type":"text"},{"text":"__GALLERY_*__","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"__WORDMARK_LABEL__","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"__HERO_*__","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"__ATTRIBUTION__","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"__SITE_HOST__","type":"text","marks":[{"type":"code_inline"}]},{"text":" tokens in ","type":"text"},{"text":"index.html","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"src/gallery/site.ts","type":"text","marks":[{"type":"code_inline"}]},{"text":", and ","type":"text"},{"text":"README.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"; write the ","type":"text"},{"text":"tech-specs/README.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" pointer. The gallery page is a ","type":"text"},{"text":"roadmap","type":"text","marks":[{"type":"strong"}]},{"text":": hero copy in roadmap voice (","type":"text"},{"text":"__HERO_TITLE__","type":"text","marks":[{"type":"code_inline"}]},{"text":" ≈ \"what we're working on\"; ","type":"text"},{"text":"__HERO_LEAD__","type":"text","marks":[{"type":"code_inline"}]},{"text":" hints at the current priority and what already landed, without naming specs), and the spec list renders as a one-column timeline, newest first, grouped by month. In a workspace repo, add the base to ","type":"text"},{"text":"pnpm-workspace.yaml","type":"text","marks":[{"type":"code_inline"}]},{"text":" ","type":"text"},{"text":"with user confirmation","type":"text","marks":[{"type":"strong"}]},{"text":" (a repo-level file). Never touch ","type":"text"},{"text":"build.mjs","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"vite.config.ts","type":"text","marks":[{"type":"code_inline"}]},{"text":", tsconfigs, or ","type":"text"},{"text":"src/","type":"text","marks":[{"type":"code_inline"}]},{"text":" beyond this copy.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"4. Generate the content layer","type":"text"}]},{"type":"paragraph","content":[{"text":"Edit only these — the write surface is ","type":"text"},{"text":"\u003cbase>/\u003cslug>/**","type":"text","marks":[{"type":"code_inline"}]},{"text":" plus the spec's frontmatter block (and an approved promotion):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"src/content/deck.ts","type":"text","marks":[{"type":"code_inline"}]},{"text":" — ","type":"text"},{"text":"DECK_META.wordmarkLabel","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"NAV","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"FOOTER","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"src/content/\u003ctopic>.ts","type":"text","marks":[{"type":"code_inline"}]},{"text":" — the typed data arrays each archetype consumes (map nodes/edges/info, sequence lanes/steps, reveal stages, cli tracks, metrics, rows). Keep data here, out of components.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"src/sections/\u003cName>.tsx","type":"text","marks":[{"type":"code_inline"}]},{"text":" — one thin section per slide: import the matching archetype from ","type":"text"},{"text":"@lib","type":"text","marks":[{"type":"code_inline"}]},{"text":", feed it data, wrap it in ","type":"text"},{"text":"\u003cSection>","type":"text","marks":[{"type":"code_inline"}]},{"text":". Replace the example sections; delete ","type":"text"},{"text":"src/content/example.ts","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"pages/ExamplePage.tsx","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"src/pages/\u003cName>.tsx","type":"text","marks":[{"type":"code_inline"}]},{"text":" — deep dives via ","type":"text"},{"text":"@lib","type":"text","marks":[{"type":"code_inline"}]},{"text":" ","type":"text"},{"text":"\u003cPageShell>","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"src/App.tsx","type":"text","marks":[{"type":"code_inline"}]},{"text":" — wire the ordered ","type":"text"},{"text":"SECTIONS","type":"text","marks":[{"type":"code_inline"}]},{"text":" array and the ","type":"text"},{"text":"PAGES","type":"text","marks":[{"type":"code_inline"}]},{"text":" map.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"The component protocol","type":"text","marks":[{"type":"strong"}]},{"text":" (when a load-bearing concept has no fit in ","type":"text"},{"text":"COMPONENTS.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"):","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Default: build it deck-local","type":"text","marks":[{"type":"strong"}]},{"text":" in ","type":"text"},{"text":"\u003cbase>/\u003cslug>/src/diagrams/\u003cName>.tsx","type":"text","marks":[{"type":"code_inline"}]},{"text":", following ","type":"text"},{"text":"@lib/components/diagrams/SequencePlayer.tsx","type":"text","marks":[{"type":"code_inline"}]},{"text":" conventions.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Promote into ","type":"text","marks":[{"type":"strong"}]},{"text":"\u003cbase>/src/components/","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" only when all three hold:","type":"text","marks":[{"type":"strong"}]},{"text":" (a) it is generic over its data — nothing spec-specific inside, everything arrives via typed props; (b) it maps to a recurring spec shape (a lifecycle, a tree, a timeline, a fan-out…) future decks will plausibly need; (c) it passes the checklist in ","type":"text"},{"text":"reference/component-standards.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" without deck-specific hacks.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"A promotion = the component file ","type":"text"},{"text":"plus its ","type":"text","marks":[{"type":"strong"}]},{"text":"COMPONENTS.md","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" entry in the same change","type":"text","marks":[{"type":"strong"}]},{"text":". An unregistered shared component is a defect (the base's registry check warns — ","type":"text"},{"text":"scripts/validate-roadmap.ts","type":"text","marks":[{"type":"code_inline"}]},{"text":" in iii, ","type":"text"},{"text":"build.mjs","type":"text","marks":[{"type":"code_inline"}]},{"text":" standalone; strict mode makes it fatal).","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Never fork a shared component into the deck to tweak it — extend it via additive, non-breaking props, or build a genuinely different deck-local one. ","type":"text"},{"text":"Modifying an existing shared component requires explicit user approval","type":"text","marks":[{"type":"strong"}]},{"text":" (it re-renders every other deck).","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Built-in spec viewer — do not delete.","type":"text","marks":[{"type":"strong"}]},{"text":" Every deck ships the ","type":"text"},{"text":"#/spec","type":"text","marks":[{"type":"code_inline"}]},{"text":" page: the template wires ","type":"text"},{"text":"spec-docs.ts","type":"text","marks":[{"type":"code_inline"}]},{"text":" (the compile-time glob over the paired spec's markdown) into ","type":"text"},{"text":"@lib/pages/SpecPage","type":"text","marks":[{"type":"code_inline"}]},{"text":" via ","type":"text"},{"text":"PAGES.spec","type":"text","marks":[{"type":"code_inline"}]},{"text":", and the shared ","type":"text"},{"text":"TopNav","type":"text","marks":[{"type":"code_inline"}]},{"text":" renders the ","type":"text"},{"text":"spec","type":"text","marks":[{"type":"code_inline"}]},{"text":" link. The shared markdown renderer strips the frontmatter block. It needs no per-deck content — leave the wiring in place.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"5. Verify — THE SECOND GATE","type":"text"}]},{"type":"paragraph","content":[{"text":"All commands run from ","type":"text"},{"text":"\u003cbase>","type":"text","marks":[{"type":"code_inline"}]},{"text":"'s package (iii: ","type":"text"},{"text":"pnpm --filter iii-website \u003cscript>","type":"text","marks":[{"type":"code_inline"}]},{"text":" from the repo root; standalone: inside ","type":"text"},{"text":"\u003cbase>","type":"text","marks":[{"type":"code_inline"}]},{"text":"):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"pnpm type-check","type":"text","marks":[{"type":"code_inline"}]},{"text":" — the whole roadmap project (shared src + gallery + every deck) must pass strict; fix every error.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"The build must succeed with zero frontmatter-validation or registry-parity warnings — iii: ","type":"text"},{"text":"pnpm build","type":"text","marks":[{"type":"code_inline"}]},{"text":" (the site build runs the roadmap contract checks and emits ","type":"text"},{"text":"dist/roadmap/\u003cslug>/","type":"text","marks":[{"type":"code_inline"}]},{"text":"); standalone: ","type":"text"},{"text":"node build.mjs --only=\u003cslug>","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"pnpm dev","type":"text","marks":[{"type":"code_inline"}]},{"text":" in the background, then dogfood with the ","type":"text"},{"text":"/browse","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" skill","type":"text","marks":[{"type":"strong"}]},{"text":" (never ","type":"text"},{"text":"mcp__claude-in-chrome__*","type":"text","marks":[{"type":"code_inline"}]},{"text":"): load ","type":"text"},{"text":"http://localhost:4321/roadmap/\u003cslug>/","type":"text","marks":[{"type":"code_inline"}]},{"text":" (standalone: ","type":"text"},{"text":":5173/\u003cslug>/","type":"text","marks":[{"type":"code_inline"}]},{"text":"), click the map, run a stepper, toggle the theme, open a deep-dive, open ","type":"text"},{"text":"#/spec","type":"text","marks":[{"type":"code_inline"}]},{"text":" and confirm every markdown file renders (mermaid fences live, no raw frontmatter). Zero console errors; no horizontal body scroll at 375px.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"pnpm build && pnpm preview","type":"text","marks":[{"type":"code_inline"}]},{"text":", then ","type":"text"},{"text":"/browse http://localhost:4321/roadmap/","type":"text","marks":[{"type":"code_inline"}]},{"text":" (standalone: ","type":"text"},{"text":":4173/","type":"text","marks":[{"type":"code_inline"}]},{"text":"): the spec appears on the roadmap timeline in date order under its month, its card shows the frontmatter title/tagline/tags with the day marker in the timeline gutter, and clicking it lands on ","type":"text"},{"text":"/roadmap/\u003cslug>/","type":"text","marks":[{"type":"code_inline"}]},{"text":". If the spec previously served the md-only viewer, confirm the deck replaced it at the same URL.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If anything under ","type":"text","marks":[{"type":"strong"}]},{"text":"\u003cbase>/src/","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" was touched (a promotion): run the full site build","type":"text","marks":[{"type":"strong"}]},{"text":" — a shared change must not break sibling decks.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"reference/quality-bar.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" end to end; fix anything red.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"6. Hand off","type":"text"}]},{"type":"paragraph","content":[{"text":"Report: the deck path (","type":"text"},{"text":"\u003cbase>/\u003cslug>/","type":"text","marks":[{"type":"code_inline"}]},{"text":"), the dev URL, the slide list, which interactions are live, the frontmatter written, and any promoted components (with their registry entries). Offer to flip ","type":"text"},{"text":"status: draft","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"live","type":"text","marks":[{"type":"code_inline"}]},{"text":". Deploy is not a step: ","type":"text"},{"text":"in iii, merging to main ships everything via ","type":"text","marks":[{"type":"strong"}]},{"text":".github/workflows/deploy-website.yml","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" to ","type":"text","marks":[{"type":"strong"}]},{"text":"iii.dev/roadmap/\u003cslug>/","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":"; in other repos ","type":"text"},{"text":"dist/","type":"text","marks":[{"type":"code_inline"}]},{"text":" is a portable static site for whatever CI they use. Do ","type":"text"},{"text":"not","type":"text","marks":[{"type":"strong"}]},{"text":" commit, push, or configure hosting unless asked. Never run ","type":"text"},{"text":"vercel","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Rules","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"The shared layer is law","type":"text","marks":[{"type":"strong"}]},{"text":": never edit ","type":"text"},{"text":"\u003cbase>/src/**","type":"text","marks":[{"type":"code_inline"}]},{"text":", the base's build glue (iii: ","type":"text"},{"text":"website/src/pages/roadmap/","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"scripts/validate-roadmap.ts","type":"text","marks":[{"type":"code_inline"}]},{"text":"; standalone: ","type":"text"},{"text":"build.mjs","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"vite.config.ts","type":"text","marks":[{"type":"code_inline"}]},{"text":"), tsconfigs, ","type":"text"},{"text":"package.json","type":"text","marks":[{"type":"code_inline"}]},{"text":", or the gallery in a deck run. Sole exception: additive component promotion under ","type":"text"},{"text":"reference/component-standards.md","type":"text","marks":[{"type":"code_inline"}]},{"text":", always paired with a ","type":"text"},{"text":"COMPONENTS.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" entry.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"A deck run's write surface is ","type":"text"},{"text":"\u003cbase>/\u003cslug>/**","type":"text","marks":[{"type":"code_inline"}]},{"text":" plus the frontmatter block of ","type":"text"},{"text":"tech-specs/\u003cslug>/README.md","type":"text","marks":[{"type":"code_inline"}]},{"text":". Nothing else.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"tech-specs/","type":"text","marks":[{"type":"code_inline"}]},{"text":" holds markdown only. Never write a non-md file there; never create a ","type":"text"},{"text":"presentation/","type":"text","marks":[{"type":"code_inline"}]},{"text":" directory inside it.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Reuse first: consult ","type":"text"},{"text":"COMPONENTS.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" before building any visual; the repo registry outranks the bundled catalog.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Slug = the spec directory basename, used identically as the deck dir and the URL. Never prettify it. ","type":"text"},{"text":"slug","type":"text","marks":[{"type":"code_inline"}]},{"text":" is never a frontmatter field.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"One claim per slide. Put depth behind a ","type":"text"},{"text":"\u003cSpecSheet>","type":"text","marks":[{"type":"code_inline"}]},{"text":" (","type":"text"},{"text":"\u003cdetails>","type":"text","marks":[{"type":"code_inline"}]},{"text":"), closed by default — execs skim, engineers drill.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ration the accent (success / active / CTA only). Lowercase copy; identifiers keep their casing. No em-dashes. No \"robust / comprehensive / crucial / seamless / unlock\".","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ground every claim in the spec. Keep one honest trade-offs/open-questions beat — honesty reads as credibility.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Quantify the win: use the spec's numbers verbatim; if you compute one, say so.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Decisions","type":"text"}]},{"type":"paragraph","content":[{"text":"Ask the user: the narrative outline (Phase 2, always); output location when occupied; audience tilt (execs vs engineers; default balanced); fonts offline vs CDN (default CDN); scope cap when a spec has many domain docs; first-run base location + gallery identity + the ","type":"text"},{"text":"pnpm-workspace.yaml","type":"text","marks":[{"type":"code_inline"}]},{"text":" edit; any ","type":"text"},{"text":"modification","type":"text","marks":[{"type":"strong"}]},{"text":" to an existing shared component; flipping ","type":"text"},{"text":"status","type":"text","marks":[{"type":"code_inline"}]},{"text":" to ","type":"text"},{"text":"live","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"paragraph","content":[{"text":"Decide yourself: which archetype each slide uses; slide order within the arc; hero line and stats; SVG coordinates and step counts; what goes behind a ","type":"text"},{"text":"\u003cdetails>","type":"text","marks":[{"type":"code_inline"}]},{"text":"; copy voice; the frontmatter field values; deck-local vs promote per the component protocol (announce promotions in the outline and hand-off — don't ask). Everything under ","type":"text"},{"text":"\u003cbase>/src/","type":"text","marks":[{"type":"code_inline"}]},{"text":" and the build glue is settled — never re-litigate it in a deck run.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Verify","type":"text"}]},{"type":"paragraph","content":[{"text":"pnpm type-check","type":"text","marks":[{"type":"code_inline"}]},{"text":" and the roadmap build (iii: ","type":"text"},{"text":"pnpm --filter iii-website build","type":"text","marks":[{"type":"code_inline"}]},{"text":"; standalone: ","type":"text"},{"text":"node build.mjs --only=\u003cslug>","type":"text","marks":[{"type":"code_inline"}]},{"text":") are green with zero registry/frontmatter warnings; ","type":"text"},{"text":"/browse","type":"text","marks":[{"type":"code_inline"}]},{"text":" shows zero console errors, working interactions, and a frontmatter-free ","type":"text"},{"text":"#/spec","type":"text","marks":[{"type":"code_inline"}]},{"text":"; the roadmap timeline lists the spec in date order, its card rendered from the frontmatter; ","type":"text"},{"text":"reference/quality-bar.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" passes; a promotion ran the full build (","type":"text"},{"text":"reference/hosting.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" has the layout this all serves).","type":"text"}]}]},"metadata":{"date":"2026-11-02","name":"presentation","author":"@skillopedia","source":{"stars":18880,"repo_name":"iii","origin_url":"https://github.com/iii-hq/iii/blob/HEAD/skills/presentation/SKILL.md","repo_owner":"iii-hq","body_sha256":"16916565b2b0a93bb5d6d800b382e3adc175e527d10279c8eff3d1aae5b12b9c","cluster_key":"a95984d2d72d3ead4f8ae475128ea7aa87328f6d789dc2355c0a1e52be9b162e","clean_bundle":{"format":"clean-skill-bundle-v1","source":"iii-hq/iii/skills/presentation/SKILL.md","text_bytes":262936,"source_commit":"618a6fbe69f0e09664b9c3b7567dafdf7fd4aec8","skills_sh_rank":5383,"attachment_count":77,"text_attachments":77,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/presentation/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"documents-office","category_label":"Documents"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"documents-office","import_tag":"skills-sh-top20k-2026-11","description":"Turn a tech-spec directory into an interactive, marketing-grade web presentation — built so engineers understand the design, the reader is convinced of the why, and the result is shareable in public. Use when someone wants a spec turned into a deck."}},"renderedAt":1793671350934}

Presentation Turn a technical specification into an interactive, persuasive web deck — the kind at iii.dev/roadmap/. The output is a content layer inside the repo's roadmap base (the shared component library, gallery, and markdown spec viewer that build every deck into one static site — Astro routes of the site package in iii, a standalone Vite project in other repos): 1. helps engineers understand the spec — the architecture is a navigable map, not prose; 2. is interactive — steppable diagrams, a selectable system map, live toggles; interactivity is what makes it stick; 3. reads like marketi…