@komuta/frontend-harness
v1.6.0
Published
Generative Design System, Multi-Suite Architecture & Agentic Governance Test Harness
Readme
@komuta/frontend-harness
Generative Design System, Multi-Suite Architecture & Agentic Governance Test Harness
@komuta/frontend-harness is an enterprise generative design system and agentic governance engine built for modern React and TypeScript applications. It enforces strict information hierarchy, cognitive load budgets, and design token isolation across multi-suite design vocabularies.
📦 Installation
npm install @komuta/frontend-harness material-symbols
# or
pnpm add @komuta/frontend-harness material-symbols
# or
yarn add @komuta/frontend-harness material-symbols🚀 Quickstart
1. Import Styles & Initialize Theme
In your main application entry point (e.g. main.tsx or index.tsx):
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
// 1. Import base styles, keyframe animations, token declarations & Material Symbols
import '@komuta/frontend-harness/styles.css';
import 'material-symbols/outlined.css';
// 2. Install the system: colour, spacing ladder and motion, in one call
import { applySystemStyle } from '@komuta/frontend-harness';
applySystemStyle({
density: 'comfortable', // 'compact' | 'comfortable' | 'spacious'
mode: 'light', // 'light' | 'dark'
});
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>
);
applySystemStyleinstalls all three subsystems. Installing colour on its own leaves everyvar(--pad-*)andvar(--space-*)unresolved, and an unresolved custom property inside a Tailwind arbitrary value produces no declaration at all — a fully coloured page with zero padding everywhere. The underlyingapplyTheme/applyDensity/applyMotionremain exported for callers that genuinely want one of them.
🌗 Server rendering & dark mode
Astro, Next.js, Remix and any other static or server-rendered page cannot run applySystemStyle
before the first paint. generateSystemCssBlock returns the same installation as a CSS string:
// '/css' is the token layer without the component library — nothing that renders.
import { generateSystemCssBlock } from '@komuta/frontend-harness/css';
// In your document head — no JavaScript, no hydration gap.
<style dangerouslySetInnerHTML={{
__html: generateSystemCssBlock({ mode: 'dark', density: 'spacious' })
}} />The block contains every custom property the system needs: the --color-* ramps, the ground
surfaces, the --space-* / --pad-* ladder and the motion durations. generateSystemCssVariables
returns the same set as an object if you would rather write it somewhere else.
@komuta/frontend-harness/styles.css already carries this block for the default light,
comfortable configuration, declared in @layer base — so a page that only imports the stylesheet
renders correctly, and any block you inject yourself overrides it regardless of source order.
⚠️ Do not use Tailwind's built-in colour palette
In Tailwind v4 the built-in palette is itself a set of custom properties: bg-neutral-500 compiles
to background-color: var(--color-neutral-500). This package defines those same names on :root
as channel triplets (215 14% 48%), because hsl(var(--color-*) / α) composition depends on it.
So on a page that loads this system, Tailwind's own colour utilities die silently:
bg-neutral-900 produces background-color: 215 9.1% 15%, the browser discards it as invalid, and
the element renders transparent. No error, no warning — just an invisible surface.
Take colour from the ramp instead: bg-[hsl(var(--color-neutral-900))],
text-[hsl(var(--color-accent-600))], and the ground variables above for surfaces.
Multi-tenant theming
A tenant's brand is two or three numbers in a database, and the whole system re-skins from them — no rebuild, no CSS to write:
import { createTheme, generateSystemCssBlock } from '@komuta/frontend-harness/css';
// In a loader / middleware / edge function
const theme = createTheme({
accent: { h: tenant.accentHue, s: tenant.accentSat },
neutral: { h: 220, s: 12 },
mode: tenant.mode, // 'light' | 'dark'
});
const css = generateSystemCssBlock({ theme, density: 'comfortable' }); // ~0.1 ms per tenant<style dangerouslySetInnerHTML={{ __html: css }} />Use generateSystemCssBlock, not themeToCssBlock. The latter emits colour only — 77
variables, no --pad-*, no --space-*, no --motion-* — and a page installed that way renders
with the full palette and zero padding everywhere.
For an isolated fragment (closed shadow root, embedded in someone else's site), pass the selector:
generateSystemCssBlock({ theme, density: 'compact', selector: ':host' })Custom properties inherit through a shadow boundary, so a partial block lets the host page's own
--color-* values leak in. A complete block on :host is what makes the fragment immune. The
utility classes still come from the compiled stylesheet — adopt it into the shadow root too
(shadowRoot.adoptedStyleSheets = [sheet]), or the components render unstyled.
Contrast is hue-invariant by construction. The accent ramp is tone-mapped: a stop carries the
same relative luminance as the neutral gray at that stop, whatever hue the tenant picked. Measured
without it, half the hue circle (30–200°) broke AA in light mode at s≥70. The build sweeps 216
themes across the circle in both modes — 4752 contrast checks — and fails on a single shortfall.
A gray accent is unaffected (it is the reference); toneMapping: 'raw' opts out and forfeits the
guarantee.
Dark mode
mode: 'dark' mirrors the ramp rather than introducing a second palette. A stop keeps its meaning
— neutral-50 is always the tone furthest from the text colour, neutral-900 is always the text
colour — so components invert with the theme and nothing needs a dark: variant:
import { createTheme, generateSystemCssBlock } from '@komuta/frontend-harness';
const dark = createTheme({ accent: { h: 22, s: 92 }, neutral: { h: 215, s: 14 }, mode: 'dark' });
const css = generateSystemCssBlock({ theme: dark, density: 'comfortable' });Four roles cannot be expressed as a ramp stop, because they sit outside the ramp in opposite
directions per mode. Use these instead of white, black or a stop:
| Variable | Role | Light | Dark |
| :--- | :--- | :--- | :--- |
| --surface-canvas | the page ground | 96% L | 4% L |
| --surface-panel | a card, a panel, an input — the base surface | 100% L | 10% L |
| --surface-raised | that surface lifted on hover or overlay | 100% L | 14% L |
| --text-inverse | text on an inverted fill (solid button, dark panel) | 98% L | 8% L |
| --text-muted | meta labels, units, timestamps | 45% L | 58% L |
| --shadow-tint | depth — always downward, never a ramp stop | 15% L | 2% L |
Write them like any other token: bg-[hsl(var(--surface-panel))],
text-[hsl(var(--text-inverse))], bg-[hsl(var(--surface-panel)/0.95)] for alpha.
Authoring rule, enforced by Phase 24 of the harness: bg-white, text-white, bg-black and
their alpha forms are absolutes. They render identically in both modes, so on a dark canvas they
become a page of white cards. The budget is zero; a colour that genuinely must stay absolute is
marked // theme-exempt: <reason>.
Contrast is computed, not claimed
Colour is generated here, so contrast is derivable. tokens/contrast.ts declares 22
foreground/background pairs and Phase 25 re-computes all of them in both modes on every build.
Text pairs are checked against WCAG 2.1 §1.4.3 (4.5:1); boundary pairs — a hairline, the panel/page
tone step, the hover lift — carry a declared perceptibility floor and are not WCAG claims.
import { auditContrast } from '@komuta/frontend-harness/css';
auditContrast(); // the active theme, both modes
auditContrast(myThemeParams); // your theme — ratios re-derived, nothing to re-assertIf a pair falls under its floor, move the role, not the threshold: give it its own per-mode
value the way --text-muted and the ground surfaces have one. Lowering a floor makes the claim
false instead of making the product readable.
🎬 Motion
Animation ships as CSS classes; there is no runtime animation dependency:
import { KmtAnimatePresence, KmtTransition } from '@komuta/frontend-harness';
<KmtAnimatePresence mode="wait">
<KmtTransition key={tab} variant="rise"><Panel … /></KmtTransition>
</KmtAnimatePresence>.kmt-animate-enter | -exit | -fade | -rise | -sheet | -backdrop | -drawer-in | -drawer-out | -pulse
| -ping | -spin | -shimmer. Every duration and easing comes from a role in motionContracts.ts —
feedback 100ms, swap 120ms, state 150ms, enter 200ms, exit 120ms, travel 220ms,
ambient 2000ms, loader 1000ms — and Phase 27 fails the build on a duration, an easing or an animated
property that does not trace to one. Only opacity, transform and filter may be animated.
The earlier .motion-* / .swap-transition class names still work as deprecated aliases sharing
the same declaration.
🔎 Validating the app that installs this
The design system's audits run in your project, not just in this package:
npx komuta-harness srcTen portable audits — off-theme colour, undeclared pixels and type stops, box-in-box, surface collisions, detached repetition, icon axes, mode-locked colour — plus two rules that only exist on this side of the package boundary:
| Rule | Why |
| :--- | :--- |
| IMPORTANT_OVERRIDE | An !important against the design system measures a missing token. Write the token; if the override is genuinely required, keep it with important-allowed: <reason>. |
| TAILWIND_PALETTE_COLLISION | bg-neutral-500 reads var(--color-neutral-500), a name this package overwrites with a channel triplet — invalid declaration, transparent element, no error. |
Flags: --json (CI), --warn-only, --skip RULE_A,RULE_B. Exit code is 1 when anything is found.
The same audits are callable directly:
import { validateTree } from '@komuta/frontend-harness/validate';
const report = validateTree(files); // [{ path, content }, …]🎯 Composing a landing page
Marketing pages are a governed page kind, not an exception to the system:
import { MarketingShell, AtmosphericHero, BentoGrid } from '@komuta/frontend-harness';MarketingArchetype + MarketingShell + the marketing intent, whose dominant capability is
value-proposition — one hero per page. The budget is generous where a scroll narrative needs it
(7 patterns, cognitive load 14.0) and stricter than any other archetype where it matters: one
dominant region for the whole page. Every other archetype budgets co-present regions competing
for one reader's attention; a landing page is read in sequence, one viewport at a time.
🧩 Usage
Core Components
import {
Button,
Card,
Icon,
MetricCard,
StatusPill,
ContiguousGroup,
ContiguousStrip,
DiagnosticRail,
DistributionMeterList,
CommandPaletteModal
} from '@komuta/frontend-harness';
export function AnalyticsWidget() {
return (
<Card className="p-4 space-y-4">
<div className="flex items-center justify-between">
<StatusPill status="healthy" label="Operational" />
<Button variant="primary" size="sm">
<Icon name="rocket_launch" size={14} />
Deploy
</Button>
</div>
<ContiguousStrip columns={3}>
<MetricCard label="Latency" value="14ms" trend="+2.4%" />
<MetricCard label="Throughput" value="1.2M req/s" trend="+5.1%" />
<MetricCard label="Error Rate" value="0.001%" />
</ContiguousStrip>
</Card>
);
}Composition Patterns & Shells
import {
DashboardShell,
MetricStrip,
LaunchpadGrid,
FacetedCatalog,
ReadingColumn
} from '@komuta/frontend-harness';
export function DashboardPage() {
return (
<DashboardShell
title="Edge Compute Console"
density="comfortable"
>
<MetricStrip
columns={4}
metrics={[
{ label: 'Ingress Traffic', value: '4.8 TB' },
{ label: 'Active Workers', value: '1,420' },
{ label: 'Cache Hit Ratio', value: '98.6%' },
{ label: 'P99 Response', value: '18ms' }
]}
/>
</DashboardShell>
);
}🛡️ Agentic Design Governance & Rules
@komuta/frontend-harness is designed to be paired with AI coding agents (Claude, Gemini, GPT-4, Cursor, AGY). The package includes:
AGENTS.md: Binding agentic decision hierarchy (Context→Intent→Hierarchy→Budget→Composition→Layout→Density→Tokens).- Surface Exclusivity & Box-in-Box Prevention: Surfaces must not nest duplicate borders or double-state boundaries (
SURFACE_COLLISION_BUDGET = 0). - Typography & Repetition Contracts: Guarantees contiguous grouping over detached card stacks and strict micro-typography scales.
- Mode Inversion Ratchet: No surface, text colour or hairline may be written as an absolute (
white/black), so a theme inverts without a singledark:variant (BUDGET_MODE_LOCKED = 0).
🧪 Compliance & Test Harness
Run the design system validation suite against your codebase:
npm run validate📄 License
MIT © Komuta
