Skip to content

Commit 862874b

Browse files
authored
Merge pull request #7 from engineio/docs/agent-reference
docs: ship an agent reference in the package, plus a Claude Code skill
2 parents 9be6199 + a44a8a2 commit 862874b

4 files changed

Lines changed: 194 additions & 0 deletions

File tree

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
name: engine-design-system
3+
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.
4+
---
5+
6+
Read `node_modules/@engineio/ui/AGENTS.md` before writing UI. It ships with the
7+
package, so it matches the installed version — do not rely on memory of these
8+
rules, and do not copy them into a repo where they will go stale.
9+
10+
If that file is absent the package is not installed here; say so rather than
11+
guessing at the system.
12+
13+
Non-negotiable, and worth having in mind before you read further:
14+
15+
- Three brand colours: Off Black `#0E0E0E`, Pure White `#FFFFFF`, Magenta
16+
`#FF006A`. One accent per surface.
17+
- Never a hex literal or a Tailwind stock colour. Use a token. CI fails on both.
18+
- `success` / `warning` / `danger` are FUNCTIONAL. They report state, never
19+
category, and never decoration.
20+
- Ink on any status or accent fill is Off Black. White fails AA on all three.
21+
- No emoji. No gradients. No light theme. No `dark:` variants.
22+
- Add a variant by `tv({ extend: … })` in the product, never by forking a
23+
component or upstreaming a product-only variant.
24+
25+
For anything the file does not cover, choose the quieter and more mechanical
26+
option, and flag the gap rather than inventing a rule.

AGENTS.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# @engineio/ui — agent reference
2+
3+
The Engine design system. This file ships inside the package, so it arrives in
4+
`node_modules/@engineio/ui/AGENTS.md` and versions with the code — point at it
5+
rather than copying its contents into a repo, or the copy goes stale.
6+
7+
Authoritative source: `docs/brand/ENGINE-DESIGN-SYSTEM.md` and
8+
`ENGINE-BRAND.md` in the `engineio/engine` repo. Where this file and those
9+
disagree, **they win and this is a bug**.
10+
11+
## Setup
12+
13+
```css
14+
@import "tailwindcss";
15+
@import "@engineio/ui/styles";
16+
@source "../../../node_modules/@engineio/ui/dist";
17+
```
18+
19+
**The `@source` line is not optional and its absence is silent.** Tailwind 4
20+
does not scan `node_modules`, so without it the utility classes the components
21+
are written against are never generated. The tokens still land and any class
22+
that also appears in local source still works, so you get a half-styled app
23+
that reads like a component bug. Path is relative to the CSS file declaring it.
24+
25+
## Importing
26+
27+
```svelte
28+
import { Button, Card, CardHeader } from "@engineio/ui"
29+
import { Button } from "@engineio/ui/components/ui/button/index.js"
30+
import * as Card from "@engineio/ui/components/ui/card/index.js"
31+
import { EngineWordmark } from "@engineio/ui/components/brand/index.js"
32+
```
33+
34+
Root barrel exports flat prefixed names (`CardHeader`). Subpath modules export
35+
`Root`/`Header`/`Content`, so `import * as Card` works. Both `/index.js` and the
36+
bare subpath resolve.
37+
38+
## Components
39+
40+
Alert, Badge, Button, Card, Checkbox, Dialog, Input, Label, Popover, Progress,
41+
RadioGroup, Select, Separator, Skeleton, Switch, Table, Tabs, Textarea, Tooltip.
42+
Marks: `EngineWordmark`, `EngineIcon`.
43+
44+
Not shipped, on purpose: `sonner`, `form`, `data-table`, `drawer`, `resizable`,
45+
`carousel`, `chart`. Copy from the engine repo if needed.
46+
47+
| Component | Variants |
48+
| --- | --- |
49+
| Button | `default` `inverse` `outline` `ghost` `secondary` `link` `icon` `destructive` `success`; sizes `sm` `default` `lg` `icon` `icon-sm` `icon-lg` |
50+
| Badge | `default` `secondary` `outline` `partner` `success` `warning` `danger` `destructive` |
51+
| Alert | `default` `success` `warning` `danger` `destructive`; optional `onDismiss` |
52+
| Marks | `variant="primary"` (white) or `"secondary"` (Off Black) |
53+
54+
There is **one** chip. Badge absorbed Tag — a soft tinted chip, not a solid
55+
pill. There is no `Tag` export and no `solid` badge variant: an opaque fill can
56+
only be correct on one surface, and badge fills are translucent so they read on
57+
the page, on a card and on a table tile alike.
58+
59+
## Tokens
60+
61+
Use these names; never a literal.
62+
63+
```
64+
colour --color-background #0E0E0E --color-foreground #FFFFFF
65+
--color-primary #FF006A --color-primary-press #D60059
66+
--color-primary-300 #FF5C9B (ink on a magenta tint)
67+
--color-primary-tint-12 / -24
68+
--color-card #161616 --color-popover #1C1C1C
69+
--color-grey-950 … --color-grey-050 (the only greys)
70+
--color-partner-yellow #FFDD00 (reserved, not in use)
71+
status --color-success #00C46A --color-warning #FFB020 --color-danger #FF3B30
72+
each with -foreground (always Off Black) and -tint-12
73+
--color-destructive aliases danger
74+
radii --radius-tag 6 --radius-field 10 --radius-card-inner 10
75+
--radius-media 14 --radius-card 18 --radius-frame 26
76+
--radius-control 999
77+
motion --ease-brand --ease-brand-out --ease-brand-accelerate
78+
140ms controls · 220ms surfaces · 360–640ms reveals
79+
type --font-brand (Proxima Nova) --font-mono (JetBrains Mono, see gaps)
80+
depth --shadow-panel --shadow-modal (product chrome and modals only)
81+
utility `field` — the shared input skin, incl. the focus ring
82+
```
83+
84+
## Rules
85+
86+
- **Three brand colours**: Off Black, Pure White, Magenta. One accent per
87+
surface, never two.
88+
- **Status colour is functional.** `success`/`warning`/`danger` report state.
89+
Never use them as a categorical palette — `success` for "slots" because green
90+
looked right spends the only signal they carry.
91+
- **No off-palette colour.** Not Tailwind's stock ramps, not a hex literal. CI
92+
fails on both.
93+
- **Retired and unavailable**: Originals Orange `#FF6200`, Sportsbook Blue
94+
`#00CCFF`. No accents, no charts, no status.
95+
- **Ink on any status or accent fill is Off Black.** White fails AA on all three.
96+
- **Magenta text**: never below 15px bold. Use `--color-primary-300` on a tint.
97+
- No gradients. No light theme. No `dark:` variants — the dark palette is the
98+
only palette. No drop shadows on brand surfaces. No coloured borders, and no
99+
coloured left-edge accent to signal category or ownership.
100+
- Radii by role, and the outer frame is always larger than the inner panel.
101+
- Borders are 1px hairline or 1.5px container rule. Nothing else.
102+
- **No emoji, anywhere.** Only `×` for close and `` for footnotes.
103+
- Voice: declarative, British/AU spelling, headlines end in a full stop.
104+
- Icons: Lucide, 2px stroke, `currentColor`.
105+
106+
## Extending
107+
108+
Do not fork a component to add a variant, and do not upstream a product-only
109+
variant. Every variant map is exported:
110+
111+
```ts
112+
import { buttonVariants } from "@engineio/ui"
113+
import { tv } from "tailwind-variants"
114+
115+
export const appButtonVariants = tv({
116+
extend: buttonVariants,
117+
variants: { variant: { drawer: "w-full justify-start rounded-none …" } },
118+
})
119+
```
120+
121+
Brand rules stay in the package; product variants stay in the product. Every
122+
primitive also passes `class` through `cn`, so `<Button class="w-full" />` works
123+
without `!important`.
124+
125+
## Known gaps
126+
127+
State these rather than working around them silently.
128+
129+
1. **No categorical palette.** A per-topic hue set is an unmade brand decision.
130+
2. **Two deviations from the brand document**, both deliberate: Badge is one
131+
component where §6 specifies two, and Alert signals state with a coloured
132+
left-edge bar which §11 prohibits for *category or ownership* — state is a
133+
narrower reading, not an exemption.
134+
3. **JetBrains Mono is not loaded.** `--font-mono` falls back to the platform
135+
monospace, so every mono surface is off-brand until the binary ships.
136+
4. **Proxima Nova is commercially licensed** and ships inside this package.
137+
5. **Engine Integration's accent is unsettled** — build Integration in magenta;
138+
`--color-partner-yellow` exists but is not in use.

