b. Zane Design System

Zane
design system

Everything /, /easyagent/ and /llmbench/ have in common, in four files. Ink on paper, hairline rules, deep navy for emphasis — plus a WebGL dither field and a character-grid renderer for texture. This page loads the system exactly the way a real consumer does, so it breaks when the system breaks.

Four files

shared/editorial.css
Tokens (light and dark), reset, nav, buttons, footer, reveal keyframes, the shader-canvas CSP rule, view transitions, reduced motion.
shared/motion.js
Scroll reveals. Page-agnostic — nothing in it knows about a particular page.
shared/backdrop.js
One function: a dithering field mounted into a host element.
shared/ascii.js
One function: an image resolved to a character grid.

backdrop.js resolves its vendored shaders relative to itself, so the whole shared/ directory can sit at a site root or in a subdirectory.

The head, verbatim

<script>
  document.documentElement.classList.add("js");
  document.documentElement.dataset.theme =
    localStorage.getItem("bz-theme") || "dark";
</script>

<link rel="stylesheet" href="/shared/editorial.css">
<link rel="stylesheet" href="your-page.css">

The inline script must stay inline: html.js gates every hidden-until-revealed style, so a no-JS visitor sees everything, and the theme has to resolve before first paint or the page flashes white. Dark is the default — the OS preference is deliberately not consulted. The bz-theme key is shared across every page on the domain.

Load editorial.css before your page stylesheet. Page CSS may override anything in the layer; the layer never reaches into a page.

The ramps

Component rules use tokens only, never literal colors — that is what lets EasyAgent's body[data-profile] theming (Frampton's dark inversion especially) cascade over everything. Flip the theme in the nav: every swatch below is live, and the paper and ink ramps invert from the shared file.

Three stacks, three jobs

--serif

Source Serif 4 — body copy and headlines. The voice of the page.

--sans

Inter Tight — navigation, labels, UI. Present but not speaking.

--mono

JetBrains Mono — tags, specs, figures. 0123456789 · ↗ □ ●

accent

Playfair Display italic — exactly one word per page.

Chrome

Buttons

.ed-cta-secondary and .ed-cta-ghost both set appearance: none and a transparent background — dropping the native look alone leaves the UA's buttonface behind, which paints a near-white pill on a dark page.

Section label

Nav

.ed-nav is sticky, blurred paper — the subpage treatment, and what you are looking at above. .ed-nav--overlay is fixed, transparent and mix-blend-mode: difference; its white is literal, because difference inverts it against whatever scrolls under. It exists for the main page's photo hero.

Focus & skip link

Tab into the page from the address bar: the skip link slides down from the top-left. Every focusable element gets a 2px --blue-500 ring at 2px offset, :focus-visible only — never on mouse click.

Reveals

motion.js adds .is-inview on intersection and unobserves. Reveals are keyframe animations, not transitions, so they never clobber a component's own transition — a work row can hover-animate while its reveal is still running.

data-reveal="rise"

Fade up 14px. The default for a block of content.

data-reveal="rule"

Slide in 10px from the left. For section labels and hairlines.

data-reveal="cascade"

Children stagger 45ms via --i, which motion.js sets. Dotted .dots leaders draw in alongside.

  1. Cascade child01
  2. Cascade child02
  3. Cascade child03
  4. Cascade child04
  5. Cascade child05

Reduced motion is handled in three places that must stay in sync: motion.js short-circuits to final states, the shared CSS block kills every reveal and transition, and each page's own block covers its local effects. Any new effect must be covered in all three.

Dither backdrops

A vendored subset of paper-shaders (Apache-2.0). One shader is wired up — dithering — across seven field shapes and four dither matrices. mountBackdrop() parks at setSpeed(0) when its host scrolls off screen, when the tab is hidden, and under reduced motion, which cancels the rAF outright.

import { mountBackdrop } from "/shared/backdrop.js";

mountBackdrop(hostOrSelector, {
  back, front,        // two colors; the field dithers between them
  shape,  // 1 simplex · 2 warp · 3 dots · 4 wave · 5 ripple · 6 swirl · 7 sphere
  type,   // 1 noise · 2 Bayer 2x2 · 3 Bayer 4x4 · 4 Bayer 8x8
  pxSize, scale, speed, frame,
  observe,            // false for fixed hosts that are always on screen
});  // → { setColors(back, front) }, or null when the host is absent

Host contract: an empty aria-hidden div that is a sibling of the content, never a wrapper. The content wrapper carries position: relative; z-index: 1; the host's parent carries position: relative; overflow: hidden. The module adds .is-live only once a canvas exists, so a CSS fallback shows through when WebGL is unavailable. Canvas positioning comes from the [data-paper-shader] > canvas rule in editorial.css, because the production CSP blocks the inline <style> the library injects — without it a backdrop works locally and is invisible in production.

Field shapes · Bayer 4×4

Dither matrices · simplex field

Character grids

There is no ASCII shader in paper-shaders — dithering emits 1-bit pixel cells, not glyphs. So ascii.js is the character-grid counterpart to backdrop.js: the same quiet-texture job, done with type. No WebGL context, nothing to dispose, nothing for the reduced-motion blocks to suppress — the output is a string.

import { asciiFromImage } from "/shared/ascii.js";

host.textContent = await asciiFromImage("/assets/work/shuttrr-row.webp", {
  cols,      // grid width in characters
  charset,   // dense → sparse glyph ramp
});

Bright pixels get the heaviest glyph, because these marks are drawn as light ink on a dark ground. Each image is stretched to its own 2nd/98th-percentile black and white points first — without that a dark frame renders as a blank grid. The Shuttrr row below has 78% of its pixels below 0.1 luma.

Ramp · default charset

Specimen · the Shuttrr work row

Hand-authored ASCII is the other half of the story: EasyAgent's per-agent wordmarks and mascots are figlet string arrays set with textContent, never innerHTML. Meaningful marks carry an aria-label; decorative ones carry aria-hidden, like the specimen above.