# Sacred Computer — full doc bundle

> Concatenation of every AGENTS.md and SKILL.md in the sacred repo, in the same
> order as https://sacred.computer/llms.txt. Sacred Computer (React) and Simulacrum
> (CLI) are two halves of one framework — the React surface is documented in
> components/AGENTS.md, the CLI surface in scripts/cli/AGENTS.md and
> scripts/python/AGENTS.md. Component source is available individually at
> https://sacred.computer/llm/components/<Name>.tsx.txt but not included in this
> bundle to keep it focused on contracts.

---

# AGENTS.md

# AGENTS.md

Orientation for any agent working in `www-sacred`. Read this before touching code.

## What this repo is

`www-sacred` (npm package `srcl`) is an open-source React component library with terminal aesthetics. It is consumed in two ways:

1. **A Next.js 16 / React 19 site at `sacred.computer`** that renders every component in a kitchen sink at `app/page.tsx`.
2. **Simulacrum**, a zero-dependency CLI framework under `scripts/cli/lib/` (and a snake_case Python mirror under `scripts/python/sacred_cli/`) so the same layouts can render in a terminal.

Colors flow from one source: `scripts/cli/colors.json`. That file holds the terminal-tested palette. `global.css` mirrors it as `--ansi-*` primitives and builds `--theme-*` tokens on top. The OKLCH tint themes in `global.css` are a web-only derivation. When a color changes, it changes in `colors.json` first.

## Repo map

- `app/` — Next.js App Router. `app/page.tsx` is the kitchen sink. The `/llm/*` routes serve docs as markdown and component source as plain text so agents can fetch them without cloning.
- `components/` — Sacred React components. Read `components/AGENTS.md` first when picking a component. `components/examples/` has larger demo surfaces. `SimpleTable` is the table for CLI ports (maps onto `formatRow` + `cardHeaderRow`). `Window` is the React peer of the CLI window frame.
- `common/` — Constants and utilities shared across components.
- `modules/` — Stand-alone, dependency-free modules: the vendored `hotkeys/` library plus a few vendored Node helpers (`cors.ts`, `vary.ts`, `object-assign.ts`).
- `scripts/cli/` — Simulacrum, the sacred CLI framework (TypeScript, zero dependencies, run via `tsx`). `lib/` is the framework, `lib/__tests__/` is the vitest suite (and the `dump_reference.ts` fixture generator), `templates/` is the canonical TS template, `colors.json` is the shared palette.
- `scripts/python/` — Simulacrum's Python mirror. `sacred_cli/` is the package, `sacred_cli/__tests__/` is the unittest suite (and the parity test against the JS fixture), `templates/` is the canonical Python template.
- `scripts/test_python.ts` — TypeScript orchestrator for `npm run test:python`. Probes for `python3`, regenerates the TS fixture, then invokes `python3 -m unittest discover`. Skips with a warning if `python3` is missing.
- `skills/` — Four porting skills (TS CLI, Python CLI, React-to-React, hostile React host). Read `skills/*/SKILL.md` before porting.
- `.workdir/` — Read-only reference material from sibling projects. Never edit, never ship.

## Conventions

- All comments use `//NOTE(jimmylee): ...` in TS/JS/CSS (no space after `//`, no `@`) and `# NOTE(jimmylee): ...` in Python. Comments explain _why_, not _what_. If the code reads clearly on its own, write no comment — and delete self-documenting comments on sight.
- The CLI framework is intentionally zero-dependency TypeScript, run via `tsx` with no build step.
- The Python framework mirrors the JS framework one-to-one but uses snake_case. The same `colors.json` is the single source of truth — do not duplicate the palette. The two runtimes are locked into byte-identical output by the parity suite under `scripts/python/sacred_cli/__tests__/test_parity.py`. When you change a JS module, port the change to its Python mirror in the same PR — `npm test` will fail otherwise.
- React example components in `components/examples/*` should only depend on sacred's existing primitives (`Card`, `SimpleTable`, `Button`, `RowSpaceBetween`, etc.). The CLI port examples (`CLITemplate`, `InvoiceTemplate`, `ResultsList`) use `SimpleTable`, not `DataTable`, because `SimpleTable`'s column + status contract maps one-to-one onto `formatRow` and `cardHeaderRow`. Do not import from `scripts/cli/lib/*` from React — that code is Node-only and uses `process.stdout`.
- Tests live in four places: `scripts/cli/lib/__tests__/` (CLI framework), `components/__tests__/` (catalog sync guards), `app/llm/__tests__/` (URL surface), and `scripts/python/sacred_cli/__tests__/` (Python + parity). The sync guards keep docs, props, theming tokens, palette colors, and URL surfaces honest against the source. `npm test` runs everything. Run it before opening a PR.
- Sacred CLI ports are static — no animation diffing system. The React side keeps its existing animation primitives (canvas snake, canvas platformer, etc.). The one exception is `OneLineLoaders.tsx` because the spinners are the entire point of that component.

## The Fonts menu previews

The Fonts menu in `components/page/DefaultActionBar.tsx` previews each font in its own typeface on hover/keyboard focus. The pieces fit together like this — keep them in sync when touching any of them:

