jixoai-ui
the terminal design language
loading the style sheet…
Skip to content
docs · print medium: screen

registry:ui · Layout

website-scaffold — the grid shell

The layout root of every page on this site — including this one. A named container host whose ONE grid both layers subgrid (columns shared, placement by named areas), forms driven by container queries on the host's own width, per-zone immersive motion, the boot splash seat, and systematized view transitions. The strictest prop contract in the fleet: four snippet seams, eight axes, no rest.

install — website-scaffold

$npx jixoai-ui add website-scaffold

https://ui.jixoai.com/r/website-scaffold.json

named container subgrid layers container-query forms immersive chrome boot splash seat

overview

Overview — the shell documenting itself

The self-reference at maximum: this page LIVES in the shell it documents. Every claim names its surface — the LIVE shell (this page's own chrome) or a measured demo instance — and the theme strata terminate here, because the scaffold hosts them.

The architecture is four names. .jx-shell-host is the named container (container-type: inline-size, container-name: jx-shell) — the ONE responsive truth source: forms switch on ITS width, so the scaffold is embeddable (a narrow host shows the narrow form inside a wide window — measured: a 480px instance ran the single-column form while this page ran the three-column one). .jx-shell is one grid; both layers overlap by spanning all columns of row 1 (line placement — never grid-template-areas on the shell). .jx-top-layer is the click-through chrome plane: pointer-transparent, children opt back in, per-zone immersive transforms — the plane itself never moves. .jx-shell-body spans the whole shell as THE scroll container, reserving chrome via padding driven by the single measured var --jx-header-h.

Three forms, container-queried on the host: at 1200px+ the grid is [rail 16rem][content 1fr][toc 15rem] (tree nav rail); at 900–1199 the tree folds to a bottom bar; below 900 the tocbar row slides under the header. The named areas move with them — measured: header header header / tree stage toc wide, header header / stage toc mid, header tocbar stage narrow — the named-area budget every adopted node places into. The immersive law is per-zone and scroll-position-driven (an 8px threshold, rAF-throttled): scroll DOWN and the header leaves upward (measured translateY −74.74px — the header-h itself); scroll UP and everything returns; the reading rails NEVER leave — they compact by the header height.

The prop contract is the fleet's strictest: FOUR snippet seams (header, chrome, children, footer) plus an optional splash seat and the eight axes — and NOTHING else. No rest spread exists: consumers author their chrome in the seams, static chrome nodes carry data-area roles (toc | tree), and dynamic adoption rides the jx-top-layer context (adopt(node, area) — ordered, release fn returned, teardown the consumer's job). Theme is a declarative stamp over the page ground (measured flip); density/size/shape/radius/color/elevation/motion are the no-own container's supply lanes. Kinship: terminal-header, toc and terminal-footer compose INTO this shell — the docs pages for each live inside it.

website-scaffold

This page is already the running instance — the canvas below holds the architecture diagram, and the playground drives the REAL top layer you are reading through.

architecture · no nested LIVE instance

This page is already the demo

You are reading main#main inside .jx-shell-body right now — the nav band above is .jx-top-layer. A second scaffold cannot nest here without trapping the page in two competing scroll planes, so the LIVE area holds the architecture; use the Playground buttons to drive the real top layer.

.jx-shell-host              container: jx-shell (inline-size) · 100dvh
└── .jx-shell                ONE grid · cols [rail][content][toc] per form
    ├── .jx-top-layer        grid-row 1 · col-subgrid · rows [header][tocbar][stage]
    │   ├── .jx-scaffold-header     the nav band (visible above)
    │   └── .jx-float-slot          subgrid — adopted nodes land by [data-area]
    └── .jx-shell-body        grid-row 1 · col-subgrid · THE scroll container
        ├── main#main         [content] column · padding = --jx-header-h (+tocbar)
        └── footer            in the content flow
  • one measurement — a single ResizeObserver publishes --jx-header-h; the body's chrome reservation, the toc compaction offset and the shared --jx-toc-line all derive from it in CSS. Disclosure rows re-reserve automatically. The correction lands on .jx-shell — the var's DECLARING scope (a host-level write is shadowed for every descendant; the toc-flush bug)
  • per-zone immersive law — scroll DOWN past 8px: the header leaves upward and the tree bottom bar slides down; the toc and the catalog rail NEVER leave — they compact by exactly the header height (Owner ruling, 2026-08-24); the slightest scroll UP returns everything; reduced motion swaps to instant. Measured: translateY(−74.74px) = the header-h itself
  • view transitions — the header band keeps view-transition-name site-header and persists across navigations; main#main animates as page-main (measured live)
  • skip link — a keyboard-reachable Skip to content target on #main, hidden until focused
  • top-layer context — the scaffold publishes the jx-top-layer context: adopt(node, area) with semantic roles (toc | tree | float); the shell grid resolves the physical cell per container form — one adoption mechanism, many cells, zero per-breakpoint JS (Owner request, 2026-08-23)
