brand-identity
Use when a project needs its visual foundation built or consolidated into one system: logo brief, color system in HEX/RGB/CMYK/OKLCH with proven AA contrast, type system, usage rules, and an exported W3C design-tokens.json that later skills consume. NOT the applied UI pixels (tha
Install
npx skills add https://github.com/ericrisco/rsc-harness/tree/main/skills/brand-identity
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install ericrisco-rsc-harness@llmmart
git clone https://github.com/ericrisco/rsc-harness.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole ericrisco/rsc-harness collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Brand Identity — Define the Foundation, Not the Pixels
This skill emits the brand book — logo brief, color system, type system, usage rules — and a machine-readable design-tokens.json that design consumes. You write the rules every later pixel must obey; you do not paint the live UI.
A brand identity with nothing checkable behind it is a mood board. The bar here is a brand book that compiles: roles named, every color carrying four channels, contrast pairs proven against WCAG, and a tokens file that scripts/verify.sh can validate.
All four parts ship together — logo brief, color system, type system, usage guidelines with the tokens export. A part missing its bar is incomplete, not "lite".
The one-line boundary test: "define what our brand looks like everywhere" → here. "make this surface look premium" → design.
Logo brief
Specify a system, not a single picture. The mark must survive from favicon to billboard, in color and in one ink.
- Variation set — primary (horizontal lockup), stacked (vertical, for square/tight slots), mark-only (the symbol alone, for avatars/favicons), monochrome (single-ink: black, white-knockout). A logo with no mono version fails the moment it lands on a colored background or a fax. Test the mono version first; if it dies in one color, the design is too fragile.
- Clear space — define it relative to the mark, not in fixed px, so it scales: clear space = the cap-height (or x-height of the mark) on all four sides. Nothing intrudes inside it.
- Minimum size — below this, detail collapses. Defaults: 24px wide digital, 10mm wide print for the full lockup; the mark-only may go smaller (favicon).
- File + favicon matrix — ship the formats below. SVG is the digital primary (scales, tiny); PNG carries transparency; JPEG is print-safe; 72 DPI digital / 300 DPI print.
| Asset | Format | Notes |
|---|---|---|
| Logo (digital primary) | SVG | Vector, scales infinitely, smallest |
| Logo (raster, transparency) | PNG | @1x/@2x, transparent bg |
| Logo (print) | JPEG/PDF | 300 DPI, CMYK |
| Favicon (modern) | favicon.svg |
<1KB, can embed prefers-color-scheme for dark mode |
| Favicon (legacy fallback) | favicon.ico |
At site root |
| Favicon PNG | favicon-16.png, favicon-32.png |
Tab/bookmark |
| Apple touch | apple-touch-icon.png 180×180 |
iOS home screen |
| Android | android-chrome-192.png, -512.png |
PWA/manifest |
| Manifest | site.webmanifest |
Declares the icon set |
Full variation grid, clear-space/min-size formulas, and the favicon HTML markup + prefers-color-scheme SVG snippet → references/logo-and-assets.md.
Color system
Assign roles first, values second. A color with no role is decoration waiting to be misused.
- Role taxonomy — 2–3 primary (the brand's signature), 2–3 secondary (support), a neutral ramp (text, surfaces, borders), and exactly one accent reserved for CTAs/highlights. One accent keeps "click here" unambiguous.
- Four channels, every color, no exceptions — HEX (web), RGB (screen math), CMYK (print), OKLCH (perceptual + wide-gamut). This one is absolute because a HEX-only palette silently breaks the two places nobody tests: print (no CMYK) and wide-gamut screens (no OKLCH). The W3C Design Tokens Color Module (2025.10) supports CSS Color 4 spaces including OKLCH and Display P3, so wide-gamut color lives in the token file natively — author in OKLCH and let HEX be the fallback.
- AA contrast pairing — every text-on-background pair you document clears WCAG 2 AA: 4.5:1 normal text, 3:1 large text (≥18.66px bold or ≥24px). Not negotiable — it is a conformance threshold, not a taste call, and shipping under it ships an inaccessible product. AAA is 7:1 / 4.5:1 — reach for it on body text where you can. Pair colors explicitly ("
fgonbg: 12.4:1 ✓"). - Logo-text exemption caveat — WCAG 1.4.3 exempts logos and brand-name text from the contrast minimums. But a typed sub-brand or tagline that is plain text (not a graphical logo) IS subject to text-contrast rules. Mark logo-only tokens exempt; hold everything else to 4.5:1.
- Light/dark roles — define the role in both schemes from day one (
bg/fginvert, brand stays anchored). Retrofitting dark mode onto a light-only palette produces muddy, low-contrast surfaces.
Full role taxonomy, a fully worked palette in HEX/RGB/CMYK/OKLCH, the contrast-pair matrix with computed ratios, and the dark-mode token strategy → references/color-and-tokens.md.
Type system
Two to three typefaces, no more. Most brands need exactly two: one display (headlines, personality) and one text (body, ≤16px legibility); a third is justified only for monospace/data.
- Scale — pick a modular ratio (1.2 minor third for dense UI, 1.25 major third for marketing) and ladder the sizes from it. Document the ladder; do not re-guess sizes per screen.
- Weights — name which weights ship (e.g. 400 body, 500 UI, 600/700 display) and which are banned (no faux-bold, no faux-italic).
- Pairing rationale — one line on why the pair works (contrast in structure: a geometric sans display over a humanist text face; or a serif display over a neutral sans body). "They both look nice" is not a rationale.
- Variable-font note — prefer a variable font where available: one file spans the weight axis, cuts requests, and removes the faux-bold temptation. Pin the named instances you use.
Emit the tokens (the hand-off contract)
Ship design-tokens.json even when the client only asked for a PDF — it is the one artifact design can read, and without it the palette gets re-derived by eye and drifts. Use the W3C Design Tokens format, which reached its first stable version (2025.10) on 2025-10-28 — a vendor-neutral JSON for sharing design decisions, with light/dark and multi-brand themes via group inheritance / $extends.
{
"$schema": "https://tokens.designtokens.org/2025.10/schema.json",
"color": {
"brand": {
"$type": "color",
"primary": {
"$value": { "colorSpace": "oklch", "components": [0.55, 0.19, 256], "hex": "#3b5bdb" }
},
"accent": {
"$value": { "colorSpace": "oklch", "components": [0.72, 0.17, 50], "hex": "#f08c00" }
}
},
"bg": { "$type": "color", "$value": { "colorSpace": "oklch", "components": [0.99, 0, 0], "hex": "#fcfcfc" } },
"fg": { "$type": "color", "$value": { "colorSpace": "oklch", "components": [0.21, 0.01, 256], "hex": "#1f2430" } }
}
}
Map the tokens to CSS custom properties (and, if the consumer is Tailwind v4, an @theme block) so the values flow into utilities — author once, consume everywhere:
/* design consumes these — generated from design-tokens.json, never hand-edited */
:root {
--color-brand-primary: oklch(0.55 0.19 256);
--color-brand-accent: oklch(0.72 0.17 50);
--color-bg: oklch(0.99 0 0);
--color-fg: oklch(0.21 0.01 256);
}
Full tokens file with light/dark via $extends, the Tailwind v4 @theme mapping, and the dark-mode strategy → references/color-and-tokens.md.
Usage guidelines + anti-patterns
State the misuse rules explicitly — the gap a brand book exists to close is the well-meaning teammate who stretches the logo to fit.
| Misuse in the wild | Why it breaks / Fix |
|---|---|
| "Stretch the logo to fill the space" | Non-uniform scaling distorts the mark. Lock aspect ratio; pick the variation that fits (stacked vs primary). |
| "This blue is close enough" | Off-palette colors fracture recognition. Use the token; if a need is unmet, add a role, don't eyeball one. |
| "HEX is enough, we're a web brand" | Print and wide-gamut break. Every color carries HEX + RGB + CMYK + OKLCH or it is not in the system. |
| "Four fonts give us range" | Reads as chaos and bloats load. Cap at 2–3; get range from weights + scale. |
| "We'll add dark mode later" | Light-only palettes go muddy when inverted. Define light/dark roles from day one. |
| "Contrast is a design detail" | It is a WCAG requirement. Document each text/bg pair at ≥4.5:1 before shipping. |
| "Drop the logo on any background" | Color/photo backgrounds kill legibility. Provide and require the mono/knockout variation with clear space. |
| "The tokens file is optional, the PDF is the brand" | A PDF can't be consumed by code; design will drift. The design-tokens.json is the contract. |
Do/don't rules, the full misuse grid with examples, and lockup rules → references/logo-and-assets.md.
Verify
The skill emits a checkable artifact, so verify it before claiming done. Run against your tokens file:
./scripts/verify.sh path/to/design-tokens.json
It checks: the file parses as JSON; required color roles are present (primary, neutral, accent at minimum); every color token carries a HEX value; and, for each documented text/background pair (declared via $extensions["com.risco.contrast"] pairs), it computes the WCAG relative-luminance contrast ratio and fails any normal-text pair below 4.5:1. Logo-only tokens are exempt. On an empty or clean target it exits 0 — no false failures.
Boundary + hand-off
| Request | Route to | Why |
|---|---|---|
| Tone of voice, tagline, naming, messaging pillars | ../brand-voice/SKILL.md |
Verbal identity — the words, not the pixels. Pair it with this so copy and visuals agree. |
| Make this page premium, pick layout + motion, ship the Tailwind | ../design/SKILL.md |
The applied UI layer: it reads design-tokens.json and builds the accessible, fast UI. This skill produces the brand study's visual half that design STOPS without. |
| Hero headline, value prop, CTA copy | ../marketing/SKILL.md |
Page words, not the visual system. |
| Press kit — boilerplate, logos-for-press, fact sheet | ../press-kit/SKILL.md |
Media packaging of finished assets, not system definition. |
| Investor pitch deck visuals | ../presentations/SKILL.md |
Deck composition consuming the tokens, not the brand foundation. |
Files (rsc-harness)
-
evals
-
cases.yaml 3.8 KB
skill: brand-identity should_trigger: - prompt: "Build our brand identity — logo brief, colors, fonts, the whole brand book." why: "The core ask: all four deliverable parts (logo, color, type, usage) named explicitly. Exact center of the skill." - prompt: "Pick a color palette and document the hex, rgb, and cmyk values for our brand." why: "Color-system core; the four-channel value requirement (HEX/RGB/CMYK/OKLCH) is the skill's contract for colors." - prompt: "Define our type system: primary and secondary typefaces with a scale and weights." why: "Type-system core — 2-3 typefaces, scale, weights, pairing rationale are exactly this skill's bar." - prompt: "We've got random fonts and hex codes scattered across files — consolidate them into one system." why: "Non-obvious rebrand/consolidation trigger: no 'brand book' wording, but unifying ad-hoc colors/fonts into a system is precisely the rebrand path." - prompt: "Necesito una identidad de marca y la guia de marca con normas de uso del logo." why: "Spanish/Catalan trigger naming brand identity, brand guidelines, and logo usage rules — all owned here." - prompt: "Export a design-tokens.json with our brand colors so the dev team stops eyeballing the palette." why: "Non-obvious: phrased as a tokens export, but emitting the W3C design-tokens.json hand-off contract is this skill's machine-readable deliverable." should_not_trigger: - prompt: "Make this landing page look premium — pick the layout, motion, and ship the Tailwind." route_to: design why: "Applied UI layer (layout, motion, real code) consumes the brand foundation; it is not the foundation itself." - prompt: "Write our tone of voice and a tagline for the homepage." route_to: brand-voice why: "Verbal identity — words and tone — not the visual system." - prompt: "Write the hero headline and the CTA copy for our pricing page." route_to: marketing why: "Page words / conversion copy, not the logo/color/type system." - prompt: "Put together a press kit with our logos and boilerplate for journalists." route_to: press-kit why: "Media packaging of finished assets, not defining the brand system." - prompt: "Design the investor pitch deck slides for our seed round." route_to: presentations why: "Deck composition/visuals, not the brand foundation the deck would draw from." capability: - scenario: "We're a fintech startup 'Ledgerly'. Create our brand identity foundation." must_include: - "A logo brief with the full variation set (primary / stacked / mark-only / monochrome), a clear-space rule tied to the mark's cap/x-height, minimum sizes (e.g. ~24px digital / ~10mm print), and a file + favicon export matrix (SVG primary, PNG/ICO fallbacks, apple-touch 180, android 192/512, site.webmanifest)." - "Color roles assigned (2-3 primary, 2-3 secondary, a neutral ramp, exactly one accent), each color carrying HEX + RGB + CMYK + OKLCH — not HEX alone." - "At least one documented text-on-background pair meeting WCAG 2 AA (>= 4.5:1 normal text / 3:1 large), stated as an explicit pair (fg on bg with the ratio), and a note that logo/brand-name text is exempt under WCAG 1.4.3 while typed taglines are not." - "A type system of 2-3 typefaces max with a modular scale, named weights, and a one-line pairing rationale (plus a variable-font note)." - "A W3C-format design-tokens.json (2025.10) emitted with light/dark roles via group inheritance / $extends and OKLCH values, mapped to CSS custom properties / Tailwind v4 @theme." - "Usage/misuse rules (no stretching, no off-palette color, require the mono variation on busy backgrounds) plus an explicit hand-off note to design as the skill that applies the tokens." - "A pointer to run scripts/verify.sh on the emitted design-tokens.json to confirm roles, hex coverage, and AA contrast before claiming done." -
README.md 1 KB
# Evals — brand-identity `cases.yaml` is read by the harness eval runner. The `should_trigger` and `should_not_trigger` blocks check routing precision: that brand-foundation requests (logo brief, color/type system, tokens export, the Catalan/Spanish phrasings, and the non-obvious "consolidate scattered fonts/hex" rebrand case) select this skill, while adjacent asks correctly route to the real siblings — `design` (applied UI), `brand-voice` (words/tone), `marketing` (page copy), `press-kit` (media pack), `presentations` (deck). The `capability` block is a rubric scored against a real generation: the "Ledgerly" prompt must produce all four deliverable parts (logo brief, four-channel color roles, an AA-proven contrast pair, a 2-3 typeface system, a W3C `design-tokens.json` with light/dark) plus usage rules and the hand-off to `design`. Run it via the repo's eval command; no network is required. To sanity-check the verify gate by hand, run `scripts/verify.sh path/to/design-tokens.json` against a generated tokens file.
-
-
references
-
color-and-tokens.md 6.1 KB
# Color system & design tokens Depth offloaded from SKILL.md: the full role taxonomy, a worked palette in all four channels, the contrast-pair matrix, the complete W3C `design-tokens.json` with light/dark, the Tailwind v4 `@theme` mapping, and the dark-mode strategy. ## Role taxonomy (assign roles before values) | Role | Count | Job | Example token | | --- | --- | --- | --- | | Primary | 2–3 | The brand's signature; the color people recall | `color.brand.primary` | | Secondary | 2–3 | Support; section accents, illustration | `color.brand.secondary` | | Neutral | a ramp (50→900) | Text, surfaces, borders, dividers | `color.neutral.*` | | Accent | exactly 1 | CTAs, highlights, the "click here" color | `color.brand.accent` | | Semantic | as needed | success / warning / danger / info states | `color.status.*` | One accent only. The moment a palette has two "primary action" colors, every button becomes a judgment call and the interface loses its one unambiguous next step. ## Worked palette — all four channels A color is not in the system until it carries HEX (web), RGB (screen), CMYK (print), and OKLCH (perceptual + wide-gamut). Author in OKLCH; let HEX be the fallback. | Token | HEX | RGB | CMYK | OKLCH | | --- | --- | --- | --- | --- | | brand.primary | `#3b5bdb` | 59, 91, 219 | 73, 58, 0, 14 | `oklch(0.55 0.19 256)` | | brand.accent | `#f08c00` | 240, 140, 0 | 0, 42, 100, 6 | `oklch(0.72 0.17 50)` | | bg (light) | `#fcfcfc` | 252, 252, 252 | 0, 0, 0, 1 | `oklch(0.99 0 0)` | | fg (light) | `#1f2430` | 31, 36, 48 | 35, 25, 0, 81 | `oklch(0.21 0.01 256)` | | bg (dark) | `#15171c` | 21, 23, 28 | 25, 18, 0, 89 | `oklch(0.18 0.01 256)` | | fg (dark) | `#e9ebf0` | 233, 235, 240 | 3, 2, 0, 6 | `oklch(0.93 0.005 256)` | CMYK is approximate — final print values come from the press profile (e.g. coated vs uncoated stock). Document the intent; let the printer's profile resolve the exact ink mix. ## Contrast-pair matrix (WCAG 2) Thresholds: AA 4.5:1 normal / 3:1 large (≥18.66px bold or ≥24px); AAA 7:1 / 4.5:1. Document every pair you ship as text-on-background. | Foreground | Background | Ratio | Normal AA | Large AA | AAA | | --- | --- | --- | --- | --- | --- | | fg `#1f2430` | bg `#fcfcfc` | ~12.4:1 | ✓ | ✓ | ✓ | | brand.primary `#3b5bdb` | bg `#fcfcfc` | ~5.0:1 | ✓ | ✓ | ✗ | | white `#ffffff` | brand.primary `#3b5bdb` | ~4.9:1 | ✓ | ✓ | ✗ | | brand.accent `#f08c00` | bg `#fcfcfc` | ~2.1:1 | ✗ | ✗ | ✗ | | fg(dark) `#e9ebf0` | bg(dark) `#15171c` | ~13.6:1 | ✓ | ✓ | ✓ | The accent on white fails — that is expected. An accent earns its saturation by being *reserved*; use it as a fill behind white/dark text or as a non-text highlight, never as body text on the page background. Verify each pair with a checker, not by eye. **Logo-text caveat:** WCAG 1.4.3 exempts logos and brand-name graphics from these minimums. A *typed* tagline or sub-brand that is plain text (not a graphical logo) is NOT exempt — hold it to 4.5:1. Mark only logo tokens exempt. ## Complete `design-tokens.json` (W3C 2025.10, light/dark via group inheritance) W3C Design Tokens reached first stable (2025.10) on 2025-10-28. The Color Module supports CSS Color 4 spaces (OKLCH, Display P3). Themes share a base and override via group inheritance / `$extends`. ```json { "$schema": "https://tokens.designtokens.org/2025.10/schema.json", "$description": "Brand tokens — single source consumed by the design skill.", "color": { "$type": "color", "brand": { "primary": { "$value": { "colorSpace": "oklch", "components": [0.55, 0.19, 256], "hex": "#3b5bdb" } }, "secondary": { "$value": { "colorSpace": "oklch", "components": [0.62, 0.12, 200], "hex": "#1c8ab0" } }, "accent": { "$value": { "colorSpace": "oklch", "components": [0.72, 0.17, 50], "hex": "#f08c00" } } }, "neutral": { "50": { "$value": { "colorSpace": "oklch", "components": [0.98, 0, 0], "hex": "#f5f6f8" } }, "500": { "$value": { "colorSpace": "oklch", "components": [0.55, 0.01, 256], "hex": "#6b7280" } }, "900": { "$value": { "colorSpace": "oklch", "components": [0.21, 0.01, 256], "hex": "#1f2430" } } }, "theme": { "light": { "bg": { "$value": { "colorSpace": "oklch", "components": [0.99, 0, 0], "hex": "#fcfcfc" } }, "fg": { "$value": { "colorSpace": "oklch", "components": [0.21, 0.01, 256], "hex": "#1f2430" } } }, "dark": { "bg": { "$value": { "colorSpace": "oklch", "components": [0.18, 0.01, 256], "hex": "#15171c" } }, "fg": { "$value": { "colorSpace": "oklch", "components": [0.93, 0.005, 256], "hex": "#e9ebf0" } } } } }, "$extensions": { "com.risco.contrast": [ { "fg": "#1f2430", "bg": "#fcfcfc", "use": "body", "logo": false }, { "fg": "#ffffff", "bg": "#3b5bdb", "use": "button", "logo": false }, { "fg": "#e9ebf0", "bg": "#15171c", "use": "body-dark", "logo": false } ] } } ``` The `$extensions["com.risco.contrast"]` array is what `scripts/verify.sh` reads to prove each text/bg pair clears AA. `"logo": true` exempts a pair from the 4.5:1 floor. ## Tailwind v4 `@theme` + CSS custom-properties mapping Generate these from the tokens file; never hand-edit them — the JSON is the source. ```css @import "tailwindcss"; @theme { --color-brand-primary: oklch(0.55 0.19 256); --color-brand-secondary: oklch(0.62 0.12 200); --color-brand-accent: oklch(0.72 0.17 50); --color-neutral-50: oklch(0.98 0 0); --color-neutral-500: oklch(0.55 0.01 256); --color-neutral-900: oklch(0.21 0.01 256); --color-bg: oklch(0.99 0 0); --color-fg: oklch(0.21 0.01 256); } ``` ## Dark-mode strategy - Define `bg`/`fg` per theme; keep `brand.*` anchored across both (recognition is constant). - Don't simply invert lightness — dark surfaces want slightly desaturated, slightly warmer neutrals to avoid the "pure black + pure white" vibration. Re-check contrast in dark too. - Switch with a `prefers-color-scheme` media query or a `.dark` class that re-points the `--color-bg`/`--color-fg` vars at the `theme.dark` token group. -
logo-and-assets.md 4.4 KB
# Logo brief & asset export Depth offloaded from SKILL.md: the variation grid with when-to-use each, clear-space and min-size formulas, the full export matrix with DPI, the favicon set with HTML markup and a `prefers-color-scheme` SVG snippet, and the file-naming convention. ## Variation grid A logo is a system of variations, each earning its place by the context it survives. | Variation | Form | When to use | | --- | --- | --- | | Primary | Horizontal lockup (mark + wordmark) | Default — headers, docs, most digital | | Stacked | Vertical (mark over wordmark) | Square/tight slots, social avatars, merch | | Mark-only | The symbol alone | Favicons, app icons, watermarks, ≤32px | | Monochrome | Single ink (black, or white knockout) | One-color print, dark/photo backgrounds, embossing | Build and test the **monochrome** version first. If the mark dies in one ink — needs its gradient or two colors to read — it is too fragile and must be simplified before color work. ## Clear-space formula Define clear space relative to the mark so it scales with the logo instead of breaking at small sizes: ```text clear space = cap-height of the wordmark (or x-height of the mark), on all four sides ``` Nothing — text, other logos, page edges — intrudes inside that margin. Expressing it as a ratio (not a fixed px) means it stays correct from favicon to billboard. ## Minimum sizes Below these, detail collapses and the mark stops reading: | Variation | Digital min | Print min | | --- | --- | --- | | Primary lockup | 24px wide | 10mm wide | | Stacked | 32px wide | 12mm wide | | Mark-only | 16px wide (favicon territory) | 6mm wide | ## Export matrix Ship vector first; raster for the cases vector can't cover. 72 DPI digital, 300 DPI print. | Asset | Format | DPI | Notes | | --- | --- | --- | --- | | Logo, digital primary | SVG | n/a (vector) | Scales infinitely, smallest file | | Logo, raster transparency | PNG @1x/@2x | 72 | Transparent background | | Logo, print | PDF or JPEG | 300 | CMYK color, embed fonts/outline | | Mark, app icon | PNG | 72 | Square, safe-zone padded | ## Favicon set (2025 baseline) Modern baseline: an SVG primary that can carry a `prefers-color-scheme` dark variant, with PNG/ICO fallbacks for engines that don't render SVG favicons (notably older Safari). | File | Size | Purpose | | --- | --- | --- | | `favicon.svg` | vector, <1KB | Primary; can embed dark-mode CSS | | `favicon.ico` | 16/32 multi | Legacy root fallback | | `favicon-16.png`, `favicon-32.png` | 16, 32 | Tab/bookmark raster | | `apple-touch-icon.png` | 180×180 | iOS home screen | | `android-chrome-192.png`, `-512.png` | 192, 512 | Android / PWA | | `site.webmanifest` | — | Declares the icon set + theme color | ### HTML markup ```html <link rel="icon" href="/favicon.ico" sizes="32x32"> <link rel="icon" href="/favicon.svg" type="image/svg+xml"> <link rel="apple-touch-icon" href="/apple-touch-icon.png"> <link rel="manifest" href="/site.webmanifest"> ``` ### Dark-mode favicon (SVG with `prefers-color-scheme`) An SVG favicon can flip its fill in dark UI chrome — one file, no extra requests: ```html <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"> <style> path { fill: #1f2430; } @media (prefers-color-scheme: dark) { path { fill: #e9ebf0; } } </style> <path d="M6 6 H26 V26 H6 Z" /> </svg> ``` ## File-naming convention Predictable names keep the asset folder usable years later: ```text brand/ logo-primary.svg logo-primary@2x.png logo-stacked.svg logo-stacked@2x.png logo-mark.svg logo-mark@2x.png logo-mono-black.svg logo-mono-white.svg logo-print.pdf favicon.svg favicon.ico favicon-16.png favicon-32.png apple-touch-icon.png android-chrome-192.png android-chrome-512.png site.webmanifest ``` Pattern: `logo-<variation>[-<modifier>][@<scale>].<ext>`. Lowercase, hyphenated, no spaces. ## Misuse rules (do / don't) - DON'T stretch, squash, or rotate the mark — scale uniformly only. - DON'T recolor the logo off-palette or apply gradients/shadows not in the brief. - DON'T place the color logo on a busy/low-contrast background — switch to the mono knockout. - DON'T violate clear space or drop below the minimum size. - DON'T recreate the lockup by hand-typing the wordmark — use the supplied files. - DO use the variation that fits the slot (stacked for square, mark-only for ≤32px). - DO keep the accent reserved; the logo is not a place to introduce new colors.
-
-
scripts
-
verify.sh 7.6 KB
#!/usr/bin/env bash # # verify.sh — brand-token gate for the `brand-identity` skill. # # WHAT IT DOES (read-only; never writes or mutates anything) # Given a W3C design-tokens.json path, validates the brand book's # machine-readable artifact: # 1. File exists and parses as JSON (fail loud otherwise). # 2. Required color roles present: primary, neutral, accent (anywhere in # the color tree). # 3. Every color token carries a HEX value (in its `$value.hex`). # 4. For each documented text/background pair under # $extensions["com.risco.contrast"], computes the WCAG 2 relative- # luminance contrast ratio and FAILS any normal-text pair < 4.5:1. # Pairs flagged "logo": true are exempt (WCAG 1.4.3 logo exemption). # 5. Prints an ok/skip/warn/fail summary naming the failing pairs. # # HOW TO RUN (inside YOUR project, not the skills repo) # ./verify.sh path/to/design-tokens.json # ./verify.sh # no arg: auto-discovers design-tokens.json, # # clean exit 0 if none found (no false fail) # ./verify.sh --help # # EXIT CODES # 0 no failures (also: empty/clean target — nothing to check) # 1 a real failure (bad JSON, missing role, color w/o hex, AA pair < 4.5:1) # 2 bad usage # # Dependency-light: prefers python3 (stdlib only) for JSON + contrast math. # If python3 is absent, JSON-dependent checks are SKIPPED, never failed. set -euo pipefail if [ -z "${BASH_VERSION:-}" ]; then printf 'This script requires bash (any version >= 3.2). Run: bash %s\n' "$0" >&2 exit 2 fi if [ -t 1 ]; then RED=$'\033[31m'; GREEN=$'\033[32m'; YELLOW=$'\033[33m'; NC=$'\033[0m' else RED=''; GREEN=''; YELLOW=''; NC='' fi ok_count=0; skip_count=0; warn_count=0; fail_count=0 ok() { printf '%s[ ok ]%s %s\n' "$GREEN" "$NC" "$*"; ok_count=$((ok_count + 1)); } skip() { printf '%s[skip]%s %s\n' "$YELLOW" "$NC" "$*"; skip_count=$((skip_count + 1)); } warn() { printf '%s[warn]%s %s\n' "$YELLOW" "$NC" "$*"; warn_count=$((warn_count + 1)); } fail() { printf '%s[fail]%s %s\n' "$RED" "$NC" "$*"; fail_count=$((fail_count + 1)); } usage() { sed -n '2,40p' "$0" | sed 's/^# \{0,1\}//'; } have() { command -v "$1" >/dev/null 2>&1; } # --- arg parse -------------------------------------------------------------- TOKENS="" while [ $# -gt 0 ]; do case "$1" in -h|--help) usage; exit 0 ;; -*) printf '%sUnknown argument: %s%s\n\n' "$RED" "$1" "$NC"; usage; exit 2 ;; *) TOKENS="$1"; shift ;; esac done # --- locate the tokens file (clean exit if none — no false failure) --------- if [ -z "$TOKENS" ]; then # search common spots; pick the first match. Never fail when absent. for cand in \ ./design-tokens.json \ ./tokens/design-tokens.json \ ./02-DOCS/wiki/brand/design-tokens.json; do if [ -f "$cand" ]; then TOKENS="$cand"; break; fi done if [ -z "$TOKENS" ]; then found="$(find . -maxdepth 4 -name 'design-tokens.json' -type f 2>/dev/null | head -n1 || true)" [ -n "$found" ] && TOKENS="$found" fi fi if [ -z "$TOKENS" ]; then skip "no design-tokens.json found — nothing to verify (pass a path to check one)" printf '\nok=%d skip=%d warn=%d fail=%d\n' "$ok_count" "$skip_count" "$warn_count" "$fail_count" exit 0 fi if [ ! -f "$TOKENS" ]; then fail "tokens file not found: $TOKENS" printf '\nok=%d skip=%d warn=%d fail=%d\n' "$ok_count" "$skip_count" "$warn_count" "$fail_count" exit 1 fi # --- the JSON + contrast checks (python3 stdlib) ---------------------------- if ! have python3; then skip "python3 not found — JSON/contrast checks skipped (install python3 to enable)" printf '\nok=%d skip=%d warn=%d fail=%d\n' "$ok_count" "$skip_count" "$warn_count" "$fail_count" exit 0 fi # python prints lines prefixed OK:/FAIL:/WARN:/SKIP: which we route to the # bash counters so the summary + exit code stay in one place. REPORT="$(python3 - "$TOKENS" <<'PY' import json, sys path = sys.argv[1] out = [] try: with open(path, encoding="utf-8") as fh: data = json.load(fh) except json.JSONDecodeError as e: print(f"FAIL:tokens file does not parse as JSON: {e}") sys.exit(0) except OSError as e: print(f"FAIL:cannot read tokens file: {e}") sys.exit(0) print("OK:tokens file parses as JSON") # --- walk: collect every color token (node with $type==color or $value w/ hex) colors = [] # (dotted_path, hex_or_None) role_names = set() # leaf + group key names seen, lowercased def walk(node, trail, inherited_type=None): if not isinstance(node, dict): return ntype = node.get("$type", inherited_type) if "$value" in node: if ntype == "color" or isinstance(node["$value"], dict): val = node["$value"] hexv = val.get("hex") if isinstance(val, dict) else None if isinstance(val, str) and val.startswith("#"): hexv = val if ntype == "color" or (isinstance(val, dict) and "colorSpace" in val): colors.append((".".join(trail), hexv)) return for k, v in node.items(): if k.startswith("$"): continue role_names.add(k.lower()) walk(v, trail + [k], ntype) walk(data.get("color", {}), ["color"], None) # --- required roles present for role in ("primary", "neutral", "accent"): if role in role_names: print(f"OK:required color role present: {role}") else: print(f"FAIL:required color role missing: {role}") # --- every color token carries a hex if not colors: print("WARN:no color tokens found under 'color'") else: missing = [p for p, h in colors if not h] if missing: for p in missing: print(f"FAIL:color token has no hex value: {p}") else: print(f"OK:all {len(colors)} color tokens carry a hex value") # --- WCAG 2 contrast on documented pairs def lin(c): c = c / 255.0 return c / 12.92 if c <= 0.03928 else ((c + 0.055) / 1.055) ** 2.4 def luminance(hexstr): h = hexstr.lstrip("#") if len(h) == 3: h = "".join(ch * 2 for ch in h) if len(h) != 6: return None try: r, g, b = (int(h[i:i+2], 16) for i in (0, 2, 4)) except ValueError: return None return 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b) def ratio(fg, bg): lf, lb = luminance(fg), luminance(bg) if lf is None or lb is None: return None hi, lo = max(lf, lb), min(lf, lb) return (hi + 0.05) / (lo + 0.05) pairs = (data.get("$extensions", {}) or {}).get("com.risco.contrast", []) if not pairs: print("SKIP:no documented text/background pairs ($extensions.com.risco.contrast) — contrast not checked") else: for p in pairs: fg, bg = p.get("fg"), p.get("bg") use = p.get("use", "text") is_logo = bool(p.get("logo")) r = ratio(fg, bg) if fg and bg else None if r is None: print(f"WARN:could not compute contrast for pair {fg} on {bg} ({use})") continue if is_logo: print(f"SKIP:logo-exempt pair {fg} on {bg} ({use}): {r:.2f}:1 (WCAG 1.4.3 logo exemption)") elif r < 4.5: print(f"FAIL:contrast {r:.2f}:1 < 4.5:1 AA — {fg} on {bg} ({use})") else: print(f"OK:contrast {r:.2f}:1 >= 4.5:1 AA — {fg} on {bg} ({use})") PY )" while IFS= read -r line; do [ -z "$line" ] && continue case "$line" in OK:*) ok "${line#OK:}" ;; FAIL:*) fail "${line#FAIL:}" ;; WARN:*) warn "${line#WARN:}" ;; SKIP:*) skip "${line#SKIP:}" ;; *) printf '%s\n' "$line" ;; esac done <<EOF $REPORT EOF printf '\nverified: %s\n' "$TOKENS" printf 'ok=%d skip=%d warn=%d fail=%d\n' "$ok_count" "$skip_count" "$warn_count" "$fail_count" [ "$fail_count" -gt 0 ] && exit 1 exit 0
-
-
SKILL.md 10.4 KB
--- name: brand-identity description: "Use when a project needs its visual foundation built or consolidated into one system: logo brief, color system in HEX/RGB/CMYK/OKLCH with proven AA contrast, type system, usage rules, and an exported W3C design-tokens.json that later skills consume. NOT the applied UI pixels (that is design), NOT the words or tone (that is brand-voice)." tags: [brand, identity, logo, color, typography] recommends: [design, brand-voice, press-kit, presentations] origin: risco --- # Brand Identity — Define the Foundation, Not the Pixels *This skill emits the brand book — logo brief, color system, type system, usage rules — and a machine-readable `design-tokens.json` that `design` consumes. You write the rules every later pixel must obey; you do not paint the live UI.* A brand identity with nothing checkable behind it is a mood board. The bar here is a **brand book that compiles**: roles named, every color carrying four channels, contrast pairs proven against WCAG, and a tokens file that `scripts/verify.sh` can validate. All four parts ship together — logo brief, color system, type system, usage guidelines with the tokens export. A part missing its bar is incomplete, not "lite". The one-line boundary test: "define what our brand looks like everywhere" → here. "make *this surface* look premium" → `design`. ## Logo brief Specify a system, not a single picture. The mark must survive from favicon to billboard, in color and in one ink. - **Variation set** — primary (horizontal lockup), stacked (vertical, for square/tight slots), mark-only (the symbol alone, for avatars/favicons), monochrome (single-ink: black, white-knockout). A logo with no mono version fails the moment it lands on a colored background or a fax. Test the mono version first; if it dies in one color, the design is too fragile. - **Clear space** — define it relative to the mark, not in fixed px, so it scales: clear space = the cap-height (or x-height of the mark) on all four sides. Nothing intrudes inside it. - **Minimum size** — below this, detail collapses. Defaults: 24px wide digital, 10mm wide print for the full lockup; the mark-only may go smaller (favicon). - **File + favicon matrix** — ship the formats below. SVG is the digital primary (scales, tiny); PNG carries transparency; JPEG is print-safe; 72 DPI digital / 300 DPI print. | Asset | Format | Notes | | --- | --- | --- | | Logo (digital primary) | SVG | Vector, scales infinitely, smallest | | Logo (raster, transparency) | PNG | @1x/@2x, transparent bg | | Logo (print) | JPEG/PDF | 300 DPI, CMYK | | Favicon (modern) | `favicon.svg` | <1KB, can embed `prefers-color-scheme` for dark mode | | Favicon (legacy fallback) | `favicon.ico` | At site root | | Favicon PNG | `favicon-16.png`, `favicon-32.png` | Tab/bookmark | | Apple touch | `apple-touch-icon.png` 180×180 | iOS home screen | | Android | `android-chrome-192.png`, `-512.png` | PWA/manifest | | Manifest | `site.webmanifest` | Declares the icon set | Full variation grid, clear-space/min-size formulas, and the favicon HTML markup + `prefers-color-scheme` SVG snippet → `references/logo-and-assets.md`. ## Color system Assign roles first, values second. A color with no role is decoration waiting to be misused. - **Role taxonomy** — 2–3 primary (the brand's signature), 2–3 secondary (support), a neutral ramp (text, surfaces, borders), and exactly **one accent** reserved for CTAs/highlights. One accent keeps "click here" unambiguous. - **Four channels, every color, no exceptions** — HEX (web), RGB (screen math), CMYK (print), OKLCH (perceptual + wide-gamut). This one is absolute because a HEX-only palette silently breaks the two places nobody tests: print (no CMYK) and wide-gamut screens (no OKLCH). The W3C Design Tokens Color Module (2025.10) supports CSS Color 4 spaces including OKLCH and Display P3, so wide-gamut color lives in the token file natively — author in OKLCH and let HEX be the fallback. - **AA contrast pairing** — every text-on-background pair you document clears WCAG 2 AA: **4.5:1 normal text, 3:1 large text** (≥18.66px bold or ≥24px). Not negotiable — it is a conformance threshold, not a taste call, and shipping under it ships an inaccessible product. AAA is 7:1 / 4.5:1 — reach for it on body text where you can. Pair colors explicitly ("`fg` on `bg`: 12.4:1 ✓"). - **Logo-text exemption caveat** — WCAG 1.4.3 exempts logos and brand-name text from the contrast minimums. But a *typed* sub-brand or tagline that is plain text (not a graphical logo) IS subject to text-contrast rules. Mark logo-only tokens exempt; hold everything else to 4.5:1. - **Light/dark roles** — define the role in both schemes from day one (`bg`/`fg` invert, brand stays anchored). Retrofitting dark mode onto a light-only palette produces muddy, low-contrast surfaces. Full role taxonomy, a fully worked palette in HEX/RGB/CMYK/OKLCH, the contrast-pair matrix with computed ratios, and the dark-mode token strategy → `references/color-and-tokens.md`. ## Type system Two to three typefaces, no more. Most brands need exactly two: one display (headlines, personality) and one text (body, ≤16px legibility); a third is justified only for monospace/data. - **Scale** — pick a modular ratio (1.2 minor third for dense UI, 1.25 major third for marketing) and ladder the sizes from it. Document the ladder; do not re-guess sizes per screen. - **Weights** — name which weights ship (e.g. 400 body, 500 UI, 600/700 display) and which are banned (no faux-bold, no faux-italic). - **Pairing rationale** — one line on *why* the pair works (contrast in structure: a geometric sans display over a humanist text face; or a serif display over a neutral sans body). "They both look nice" is not a rationale. - **Variable-font note** — prefer a variable font where available: one file spans the weight axis, cuts requests, and removes the faux-bold temptation. Pin the named instances you use. ## Emit the tokens (the hand-off contract) Ship `design-tokens.json` even when the client only asked for a PDF — it is the one artifact `design` can read, and without it the palette gets re-derived by eye and drifts. Use the **W3C Design Tokens format**, which reached its first stable version (2025.10) on 2025-10-28 — a vendor-neutral JSON for sharing design decisions, with light/dark and multi-brand themes via group inheritance / `$extends`. ```json { "$schema": "https://tokens.designtokens.org/2025.10/schema.json", "color": { "brand": { "$type": "color", "primary": { "$value": { "colorSpace": "oklch", "components": [0.55, 0.19, 256], "hex": "#3b5bdb" } }, "accent": { "$value": { "colorSpace": "oklch", "components": [0.72, 0.17, 50], "hex": "#f08c00" } } }, "bg": { "$type": "color", "$value": { "colorSpace": "oklch", "components": [0.99, 0, 0], "hex": "#fcfcfc" } }, "fg": { "$type": "color", "$value": { "colorSpace": "oklch", "components": [0.21, 0.01, 256], "hex": "#1f2430" } } } } ``` Map the tokens to CSS custom properties (and, if the consumer is Tailwind v4, an `@theme` block) so the values flow into utilities — author once, consume everywhere: ```css /* design consumes these — generated from design-tokens.json, never hand-edited */ :root { --color-brand-primary: oklch(0.55 0.19 256); --color-brand-accent: oklch(0.72 0.17 50); --color-bg: oklch(0.99 0 0); --color-fg: oklch(0.21 0.01 256); } ``` Full tokens file with light/dark via `$extends`, the Tailwind v4 `@theme` mapping, and the dark-mode strategy → `references/color-and-tokens.md`. ## Usage guidelines + anti-patterns State the misuse rules explicitly — the gap a brand book exists to close is the well-meaning teammate who stretches the logo to fit. | Misuse in the wild | Why it breaks / Fix | | --- | --- | | "Stretch the logo to fill the space" | Non-uniform scaling distorts the mark. Lock aspect ratio; pick the variation that fits (stacked vs primary). | | "This blue is close enough" | Off-palette colors fracture recognition. Use the token; if a need is unmet, add a role, don't eyeball one. | | "HEX is enough, we're a web brand" | Print and wide-gamut break. Every color carries HEX + RGB + CMYK + OKLCH or it is not in the system. | | "Four fonts give us range" | Reads as chaos and bloats load. Cap at 2–3; get range from weights + scale. | | "We'll add dark mode later" | Light-only palettes go muddy when inverted. Define light/dark roles from day one. | | "Contrast is a design detail" | It is a WCAG requirement. Document each text/bg pair at ≥4.5:1 before shipping. | | "Drop the logo on any background" | Color/photo backgrounds kill legibility. Provide and require the mono/knockout variation with clear space. | | "The tokens file is optional, the PDF is the brand" | A PDF can't be consumed by code; `design` will drift. The `design-tokens.json` is the contract. | Do/don't rules, the full misuse grid with examples, and lockup rules → `references/logo-and-assets.md`. ## Verify The skill emits a checkable artifact, so verify it before claiming done. Run against your tokens file: ```bash ./scripts/verify.sh path/to/design-tokens.json ``` It checks: the file parses as JSON; required color roles are present (primary, neutral, accent at minimum); every color token carries a HEX value; and, for each documented text/background pair (declared via `$extensions["com.risco.contrast"]` pairs), it computes the WCAG relative-luminance contrast ratio and **fails any normal-text pair below 4.5:1**. Logo-only tokens are exempt. On an empty or clean target it exits 0 — no false failures. ## Boundary + hand-off | Request | Route to | Why | | --- | --- | --- | | Tone of voice, tagline, naming, messaging pillars | `../brand-voice/SKILL.md` | Verbal identity — the words, not the pixels. Pair it with this so copy and visuals agree. | | Make this page premium, pick layout + motion, ship the Tailwind | `../design/SKILL.md` | The applied UI layer: it reads `design-tokens.json` and builds the accessible, fast UI. This skill produces the brand study's visual half that `design` STOPS without. | | Hero headline, value prop, CTA copy | `../marketing/SKILL.md` | Page words, not the visual system. | | Press kit — boilerplate, logos-for-press, fact sheet | `../press-kit/SKILL.md` | Media packaging of finished assets, not system definition. | | Investor pitch deck visuals | `../presentations/SKILL.md` | Deck composition consuming the tokens, not the brand foundation. |
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.