# 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.