# Spotkit spec — start here
This one file, plus [`references/icons.md`](references/icons.md) for icon paths,
is enough to draw an illustration that matches the rest of the family. The other
files in `references/` add depth — how to pick a metaphor, how to pick a layout,
how to build a set — but every number lives here.
Every value below was copied from `build.py`, which generated every example in
this repo, and `python3 check.py --docs` fails if this file drifts from it.
Don't improvise any of them: this style is sub-pixel geometry, and a stroke of 1
where the system uses 0.5 is visibly wrong.
## 0 · The standing rule: adapt, don't invent
**Pick the nearest of the twelve layouts in §7, start from its example file,
keep its geometry and change only the content** — the icon, what sits inside
the cards, how many rows within the layout's limit. Every tool that follows
this produces the same family; every tool that composes from scratch drifts.
Invent a new composition only when none of the twelve fits, and say so.
- **You can run Python in this repo:** copy that layout's `L*` function in
`build.py`, edit its content, write the SVG out, run `python3 check.py out.svg`.
- **You can't run code:** fetch the layout's example file from §7, edit its
content by hand, and go through §9 before you answer.
- **Write SVG code.** Never hand this to an image-generation model — it cannot
hold a 0.5 stroke, and it will not match the family.
## 1 · Canvas
- `viewBox="0 0 160 160"`, whatever size it is shown at. No `width`/`height` on
the root. **No background rect** — the fade dissolves into the host page.
- Lanes: outer **10** units are bleed (shadow spill only) · floating cards live in
**x 11 → 149** · the panel lives in **x 21 → 139**.
- The fade runs from **y 112 to y 131** (70% → 82%). Nothing important below y 112.
- Centre of gravity on x 80, weighted to the upper two-thirds.
## 2 · The one stroke
**Every stroked element uses `stroke-width="0.5"` and
`stroke="var(--il-line, #B9B1A4)"`.** Panels, cards, backdrops, pills, hollow
dots, connectors — all of them. There is no second width and no second stroke
colour. Hierarchy comes from fills, opacity and the one shadow, never line weight.
- Separators are **filled rects 0.5 tall**, not strokes.
- Icons are **filled** Phosphor paths. Never `stroke` an icon, a tick or a plus.
- Placeholder bars are filled, fully rounded (`rx` = height / 2), never stroked.
## 3 · Tokens
Every colour is written `var(--il-token, #fallback)`, so the file works standalone
and still themes. Use the light value as the fallback.
| Token | Light | Dark | Used for |
|---|---|---|---|
| `--il-canvas` | `#EDEAE6` | `#1A1918` | the host page behind the illustration |
| `--il-ghost` | `#EAE7E2` | `#1F1E1C` | backdrop sheets |
| `--il-panel` | `#F7F5F2` | `#262523` | base panel, gradient bottom |
| `--il-panel-top` | `#FCFBF9` | `#2E2C29` | base panel, gradient top |
| `--il-line` | `#B9B1A4` | `#5C564D` | **every stroke** |
| `--il-surface` | `#FFFFFF` | `#322F2B` | floating cards, medallion |
| `--il-stroke` | `#35322D` | `#DDD9D3` | primary icons — the only dark value |
| `--il-stroke-soft` | `#9B948A` | `#877F74` | secondary icons, avatars, kebabs |
| `--il-fill` | `#DCD6CE` | `#4A463E` | placeholder bars, "yes" dots |
| `--il-fill-soft` | `#E9E4DC` | `#35322D` | selected pill, `+N` chip |
| `--il-accent` | `#3E9077` | `#5FB694` | **at most two elements**, one meaning |
| `--il-shadow-c` | `#4A3F33` | `#000000` | shadow colour |
| `--il-shadow-o` | `0.16` | `0.55` | shadow opacity |
Want your brand's colours? Tint canvas, panel and surface 4–8% toward the brand
hue, keep `--il-fill` neutral, and use the brand colour only as `--il-accent`.
Everything else in this file stays the same. (`references/theme.md`)
## 4 · Boilerplate
Replace `ID` with the illustration's name everywhere (`fade-audit`, `lift-audit`)
— two illustrations on one page with the same ids will swap masks. **Keep every
def**: the panel fill is `url(#panelG-ID)`.
```svg
```
## 5 · Building blocks
Coordinates are for the default panel (`x 21 w 118 y 8`); move them with it.
```svg
```
**Icons:** ``
with a path from [`references/icons.md`](references/icons.md). Sizes: 16 header
card · 15 medallion · 12 chip · 10–13 inline. Never draw your own glyph.
**Padding inside every card is equal top and bottom** — about 8 in a content
card; a chip's 12px icon sits 5 from each edge. Check it with arithmetic:
`top = content_top - card_y`, `bottom = card_y + card_h - content_bottom`.
## 6 · Depth
- **At most one element casts a shadow** — the floating element. (L5's two
diagonal chips count as one; a flat medallion layout may have none.)
- `lift` (dy 2, blur 2.6) for anything under ~2600 sq units, `liftL` (dy 4,
blur 5) above. Opacity comes from `--il-shadow-o` — 16% in light. If you can
see a dark edge under the card at display size, it is too strong.
- **Every card has the 0.5 line as well as its fill.** A shadow alone does not
separate white from near-white at 160px.
- The float **overhangs** the panel decisively, 8–15 units, or not at all.
- One gradient only: the panel's. No blur, glow, gloss, bevel, perspective.
## 7 · Layouts
Pick by the feature's **relationship**, then by how many elements it needs
(1–2: L7 L8 L12 · 3–4: L1 L2 L3 L5 L11 · 4–6: L4 L6 L9 L10). In a set, no
layout more than twice in twelve, and at most two full-width header cards.
**Then open the example file and edit it.** Each is a finished, checked
illustration of its layout — all twelve are also in `references/examples.md`,
one file — or fetch one raw: `https://raw.githubusercontent.com/Devesh-Shirsath/spotkit/main/examples/.svg`. Keep every coordinate of the
panel, backdrop, float and cards; rename the ids (`-approval` → `-yourname`);
swap the icon and the contents.
| | Layout | Start from | Panel (x, w, edge, backdrop) | Float | Content |
|---|---|---|---|---|---|
| L1 | Header + rows | `billing.svg` | 21, 118, fade, twin | header card 11,24 138×27 | 3 rows at y 60/81/102: 15px avatar + bar pair |
| L2 | Cascade | `teams.svg` | 25, 110, fade, offset | raised row 13,56 134×21 r7 + flat medallion | 2 receding rows, opacity .70 / .40 |
| L3 | Tab bar | `categories.svg` | 24, 112, fade, plate | card 11,24 138×24: icon + 4 pills | 3 rows at y 62/84/106 |
| L4 | Toolbar | `workspace.svg` | 22, 116, fade, none | card 11,24 138×26: 4 brand tiles + search | avatar cluster, rule, 3 rows with checks |
| L5 | Corner chips | `docs.svg` | 28, 104, fade, offset | chips 13,12 and 91,94, 58×21 | header bar + kebab, 4 rows |
| L6 | Window | `connectors.svg` | 13, 134, fade, chrome, twin | none — first row raised | 3 row cards 118×18 at y 34/56/78 |
| L7 | Fanned | `contributors.svg` | 16, 128, contained y44 h92, none | middle card 55,32 50×60 r11 | 2 flat side cards 46×50 |
| L8 | Notifications | `notifications.svg` | 26, 108, contained y30 h100, offset | card 16,44 112×34 r10 | 1 flat card behind, 92×32 |
| L9 | Constellation | `gateway.svg` | 21, 118, fade, plate | hub 63,46 34×34 r11, 18px icon | 4 tiles, dashed connectors to the hub |
| L10 | Matrix | `roles.svg` | 21, 118, fade, none | corner chip 13,16 62×22 | 3 icon columns × 4 avatar rows of dots |
| L11 | Timeline | `audit.svg` | 28, 104, fade, offset | column chip 18,14 74×22 | rail at x 44, nodes y 56/80/104 |
| L12 | Split | `approval.svg` | 22, 116, contained y30 h100, plate | flat medallion 80,37 r17 | 2 state cards 44×44, arrow in the gap |
A float that covers only one side of the panel's top edge gets answered on the
other side — a short bar and a kebab (L5, L11). Full detail: `references/archetypes.md`.
## 8 · A complete example
`examples/audit.svg` — L11, a timeline for an audit log. Copy its structure.
```svg
```
## 9 · Before you answer
If you can run code, `python3 check.py your.svg` checks most of these. If not,
go through them yourself — each one is a failure people have actually shipped.
1. Every `stroke-width` is `0.5`; every `stroke` is `var(--il-line, #B9B1A4)`.
2. No icon, tick or plus is stroked. Icons are Phosphor paths from `icons.md`.
3. At most one element has a `filter` (L5's chip pair aside), and it uses
`lift`/`liftL` unchanged.
4. No background rect, no ``, no second gradient, no blur.
5. Every id carries the same `-name` suffix.
6. The fade stops are exactly `0.7` and `0.82`.
7. Every card's top padding equals its bottom padding, and bottom > 0.
8. Nothing crosses what it sits between: a glyph in a gap clears both sides by
2+; a connector ends at the edges it joins; a rail starts at its first node.
9. The float overhangs 8–15 units or not at all; only the float breaks the panel.
The composition is centred on x=80 and fills the square.
10. At most two accent-coloured elements. It still reads in grayscale.
11. Bars are short-over-long, never equal. Fewer than six content blocks.
Nothing that carries meaning is under 9 units.
12. It reads as the feature with every label removed — and would never be
mistaken for a screenshot.
## 10 · Other sizes and themes
- **Any display size:** keep the 160 viewBox and scale with CSS. Only author a
bigger viewBox if you must, and then multiply every number by `size / 160`
(a 320 viewBox has 1.0 strokes) and shadow blur by its square root.
Wide and hero formats change the density — `references/scaling.md`.
- **Dark mode:** one file. Inline the SVG in the page and the tokens switch it.
An SVG in `` or Figma can't read CSS variables and shows the fallbacks —
use the flat exports in `examples/flat/` there.
## 11 · Delivering
> **Feature interpretation** — one line on what it actually does.
> **Metaphor** — one line: the relationship shown.
> **Layout** — which of the twelve it adapts (or why none fit).
> **Primitives** — the 2–5 used.
> **The SVG.**
Don't pad it with explanation nobody asked for.