- The `.font-use-*` rules in `global-fonts.css` only define `--font-family-mono`; a class on its own changes nothing. The `[role='menuitem']:hover/:focus-visible` rule at the top of that file is what applies the variable, letting each menu label (a `<span className="font-use-...">` wrapping the same class its `onClick` passes to `onHandleFontChange`) preview its font without duplicating family names in TSX. The default entry's label uses `font-use-fira-code`, which is intentionally never wired to a click handler (see `components/__tests__/font_sync.test.mjs`).
- Previews are hover/focus-only so the woffs download lazily, one per hovered row, instead of all of them when the menu opens.
- The focus half of the rule must stay `:focus-visible`, not `:focus`: `DropdownMenuTrigger` programmatically focuses the first menu item on open, and with `:focus` the first row (Cascadia Mono) rendered permanently in its own font as if hovered. `:focus-visible` skips that programmatic/mouse focus but still previews while arrow-keying through the menu.
- The preview rule is built so previews cannot resize the open menu: the pinned `line-height` stops vertical growth; `font-size-adjust: 0.5` (a typical monospace x-height ratio) normalizes visual size across fonts with wildly different metrics — a neutral value picked to sit each preview inside its row rather than matched to any one font, so a decorative-metric face (e.g. Mekzantine's tall x) does not upscale out of its row; `contain: inline-size` keeps a wide preview from widening the menu, clipping an over-wide label at the row edge instead.

## Changing the default font

The default font (applied on first mount, before anyone opens the Fonts menu) is a convention spread across four coupled spots — change all four in the same PR or `npm test` fails:

1. `global.css` — the base `--font-family-mono` declaration is the real default. Selecting the default in the menu calls `onHandleFontChange('')`, which strips every `font-use-*` class off `<body>` and falls back to this value. It currently names `'FiraCode-Regular'` (whose `@font-face` lives in `global-fonts.css`).
2. `components/page/DefaultActionBar.tsx` — the default's menu row is wired to `onHandleFontChange('')` (not to its own class) and carries the `[DEFAULT]` tag in its label. Its `<span>` still uses the matching `font-use-*` class so the row previews the default font on hover. Every *other* font's row wires `onHandleFontChange('font-use-<name>')`.
3. `components/__tests__/font_sync.test.mjs` — `DEFAULT_SELECTOR` names the default's `font-use-*` class. That class is the one selector exempt from the "referenced by exactly one menu entry" rule: it must stay in `global-fonts.css` and must *not* be wired to any `onClick`.
4. When you promote a font to default, the font it replaces must gain a normal wired menu row (`onHandleFontChange('font-use-<name>')`), or the test flags its now-unreferenced CSS rule as an unreachable font.
- `contain` also removes a row's own width contribution, so hovering the widest row would shrink the menu — which is why `components/DropdownMenuTrigger.tsx` locks the menu's natural width (`elementRef.current.style.width = ...`) when it opens. That line exists for the previews; do not remove it as a cleanup.

## Scripts

```sh
npm install             # install deps
npm run dev             # Next.js dev server on http://localhost:10000
npm test                # tsc --noEmit + JS vitest suite + Python unittest + parity suite (chained)
npm run test:js         # only the JS vitest suite
npm run test:python     # only the Python suite (skips with a warning if python3 missing)
npm run cli:typescript  # render the canonical TS CLI template (alt screen, ESC to quit)
npm run cli:python      # render the canonical Python CLI template (alt screen, ESC to quit)
```

## Where to start when porting

- **React → CLI (TS):** read `skills/port-sacred-terminal-ui-to-typescript-cli/SKILL.md` and `scripts/cli/templates/template.ts`.
- **React → CLI (Python):** read `skills/port-sacred-terminal-ui-to-python/SKILL.md` and `scripts/python/templates/template.py`.
- **CLI → React (sacred host):** read `skills/port-sacred-terminal-ui-to-react-using-same-conventions/SKILL.md` and any of the `components/examples/CLITemplate.tsx` / `InvoiceTemplate.tsx` / `ResultsList.tsx` files.
- **Sacred → foreign React app:** read `skills/port-sacred-terminal-ui-to-hostile-react-codebase/SKILL.md`.

## Keyboard and hotkey system

Sacred uses a vendored copy of [react-hotkeys-hook](https://github.com/JohannesKlauss/react-hotkeys-hook) at `modules/hotkeys/`. The module is self-contained CommonJS-compatible React code — no npm dependency. It provides `useHotkeys`, `HotkeysProvider`, `isHotkeyPressed`, and `useRecordHotkeys`.

### Architecture

- **`modules/hotkeys/parse-hotkeys.ts`** — parses key strings (`ctrl+a`, `ArrowDown`, `esc`) into a `Hotkey` descriptor with modifier flags (`alt`, `ctrl`, `meta`, `shift`, `mod`) and non-modifier key names. `mod` is a platform-aware shortcut: meta on macOS, ctrl elsewhere.
- **`modules/hotkeys/validators.ts`** — matching logic: `isHotkeyMatchingKeyboardEvent` compares a live `KeyboardEvent` against a parsed `Hotkey`, respecting modifier state. Guards (`isHotkeyEnabledOnTag`, `isKeyboardEventTriggeredByInput`) suppress hotkeys when focus is inside form elements unless explicitly opted in.
- **`modules/hotkeys/use-hotkeys.ts`** — the main hook. Attaches `keydown`/`keyup` listeners to either a ref'd DOM node or `document`. Supports `scopes` for conditional activation, `enableOnFormTags` / `enableOnContentEditable` overrides, `preventDefault`, and `keyup`-only mode.
- **`modules/hotkeys/hotkeys-provider.tsx`** — React context for scope management (`enableScope`, `disableScope`, `toggleScope`) and a registry of all bound hotkeys via `BoundHotkeysProxyProvider`. `HotkeysProvider` is mounted at the app root in `components/Providers.tsx`, activating scope-based hotkey gating for the entire tree.
- **`modules/hotkeys/is-hotkey-pressed.ts`** — global `Set<string>` tracking all currently held keys via document-level `keydown`/`keyup` listeners. Used by `useHotkeys` for multi-key combination matching. Handles the macOS meta-key quirk (clears non-modifier keys when meta is released).
- **`modules/hotkeys/use-record-hotkeys.ts`** — records key combinations pressed by the user into a `Set<string>`, useful for UI that lets users define their own shortcuts.
- **`modules/hotkeys/use-deep-equal-memo.ts`** — memoization helper using `Utilities.deepEqual` to prevent unnecessary re-renders when options objects are structurally equal.

### Where hotkeys are registered

| Component | Hotkeys | Purpose |
| --- | --- | --- |
| `components/page/DefaultActionBar.tsx` | `ArrowDown`, `ArrowUp`, `ArrowRight`, `ArrowLeft`, `Enter`, `Space`, `ctrl+g`, `Escape` | Global focus navigation across all focusable elements + debug grid toggle + dismiss topmost modal |
| `components/DropdownMenuTrigger.tsx` | Configurable via `hotkey` prop (e.g. `ctrl+o`, `ctrl+a`, `ctrl+t`) | Opens/closes a dropdown menu |
| `components/DropdownMenu.tsx` | `Escape` | Closes the active dropdown (fallback for when focus is outside the menu container) |
| `components/modals/ModalError.tsx` | `enter` | Closes the error modal |
| `components/modals/ModalChess.tsx` | `enter` | Closes the chess modal |

### Where keyboard events are handled directly (onKeyDown / addEventListener)

| Component | Keys | Purpose |
| --- | --- | --- |
| `components/DropdownMenu.tsx` | `ArrowDown`, `ArrowUp`, `Enter`, `Space`, `Escape` | Menu item navigation with focus wrapping, activation, and dismiss |
| `components/DataTable.tsx` | `Enter`, arrow keys | Cell navigation and activation within the gradient table |
| `components/ListItem.tsx` | `Enter`, arrow keys | Item activation and sequential focus traversal |
| `components/Select.tsx` | `Enter`, `Space`, `Escape`, arrow keys | Open/close listbox, navigate and select options, dismiss |
| `components/Input.tsx` | Native `onKeyDown` passthrough | Delegates to consumer callback |
| `components/TextArea.tsx` | Native `onKeyDown` passthrough | Delegates to consumer callback |
| `components/Checkbox.tsx` | Native `onKeyDown` via `<input>` | Standard checkbox toggling |
| `components/RadioButton.tsx` | Native `onKeyDown` via `<input>` | Standard radio selection |
| `components/ActionButton.tsx` | `Enter`, `Space` (inline) | Click activation for keyboard users |
| `components/ActionListItem.tsx` | `Enter`, `Space` (inline) | Click activation for keyboard users |
| `components/Accordion.tsx` | `Enter`, `Space` (inline) | Toggle open/close for keyboard users |
| `components/TreeView.tsx` | `Enter`, `Space` (inline) | Toggle expand/collapse for keyboard users |
| `components/CanvasPlatformer.tsx` | Arrow keys, `Space` (window listener) | Player movement and jumping |
| `components/CanvasSnake.tsx` | Arrow keys (window listener) | Snake direction control |
| `components/DOMSnake.tsx` | Arrow keys (window listener) | Snake direction control |

### Integration with the CLI framework

The CLI framework (`scripts/cli/lib/app.ts`) has its own keyboard system based on Node.js `process.stdin` raw mode. It handles `Ctrl-C`, `Escape` (quit), arrow keys (pagination/selection), and `Enter` (selection confirm). This is completely separate from the React hotkey module — the two systems share concepts but no code.

## Working agreements

- Don't commit unless the user explicitly asks. Sacred ships releases manually.
- Don't add features the task didn't ask for. If you find a tangential bug, surface it instead of fixing it silently.
- Don't import from `.workdir/` at runtime. It is reference material only.
- Don't break the kitchen sink. After any component change, render `app/page.tsx` mentally (or in `npm run dev`) and confirm nothing regresses.


---

# components/AGENTS.md

# AGENTS.md — components

Catalog of every React component under `components/`. One entry per `.tsx` file. Subdirectories (`examples/`, `modals/`, `svg/`, `page/`, `detectors/`) are excluded — those compose this library, they are not the library itself.

Tests under `components/__tests__/` enforce that this catalog stays in sync with the source. Adding a component without documenting it here fails CI.

## How to read each entry

- **Path** — where the source file lives.
- **Purpose** — one sentence describing what the component does.
- **Props** — copied from the source `interface` or `type Props` block. Kept in sync by `props_sync.test.mjs`.
- **Theming tokens** — CSS custom properties (`--theme-*`, `--ansi-*`, `--font-*`, etc.) the component uses. Kept in sync by `theming_tokens_sync.test.mjs`. If none, the field reads `(none)`.
- **CLI primitive** — the equivalent in the CLI framework (`scripts/cli/lib/*`). If none exists, the field reads `(React-only)`.
- **Used by** — where the component appears in the kitchen sink or examples. Kept in sync by `component_usage_sync.test.mjs`.

This catalog tells you **what** each component is. The four `skills/port-sacred-terminal-ui-to-*/SKILL.md` files tell you **how** to port one.

## Raw component source

Every `components/*.tsx` file is served at `https://sacred.computer/llm/components/<Name>.tsx.txt`. Fetch the source over HTTP without cloning the repo.

---

## Accordion

- **Path:** `components/Accordion.tsx`
- **Purpose:** Click-to-toggle collapsible section with a title row and a children body.
- **Props:**
  ```ts
  interface AccordionProps {
    defaultValue?: boolean;
    title: string;
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-focused-foreground`
- **CLI primitive:** (React-only) The CLI framework renders flat pages — there is no folding section concept.
- **Used by:** `<Accordion defaultValue={true} title="ACTION BAR">` in the kitchen sink (`app/page.tsx`).

## ASCIICanvas

- **Path:** `components/ASCIICanvas.tsx`
- **Purpose:** Animated ASCII art rendered in a `<pre>` element using per-cell `<span>` elements with DOM diffing.
- **Props:**
  ```ts
  { rows?: number }
  ```
- **Theming tokens:** `--font-family-mono`, `--font-size`, `--theme-line-height-base`
- **CLI primitive:** (React-only) The CLI framework is static — animation belongs on the React side.
- **Used by:** `<ASCIICanvas rows={20} />` in the "ASCII CANVAS" accordion in `app/page.tsx`.

## ActionBar

- **Path:** `components/ActionBar.tsx`
- **Purpose:** Horizontal toolbar of action items, each with optional hotkey and nested dropdown menu.
- **Props:**
  ```ts
  interface ActionBarProps {
    items: ActionBarItem[];
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border`
- **CLI primitive:** `buttonRow` plus repeated `button(hotkey, label)` calls. The CLI version is non-nested; nested dropdowns are React-only.
- **Used by:** `<ActionBar items={[ ... ]} />` inside the "ACTION BAR" accordion in `app/page.tsx`.

## ActionButton

- **Path:** `components/ActionButton.tsx`
- **Purpose:** Hotkey + label button pair, the React peer of the CLI `button` primitive.
- **Props:**
  ```ts
  interface ActionButtonProps {
    onClick?: () => void;
    hotkey?: any;
    children?: React.ReactNode;
    style?: any;
    rootStyle?: any;
    isSelected?: boolean;
  }
  ```
- **Theming tokens:** `--theme-button-background`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--font-family-mono`, `--font-size`
- **CLI primitive:** `button(hotkey, label)` in `scripts/cli/lib/button.ts` (`button(hotkey, label)` in the Python mirror). Pair with `buttonRow(...)` to get the same left/right layout.
- **Used by:** `<ActionButton hotkey="ESC">EXIT</ActionButton>` in `components/examples/CLITemplate.tsx`, `components/examples/InvoiceTemplate.tsx`, `components/examples/ResultsList.tsx`, and the "ACTION BUTTONS" accordion in `app/page.tsx`. Every CLI port surface uses `ActionButton` (not `Button`) so it stays in lockstep with Simulacrum's `button(hotkey, label)` primitive.

## ActionListItem

- **Path:** `components/ActionListItem.tsx`
- **Purpose:** Menu row that renders as either an anchor or a button with a leading icon glyph.
- **Props:**
  ```ts
  interface ActionListItemProps {
    style?: React.CSSProperties;
    icon?: React.ReactNode;
    children?: React.ReactNode;
    href?: string;
    target?: string;
    onClick?: React.MouseEventHandler<HTMLDivElement | HTMLAnchorElement>;
    role?: string;
  }
  ```
- **Theming tokens:** `--theme-button-background`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** `cardRow(formatRow([icon, label], colSpec, innerW), innerW)`. The CLI has no anchor concept — interactive items are wired through `createApp({ interactive, onKey })`.
- **Used by:** `<ActionListItem icon={'⭢'} href="https://internet.dev" target="_blank">` inside the navigation example in `app/page.tsx`.

## AlertBanner

- **Path:** `components/AlertBanner.tsx`
- **Purpose:** Full-width inline notification banner for advisory or warning copy.
- **Props:**
  ```ts
  interface AlertBannerProps {
    style?: any;
    children?: any;
  }
  ```
- **Theming tokens:** `--theme-border`, `--theme-border-subdued`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** `cardTop('!', innerW)` + `cardRow(text, innerW)` + `cardBot(innerW)` — sacred CLI ships no dedicated banner glyph; an unlabeled card row is the convention.
- **Used by:** `<AlertBanner>When things reach the extreme, they alternate to the opposite.</AlertBanner>` in `app/page.tsx`.

## Avatar

- **Path:** `components/Avatar.tsx`
- **Purpose:** Square portrait image (or initials placeholder) with optional inline label and external link.
- **Props:**
  ```ts
  interface AvatarProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'style' | 'className' | 'children'> {
    src?: string;
    href?: string;
    target?: string;
    style?: React.CSSProperties;
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-window-shadow`, `--theme-focused-foreground`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) The CLI is text-only; portraits do not exist there.
- **Used by:** `<Avatar src="..." href="https://internet.dev" target="_blank" />` inside the "AVATARS" accordion in `app/page.tsx`.

## Badge

- **Path:** `components/Badge.tsx`
- **Purpose:** Inline label chip used for short status / version markers next to titles.
- **Props:**
  ```ts
  interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-border`, `--theme-line-height-base`, `--font-family-mono`, `--font-size`
- **CLI primitive:** Plain string concatenated into a `cardRow`. The CLI framework has no badge glyph because monospace runs are already labeled at column boundaries.
- **Used by:** `<Badge>{Package.version}</Badge>` inside the navigation strip in `app/page.tsx`.

## BarLoader

- **Path:** `components/BarLoader.tsx`
- **Purpose:** Fill-style progress bar with optional auto-advancing interval mode.
- **Props:**
  ```ts
  interface BarLoaderProps {
    intervalRate?: number;
    progress?: number;
  }
  ```
- **Theming tokens:** `--theme-border`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) Sacred CLI ports are static — there is no animation diff loop. If you want a CLI progress indicator, render a single `cardRow` with the percentage at draw time.
- **Used by:** `<BarLoader intervalRate={1000} />` and `<BarLoader progress={50} />` inside the "BAR LOADERS" accordion in `app/page.tsx`.

## BarProgress

- **Path:** `components/BarProgress.tsx`
- **Purpose:** Character-based progress bar that fills its container width with a configurable glyph.
- **Props:**
  ```ts
  interface BarProgressProps {
    intervalRate?: number;
    progress?: number;
    fillChar?: string;
  }
  ```
- **Theming tokens:** `--theme-border-subdued`
- **CLI primitive:** (React-only) Same reason as BarLoader — the CLI is static.
- **Used by:** `<BarProgress progress={50} />` inside the "PROGRESS BARS" accordion in `app/page.tsx`.

## Block

- **Path:** `components/Block.tsx`
- **Purpose:** Inline span block used as a 1ch placeholder or measurement spacer in monospace layouts.
- **Props:**
  ```ts
  interface BlockProps extends React.HTMLAttributes<HTMLSpanElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** A single space inside a `cardRow`. The CLI lays out by character grid, so a `<Block>` is implicit.
- **Used by:** `<Block style={{ opacity: 0 }} />` as a sizing spacer in `components/Dialog.tsx`.

## BlockLoader

- **Path:** `components/BlockLoader.tsx`
- **Purpose:** Single-glyph spinner cycling through a Unicode box-drawing or block animation sequence.
- **Props:**
  ```ts
  interface BlockLoaderProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'children'> {
    mode?: number;
  }
  ```
- **Theming tokens:** `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) Sacred CLI ports are static. `OneLineLoaders.tsx` is the explicit React-side carve-out for spinners.
- **Used by:** `<BlockLoader mode={0} />` (and modes 1-11) inside the "BLOCK LOADERS" accordion in `app/page.tsx`.

## BreadCrumbs

- **Path:** `components/BreadCrumbs.tsx`
- **Purpose:** Linked breadcrumb trail with visual separators between hierarchy levels.
- **Props:**
  ```ts
  interface BreadCrumbsProps {
    items: BreadCrumbsItem[];
  }
  ```
- **Theming tokens:** `--theme-border`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`
- **CLI primitive:** A `cardRow` with `path / segments / joined / by / slashes`. The CLI has no link concept.
- **Used by:** `<BreadCrumbs items={[...]} />` inside the "BREADCRUMBS" accordion in `app/page.tsx`.

## Button

- **Path:** `components/Button.tsx`
- **Purpose:** Two-theme HTML `<button>` (PRIMARY / SECONDARY) with disabled-state styling.
- **Props:**
  ```ts
  interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
    theme?: 'PRIMARY' | 'SECONDARY';
    isDisabled?: boolean;
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border`, `--theme-button`, `--theme-button-background`, `--theme-button-foreground`, `--theme-button-text`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-family-mono`, `--font-size`
- **CLI primitive:** `button(hotkey, label)` (no theme variants — CLI buttons are uniform).
- **Used by:** `<Button>Primary Button</Button>` inside the "BUTTONS" accordion in `app/page.tsx`. Use `ActionButton` instead when porting CLI screens.

## ButtonGroup

- **Path:** `components/ButtonGroup.tsx`
- **Purpose:** Horizontal cluster of `ActionButton`s with selected-state highlighting and optional nested dropdown items.
- **Props:** _(untyped — `props.items: { body, hotkey?, selected?, onClick?, items?, openHotkey? }[]`, `props.isFull?: boolean`)_
- **Theming tokens:** (none)
- **CLI primitive:** `buttonRow(button(...), button(...), innerW)` repeated for each pair.
- **Used by:** `<ButtonGroup items={[{ body: '16 PX', selected: true }, { body: '32 PX' }, { body: '42 PX' }]} />` inside the "BUTTON GROUP" accordion in `app/page.tsx`.

## CanvasPlatformer

- **Path:** `components/CanvasPlatformer.tsx`
- **Purpose:** ASCII-grid 2D platformer mini-game with gravity, block placement, keyboard controls, and touch region controls for mobile (left third = move left, right third = move right, center = jump, multi-touch supported). Renders via pre/span grid with DOM diffing instead of canvas.
- **Props:**
  ```ts
  interface PlatformerProps {
    rows?: number;
  }
  ```
- **Theming tokens:** `--theme-focused-foreground`, `--font-size`, `--theme-line-height-base`
- **CLI primitive:** (React-only) Sacred CLI ports are static; no animation diffing.
- **Used by:** `<CanvasPlatformer rows={12} />` inside the ModalCanvasPlatformer modal triggered from `app/page.tsx`.

## CanvasSnake

- **Path:** `components/CanvasSnake.tsx`
- **Purpose:** ASCII-grid Snake mini-game with directional input (keyboard arrows and swipe gestures on mobile) and food collection. Renders via pre/span grid with DOM diffing instead of canvas.
- **Props:**
  ```ts
  interface SnakeProps {
    rows?: number;
  }
  ```
- **Theming tokens:** `--theme-focused-foreground`, `--font-size`, `--theme-line-height-base`
- **CLI primitive:** (React-only) Same reason as CanvasPlatformer.
- **Used by:** `<CanvasSnake rows={12} />` inside the ModalCanvasSnake modal triggered from `app/page.tsx`.

## Card

- **Path:** `components/Card.tsx`
- **Purpose:** Box-drawing card with a title bar and three corner modes (`default`, `'left'`, `'right'`).
- **Props:**
  ```ts
  interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
    children?: React.ReactNode;
    title?: string | any;
    mode?: string | any;
  }
  ```
- **Theming tokens:** `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** `cardTop(title, innerW)` + `cardRow(content, innerW)` + `cardBot(innerW)` (`scripts/cli/lib/card.ts`).
- **Used by:** `<Card title="EXAMPLE">...</Card>` repeated throughout `app/page.tsx`, and `<Card title="SACRED CLI / TEMPLATE" mode="left">` in `components/examples/CLITemplate.tsx`.

## CardDouble

- **Path:** `components/CardDouble.tsx`
- **Purpose:** Card variant with a double-stroke outer border, used for nested or emphasis groupings.
- **Props:**
  ```ts
  interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
    children?: React.ReactNode;
    title?: string | any;
    mode?: string | any;
    style?: any;
  }
  ```
- **Theming tokens:** `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) The sacred CLI framework only ships single-border cards in `scripts/cli/lib/card.ts`.
- **Used by:** `<CardDouble title={entry[0]}>...</CardDouble>` inside `components/ComboBox.tsx`.

## Checkbox

- **Path:** `components/Checkbox.tsx`
- **Purpose:** Custom-styled checkbox with click + keyboard toggling and a children label slot.
- **Props:**
  ```ts
  interface CheckboxProps {
    style?: React.CSSProperties;
    checkboxStyle?: React.CSSProperties;
    name: string;
    defaultChecked?: boolean;
    onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
    tabIndex?: number;
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-border-subdued`, `--theme-button-background`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`
- **CLI primitive:** `cardRow('[x] label', innerW)` rendered manually by the template; sacred CLI ships no checkbox primitive yet.
- **Used by:** `<Checkbox name="1">...</Checkbox>` inside the "CHECKBOX" accordion in `app/page.tsx`.

## Chessboard

- **Path:** `components/Chessboard.tsx`
- **Purpose:** 8×8 grid renderer that draws Unicode chess pieces from a 2D position array.
- **Props:**
  ```ts
  interface ChessboardProps {
    board: string[][];
  }
  ```
- **Theming tokens:** `--theme-border-subdued`, `--theme-focused-foreground-subdued`, `--theme-focused-foreground`, `--theme-line-height-base`
- **CLI primitive:** (React-only) The CLI framework has no grid primitive; a CLI port would render the board with eight `cardRow` calls of joined glyphs.
- **Used by:** `<Chessboard board={Constants.CHESSBOARD_DEFAULT_POSITIONS} />` inside the "CHESSBOARD" accordion in `app/page.tsx`.

## CodeBlock

- **Path:** `components/CodeBlock.tsx`
- **Purpose:** Pre-formatted source code block with line numbers and a fixed monospace style.
- **Props:**
  ```ts
  interface CodeBlockProps extends React.HTMLAttributes<HTMLPreElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border-subdued`
- **CLI primitive:** A `cardRow` per line of source. The CLI has no syntax highlighting because the framework is colorless except for status columns.
- **Used by:** `<CodeBlock>...</CodeBlock>` inside the "CODE BLOCK" accordion in `app/page.tsx`.

## ComboBox

- **Path:** `components/ComboBox.tsx`
- **Purpose:** Searchable input + filtered result cards combo, optionally backed by a dataset.
- **Props:**
  ```ts
  interface ComboBoxProps {
    data: string[][];
    label?: string;
  }
  ```
- **Theming tokens:** (inherited from `Input` and `CardDouble`)
- **CLI primitive:** `createApp({ interactive: { count, onSelect } })` plus `cardSelectRow` for each filtered row. Sacred CLI's interactive selection lifecycle is the equivalent.
- **Used by:** `<ComboBox data={Constants.LANDSCAPES} label="SEARCH THE WORLD" />` inside the "COMBO BOX" accordion in `app/page.tsx`.

## ContentFluid

- **Path:** `components/ContentFluid.tsx`
- **Purpose:** Block container that expands to the full available width, used as the page-content shell.
- **Props:**
  ```ts
  interface ContentFluidProps extends React.HTMLAttributes<HTMLSpanElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** (none)
- **CLI primitive:** `getInnerWidth(termW)` plus the surrounding window frame in `scripts/cli/lib/window.ts` — the CLI framework computes width once and the templates fill it.
- **Used by:** `<ContentFluid>...</ContentFluid>` inside the "DRAWER" accordion in `app/page.tsx`.

## DataTable

- **Path:** `components/DataTable.tsx`
- **Purpose:** Gradient-tinted interactive data table that animates background fill on cell change.
- **Props:**
  ```ts
  interface TableProps {
    data: string[][];
  }
  ```
- **Theming tokens:** `--theme-focused-foreground-subdued`, `--theme-focused-foreground`
- **CLI primitive:** (React-only) The CLI port story uses `SimpleTable` instead because `SimpleTable`'s column + status contract maps one-to-one onto `formatRow`. `DataTable`'s gradient backgrounds are not part of the CLI surface — do not use it for CLI ports.
- **Used by:** `<DataTable data={Constants.SAMPLE_TABLE_DATA_CHANGE_ME} />` inside the "DATA TABLE" accordion in `app/page.tsx`.

## DatePicker

- **Path:** `components/DatePicker.tsx`
- **Purpose:** Calendar widget with month navigation and day cell selection in a 7-column grid.
- **Props:**
  ```ts
  interface DatePickerProps {
    year?: number;
    month?: number;
  }
  ```
- **Theming tokens:** `--theme-border-subdued`, `--theme-border`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`
- **CLI primitive:** (React-only) No date grid in the CLI framework yet — a port would render rows of `formatRow` cells.
- **Used by:** `<DatePicker year={2012} month={12} />` inside the "DATE PICKER" accordion in `app/page.tsx`.

## DebugGrid

- **Path:** `components/DebugGrid.tsx`
- **Purpose:** Hidden character-grid overlay for visualizing alignment during layout work.
- **Props:** _(no props)_
- **Theming tokens:** `--theme-border`
- **CLI primitive:** (React-only) The CLI framework already snaps to character columns by definition.
- **Used by:** `<DebugGrid />` rendered above the kitchen sink in `app/page.tsx`.

## DefaultMetaTags

- **Path:** `components/DefaultMetaTags.tsx`
- **Purpose:** Static `<head>` metadata block for viewport, language, and favicon defaults.
- **Props:** _(no props)_
- **Theming tokens:** (none)
- **CLI primitive:** (React-only) HTML metadata has no CLI analogue.
- **Used by:** `app/head.tsx` for the kitchen sink page.

## Dialog

- **Path:** `components/Dialog.tsx`
- **Purpose:** Lightweight modal dialog with a title slot, body slot, and OK/Cancel actions.
- **Props:**
  ```ts
  interface DialogProps {
    title?: React.ReactNode;
    children?: React.ReactNode;
    style?: React.CSSProperties;
    onConfirm?: () => void;
    onCancel?: () => void;
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border-subdued`, `--theme-border`, `--theme-text`
- **CLI primitive:** A bordered card plus a `buttonRow(button('ESC','cancel'), button('↵','ok'), innerW)`.
- **Used by:** `<Dialog title="FAREWELL">...</Dialog>` inside the "DIALOG" accordion in `app/page.tsx`.

## Divider

- **Path:** `components/Divider.tsx`
- **Purpose:** Horizontal rule with three styles: single, double, and gradient.
- **Props:**
  ```ts
  interface DividerProps extends React.HTMLAttributes<HTMLSpanElement> {
    children?: React.ReactNode;
    type?: string | any;
    style?: any;
  }
  ```
- **Theming tokens:** `--theme-border`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** A `cardRow` of `'─'` glyphs (or `'═'` for double) at full inner width. The CLI framework has no dedicated divider helper.
- **Used by:** `<Divider type="DOUBLE" />` inside the "DIVIDERS" accordion in `app/page.tsx`.

## DOMSnake

- **Path:** `components/DOMSnake.tsx`
- **Purpose:** DOM-grid Snake mini-game (sibling of `CanvasSnake`) using CSS cells instead of canvas pixels.
- **Props:**
  ```ts
  interface SnakeGameProps {
    width?: number;
    height?: number;
    startSpeed?: number;
  }
  ```
- **Theming tokens:** `--theme-focused-foreground`, `--theme-text`
- **CLI primitive:** (React-only) Animation game.
- **Used by:** `<DOMSnake />` inside the "DOM SNAKE" accordion in `app/page.tsx`.

## Drawer

- **Path:** `components/Drawer.tsx`
- **Purpose:** Collapsible sidebar drawer with a single toggle button and an animated hide/show state.
- **Props:**
  ```ts
  interface DrawerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'defaultValue'> {
    children?: React.ReactNode;
    defaultValue?: boolean;
  }
  ```
- **Theming tokens:** `--theme-background-input`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) The CLI alt-screen is a single window; there is no drawer concept.
- **Used by:** `<Drawer>...</Drawer>` inside the "DRAWER" accordion in `app/page.tsx`.

## DropdownMenu

- **Path:** `components/DropdownMenu.tsx`
- **Purpose:** Floating list of action items with `role="menu"`, arrow-key navigation with focus wrapping, Enter/Space activation, and Escape to dismiss. Each item receives `role="menuitem"`.
- **Props:**
  ```ts
  interface DropdownMenuProps extends React.HTMLAttributes<HTMLDivElement> {
    onClose?: (event?: MouseEvent | TouchEvent | KeyboardEvent) => void;
    items?: DropdownMenuItemProps[];
  }
  ```
- **Theming tokens:** `--theme-background-modal-footer`, `--theme-border`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** Sacred CLI's `createApp({ interactive: { count, onSelect } })` lifecycle plus `cardSelectRow` is the closest equivalent.
- **Used by:** Wired through `DropdownMenuTrigger` inside the "DROPDOWN MENU" accordion in `app/page.tsx`.

## DropdownMenuTrigger

- **Path:** `components/DropdownMenuTrigger.tsx`
- **Purpose:** Wrapper that opens an associated `DropdownMenu` on click or hotkey, dismisses on outside click, and returns focus to the trigger element when the menu closes.
- **Props:**
  ```ts
  interface DropdownMenuTriggerProps {
    children: React.ReactElement<React.HTMLAttributes<HTMLElement>>;
    items: any;
    hotkey?: string;
  }
  ```
- **Theming tokens:** `--z-index-page-dropdown-menus`
- **CLI primitive:** (React-only) Hover/click trigger interaction is browser-specific.
- **Used by:** `<DropdownMenuTrigger items={...}>...</DropdownMenuTrigger>` inside the "DROPDOWN MENU" accordion in `app/page.tsx`.

## Grid

- **Path:** `components/Grid.tsx`
- **Purpose:** Responsive multi-column grid container that wraps its children in a flexible grid track.
- **Props:**
  ```ts
  interface GridProps extends React.HTMLAttributes<HTMLDivElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-line-height-base`, `--font-size`
- **CLI primitive:** Multiple `cardRow(formatRow(...), innerW)` calls — the CLI framework treats every layout as a single column, multiple rows.
- **Used by:** `<Grid>...</Grid>` wraps the navigation strip near the top of `app/page.tsx`.

## HoverComponentTrigger

- **Path:** `components/HoverComponentTrigger.tsx`
- **Purpose:** Wrapper that pops a tooltip or popover on hover/click with auto-positioning and outside-click dismissal.
- **Props:**
  ```ts
  interface HoverComponentTriggerProps {
    children: React.ReactElement<React.HTMLAttributes<HTMLElement>>;
    text: string;
    component: 'popover' | 'tooltip';
  }
  ```
- **Theming tokens:** `--z-index-page-popover`, `--z-index-page-tooltips`
- **CLI primitive:** (React-only) Hover-driven UI is browser-specific.
- **Used by:** `<HoverComponentTrigger text="..." component="tooltip">` inside the "TOOLTIP" accordion in `app/page.tsx`.

## Indent

- **Path:** `components/Indent.tsx`
- **Purpose:** Wrapper that applies a left padding to its children for nested content blocks.
- **Props:**
  ```ts
  interface IndentProps extends React.HTMLAttributes<HTMLDivElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** (none)
- **CLI primitive:** Manual `' '.repeat(N)` prefix inside `cardRow`. The CLI framework leaves indentation up to the template.
- **Used by:** `<Indent>...</Indent>` inside the "AVATARS" accordion in `app/page.tsx`.

## Input

- **Path:** `components/Input.tsx`
- **Purpose:** Single-line text input with a custom caret glyph, password masking, and optional label.
- **Props:**
  ```ts
  type InputProps = React.InputHTMLAttributes<HTMLInputElement> & {
    caretChars?: string | any;
    label?: string | any;
    isBlink?: boolean;
  };
  ```
- **Theming tokens:** `--theme-background-input`, `--theme-background`, `--theme-border`, `--theme-focused-foreground`, `--theme-overlay`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) The CLI templates capture keystrokes through `createApp({ onKey })` and compose their own input strings — sacred CLI ships no boxed input primitive.
- **Used by:** `<Input label="MULTIPLE INPUTS" autoComplete="off" isBlink={false} name="input_test_empty" />` inside the "INPUT" accordion in `app/page.tsx`.

## ListItem

- **Path:** `components/ListItem.tsx`
- **Purpose:** Keyboard-focusable list row with Enter / arrow-key navigation between siblings.
- **Props:** _(untyped — accepts standard `<li>` HTML attributes)_
- **Theming tokens:** `--theme-focused-foreground`
- **CLI primitive:** `cardRow` with manual prefix glyphs.
- **Used by:** `<ListItem>` inside the "LINK" accordion in `app/page.tsx`.

## MatrixLoader

- **Path:** `components/MatrixLoader.tsx`
- **Purpose:** Matrix-rain effect rendered via pre/span grid with DOM diffing. Configurable direction and Greek/Katakana glyph mode.
- **Props:**
  ```ts
  interface MatrixLoaderProps {
    rows?: number;
    direction?: undefined | 'top-to-bottom' | 'left-to-right';
    mode?: undefined | 'greek' | 'katakana';
  }
  ```
- **Theming tokens:** `--font-size`, `--theme-line-height-base`
- **CLI primitive:** (React-only) Animation surface.
- **Used by:** `<MatrixLoader rows={32} mode="katakana" />` inside the ModalMatrixModes modal triggered from `app/page.tsx`.

## Message

- **Path:** `components/Message.tsx`
- **Purpose:** Chat message bubble (left-tail) for outgoing user messages.
- **Props:** _(untyped — accepts an optional children prop)_
- **Theming tokens:** `--theme-border-subdued`, `--theme-border`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** A `cardRow` per wrapped line with no special styling.
- **Used by:** `<Message>...</Message>` inside `components/examples/MessagesInterface.tsx`.

## MessageViewer

- **Path:** `components/MessageViewer.tsx`
- **Purpose:** Chat message bubble (right-tail) for incoming messages from another participant.
- **Props:** _(untyped — accepts an optional children prop)_
- **Theming tokens:** `--theme-focused-foreground`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** Same as `Message` — a `cardRow` per wrapped line.
- **Used by:** `<MessageViewer>...</MessageViewer>` inside `components/examples/MessagesInterface.tsx`.

## ModalStack

- **Path:** `components/ModalStack.tsx`
- **Purpose:** Stacked modal overlay container that manages z-index ordering and backdrop blur.
- **Props:** _(no props)_
- **Theming tokens:** `--z-index-page-modals`
- **CLI primitive:** (React-only) The CLI alt-screen has a single layer.
- **Used by:** `<ModalStack />` mounted directly in `app/page.tsx` for any `ModalTrigger` in the kitchen sink.

## ModalTrigger

- **Path:** `components/ModalTrigger.tsx`
- **Purpose:** Wraps its children in a `display: contents` span whose click opens the given modal component through the `useModals()` context.
- **Props:**
  ```ts
  interface ModalTriggerProps {
    children: React.ReactNode;
    modal: React.ComponentType<any>;
    modalProps?: Record<string, any>;
  }
  ```
- **Theming tokens:** (none)
- **CLI primitive:** (React-only) See `ModalStack`.
- **Used by:** `<ModalTrigger modal={ModalCreateAccount}>` inside the "MODAL" accordion in `app/page.tsx`.

## Navigation

- **Path:** `components/Navigation.tsx`
- **Purpose:** Top navigation bar with logo, left/right slot rails, and a center children slot.
- **Props:**
  ```ts
  interface NavigationProps extends React.HTMLAttributes<HTMLElement> {
    children?: React.ReactNode;
    logoHref?: string;
    logoTarget?: React.HTMLAttributeAnchorTarget;
    onClickLogo?: React.MouseEventHandler<HTMLButtonElement>;
    logo?: React.ReactNode;
    left?: React.ReactNode;
    right?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-border`, `--theme-focused-foreground`, `--theme-text`, `--font-size`
- **CLI primitive:** A `buttonRow(left, right, innerW)` plus a leading `cardRow` for the title.
- **Used by:** `<Navigation logo="✶" ...>` inside the "NAVIGATION BAR" accordion in `app/page.tsx`.

## NumberRangeSlider

- **Path:** `components/NumberRangeSlider.tsx`
- **Purpose:** Range slider with a labeled current value and configurable min/max/step bounds.
- **Props:**
  ```ts
  interface RangerProps {
    defaultValue?: number;
    max?: number;
    min?: number;
    step?: number;
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border-subdued`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) Pointer-driven slider — port to a discrete `formatRow` of step labels if you need a CLI version.
- **Used by:** `<NumberRangeSlider defaultValue={50} />` inside the "NUMBER RANGE SLIDER" accordion in `app/page.tsx`.

## Popover

- **Path:** `components/Popover.tsx`
- **Purpose:** Generic floating panel container reused by `DropdownMenu` and `HoverComponentTrigger`.
- **Props:**
  ```ts
  interface PopoverProps extends React.HTMLAttributes<HTMLDivElement> {}
  ```
- **Theming tokens:** `--theme-border-subdued`, `--theme-border`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) See `DropdownMenu`.
- **Used by:** Mounted by `HoverComponentTrigger` in the "POPOVER" accordion in `app/page.tsx`.

## Providers

- **Path:** `components/Providers.tsx`
- **Purpose:** Top-level context provider wrapping the app in `HotkeysProvider` and `ModalProvider`.
- **Props:**
  ```ts
  interface ProvidersProps {
    children: React.ReactNode;
  }
  ```
- **Theming tokens:** (none)
- **CLI primitive:** (React-only) Sacred CLI is a single process; there is no provider tree.
- **Used by:** `app/layout.tsx`.

## RadioButton

- **Path:** `components/RadioButton.tsx`
- **Purpose:** Custom-styled radio input with click + arrow-key selection inside a `RadioButtonGroup`.
- **Props:**
  ```ts
  interface RadioButtonProps {
    style?: React.CSSProperties;
    name: string;
    value: string;
    selected?: boolean;
    onSelect?: (value: string) => void;
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border-subdued`, `--theme-button-background`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** `cardSelectRow(content, innerW, isSelected)` driven by `createApp({ interactive: { count, onSelect } })`.
- **Used by:** Inside `RadioButtonGroup` in the "RADIO BUTTON" accordion in `app/page.tsx`.

## RadioButtonGroup

- **Path:** `components/RadioButtonGroup.tsx`
- **Purpose:** Container that owns the selected value across a list of `RadioButton` siblings.
- **Props:**
  ```ts
  interface RadioButtonGroupProps {
    options: { value: string; label: string }[];
    defaultValue?: string;
  }
  ```
- **Theming tokens:** (none)
- **CLI primitive:** Same as `RadioButton` — `createApp` with `interactive: { count, onSelect, persist: true }`.
- **Used by:** `<RadioButtonGroup options={[...]} defaultValue="..." />` in the "RADIO BUTTON" accordion in `app/page.tsx`.

## Row

- **Path:** `components/Row.tsx`
- **Purpose:** Block-level row container with focus styling.
- **Props:**
  ```ts
  type RowProps = React.HTMLAttributes<HTMLElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** `--theme-focused-foreground`
- **CLI primitive:** A single `cardRow(content, innerW)`.
- **Used by:** `<Row>...</Row>` near the top of `app/page.tsx`.

## RowEllipsis

- **Path:** `components/RowEllipsis.tsx`
- **Purpose:** Row container with `text-overflow: ellipsis` for single-line truncation.
- **Props:**
  ```ts
  type RowEllipsisProps = React.HTMLAttributes<HTMLElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** `--theme-focused-foreground`
- **CLI primitive:** `truncateVisible(line, innerW)` from `scripts/cli/lib/ansi.ts`.
- **Used by:** `<RowEllipsis>...</RowEllipsis>` as the dimmed single-line chat preview (`ChatPreviewInline`) in `components/examples/MessagesInterface.tsx`.

## RowSpaceBetween

- **Path:** `components/RowSpaceBetween.tsx`
- **Purpose:** Flexbox row that pushes its first and last child to opposite ends.
- **Props:**
  ```ts
  type RowSpaceBetweenProps = React.HTMLAttributes<HTMLElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** (none)
- **CLI primitive:** `buttonRow(left, right, innerW)` in `scripts/cli/lib/button.ts`.
- **Used by:** `<RowSpaceBetween><span><ActionButton hotkey="ESC">EXIT</ActionButton></span><span><ActionButton hotkey="↵">SELECT</ActionButton></span></RowSpaceBetween>` in `components/examples/CLITemplate.tsx`, with the same shape repeated in `components/examples/InvoiceTemplate.tsx` (ESC EXIT / ↵ SUBMIT) and `components/examples/ResultsList.tsx` (ESC EXIT / ← PREV → NEXT).

## Select

- **Path:** `components/Select.tsx`
- **Purpose:** Custom dropdown select with keyboard navigation and styled option list.
- **Props:**
  ```ts
  interface SelectProps {
    name: string;
    options: string[];
    placeholder?: string;
    defaultValue?: string;
    onChange?: (selectedValue: string) => void;
  }
  ```
- **Theming tokens:** `--theme-background`, `--theme-border-subdued`, `--theme-border`, `--theme-button-foreground`, `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-family-mono`, `--font-size`, `--z-index-page-select`
- **CLI primitive:** `createApp({ interactive: { count, onSelect } })` plus `cardSelectRow`.
- **Used by:** `<Select name="select_test" options={[...]} />` inside the "SELECT" accordion in `app/page.tsx`.

## SidebarLayout

- **Path:** `components/SidebarLayout.tsx`
- **Purpose:** Two-column layout with a draggable sidebar handle and optional reversed column order.
- **Props:**
  ```ts
  interface SidebarLayoutProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'defaultValue'> {
    children?: React.ReactNode;
    sidebar?: React.ReactNode;
    defaultSidebarWidth?: number;
    isShowingHandle?: boolean;
    isReversed?: boolean;
  }
  ```
- **Theming tokens:** `--theme-focused-foreground`, `--theme-text`
- **CLI primitive:** (React-only) The CLI uses a single full-width window — there is no resizable sidebar.
- **Used by:** `<SidebarLayout sidebar={...}>...</SidebarLayout>` inside the "SIDEBAR LAYOUT" accordion in `app/page.tsx`.

## SimpleTable

- **Path:** `components/SimpleTable.tsx`
- **Purpose:** Fluid HTML table that mirrors the CLI framework's `formatRow` + `cardHeaderRow` contract one-to-one. First row is the header. Status coloring fires on `ACTIVE`/`OPEN`/`APPROVED` (bold green) and `CLOSED`/`PAID`/`SUSPENDED` (gray). Use this table — not `DataTable` — for any CLI port surface. The table is wrapped in a `scrollWrapper` div with `overflow-x: auto` (and `overflow-y: hidden`, to suppress the spurious native vertical bar the browser paints when only one axis is set) so it scrolls horizontally inside its container on narrow viewports instead of forcing page-level scroll. The horizontal bar uses the same custom scrollbar as `global.css` — `1ch` wide, one line tall, painted from `--theme-border` and `--theme-background` — so it reads as sacred, not native.
- **Props:**
  ```ts
  interface SimpleTableProps {
    data: string[][];
    align?: ('left' | 'right')[];
  }
  ```
- **Theming tokens:** `--ansi-10-lime`, `--ansi-240-gray-35`, `--ansi-248-gray-66`, `--color-white`, `--theme-background`, `--theme-border`, `--theme-focused-foreground`, `--theme-line-height-base`
- **CLI primitive:** `cardHeaderRow(formatRow(TH, COL_SPEC, innerW), innerW)` for the header plus `cardRow(formatRow(row, COL_SPEC, innerW), innerW)` for each body row. The status set is the contract — `ACTIVE`/`OPEN`/`APPROVED` and `CLOSED`/`PAID`/`SUSPENDED`.
- **Used by:** `<SimpleTable data={PRIMITIVES} />` in `components/examples/CLITemplate.tsx`, `<SimpleTable data={LINE_ITEMS} align={LINE_ITEM_ALIGN} />` in `components/examples/InvoiceTemplate.tsx`, `<SimpleTable data={RESULTS} />` in `components/examples/ResultsList.tsx`.

## Table

- **Path:** `components/Table.tsx`
- **Purpose:** Semantic `<table>` wrapper that renders a `<tbody>` shell for sacred-styled tables.
- **Props:**
  ```ts
  type TableProps = React.HTMLAttributes<HTMLElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** (none)
- **CLI primitive:** A column of `cardRow(formatRow(...))` calls — there is no separate `<table>` analogue in the CLI.
- **Used by:** `<Table>...</Table>` inside the "TABLE" accordion in `app/page.tsx`.

## TableColumn

- **Path:** `components/TableColumn.tsx`
- **Purpose:** Semantic `<td>` wrapper used inside `Table`/`TableRow`.
- **Props:**
  ```ts
  type TableColumnProps = React.HTMLAttributes<HTMLTableCellElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** `--font-size`
- **CLI primitive:** A single cell inside `formatRow`.
- **Used by:** Inside `<TableRow>` in the "TABLE" accordion in `app/page.tsx`.

## TableRow

- **Path:** `components/TableRow.tsx`
- **Purpose:** Semantic `<tr>` wrapper with focus styling for keyboard navigation.
- **Props:**
  ```ts
  type TableRowProps = React.HTMLAttributes<HTMLElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** `--theme-focused-foreground`
- **CLI primitive:** A single row inside `formatRow`.
- **Used by:** `<TableRow>...</TableRow>` inside `<Table>` in the "TABLE" accordion in `app/page.tsx`.

## Text

- **Path:** `components/Text.tsx`
- **Purpose:** Semantic `<p>` paragraph wrapper for body copy.
- **Props:**
  ```ts
  interface TextProps extends React.HTMLAttributes<HTMLParagraphElement> {
    children?: React.ReactNode;
  }
  ```
- **Theming tokens:** (none)
- **CLI primitive:** `wordWrap(text, contentW)` in `scripts/cli/lib/card.ts`, fed into a sequence of `cardRow` calls.
- **Used by:** Imported in `app/page.tsx` but not currently rendered in the kitchen sink.

## TextArea

- **Path:** `components/TextArea.tsx`
- **Purpose:** Multi-line text input with auto-resizing height, custom caret, and an optional autoplay typewriter mode.
- **Props:**
  ```ts
  type TextAreaProps = React.TextareaHTMLAttributes<HTMLTextAreaElement> & {
    autoPlay?: string;
    autoPlaySpeedMS?: number;
    isBlink?: boolean;
  };
  ```
- **Theming tokens:** `--theme-focused-foreground`, `--theme-text`, `--theme-line-height-base`, `--font-size`
- **CLI primitive:** (React-only) The CLI captures keystrokes through `createApp({ onKey })`.
- **Used by:** `<TextArea autoPlay="..." />` inside the "TEXT AREA" accordion in `app/page.tsx`.

## Tooltip

- **Path:** `components/Tooltip.tsx`
- **Purpose:** Generic short-text tooltip container, mounted by `HoverComponentTrigger`.
- **Props:**
  ```ts
  interface TooltipProps extends React.HTMLAttributes<HTMLDivElement> {}
  ```
- **Theming tokens:** `--theme-border-subdued`, `--theme-border`
- **CLI primitive:** (React-only) Hover-driven UI is browser-specific.
- **Used by:** Mounted via `<HoverComponentTrigger component="tooltip">` in the "TOOLTIP" accordion in `app/page.tsx`.

## TreeView

- **Path:** `components/TreeView.tsx`
- **Purpose:** Hierarchical file/folder tree with expand/collapse toggles and Unicode branch glyphs.
- **Props:**
  ```ts
  interface TreeViewProps {
    children?: React.ReactNode;
    defaultValue?: boolean;
    depth?: number;
    isFile?: boolean;
    isLastChild?: boolean;
    isRoot?: boolean;
    parentLines?: boolean[];
    style?: any;
    title: string;
  }
  ```
- **Theming tokens:** `--theme-focused-foreground`
- **CLI primitive:** A sequence of `cardRow` calls with manually composed `'├──'` / `'└──'` glyphs.
- **Used by:** `<TreeView title="root">...</TreeView>` inside the "TREE VIEW" accordion in `app/page.tsx`.

## Window

- **Path:** `components/Window.tsx`
- **Purpose:** Terminal-window frame for sacred React surfaces — slight off-background body fill plus a `1ch` right + 1-row bottom drop shadow (intentionally a step darker than the body so the panel reads as "lifted") that mirrors Simulacrum's window primitive. Uses a responsive `min-width: min(24ch, 100%)` so the window shrinks gracefully on narrow viewports (320px and up) without forcing horizontal scroll.
- **Props:**
  ```ts
  type WindowProps = React.HTMLAttributes<HTMLElement> & {
    children?: React.ReactNode;
  };
  ```
- **Theming tokens:** `--theme-window-background`, `--theme-window-shadow`, `--theme-line-height-base`
- **CLI primitive:** `getInnerWidth(termW)` + `wrapLine` / `wrapLineTop` / `shadowBottomRow` in `scripts/cli/lib/window.ts`. Wrapping a CLI-port React surface in `<Window>` is the React-side equivalent of running the screen inside the Simulacrum alt-screen window frame.
- **Used by:** `<Window>...</Window>` wraps the cards + button row in `components/examples/CLITemplate.tsx`, `components/examples/InvoiceTemplate.tsx`, `components/examples/ResultsList.tsx`, `components/examples/AS400.tsx`, `components/examples/Denabase.tsx`, `components/examples/DashboardRadar.tsx`, and `components/examples/MessagesInterface.tsx`, plus the standalone "WINDOW" accordion in `app/page.tsx`.
- **Drop shadow spacing:** Window's bottom drop shadow (1 row) extends below the component's bounding box. When a Window-wrapped component sits inside an Accordion or any container that clips or collapses whitespace, add a double `<br />` after the component so the shadow has room to render. Single `<br />` clips the shadow.


---

# scripts/cli/AGENTS.md

# AGENTS.md — scripts/cli

Simulacrum, the sacred CLI framework. Zero-dependency TypeScript, run via `tsx` with no build step. Imported by `scripts/cli/templates/*.ts` and mirrored in Python under `scripts/python/sacred_cli/`.

## Why TypeScript via tsx

`tsx` runs TypeScript directly with no build step and no `tsconfig` ceremony. The framework source lives as `.ts` files and is imported normally. No compilation output, no `dist/` folder, no module-format headaches.

## Layout

- `colors.json` — the sacred palette and the root source of truth for color across the whole project. These are the true, terminal-tested colors. The Python mirror loads this same file, and `global.css` mirrors it as `--ansi-*` primitives; the web side's OKLCH tints are a derivation of it, never a separate source.
- `lib/ansi.ts` — ANSI escapes, hex helpers (`fgHex`/`bgHex`), padding (`padR`/`padL`), gradient text, visible-length math (`strip`/`visLen`/`truncateVisible`), color constants (`COLORS`).
- `lib/window.ts` — window frame: margin (2ch), shadow (1ch right + 1 row bottom), `getInnerWidth`, `wrapLine`/`wrapLineTop`/`shadowBottomRow`/`wrapLines`, `bgTerm`/`bgWin`/`bgShd`, `MIN_TERM_W`/`MIN_INNER_W`.
- `lib/card.ts` — box-drawing card (`B`, `cardTop`, `cardRow`, `cardSelectRow`, `cardHeaderRow`, `cardBot`, `wordWrap`).
- `lib/table.ts` — `formatRow(vals, colSpec, innerW)`, `kvTable`, `kvTableGradient`. Status coloring fires when a column has `status: true` (`ACTIVE`/`OPEN`/`APPROVED` → bold green, `CLOSED`/`PAID`/`SUSPENDED` → gray).
- `lib/button.ts` — `button(hotkey, label)` and `buttonRow(left, right, innerW)`.
- `lib/app.ts` — lifecycle: alt screen, raw mode, resize debounce, pagination, optional row selection. Exports `createApp({ build, totalPages, interactive, onKey }).start()`.

## What this framework deliberately does NOT have

- **No animation diffing.** Sacred CLI ports are static. The React side handles animation via `<ASCIICanvas>` and the canvas modules. If you find yourself adding a frame loop here, stop and use the React side instead.
- **No mode loader, no plugin system.** Templates wire data and call `createApp`. Anything more belongs in the template.
- **No third-party deps.** `package.json`'s only role here is to expose the `cli:typescript` and `cli:python` scripts. The framework itself never imports from `node_modules` (except `tsx` as the runner).

## Tests

`__tests__/*.test.mjs` cover the framework. Tests are `.mjs` so they can use `vitest`'s ESM imports while pulling the TypeScript source through `createRequire`. Run with `npm test` (which also runs the Python parity suite) or `npm run test:js` to skip Python. Add a test alongside the module you change.

## Parity fixture

`__tests__/dump_reference.ts` is a tiny script that pipes a fixed dataset through every public primitive (`cardTop`, `cardRow`, `cardHeaderRow`, `cardBot`, `cardSelectRow`, `formatRow`, `kvTable`, `kvTableGradient`, `button`, `buttonRow`, `wrapLine`/`wrapLineTop`/`shadowBottomRow`, `wordWrap`) and prints the result as JSON on stdout. The output is the source-of-truth fixture that the Python parity test (`scripts/python/sacred_cli/__tests__/test_parity.py`) loads. `npm run test:python` regenerates the fixture before running the Python suite, so any drift between the TS framework and the Python mirror produces a hard test failure within a single PR cycle.

If you change a primitive's output, the fixture changes automatically — port the change into the Python mirror in the same PR, never edit the JSON by hand.

## Templates

`templates/template.ts` is the canonical TypeScript template. It is the reference for the `port-sacred-terminal-ui-to-typescript-cli` skill. Keep it short, opinionated, and runnable: `npm run cli:typescript` must always work.


---

# scripts/python/AGENTS.md

# AGENTS.md — scripts/python

Python mirror of Simulacrum (the sacred CLI framework). Mirrors `scripts/cli/lib/*` one-to-one but with snake_case symbol names so the Python surface is idiomatic. The package is `sacred_cli` so Python imports stay obviously sacred-flavored.

## Why a Python mirror

The CLI framework is small enough that maintaining a parallel Python implementation is cheap, and porting React → Python is easier when the source-of-truth API is identical to the JS version. Both runtimes load the **same** `scripts/cli/colors.json`, so terminal output is byte-identical between `npm run cli:typescript` and `npm run cli:python` modulo numeric formatting.

## Layout

- `sacred_cli/__init__.py` — re-exports the public surface so templates can `from sacred_cli import ...`.
- `sacred_cli/ansi.py` — mirrors `ansi.ts`. Loads colors via `os.path.join(_HERE, "..", "..", "cli", "colors.json")` — do not duplicate the palette. `_js_round` (private helper) reproduces JavaScript's `Math.round` semantics so byte-level parity holds against the TS framework; do **not** replace it with Python's banker-rounding `round()`.
- `sacred_cli/window.py` — mirrors `window.ts`. `get_inner_width`, `wrap_line`, `wrap_line_top`, `shadow_bottom_row`, `wrap_lines`.
- `sacred_cli/card.py` — mirrors `card.ts`. `card_top`, `card_row`, `card_select_row`, `card_header_row`, `card_bot`, `word_wrap`. `B` is a dict instead of a TS object.
- `sacred_cli/table.py` — mirrors `table.ts`. `format_row`, `kv_table`, `kv_table_gradient`.
- `sacred_cli/button.py` — mirrors `button.ts`. `button`, `button_row`.
- `sacred_cli/app.py` — mirrors `app.ts`. `create_app(*, build, total_pages=1, interactive=None, on_key=None)` using `termios`/`tty` for POSIX raw mode.
- `sacred_cli/__tests__/` — unittest suite. One file per module (`test_ansi.py`, `test_window.py`, `test_card.py`, `test_table.py`, `test_button.py`) plus `test_parity.py` that asserts byte-identical output against the JS reference fixture under `fixtures/reference.json`. `_bootstrap.py` adds `scripts/python/` to `sys.path` so `import sacred_cli` works under `unittest discover` regardless of cwd. We use the `__tests__/` directory name to mirror the JS test layout under `scripts/cli/lib/__tests__/`.
- `templates/template.py` — canonical Python template, runs with `npm run cli:python`.

## Naming convention

| JavaScript | Python |
| --- | --- |
| `cardTop` | `card_top` |
| `cardRow` | `card_row` |
| `cardSelectRow` | `card_select_row` |
| `cardHeaderRow` | `card_header_row` |
| `cardBot` | `card_bot` |
| `formatRow` | `format_row` |
| `kvTable` | `kv_table` |
| `kvTableGradient` | `kv_table_gradient` |
| `buttonRow` | `button_row` |
| `wordWrap` | `word_wrap` |
| `createApp` | `create_app` |

`button(hotkey, label)` and `COLORS` keep the same name in both runtimes.

## Platform support

The Python lifecycle uses `termios` + `tty` for raw mode, so it runs on macOS / Linux. Windows users would need a `msvcrt` shim that the sacred port does not currently provide. If you add one, mirror the JS lifecycle byte-for-byte rather than introducing platform branches inside `app.py`. (The parity test suite intentionally does not exercise `app.py` — it only covers the layout primitives, which are platform-agnostic.)

## Tests

`npm run test:python` regenerates the reference fixture (via `tsx scripts/cli/lib/__tests__/dump_reference.ts`) and then runs `python3 -m unittest discover -s sacred_cli/__tests__ -t .`. The `npm test` script chains the TS suite and the Python suite, so a single command catches both kinds of regression. If `python3` is not on PATH, the runner prints a warning and exits 0 — sacred contributors on minimal containers can still run `npm test`.

When the parity test fails, the cause is almost always a TS module that changed without a matching Python port. Open the failing assertion (e.g. `test_format_row_status`), read the JS source side-by-side with the Python mirror, and port the change. Re-run `npm test` — the fixture regenerates automatically.

## What this mirror deliberately does NOT have

- No third-party Python deps. Stdlib only. The mirror exists so a Python team can ship a sacred-styled CLI without `pip install` overhead. The test suite uses `unittest` from the stdlib for the same reason.
- No `pytest`. The JS suite is `vitest`; the Python suite is `unittest`. Both runtimes lean on their stdlib-equivalent test runner so there is nothing to install.


---

# skills/fast-typescript-check/SKILL.md

---
name: fast-typescript-check
description: Keep www-sacred's TypeScript fast to type-check and fast to run. Use when touching the ASCII/canvas animation components (the only real per-frame code here), tightening type-check wall-clock, or auditing a change for runtime or compiler regressions. Scoped to this repo — a React 19 / Next.js 16 component library plus the zero-dependency Simulacrum CLI framework.
---

# fast-typescript-check

A performance discipline for `www-sacred`. Every rule here is justified against this codebase: either fewer CPU cycles in the components that actually run a render loop, or faster `tsc --noEmit`. Nothing is cosmetic, and nothing references machinery this repo does not have.

## What runs hot here

This is not a game engine. There is no THREE.js, no physics, no 60fps simulation of a world. The only per-frame code is the ASCII/canvas animation family, all driven by `requestAnimationFrame`:

- `components/ASCIICanvas.tsx` — animated ASCII art in a `<pre>` of per-cell `<span>` elements
- `components/MatrixLoader.tsx` — falling-glyph matrix effect
- `components/CanvasSnake.tsx`, `components/DOMSnake.tsx`, `components/CanvasPlatformer.tsx` — interactive games
- `components/examples/OneLineLoaders.tsx`, `components/BarLoader.tsx`, `components/BlockLoader.tsx`, `components/BarProgress.tsx` — spinners

`components/ASCIICanvas.tsx` is the reference implementation. It already follows most of Part 1: a pre-allocated span grid, DOM diffing against `previousCharsRef` / `previousColorsRef`, refs cached into locals before the loop, an indexed `for`, guarded property writes, and an `IntersectionObserver` that stops the loop when the element scrolls off-screen. When you write or review an animation component, hold it against that file.

Everything else in the repo — the static React components, the Simulacrum CLI framework under `scripts/cli/lib/*`, the Python mirror — runs once per interaction, not per frame. Part 1 does not apply there; Part 2 (compiler) does.

## Conventions

These match what the repo already does. Follow them; do not invent new ones.

- Comments use `//NOTE(jimmylee):` (no space after `//`, no `@`) in TS/JS, `# NOTE(jimmylee):` in Python. Comment the _why_, never the _what_. If the code reads clearly, delete the comment. Spell names out — `candidateCount`, not `cnt`; `previousColors`, not `pc`. A clear name removes the need for a comment.
- This repo does **not** use a `__private` prefix. Module-private state is plain `const`; React-internal state is refs. Don't introduce a naming scheme the rest of the codebase doesn't share.
- The Simulacrum framework is zero-dependency TypeScript, run via `tsx` with no build step. Do not import that Node-only code (it uses `process.stdout`) from React.

## Profiling before optimizing

Find the bottleneck first. For the animation components:

1. Open DevTools → Performance, record while an `ASCIICanvas` / `MatrixLoader` is on screen for ~5s, stop.
2. Read the flame chart — the widest bars per frame are the cost. Sort Bottom-Up by Self Time.
3. If Scripting dominates, the `animate()` callback or the diff loop is the target. If Rendering/Painting dominates, the cost is DOM mutation (too many `<span>` writes per frame) — tighten the diff, not the math.

`performance.mark` / `performance.measure` isolate a section without DevTools overhead:

```typescript
performance.mark('asciiFrameStart');
//NOTE(jimmylee): the per-cell diff loop
performance.mark('asciiFrameEnd');
performance.measure('asciiFrame', 'asciiFrameStart', 'asciiFrameEnd');
```

Remove the marks after profiling — they are diagnostic instrumentation (see 1.9). At 60fps a frame is 16.67ms and the browser needs ~4ms for compositing, leaving ~12ms for JavaScript. A single `ASCIICanvas` fills a grid of `cols * rows` cells every frame; if that loop owns most of the budget, the win is in the diff, not the wave math.

## Part 1 — Runtime performance (animation components only)

Every rule applies to code inside a `requestAnimationFrame` loop. Outside the animation family, prioritize readability.

### 1.1 Cache refs and property chains before the loop

`ASCIICanvas` reads its refs once per frame into locals, then loops:

```typescript
const cols = colsRef.current;
const grid = gridRef.current;
const previousChars = previousCharsRef.current;
const previousColors = previousColorsRef.current;

for (let index = 0; index < total && index < grid.length; index++) {
  // ...reads previousChars[index], writes grid[index]
}
```

`ref.current` is a property access; inside a loop over hundreds of cells it is a repeated lookup that hoists trivially. Cache anything read more than once in a loop body.

### 1.2 Diff before you touch the DOM

The single biggest cost in a DOM-rendered animation is writing to the DOM. `ASCIICanvas` only mutates a `<span>` when its content actually changed:

```typescript
if (cell.char !== previousChars[index]) {
  span.textContent = cell.char;
  previousChars[index] = cell.char;
}
if (cell.color !== previousColors[index]) {
  span.style.color = cell.color;
  previousColors[index] = cell.color;
}
```

An unguarded `span.textContent = cell.char` every frame forces layout work even when the value is identical. The diff turns a full-grid repaint into only the cells that moved. Never write a DOM property unconditionally in a frame loop.

### 1.3 Indexed for-loops, no per-frame closures

Use an indexed `for`. Do not call `map` / `filter` / `forEach` / `sort` in a frame loop — each takes a fresh closure allocated every frame, which is pure GC pressure. `for...of` invokes the iterator protocol and deoptimizes in polymorphic call sites; keep it to lifecycle code (`build`, cleanup, one-shot queries).

```typescript
//NOTE(jimmylee): allocates a comparator object every frame — avoid in rAF
cells.sort((a, b) => a.depth - b.depth);
```

If a sort is genuinely needed per frame, confirm it can't be hoisted behind a change check first.

### 1.4 Pre-allocate; never allocate inside the frame loop

`ASCIICanvas` builds its span grid once in `buildGrid(cols)` and only rebuilds when the column count changes. Each frame reuses the existing spans and the existing `previousChars` / `previousColors` arrays. Allocation inside a frame loop creates GC pressure, and a single GC pause is a visible frame skip. Allocate buffers at setup, index into them each frame.

### 1.5 Guard the whole loop, not each iteration

When the component has nothing to do, skip the frame entirely. `ASCIICanvas` returns early when off-screen and never schedules the next frame:

```typescript
const loop = () => {
  if (!visibleRef.current || cancelled) return;
  // ...
  frameRef.current = requestAnimationFrame(loop);
};
```

Pair this with an `IntersectionObserver` so a loader scrolled out of view costs zero CPU. This is the highest-leverage optimization in the repo: a page with several `ASCIICanvas` instances would otherwise run every one of them forever.

### 1.6 Bitwise floor for positive grid math

`Math.floor(x)` is a call; `x | 0` truncates in one instruction. Safe only for positive values inside 32-bit signed range — exactly the case for grid column/row indexing.

```typescript
const column = index % cols;
const row = (index - column) / cols;
```

`ASCIICanvas` derives `row` by exact integer division (the subtraction guarantees divisibility), which avoids `Math.floor` entirely. Where you do need a floor on a known-positive value, `| 0` is the cheaper form.

### 1.7 Keep numbers in one type lane

V8 represents small integers (Smis) differently from boxed doubles. A counter that starts at `0` and later receives a float forces a representation change. In the wave math (`Math.sin`, `Math.cos`), values are doubles throughout — keep them that way and keep loop indices integer throughout. Don't mix `Math.random()` or division results into an integer accumulator inside a hot loop.

### 1.8 Guard property writes that trigger work

Setting `style.color` or `textContent` schedules style/layout work even when the value is unchanged (see 1.2). The same applies to any setter with side effects. Guard the write behind a difference check.

### 1.9 Strip diagnostic instrumentation from the frame path

`performance.now()` is fine once per frame (`ASCIICanvas` reads it for the time base). `console.log`, `JSON.stringify`, and extra `performance.now()` calls for profiling are not — at 60fps they are real cost. Gate them behind a debug flag or remove them after measuring.

### 1.10 Prefer `as const` objects over enums; ES modules over namespaces

Enums compile to runtime IIFEs with reverse-mapping tables; namespaces compile to IIFEs that block tree-shaking. `as const` objects produce zero runtime code and inline cleanly. This repo has **no** enums and **no** namespaces today — keep it that way. `const enum` is doubly wrong here because `isolatedModules: true` (set in `tsconfig.json`) cannot inline it across files.

```typescript
const DIRECTION = { Up: 'UP', Down: 'DOWN', Left: 'LEFT', Right: 'RIGHT' } as const;
type Direction = (typeof DIRECTION)[keyof typeof DIRECTION];
```

## Part 2 — Compiler performance

These reduce `tsc --noEmit` wall-clock and editor responsiveness. They apply across the whole repo, not just the animation family.

### 2.1 Add explicit return types on exported functions

Inferred return types on exports can balloon into anonymous types with `import("./path").Type` chains that slow editor responsiveness and incremental rebuilds. A named return type is compact.

```typescript
//NOTE(jimmylee): compiler infers a wide anonymous type
export function createState() {
  return { x: computeX(), y: computeY() };
}

export function createState(): EngineState {
  return { x: computeX(), y: computeY() };
}
```

### 2.2 Prefer `interface extends` over `&` intersections at boundaries

Interfaces produce a single cached flat type; intersections re-merge on every use and detect no conflicts. Use `interface extends` for types that cross module boundaries. Interior types used once don't matter.

### 2.3 Keep union types small

Union deduplication is pairwise (quadratic). Past ~12 members, refactor to a base type with a discriminant field instead of a wide `A | B | C | ...` union.

### 2.4 Limit recursive generic nesting

Deeply nested recursive generics (`DeepPartial<T>` style) are a common cause of slow checks — each level multiplies instantiations. Keep recursion to ≤3 levels; for known shapes, write the concrete type. This repo has no such generics today; don't add one without measuring.

### 2.5 `import type` for type-only imports

`import type` is erased at runtime, shrinking the module graph the bundler walks and heading off circular-import emit problems.

```typescript
import type { ASCIIAnimationFn } from '@components/ascii/utilities';
```

Note: this repo does **not** set `verbatimModuleSyntax`, so the compiler will not force this on you — it is a discipline, not an enforced error. Apply it to type-only imports anyway.

### 2.6 The real tsconfig.json

These are the settings actually in `tsconfig.json` and why they matter. Do not document settings the file doesn't have.

```jsonc
{
  "compilerOptions": {
    "paths": { "@root/*": ["./*"], "@common/*": ["./common/*"], "@components/*": ["./components/*"], "@modules/*": ["./modules/*"] },
    "target": "es2017",              // Next.js/SWC does the real downlevel; tsc target only affects lib surface
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,                 // kept for compatibility; the Simulacrum framework is now .ts
    "skipLibCheck": true,            // skips .d.ts checking — the largest single tsc speedup
    "strict": false,                 // only strictNullChecks is on (see below)
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,                  // tsc is a checker only; Next.js/SWC emits
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",   // matches the bundler's resolution — correctness, not speed
    "resolveJsonModule": true,       // lets TypeScript import colors.json as a typed module
    "isolatedModules": true,         // every file transpiles independently (Next/SWC); blocks const enum
    "jsx": "react-jsx",
    "incremental": true,             // writes tsconfig.tsbuildinfo, skips unchanged files
    "plugins": [{ "name": "next" }],
    "strictNullChecks": true
  },
  "exclude": ["node_modules", "**/*.spec.ts"],
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts"]
}
```

Notes that matter when editing this file:

- `strict` is **off**; only `strictNullChecks` is enabled. Turning on full `strict` would be a large, separate diff (many components are loosely typed on purpose — see `components/AGENTS.md`). Don't flip it as a side effect.
- The `paths` map lists only the four live aliases: `@root/*`, `@common/*`, `@components/*`, `@modules/*`. Dead aliases (`@system`, `@demos`, `@data`, `@pages`) were removed.
- `exclude` lists `node_modules` (not the `**/node_modules` glob). TypeScript excludes `node_modules` by default, and once any `exclude` entry exists you must keep an explicit `node_modules` entry or the compiler crawls every package — which this file does.
- There are no project references and no `verbatimModuleSyntax` / `types: []` / `moduleDetection`. The repo is small enough that none of these earn their complexity yet; revisit only if `time npx tsc --noEmit` climbs past ~30s.

**Resolved:** `baseUrl` was dropped (modern resolution maps `paths` from the config file's own location) and `target` was raised from `es5` to `es2017`. `tsc --noEmit` exits 0 with no deprecation diagnostics under TypeScript 6.x.

### 2.7 Compiler diagnostic commands

Run before and after any change that touches types broadly.

| Command | What it tells you |
| --- | --- |
| `npx tsc --noEmit --extendedDiagnostics` | Files, Bind, Check, Emit times. High Check time = type complexity. |
| `time npx tsc --noEmit` | Wall-clock budget check. Should stay well under 30s for this repo. |
| `npx tsc --noEmit --generateTrace ./trace` then `npx @typescript/analyze-trace ./trace` | Slowest files and most expensive type instantiations. |
| `npx tsc --explainFiles \| grep node_modules` | Surfaces packages pulled in that shouldn't be. |

## Part 3 — Horizon: the native TypeScript compiler

Microsoft is porting `tsc` to Go (shipping as TypeScript 7.0), with ~10x type-check speedups reported on large codebases. It does not change language semantics — every rule above applies equally to both compilers. The native port makes checking faster; it does not make a quadratic union cheaper to evaluate. Available now as `@typescript/native-preview`. This repo type-checks in seconds today, so the win here is editor latency, not CI.

## Sources

In order of authority; higher-ranked sources win on conflict.

1. **Microsoft TypeScript Performance Wiki** — https://github.com/microsoft/TypeScript/wiki/Performance — tsconfig settings, type-system complexity, diagnostics.
2. **TypeScript Native Port announcement** — https://devblogs.microsoft.com/typescript/typescript-native-port/ — the 10x figures.
3. **Vyacheslav Egorov, "What's up with monomorphism?"** — https://mrale.ph/blog/2015/01/11/whats-up-with-monomorphism.html — V8 inline caches and hidden-class transitions.
4. **V8 Blog — TurboFan JIT** — https://v8.dev/blog/turbofan-jit — the optimizing compiler.

A note on `moduleResolution: "bundler"`: blogs sometimes list it as a speed setting. The TS wiki does not — resolution mode affects which files are found, not how fast they check. It is the correct setting here because it matches the bundler, not because it is faster.

## Audit checklist

**Runtime — only for code inside a `requestAnimationFrame` loop:**

- [ ] Refs / property chains read more than once are cached in a local before the loop
- [ ] DOM writes (`textContent`, `style.*`) are guarded by a difference check — diff, don't repaint
- [ ] No `new` allocations and no closures (`map`/`filter`/`sort` callbacks) inside the loop
- [ ] Buffers (span grid, previous-value arrays) are pre-allocated and reused, rebuilt only on resize
- [ ] The loop early-returns when off-screen / cancelled, gated by an `IntersectionObserver`
- [ ] Numeric variables stay in one lane (integer indices, double math)
- [ ] No `console.log` / extra `performance.now()` left in the frame path

**Compiler — whole repo:**

- [ ] Exported functions that return complex objects have explicit return types
- [ ] Boundary object types use `interface extends`, not `&`
- [ ] Unions stay under ~12 members
- [ ] Type-only imports use `import type`
- [ ] No `enum`, no `namespace`, no `const enum`
- [ ] tsconfig edits keep an explicit `node_modules` in `exclude` and don't silently flip `strict`

**Naming:**

- [ ] Names are spelled out (`previousColors`, not `pc`)
- [ ] Comments are `//NOTE(jimmylee):` / `# NOTE(jimmylee):`, explain _why_, and aren't restating the code
- [ ] No `__private` prefix introduced — it isn't a convention in this repo


---

# skills/port-sacred-terminal-ui-to-hostile-react-codebase/SKILL.md

# Skill: Port Sacred Terminal UI to a Hostile React Codebase

> Also available at https://sacred.computer/llm/skills/port-sacred-terminal-ui-to-hostile-react-codebase/SKILL.md

Take a sacred React component (or a sacred screen that mirrors a Simulacrum CLI surface) and graft it into a foreign React codebase that already ships its own design system, build pipeline, and CSS toolchain — without breaking the host or polluting it with sacred-specific globals.

> See `components/AGENTS.md` for the canonical catalog of every sacred React component (props, theming tokens, CLI primitive equivalent). Read it to know which sacred component you are about to graft into the host.

## When to use

Use this skill when the target repository:

- Already has its own CSS reset, theme tokens, or design system (Tailwind, MUI, Chakra, ShadCN, custom)
- Uses a build tool that conflicts with sacred's CSS Modules (`vite`, `webpack`, `rollup`, `parcel`, `metro`)
- Refuses to take sacred's `global.css` as-is because it would clobber the host's typography, color tokens, or layout primitives
- Has a hostile lint config (`no-default-export`, `no-css-modules`, `no-unused-vars` on `style` props, etc.)

If you control both repos and the host has no design system, prefer `port-sacred-terminal-ui-to-react-using-same-conventions` instead — it gives you the full sacred theming for free.

## Core principle

**Isolate, don't inherit.** Sacred's terminal aesthetic must be opt-in inside one container element, not bleed into the host. You will:

1. Scope every CSS rule under a single container class.
2. Inline the ANSI palette as CSS custom properties on that container.
3. Replace sacred's CSS Modules with whatever the host supports (CSS Modules, Tailwind, vanilla-extract, etc.).
4. Keep the React component file's structure identical so future updates from sacred can be diffed cleanly.

## Step-by-step

### 1. Pick a single root class name

Every sacred selector must live under one root. Pick a host-friendly name:

```tsx
<div className="sacred-root theme-dark tint-yellow">
  <Card title="STATUS">...</Card>
</div>
```

### 2. Inline the palette

Copy the relevant `--ansi-*`, `--color-*`, and `--theme-*` tokens from `global.css` into a host-controlled CSS file scoped to `.sacred-root`:

```css
.sacred-root {
  /* NOTE(your_github_username): Pinned ANSI palette — do not inherit host theme tokens. */
  --color-black: #000000;
  --color-white: #ffffff;
  --color-brand: #e4f221;
  --theme-background: var(--color-black);
  --theme-text: var(--color-white);
  --theme-border: #3a3a3a;
  /* ... */

  background: var(--theme-background);
  color: var(--theme-text);
  font-family: 'GeistMono-Regular', Consolas, monospace;
  font-variant-numeric: tabular-nums lining-nums;
}
```

Sacred's tints (`tint-green`, `tint-blue`, etc.) work the same way — copy the OKLCH math from `global.css` and scope it under `.sacred-root.theme-dark.tint-green`.

### 3. Translate CSS Modules

Sacred uses `Foo.module.css`. If the host blocks CSS Modules, translate the rules into the host's equivalent:

| Host system | Translation strategy |
| --- | --- |
| Tailwind | Map each `--theme-*` token to a Tailwind theme extension, then use `bg-[var(--theme-background)]` etc. |
| vanilla-extract | Copy each `.foo` rule into a `style({ ... })` block |
| Stitches/Emotion/styled-components | Wrap the CSS in `styled.div\`...\`` blocks |
| Plain CSS | Inline the CSS Modules content into a single scoped stylesheet |

In every case, every selector must start with `.sacred-root` so the host's other components are unaffected.

### 4. Eject sacred dependencies

Sacred React components import from `@components/...` via `tsconfig.json` paths. The host won't have that alias. Either:

- Add the alias to the host's `tsconfig.json` (cleanest), or
- Rewrite `@components/Card` to a relative path inside the host's `src/`

Sacred avoids runtime dependencies, so there is nothing else to port — no React Query, no Redux, no animation libraries.

### 5. Avoid global side effects

Sacred's `global.css` resets `box-sizing`, margins, padding, and list styles for every element. **Do not** import `global.css` into the host. Re-create only the rules you need under the `.sacred-root` selector. The host's reset stays untouched.

### 6. Confirm theming

Wrap your sacred container in a host-managed theme switcher and verify:

```tsx
<div className={`sacred-root theme-${theme} tint-${tint}`}>
  <Card title="STATUS">...</Card>
</div>
```

If the host already has dark mode, you have two options:

- **Mirror** the host's dark mode by deriving `theme-dark` from the host theme context
- **Independent** sacred theming via its own state — recommended when the sacred surface is a "console" or "debugger" overlay

## Don'ts

- **Do not** import `global.css` into the host. It breaks `body`, `ul`, `ol`, and many other elements.
- **Do not** re-export sacred's `Button`, `Input`, or other primitives with the same name as a host primitive — you will collide. Prefix them: `SacredButton`, `SacredInput`.
- **Do not** ship `scripts/cli/lib/*` into the React bundle. It is Node-only and uses `process.stdout`.
- **Do not** rewrite sacred components to consume host theme tokens. The whole point of this skill is to keep sacred isolated so future sacred releases drop in cleanly.

## Smoke test

1. Render your sacred-rooted component in the host app.
2. Switch the host's theme and confirm sacred does not change (or does change, intentionally, if you wired it).
3. Inspect the host's other components and confirm none of them have new margin/padding/font-family from sacred's reset.
4. Run `git diff` against the previous host build and confirm no host CSS rule changed.

## Reference: minimum sacred surface

A useful "first port" is the `Card` + `DataTable` + `Button` triple. That gives you:

- Box-drawing borders
- Header/data row alignment with status coloring
- Hotkey + label button row

That's enough for a status console, an audit log, or a debugger overlay. Add more sacred primitives (`BarLoader`, `BarProgress`, `Block`, `Text`) one at a time, scoping each new selector under `.sacred-root`.


---

# skills/port-sacred-terminal-ui-to-python/SKILL.md

# Skill: Port Sacred Terminal UI to Python

> Also available at https://sacred.computer/llm/skills/port-sacred-terminal-ui-to-python/SKILL.md

Take a React `Window*.tsx` (or any sacred component) and produce a terminal CLI screen written in Python that uses **Simulacrum's** Python mirror in `scripts/python/sacred_cli/`. Simulacrum is the sacred CLI framework — the JavaScript half lives in `scripts/cli/lib/`, the Python half is a one-to-one snake_case mirror.

> See `components/AGENTS.md` for the canonical catalog of every sacred React component (props, theming tokens, CLI primitive equivalent). Read it before identifying which React surface you are porting from.

## When to use

Use this skill whenever you want a Python CLI version of an existing sacred React surface. Sacred ships a Python port of the layout primitives (one-to-one with the JavaScript framework) so the same React component can render identically from either runtime.

## What you ship

A single `.py` file under `scripts/python/templates/` that:

1. Has a `python3` shebang and `if __name__ == "__main__":` entry point.
2. Imports primitives from `sacred_cli` (the package lives in `scripts/python/sacred_cli/`).
3. Calls `create_app(build=build).start()` with a `build(page, inner_w, selected_row)` function that returns `list[str]`.

## Reference implementation

Read these files before starting:

- `scripts/python/templates/template.py` — canonical example (run with `npm run cli:python`)
- `scripts/python/sacred_cli/__init__.py` — public surface re-exports
- `scripts/python/sacred_cli/ansi.py` — ANSI escapes, hex helpers, padding, gradient text
- `scripts/python/sacred_cli/window.py` — window frame (margin + window bg + shadow)
- `scripts/python/sacred_cli/card.py` — box-drawing card borders and word wrap
- `scripts/python/sacred_cli/table.py` — `format_row`, `kv_table`, `kv_table_gradient`
- `scripts/python/sacred_cli/button.py` — `button`, `button_row`
- `scripts/python/sacred_cli/app.py` — lifecycle: alt screen, raw mode, resize, paging, selection
- `scripts/cli/colors.json` — sacred-themed color palette (the Python ANSI module loads this same JSON)

## Naming convention

The Python port mirrors the JavaScript framework one-to-one but uses **snake_case**:

| JavaScript                                 | Python                                        |
| ------------------------------------------ | --------------------------------------------- |
| `cardTop(title, innerW)`                   | `card_top(title, inner_w)`                    |
| `cardRow(content, innerW)`                 | `card_row(content, inner_w)`                  |
| `cardSelectRow(content, innerW, selected)` | `card_select_row(content, inner_w, selected)` |
| `cardHeaderRow(content, innerW)`           | `card_header_row(content, inner_w)`           |
| `cardBot(innerW)`                          | `card_bot(inner_w)`                           |
| `formatRow(vals, colSpec, innerW)`         | `format_row(vals, col_spec, inner_w)`         |
| `kvTable(pairs)`                           | `kv_table(pairs)`                             |
| `kvTableGradient(pairs)`                   | `kv_table_gradient(pairs)`                    |
| `buttonRow(left, right, innerW)`           | `button_row(left, right, inner_w)`            |
| `wordWrap(text, maxW)`                     | `word_wrap(text, max_w)`                      |
| `createApp({ build })`                     | `create_app(build=build)`                     |

`button(hotkey, label)` and the COLORS dict keep the same names because they have no JS-specific casing.

## ColSpec reference

```py
COL_SPEC = [
    {"width": 14, "align": "left"},
    {"width": 12, "align": "left", "grow": True},
    {"width": 8, "align": "right", "status": True, "gap": 2},
]
```

Status coloring: `ACTIVE`/`OPEN`/`APPROVED` → bold green; `CLOSED`/`PAID`/`SUSPENDED` → gray. The framework handles this automatically when `status: True`.

## Step-by-step

1. **Read the React file.** Identify cards, tables, paragraphs, and button rows. Skip the `<ASCIICanvas>` (CLI is static).
2. **Extract data.** Move table rows into module-level lists at the top of your `.py` file.
3. **Define COL_SPECS.** One per table. Mark a single column with `"grow": True`.
4. **Write `build(page, inner_w, selected_row)`.** Append `card_top` → rows → `card_bot` for each section. End with `button_row(...)`.
5. **Run `npm run cli:python`.** Verify margins, shadow, and inner padding match the React component.
6. **Add interactivity (optional).** Pass `interactive={"count": 5, "on_select": fn, "persist": True}` to `create_app` and use `card_select_row(content, inner_w, i == selected_row)`.
7. **Add pagination (optional).** Pass `total_pages=N` (or a callable) and slice your data by `page` inside `build`.

## Formatting rules

- Shebang `#!/usr/bin/env python3`.
- Comments use `# NOTE(your_github_username): ...`.
- Column headers are `UPPER_SNAKE_CASE`.
- Dates are ISO 8601 (`2026-04-08T09:00:00`).
- Currency uses commas (`$18,920.50`).
- Never hardcode hex colors — read from `scripts/cli/colors.json` via `sacred_cli.COLORS`.
- Python templates run on POSIX terminals (macOS / Linux); the lifecycle uses `termios` raw mode. Windows users need a `msvcrt` shim that the sacred port does not currently provide.

## Smoke test

After writing the file:

```sh
npm test                # JS framework unit tests + Python parity suite
npm run cli:python      # your screen renders, ESC quits cleanly
```

If you see garbled output, your terminal probably does not support 24-bit true color — the sacred palette assumes `\x1b[38;2;R;G;Bm` works.

## Verifying parity

The Python framework is a one-to-one mirror of the JavaScript framework. The two runtimes are locked into byte-identical output by a parity test suite under `scripts/python/sacred_cli/__tests__/`:

```sh
npm run test:python     # only the Python suite
npm test                # JS suite + Python suite (chained)
```

`npm run test:python` first regenerates the reference fixture (`scripts/python/sacred_cli/__tests__/fixtures/reference.json`) via `tsx scripts/cli/lib/__tests__/dump_reference.ts`, then runs `python3 -m unittest discover` against `sacred_cli/__tests__`. The fixture is checked into the repo so the Python test never has to shell out — regeneration is just a guard against stale snapshots.

If `python3` is not on PATH, the runner prints a warning and exits 0. Sacred contributors on minimal containers can still run `npm test` without installing Python.

### When the parity test fails

A failing parity test almost always means **a TS module was changed without porting the change to its Python mirror.** To fix:

1. Read the failing assertion (e.g. `test_format_row_status`).
2. Open the corresponding TS module (`scripts/cli/lib/table.ts`) and the Python mirror (`scripts/python/sacred_cli/table.py`) side-by-side.
3. Port the change into the Python file. Snake-case the symbol names per the naming table above.
4. Re-run `npm test`. The fixture is regenerated automatically — no manual step needed.

If you genuinely need to update the contract on **both** sides, edit the TS module first, then run `npm test` to see what the parity fixture now looks like, and only then port the new behavior into Python. Never edit the fixture JSON by hand.

The unit tests under `scripts/python/sacred_cli/__tests__/` (one file per module: `test_ansi.py`, `test_window.py`, `test_card.py`, `test_table.py`, `test_button.py`) mirror the JS tests in `scripts/cli/lib/__tests__/`. When you add a new JS test, add the equivalent Python test in the same file so the assertion sets stay synchronized.


---

# skills/port-sacred-terminal-ui-to-react-using-same-conventions/SKILL.md

# Skill: Port Sacred Terminal UI to React Using Same Conventions

> Also available at https://sacred.computer/llm/skills/port-sacred-terminal-ui-to-react-using-same-conventions/SKILL.md

Take a CLI screen written for **Simulacrum** — the sacred CLI framework (`scripts/cli/templates/*.ts` or `scripts/python/templates/*.py`) — and produce a React component that lives inside `components/examples/` (or `components/`) using only sacred's existing primitives — `Window`, `Card`, `SimpleTable`, `ActionButton`, `RowSpaceBetween`, `BarLoader`, etc.

> See `components/AGENTS.md` for the canonical catalog of every sacred React component (props, theming tokens, CLI primitive equivalent). Read it before picking a component to render.

## When to use

Use this skill whenever you have a CLI screen and want a sacred React surface that mirrors it without the canvas-based animation. This is the inverse of `port-sacred-terminal-ui-to-typescript-cli` and `port-sacred-terminal-ui-to-python`.

## Reference primitives

These are the React components that sacred ships and that the CLI framework maps onto. Read them before writing the port:

| Sacred React component | CLI primitive | What it renders |
| --- | --- | --- |
| `components/Card.tsx` | `cardTop`/`cardRow`/`cardBot` | Box-drawing card with title bar |
| `components/CardDouble.tsx` | (no equivalent) | Double-bordered card with left/right titles |
| `components/SimpleTable.tsx` | `formatRow` + `cardHeaderRow`/`cardRow` | Fluid HTML table with header background and status coloring — the canonical React surface for CLI port examples |
| `components/DataTable.tsx` | (no direct equivalent) | Sacred's gradient-tinted table — heavier, used outside CLI ports |
| `components/ActionButton.tsx` | `button(hotkey, label)` | Hotkey + label button pair |
| `components/BarLoader.tsx` | (one-line loader) | Single-row progress fill |
| `components/RowSpaceBetween.tsx` | `buttonRow(left, right, innerW)` | Left/right justified row |
| `components/Block.tsx` | `cardRow(text, innerW)` with word wrap | Padded text block |
| `components/Text.tsx` | gradient or plain text | Typography wrapper |

## Step-by-step

1. **Read the CLI screen.** Identify each `cardTop`/`cardRow`/`cardBot` block and each `buttonRow`. Each block becomes one `<Card>` element.
2. **Create the React file.** Drop it in `components/examples/` if it is a demo, or `components/` if it is a reusable surface. Use `'use client'` only if you need browser APIs (most ports do not).
3. **Map cards to `<Card title="...">`.** Wrap content children in `<Card>`. Card renders the title bar, the framework only adds borders.
4. **Map data tables to `<SimpleTable data={[...]} />`.** First row is the header, subsequent rows are data. `SimpleTable` is a fluid HTML table with the same column + status contract as the CLI framework's `formatRow` (`ACTIVE`/`OPEN`/`APPROVED` → bold green, `CLOSED`/`PAID`/`SUSPENDED` → gray). Use `align={['left','right',...]}` to mirror per-column alignment from the CLI's `colSpec`. Do **not** use the heavier `DataTable` here — its gradient backgrounds are not part of the CLI surface.
5. **Map button rows to `<RowSpaceBetween>`.** Left and right buttons go in the slots provided. Use `<ActionButton hotkey="ESC">EXIT</ActionButton>` so the React buttons match the CLI button row visually.
6. **Skip the animation header.** Sacred's React UI has its own animation surfaces (`CanvasPlatformer`, `CanvasSnake`); do not re-port the CLI's static layout into one of those. The point is **layout parity**, not animation parity.
7. **Inherit theming.** Sacred's `global.css` already drives every `--theme-*` token from the active light/dark/tint theme. Do not import `scripts/cli/colors.json` from React — the React side picks up the same ANSI palette through the CSS custom properties (`var(--theme-background)` etc.).

## What NOT to do

- **Do not** re-implement the box-drawing borders in HTML/CSS — `Card` already does this.
- **Do not** copy `scripts/cli/lib/*` into the React tree. The CLI framework is for terminals; the React tree uses CSS Modules.
- **Do not** import `scripts/cli/colors.json` from a React file. The browser palette comes from CSS custom properties — the JSON is the authoritative source for the ANSI palette but it is consumed indirectly through `global.css`.
- **Do not** add an `<ASCIICanvas>` from `.workdir/` — sacred has its own animations and porting that canvas duplicates state machines.

## Layout expectations

Sacred React components are width-fluid: use them in `<ContentFluid>` or `<Block>` containers and let CSS Grid / Flexbox do the work. The CLI framework's "innerW" concept is replaced by browser layout, so you do not need to compute column widths yourself — DataTable and Card handle their own padding.

## Smoke test

After writing the component:

```sh
npm test     # CLI framework tests still pass (sanity check)
npm run dev  # render the React surface in the browser
```

Visit the page that renders your component and confirm:

- Card titles match the CLI `cardTop` titles exactly
- SimpleTable rows match the CLI `formatRow` outputs (same order, same labels, same status colors)
- Buttons match the CLI `button(hotkey, label)` pairs
- The screen reads the same in light, dark, and every tinted theme (the global CSS handles this for free)

If anything diverges, trust the CLI screen — it is the source of truth for layout because the CLI framework forces explicit widths and the React side fills in around it.


---

# skills/port-sacred-terminal-ui-to-typescript-cli/SKILL.md

# Skill: Port Sacred Terminal UI to TypeScript CLI

> Also available at https://sacred.computer/llm/skills/port-sacred-terminal-ui-to-typescript-cli/SKILL.md

Take a React `Window*.tsx` (or any sacred component) and produce a terminal CLI screen written in TypeScript that uses **Simulacrum** — the sacred CLI framework in `scripts/cli/lib/`.

> See `components/AGENTS.md` for the canonical catalog of every sacred React component (props, theming tokens, CLI primitive equivalent). Read it before identifying which React surface you are porting from.

## When to use

Use this skill whenever you want a CLI version of an existing sacred React surface. Sacred ships a small zero-dependency layout framework that maps every React `<Card>` / `<DataTable>` / `<ActionButton>` concept onto a CLI primitive. The output is identical to the React component minus the canvas-based animations — sacred renders are static.

## What you ship

A single `.ts` file under `scripts/cli/templates/` that:

1. Uses `tsx` as a shebang or `npm run cli:typescript` as the entry point.
2. Imports the framework primitives (`import { ... } from '../lib/card'`).
3. Calls `createApp({ build }).start()` with a `build(page, innerW, selectedRow)` function that returns `string[]`.

## Reference implementation

Read these files before starting:

- `scripts/cli/templates/template.ts` — canonical example (run with `npm run cli:typescript`)
- `scripts/cli/lib/ansi.ts` — ANSI escapes, hex helpers, padding, gradient text
- `scripts/cli/lib/window.ts` — window frame (margin + window bg + shadow)
- `scripts/cli/lib/card.ts` — box-drawing card borders and word-wrap
- `scripts/cli/lib/table.ts` — `formatRow`, `kvTable`, `kvTableGradient`, `ColSpec` type
- `scripts/cli/lib/button.ts` — `button`, `buttonRow`
- `scripts/cli/lib/app.ts` — lifecycle: alt screen, raw mode, resize, paging, selection
- `scripts/cli/colors.json` — sacred-themed color palette (single source of truth)

## React-to-CLI concept map

| React surface                             | CLI primitive                                            | Notes                                                                       |
| ----------------------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------------- |
| `<Card title="T">`                        | `cardTop('T', innerW)` + `cardBot(innerW)`               | Top + bottom borders                                                        |
| Content `<div>` inside `<Card>`           | `cardRow(text, innerW)`                                  | 2ch left indent, padded to inner width                                      |
| Key-value pair with gradient styling      | `kvTableGradient([[k, v]])`                              | 24ch key column, gradient on value                                          |
| `<thead><tr><td>`                         | `cardHeaderRow(formatRow(TH, COL_SPEC, innerW), innerW)` | `#585858` background                                                        |
| `<tbody><tr><td>`                         | `cardRow(formatRow(row, COL_SPEC, innerW), innerW)`      | Per-cell alignment, status coloring                                         |
| `styles.statusOk/statusOff`               | `colSpec: { status: true }`                              | `ACTIVE`/`OPEN`/`APPROVED` → bold green; `CLOSED`/`PAID`/`SUSPENDED` → gray |
| `<ActionButton hotkey="ESC">`             | `button('ESC', 'exit')`                                  | Hotkey + label background pair                                              |
| `<RowSpaceBetween>`                       | `buttonRow(left, right, innerW)`                         | Left + right justify with windowBg gap                                      |
| Word-wrapped paragraph                    | `wordWrap(text, innerW - 6)`                             | Card padding is 3ch each side                                               |
| Animated `<ASCIICanvas>` header           | _omit_                                                   | Sacred CLI ports are static; the React side keeps the animation             |

## ColSpec reference

```ts
type ColSpec = {
  width: number;
  align?: 'left' | 'right';
  grow?: boolean; // one column per spec absorbs extra width
  status?: boolean; // ACTIVE/OPEN/APPROVED → bold green; CLOSED/PAID/SUSPENDED → gray
  gap?: number; // inter-column spacing (default 1ch)
};
```

## Step-by-step

1. **Read the React file.** Identify cards, tables, paragraphs, and button rows. Skip the `<ASCIICanvas>` (CLI is static).
2. **Extract data.** Move table rows into `const` arrays at the top of your TS file. If the React component already imports JSON, share the same JSON.
3. **Define COL_SPECS.** One per `<table>`. Mark a single column with `grow: true`.
4. **Write `build(page, innerW, selectedRow)`.** Push `cardTop` → rows → `cardBot` for each section. Append `buttonRow(...)` last.
5. **Run `npm run cli:typescript`.** Verify margins, shadow, and inner padding match the React component.
6. **Add interactivity (optional).** Pass `interactive: { count, onSelect, persist: true }` to `createApp` and use `cardSelectRow(content, innerW, i === selectedRow)`.
7. **Add pagination (optional).** Pass `totalPages: N` (or `() => N`) and slice your data by `page` inside `build`.

## Formatting rules

- File starts with `#!/usr/bin/env -S npx tsx`.
- Comments use `//NOTE(your_github_username): ...`.
- Column headers are `UPPER_SNAKE_CASE`.
- Dates are ISO 8601 (`2026-04-08T09:00:00`).
- Currency uses commas (`$18,920.50`).
- Never hardcode hex colors — read from `scripts/cli/colors.json` via the framework.

## Smoke test

After writing the file:

```sh
npm test                  # JS framework + Python parity suite (chained)
npm run cli:typescript    # your screen renders, ESC quits cleanly
```

If `npm test` fails, the framework is broken — fix it before continuing. If your screen flickers on resize, you forgot to wrap content in `cardRow`/`cardSelectRow` (the framework relies on padded rows for the in-place redraw).

If a JS module changes the bytes coming out of any primitive, the parity test in `scripts/python/sacred_cli/__tests__/test_parity.py` will fail until the Python mirror under `scripts/python/sacred_cli/` is updated to match. Port the change to both runtimes in the same PR — see `skills/port-sacred-terminal-ui-to-python/SKILL.md` § "Verifying parity".