README.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,35 @@ engine repo into your product if you need them. `sonner` was excluded because
121121
toasts need success and error colours that did not exist; now that they do, it
122122
is a candidate for the next release.
123123

124+
## Using it with AI agents
125+
126+
The package ships `AGENTS.md`, so it lands at
127+
`node_modules/@engineio/ui/AGENTS.md` and **versions with the code**. Point at
128+
that path from a consuming repo rather than copying the rules in — a copy in
129+
someone's `CLAUDE.md` silently goes stale on the next version bump, and stale
130+
brand rules are worse than none.
131+
132+
In a consumer's `AGENTS.md` or `CLAUDE.md`:
133+
134+
```md
135+
UI is built on `@engineio/ui`. Read `node_modules/@engineio/ui/AGENTS.md`
136+
before writing or reviewing any UI.
137+
```
138+
139+
For Claude Code specifically, copy the skill instead — it loads only when
140+
relevant, so the reference costs nothing until a UI task actually needs it:
141+
142+
```bash
143+
mkdir -p .claude/skills
144+
cp -R node_modules/@engineio/ui/../../../ui/.claude/skills/engine-design-system \
145+
.claude/skills/ # or from a checkout of engineio/ui
146+
```
147+
148+
Skills have to live in `.claude/skills/`, `~/.claude/skills/` or a plugin —
149+
Claude Code does not load them from `node_modules` — which is why the substance
150+
lives in `AGENTS.md` and the skill is a thin pointer to it. That way the copied
151+
file has nothing in it that can rot.
152+
124153
## Development
125154

126155
```bash

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
},
1717
"files": [
1818
"dist",
19+
"AGENTS.md",
1920
"!dist/**/*.test.*",
2021
"!dist/**/*.spec.*"
2122
],

0 commit comments

Comments
 (0)