website-scaffold-usage.svelte svelte
<script lang="ts">
  import WebsiteScaffold from '@ui/website-scaffold.svelte';
  import '@ui/website-scaffold/website-scaffold.css';
  import TerminalFooter from '@ui/terminal-footer.svelte';
  import TerminalHeader from '@ui/terminal-header.svelte';
  import { NavigationMenu, NavigationMenuLink } from '@ui/navigation-menu/index';
</script>

<!-- the layout root: one named container, two subgrid layers -->
<WebsiteScaffold>
  {#snippet header()}
    <!-- chrome-only header: the nav is composed from the family -->
    <TerminalHeader brand="my-app">
      <NavigationMenu label="primary">
        <NavigationMenuLink href="/">home</NavigationMenuLink>
        <NavigationMenuLink href="/docs" current>docs</NavigationMenuLink>
      </NavigationMenu>
      {#snippet drawer()}
        <!-- the mobile tier's nav, authored in your tree -->
      {/snippet}
    </TerminalHeader>
  {/snippet}

  <!-- STATIC chrome (SSR-stable): toc rails / nav trees authored in
       their final grid cells — never moved by hydration -->
  {#snippet chrome()}
    <MyPageToc data-area="toc" />
    <MyCatalogTree data-area="tree" />
  {/snippet}

  <!-- default snippet → main#main in the content column -->
  <RouterOutlet />

  {#snippet footer()}
    <TerminalFooter ghost="MY-APP" />
  {/snippet}
</WebsiteScaffold>

W3C foundation

What the platform gives

Container queries size the forms on the host's own width (embeddability without JS); subgrid shares the columns so chrome and content can never drift; :has() targets chrome from the content side; view transitions persist the chrome across navigations. The scaffold composes these four platform powers into one grid.

usage
<script lang="ts">
  import WebsiteScaffold from '@ui/website-scaffold.svelte';
  import '@ui/website-scaffold/website-scaffold.css';
  import TerminalFooter from '@ui/terminal-footer.svelte';
  import TerminalHeader from '@ui/terminal-header.svelte';
  import { NavigationMenu, NavigationMenuLink } from '@ui/navigation-menu/index';
</script>

<!-- the layout root: one named container, two subgrid layers -->
<WebsiteScaffold>
  {#snippet header()}
    <!-- chrome-only header: the nav is composed from the family -->
    <TerminalHeader brand="my-app">
      <NavigationMenu label="primary">
        <NavigationMenuLink href="/">home</NavigationMenuLink>
        <NavigationMenuLink href="/docs" current>docs</NavigationMenuLink>
      </NavigationMenu>
      {#snippet drawer()}
        <!-- the mobile tier's nav, authored in your tree -->
      {/snippet}
    </TerminalHeader>
  {/snippet}

  <!-- STATIC chrome (SSR-stable): toc rails / nav trees authored in
       their final grid cells — never moved by hydration -->
  {#snippet chrome()}
    <MyPageToc data-area="toc" />
    <MyCatalogTree data-area="tree" />
  {/snippet}

  <!-- default snippet → main#main in the content column -->
  <RouterOutlet />

  {#snippet footer()}
    <TerminalFooter ghost="MY-APP" />
  {/snippet}
</WebsiteScaffold>

law

The grid law

Why one grid instead of absolute positioning: the two layers share the SAME named columns through subgrid, so chrome and content can never drift apart — and forms are container queries on the host, so an embedded scaffold shows the right form at any width. Placement is declarative; motion stays per-zone transforms.

  • ONE scroll plane: .jx-shell-body owns every scroll on the site — window scrolling and fixed-position demos must target it, not the window
  • ONE grid, two layers: both layers span the same shell grid and subgrid its columns — the toc rail and the content column align by construction, and adopted nodes land by [data-area] role
  • THE OVERLAY POINTER LAW (adjudicated D-1 fix): overlay containers are pointer-TRANSPARENT; real content opts back in — and the grant STOPS at float wrappers, so an adopted float covering the stage can never shield the page beneath (measured: header pointer-events auto, the float slot none)
  • STATIC chrome and DYNAMIC floats never mix: the toc rail and catalog tree render in the chrome snippet (SSR-stable, never moved by hydration); adopted float nodes land in .jx-float-slot through the context, in adoption order

types

Types

One shell, four snippet seams, three container-query forms — the same grid re-grids per width.

≥1200 · tree nav rail

[rail 16rem][content 1fr][toc 15rem] — measured 256 / 1104 / 240 at a 1600 viewport; the catalog tree joins the top layer.

900–1199 · toc bottom fold

[content 1fr][toc 15rem] — the tree folds to a bottom bar; the toc rail keeps its column.

<900 · tocbar row

[content 1fr] + the tocbar row under the header — the glass single-row rail's home (the toc family's mobile surface).

usage

Usage

The layout root: one named container, header/chrome/children/footer snippets in their final cells.

WebsiteScaffold usage
<script lang="ts">
  import WebsiteScaffold from '@ui/website-scaffold.svelte';
  import '@ui/website-scaffold/website-scaffold.css';
  import TerminalFooter from '@ui/terminal-footer.svelte';
  import TerminalHeader from '@ui/terminal-header.svelte';
  import { NavigationMenu, NavigationMenuLink } from '@ui/navigation-menu/index';
</script>

<!-- the layout root: one named container, two subgrid layers -->
<WebsiteScaffold>
  {#snippet header()}
    <!-- chrome-only header: the nav is composed from the family -->
    <TerminalHeader brand="my-app">
      <NavigationMenu label="primary">
        <NavigationMenuLink href="/">home</NavigationMenuLink>
        <NavigationMenuLink href="/docs" current>docs</NavigationMenuLink>
      </NavigationMenu>
      {#snippet drawer()}
        <!-- the mobile tier's nav, authored in your tree -->
      {/snippet}
    </TerminalHeader>
  {/snippet}

  <!-- STATIC chrome (SSR-stable): toc rails / nav trees authored in
       their final grid cells — never moved by hydration -->
  {#snippet chrome()}
    <MyPageToc data-area="toc" />
    <MyCatalogTree data-area="tree" />
  {/snippet}

  <!-- default snippet → main#main in the content column -->
  <RouterOutlet />

  {#snippet footer()}
    <TerminalFooter ghost="MY-APP" />
  {/snippet}
</WebsiteScaffold>

theming

Theming

No density tokens — the shell publishes structural measurements; everything else derives from them in CSS. The theme stamp is declarative: the shell IS the page ground, and the canvas stage's light-island pin (the host layer) lives one family over.

xs
shell stand-in — a scaffold cannot nest
sm
shell stand-in — a scaffold cannot nest
default
shell stand-in — a scaffold cannot nest
lg
shell stand-in — a scaffold cannot nest
TokenDefaultSource
--jx-header-h58px / 74px per form (RO-corrected)structural
--jx-rail-wgrid rail widthstructural
--jx-toc-wtoc column widthstructural
--jx-toc-line76px :root standalone · 106px shell-derivedstructural
--jx-chrome-bar44pxstructural
--jx-chrome-top / --jx-chrome-bottomzone insetsstructural

api

API

The strictest contract in the fleet: FOUR snippet seams (header, chrome, children, footer) plus the splash seat and the eight axes — and NOTHING else. The scaffold is SNIPPET-COMPOSED AND REST-LESS: no rest spread exists, so nothing consumer-authored lands on the shell except through the seams. Placement for consumer chrome rides data-area roles (static) or the adopt() context (dynamic floats — ordered, release fn, consumer teardown). The eight axes are a FIRST-TIME all-no-own container contract (the universal fold serves the rows).

Properties

PropertyTypeDefaultDescription
header * Snippet—The nav band chrome (usually terminal-header with composed nav).
splash Snippet—The BOOT SPLASH seat: rendered at the HOST ROOT, above every layer — the splash’s own styles ride the HTML so it paints before any async stylesheet (the FOUC mask).
chrome Snippet—Static chrome, SSR-stable: the toc rail and catalog tree render here, never moved by hydration.
children * Snippet—The default snippet → main#main in the content column.
footer Snippet—Optional footer in the content flow.
TopLayerApi (context) adopt(node, { area }) → release—Dynamic float adoption into the top layer — ordered, multi-node, semantic areas (toc | tree | float); consumers keep node ownership.

Universal props

PropertyTypeDefaultDescription
size'small' | 'medium' | 'large' | 'auto' | number'auto' · ambient scopethe base scale — root font-size; parts size in em
shape'round' | 'scoop' | 'bevel' | 'notch' | 'square' | 'squircle' | 'auto''auto' · ambient scopecorner geometry (CSS corner-shape; §14 degrade table)
radius'small' | 'medium' | 'large' | 'auto' | number'auto' · ambient scopecorner size; auto = the concentric broadcast (§3)
density'small' | 'medium' | 'large' | 'auto' | number'auto' · ambient scopespacing/leading scale over the kernel channels (§4)
color'primary' | 'secondary' | 'error' | 'warn' | 'success' | 'info' | 'auto' | number | string'auto' · ambient scopethe hue axis of the fixed oklch primary system (§5)
theme'light' | 'dark' | 'system' | 'auto''auto' · ambient scopelight/dark profile; system = the JS-mutable global (§6)
elevation'level-1' | 'level0' | 'level1' | 'level2' | 'level3' | 'level4' | 'level5' | 'auto' | number'auto' · ambient scopeofficial M3 levels over the surface ladder (§7)
motion'reduced' | 'subtle' | 'normal' | 'expressive' | 'auto' | number'auto' · ambient scopeintensity across the motion kernels (§8)

axes

The eight axes on website-scaffold

The FIRST-TIME all-no-own CONTAINER contract, measured on the live shell: density stamps nothing at auto (the no-opinion law made visible); size is the type-scale seam at the top (every zone supplies downward); theme is the declarative stamp over the page ground — the strata's host, not a member; shape/radius/color/elevation/motion supply unread (the immersive leaves are transforms, the count readout discipline lives in the fields).

PropertyTypeDefaultDescription
density '2xs' | 'xs' | 'sm' | 'default' | 'lg' | 'auto' | number (+ the five legacy spellings)'auto'NO-OPINION CONTAINER, MEASURED ABSENT — the zones carry no density paint, and at auto the rung attr stamps NOTHING on the host (measured: data-density absent on the live shell — the no-opinion law is visible, not just declared). Zero --jx-density-effective readers (grep receipt). Number unit: coefficient.
size 'small' | 'medium' | 'large' | 'auto' | number'auto'THE TYPE-SCALE SEAM AT THE TOP — the §1 stamp scales the HOST root and every zone supplies downward: the header, the toc rail and the page content are the consumers (吃也供 — the site-level type-scale seam: one number scales the whole scaffold). Zero --jx-size-effective readers (grep receipt). Number unit: px.
shape 'round' | 'scoop' | 'bevel' | 'notch' | 'square' | 'squircle' | 'auto''auto'SUPPLY-ONLY — zero shape-channel readers (grep receipt: no corner-shape or factor consumer in ui/website-scaffold/); the shell is structural chrome. Number unit: none.
radius 'small' | 'medium' | 'large' | 'auto' | number'auto'SUPPLY-ONLY — zero radius-effective readers (grep receipt); the shell owns no decorative corners (the zones are full-bleed structural bands). Number unit: px.
color 'primary' | 'secondary' | 'error' | 'warn' | 'success' | 'info' | 'auto' | number | string'auto'SUPPLY-ONLY — the zones paint the theme profile directly (var(--border)/var(--background)/the --jx-* inks); zero --jx-color-effective readers (grep receipt). Number unit: hue degrees.
theme 'light' | 'dark' | 'system' | 'auto''auto'DECLARATIVE STAMP — THE HOST OF HOSTS. theme="dark" stamps the .dark class on the shell-host, and the shell IS the page ground: measured, the body ground flips oklch(1 0 0) → oklch(0 0 0) under the page bridge. The theme story’s strata terminate here — the canvas stage’s data-theme="light" + .jx-light island (the host layer that pins demo subtrees, measured on the sibling lanes) is stamped by the COMPONENT CANVAS, not by this scaffold: the scaffold hosts the strata rather than joining them all. system/auto = tree inheritance. No number lane.
elevation 'level-1' | 'level0' | 'level1' | 'level2' | 'level3' | 'level4' | 'level5' | 'auto' | number'auto'SUPPLY-ONLY — zero elevation-carrier readers (grep receipt); the immersive leaves are TRANSFORMS (translateY, measured matrix(…, −74.74)), never shadow tiers. Number unit: dp.
motion 'reduced' | 'subtle' | 'normal' | 'expressive' | 'auto' | number'auto'SUPPLY-ONLY — zero --jx-motion-effective readers (grep receipt); the immersive law is SCROLL-POSITION-driven (an 8px threshold, rAF-throttled, one data-hidden state) — a behavioral channel with no autonomous animation, so it is reduced-motion-safe by nature (reduced motion swaps the playground’s smooth scroll to instant). Number unit: coefficient.

Receipts (all on the LIVE shell — this page's own chrome — unless noted): the form grid (256 / 1104 / 240 at a 1600 viewport; re-grids measured at 700/1000), --jx-header-h 74px with the ResizeObserver correction landing on .jx-shell (the declaring scope), the body reservation (scroll-padding 106px; 6164px scrollable at the task-70 read — a point-in-time digit, the page grows with the campaign), the immersive law (data-hidden + header translateY −74.74px on scroll-down, reveal on scroll-up), the overlay pointer law (header auto / float slot none), the named-area budget per form (header header header / tree stage toc → header header / stage toc → header tocbar / stage), the skip link (#main), the view-transition names (site-header / page-main), the boot splash (SSR-shipped, unmounted live — the seat is the layout's), the embeddable 480px instance (the narrow form inside the wide window) and the canvas stage's data-theme="light" + .jx-light island pin were measured by the task-70 probe; the unread rows carry grep receipts over ui/website-scaffold/. The query() seat below rides the md viewport key (48rem) on the size lane.

one real query() case
<script lang="ts">
  import WebsiteScaffold from '@ui/website-scaffold.svelte';
  import { query } from '@lib/universal-props-query.svelte';
</script>

<!-- below 48rem the base (13px root) applies; at 48rem+ the md case (18px)
     wins — the type-scale seam scales every zone at once -->
<WebsiteScaffold size={query({ md: 18 }, 13)}>…</WebsiteScaffold>

website-scaffold · query()

Media keys are min-width: below 48rem the base (13px root) applies; at 48rem and wider the md case wins (18px) — the type-scale seam scales the HOST root, so every zone (header, rail, content) grows together. The number lane goes bare. Resize across 48rem and watch the whole shell breathe.

website-scaffold-query-demo.svelte svelte
<script lang="ts">
  import WebsiteScaffold from '@ui/website-scaffold.svelte';
  import { query } from '@lib/universal-props-query.svelte';
</script>

<!-- below 48rem the base (13px root) applies; at 48rem+ the md case (18px)
     wins — the type-scale seam scales every zone at once -->
<WebsiteScaffold size={query({ md: 18 }, 13)}>…</WebsiteScaffold>

WebsiteScaffold · universal props

The size stamp scales the host root — the site-level type-scale seam (one number, every zone). A scaffold cannot nest inside itself; this specimen rides the page's own shell.

website-scaffold-universal.svelte svelte
<WebsiteScaffold size={18} density="small">…</WebsiteScaffold>

a11y

Accessibility

Skip link to main#main, one landmark per zone, and chrome reservations that keep reflow honest.

Keyboard

KeyAction
TabThe hidden Skip to content link is the first stop; then header nav, then main
EnterFollows the skip link — the VIEW lands on #main at the toc line (scroll-padding); focus itself stays on body (main carries no tabindex −1 — the classic skip-link caveat)

ARIA

AttributeValueDescription
skip link"Skip to content"Keyboard-reachable target on #main, hidden until focused
landmarksheader / main#main / footerThe shell renders one landmark per zone; adopted nodes keep their authored semantics
view-transition-namessite-header / page-mainPersist across navigations so chrome never flashes
jixoai-ui ui.jixoai.com the jixoai design language

Theme

Brand hue

0°

Auto cycle · 24h