From a44a8a2c35b4a0341d119465c1cbbf4e75b7b981 Mon Sep 17 00:00:00 2001 From: Hayden Bruin Date: Tue, 25 Aug 2026 14:34:39 +1000 Subject: [PATCH] docs: ship an agent reference in the package, plus a Claude Code skill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds AGENTS.md to the published files, so it lands at node_modules/@engineio/ui/AGENTS.md and versions with the code. Consuming repos point at that path instead of copying rules into their own CLAUDE.md, where a copy goes stale on the next version bump — and stale brand rules are worse than no brand rules, because they read as authoritative. The content is what an agent actually needs and a human README buries: the @source requirement and why its absence is silent, the three import forms, the variant roster per component, the exact token names, the hard rules as rules rather than prose, the tv({ extend }) seam, and the known gaps. It deliberately repeats almost nothing from README.md, which is written for a person deciding whether to adopt this. Also adds .claude/skills/engine-design-system/SKILL.md. Skills must live in .claude/skills/, ~/.claude/skills/ or a plugin — Claude Code does not load them from node_modules — so the skill is a deliberately thin pointer at the package's AGENTS.md plus the half-dozen rules worth having in mind before reading it. Keeping the substance in the package means the copied file contains nothing that can rot, and a skill body loads lazily so the reference costs nothing until a UI task needs it. --- .claude/skills/engine-design-system/SKILL.md | 26 ++++ AGENTS.md | 138 +++++++++++++++++++ README.md | 29 ++++ package.json | 1 + 4 files changed, 194 insertions(+) create mode 100644 .claude/skills/engine-design-system/SKILL.md create mode 100644 AGENTS.md diff --git a/.claude/skills/engine-design-system/SKILL.md b/.claude/skills/engine-design-system/SKILL.md new file mode 100644 index 0000000..f9c2ff6 --- /dev/null +++ b/.claude/skills/engine-design-system/SKILL.md @@ -0,0 +1,26 @@ +--- +name: engine-design-system +description: Rules and component reference for the Engine design system (@engineio/ui). Use when building or reviewing any Engine surface — Svelte components, styles, tokens, colour, type, spacing, the brand marks — or when choosing a Button/Badge/Alert variant, adding a component variant, or picking a colour. +--- + +Read `node_modules/@engineio/ui/AGENTS.md` before writing UI. It ships with the +package, so it matches the installed version — do not rely on memory of these +rules, and do not copy them into a repo where they will go stale. + +If that file is absent the package is not installed here; say so rather than +guessing at the system. + +Non-negotiable, and worth having in mind before you read further: + +- Three brand colours: Off Black `#0E0E0E`, Pure White `#FFFFFF`, Magenta + `#FF006A`. One accent per surface. +- Never a hex literal or a Tailwind stock colour. Use a token. CI fails on both. +- `success` / `warning` / `danger` are FUNCTIONAL. They report state, never + category, and never decoration. +- Ink on any status or accent fill is Off Black. White fails AA on all three. +- No emoji. No gradients. No light theme. No `dark:` variants. +- Add a variant by `tv({ extend: … })` in the product, never by forking a + component or upstreaming a product-only variant. + +For anything the file does not cover, choose the quieter and more mechanical +option, and flag the gap rather than inventing a rule. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..eda6310 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,138 @@ +# @engineio/ui — agent reference + +The Engine design system. This file ships inside the package, so it arrives in +`node_modules/@engineio/ui/AGENTS.md` and versions with the code — point at it +rather than copying its contents into a repo, or the copy goes stale. + +Authoritative source: `docs/brand/ENGINE-DESIGN-SYSTEM.md` and +`ENGINE-BRAND.md` in the `engineio/engine` repo. Where this file and those +disagree, **they win and this is a bug**. + +## Setup + +```css +@import "tailwindcss"; +@import "@engineio/ui/styles"; +@source "../../../node_modules/@engineio/ui/dist"; +``` + +**The `@source` line is not optional and its absence is silent.** Tailwind 4 +does not scan `node_modules`, so without it the utility classes the components +are written against are never generated. The tokens still land and any class +that also appears in local source still works, so you get a half-styled app +that reads like a component bug. Path is relative to the CSS file declaring it. + +## Importing + +```svelte +import { Button, Card, CardHeader } from "@engineio/ui" +import { Button } from "@engineio/ui/components/ui/button/index.js" +import * as Card from "@engineio/ui/components/ui/card/index.js" +import { EngineWordmark } from "@engineio/ui/components/brand/index.js" +``` + +Root barrel exports flat prefixed names (`CardHeader`). Subpath modules export +`Root`/`Header`/`Content`, so `import * as Card` works. Both `/index.js` and the +bare subpath resolve. + +## Components + +Alert, Badge, Button, Card, Checkbox, Dialog, Input, Label, Popover, Progress, +RadioGroup, Select, Separator, Skeleton, Switch, Table, Tabs, Textarea, Tooltip. +Marks: `EngineWordmark`, `EngineIcon`. + +Not shipped, on purpose: `sonner`, `form`, `data-table`, `drawer`, `resizable`, +`carousel`, `chart`. Copy from the engine repo if needed. + +| Component | Variants | +| --- | --- | +| Button | `default` `inverse` `outline` `ghost` `secondary` `link` `icon` `destructive` `success`; sizes `sm` `default` `lg` `icon` `icon-sm` `icon-lg` | +| Badge | `default` `secondary` `outline` `partner` `success` `warning` `danger` `destructive` | +| Alert | `default` `success` `warning` `danger` `destructive`; optional `onDismiss` | +| Marks | `variant="primary"` (white) or `"secondary"` (Off Black) | + +There is **one** chip. Badge absorbed Tag — a soft tinted chip, not a solid +pill. There is no `Tag` export and no `solid` badge variant: an opaque fill can +only be correct on one surface, and badge fills are translucent so they read on +the page, on a card and on a table tile alike. + +## Tokens + +Use these names; never a literal. + +``` +colour --color-background #0E0E0E --color-foreground #FFFFFF + --color-primary #FF006A --color-primary-press #D60059 + --color-primary-300 #FF5C9B (ink on a magenta tint) + --color-primary-tint-12 / -24 + --color-card #161616 --color-popover #1C1C1C + --color-grey-950 … --color-grey-050 (the only greys) + --color-partner-yellow #FFDD00 (reserved, not in use) +status --color-success #00C46A --color-warning #FFB020 --color-danger #FF3B30 + each with -foreground (always Off Black) and -tint-12 + --color-destructive aliases danger +radii --radius-tag 6 --radius-field 10 --radius-card-inner 10 + --radius-media 14 --radius-card 18 --radius-frame 26 + --radius-control 999 +motion --ease-brand --ease-brand-out --ease-brand-accelerate + 140ms controls · 220ms surfaces · 360–640ms reveals +type --font-brand (Proxima Nova) --font-mono (JetBrains Mono, see gaps) +depth --shadow-panel --shadow-modal (product chrome and modals only) +utility `field` — the shared input skin, incl. the focus ring +``` + +## Rules + +- **Three brand colours**: Off Black, Pure White, Magenta. One accent per + surface, never two. +- **Status colour is functional.** `success`/`warning`/`danger` report state. + Never use them as a categorical palette — `success` for "slots" because green + looked right spends the only signal they carry. +- **No off-palette colour.** Not Tailwind's stock ramps, not a hex literal. CI + fails on both. +- **Retired and unavailable**: Originals Orange `#FF6200`, Sportsbook Blue + `#00CCFF`. No accents, no charts, no status. +- **Ink on any status or accent fill is Off Black.** White fails AA on all three. +- **Magenta text**: never below 15px bold. Use `--color-primary-300` on a tint. +- No gradients. No light theme. No `dark:` variants — the dark palette is the + only palette. No drop shadows on brand surfaces. No coloured borders, and no + coloured left-edge accent to signal category or ownership. +- Radii by role, and the outer frame is always larger than the inner panel. +- Borders are 1px hairline or 1.5px container rule. Nothing else. +- **No emoji, anywhere.** Only `×` for close and `✱` for footnotes. +- Voice: declarative, British/AU spelling, headlines end in a full stop. +- Icons: Lucide, 2px stroke, `currentColor`. + +## Extending + +Do not fork a component to add a variant, and do not upstream a product-only +variant. Every variant map is exported: + +```ts +import { buttonVariants } from "@engineio/ui" +import { tv } from "tailwind-variants" + +export const appButtonVariants = tv({ + extend: buttonVariants, + variants: { variant: { drawer: "w-full justify-start rounded-none …" } }, +}) +``` + +Brand rules stay in the package; product variants stay in the product. Every +primitive also passes `class` through `cn`, so `