/use-brand — turn a brand kit into any deliverable
The back end of the pipeline: brand → anything. Given a finished kit under brand/<id>/ (produced by /make-brand) and a request, this skill renders the deliverable in the brand's own palette, type, logos, backgrounds, signature devices, and voice — a website, a deck, a PDF, social/OG cards, marketing copy, dev tokens, or a video brief. The kit is the single source of truth; nothing here re-decides the brand.
$SKILLDIR = this skill's directory. Deterministic work runs through bundled scripts in $SKILLDIR/scripts/; the template library lives in $SKILLDIR/assets/ (web · social · deck · pdf · copy + the shared brand.mjs loader and _bake.mjs rasteriser). The skill is self-contained — it reads the kit's vendored assets and its own bundled templates, never the network at render, never a reference kit.
Inputs
- A kit —
brand/<id>/ (or a path to its brand.json, or just the <id>). If the request names none and
exactly one kit exists under brand/, use it; otherwise ask which.
- A request — plain language describing the deliverable ("a landing page", "an investor deck", "a brand
guidelines PDF", "an OG image for the launch", "tokens for my Next.js app", "a launch tweet thread", "a 30s promo video"). You route it to one or more surfaces (below).
Phase 0 — Preflight (before any creative spend)
node "$SKILL_DIR/scripts/doctor.mjs" # general; add --bake to require Chrome + playwright-core
- FAIL aborts.
playwright-core + pptxgenjs are this skill's only deps — install once with
npm i -D playwright-core pptxgenjs in $SKILL_DIR (playwright drives your installed Google Chrome, no browser download). They are needed only for bakes (PNG/PDF/PPTX); tokens, copy, video-brief, and all .html outputs work with zero deps.
- Decide the output root: default
out/<id>/ at the project root (per-surface subfolders below). Refuse to
clobber a non-empty target without confirming.
Phase 1 — Load the kit (the contract)
Steward preamble (read before any render). The kit is the single source of truth — it out-ranks anything you remember about the brand from earlier in this conversation. Before rendering ANY branded asset, re-read the primary spec (brand.json — or brand.spec.json / design.md when that's what exists), design.md, and craft/anti-slop.md. Never render from conversational memory of the palette, type, voice, or copy — memory drifts, the files don't. If a value isn't in the kit, it isn't a brand value; go get it, don't fill it in from vibes.
Missing / partial kit protocol. If brand.json (or a referenced asset — a font, a logo, an editorial file, the anti-slop list) is absent, announce exactly which file/asset is missing, then offer two paths and STOP for a choice: (a) best-effort from what exists (name what you'll infer and from where — e.g. palette scraped from design.md), or (b) regenerate the kit via /make-brand. Never silently fill a gap or substitute a default.
Enforcement strictness (strict | balanced | flexible, default balanced). This dial governs stylistic guideline adherence only — how hard you hold tone dials, layout preferences, device placement, and copy conventions. The anti-slop G1 gate stays hard at every level — banned fonts, banned hues, eyebrow pills, 3-card rows, "It's not X. It's Y.", stock metaphors never pass, strictness regardless. Only style flexes: strict = follow the kit's stated conventions to the letter; balanced = follow them, adapt when the surface genuinely needs it (state the adaptation); flexible = treat them as strong defaults, deviate freely with a one-line trace. Conflict protocol — when the request fights a guideline: (1) name the conflict in one line, (2) recommend the on-brand resolution with a reason, (3) offer follow / adapt / override and let the user pick. Don't quietly override a stated convention.
node "$SKILL_DIR/scripts/load-kit.mjs" --kit brand/<id> # writes brand/<id>/brandContext.json + prints a summary
brandContext.json is the normalized contract every generator reads — palette (bg/bg2/panel/fg/dim + accent roles + gradient/accentMode), fonts (families + vendored woff2 + fonts.css), logos, stickers, backgrounds, mockups, voice lock, editorial files, signature devices. Read its summary; the warnings tell you what the kit lacks (e.g. no fonts → system fallback) so you can set expectations. If the kit has no brand.json/brand.spec.json, the loader best-effort reconstructs from design.md + the asset folders and says so — sanity-check the palette before rendering.
Also read brand/<id>/craft/anti-slop.md when present — it is a hard gate for every surface, visual and copy alike. Older kits without it: fall back to this skill bundle's own copy at skills/make-brand/assets/craft/anti-slop.md if resolvable, else the editorial.noSlop list in brand.spec.json.
openQuestions register. When brand.json carries openQuestions[] (deferred brand decisions, each with a recommendation), check whether the deliverable touches one. If it does: flag the open question to the user in one line and apply the recorded recommendation as the working default — unless the user tells you otherwise. Don't re-litigate a deferred decision silently, and don't leave it unmade; the recommendation is the provisional answer until the brand resolves it.
Phase 2 — Route the request → surface(s)
| If the user wants… |
Surface |
Generator |
| a website / landing page / hero / docs page |
web |
web.mjs |
| a social post / OG image / Twitter card / story |
social |
social.mjs |
| a slide deck / pitch / investor deck |
deck |
deck.mjs |
| a brand-guidelines PDF, or any document → PDF |
pdf |
pdf.mjs |
| taglines / launch post / thread / ad / email / landing copy / UI microcopy |
copy |
copy.mjs |
| CSS variables / Tailwind theme / design tokens for a codebase |
tokens |
tokens.mjs |
| a video / promo / TikTok / Reel / explainer |
video |
video-brief.mjs → /make-video |
One request can fan out to several (a launch = landing + OG card + tweet thread). Ask only when genuinely ambiguous (which surface, which platform/size, which background) — use the office-hours decision-brief discipline below; otherwise pick the sensible default, state it, and proceed.
Phase 3 — Generate (per surface)
Every generator takes --kit brand/<id> and --out <dir>; baking surfaces also take --bake. After running, open/verify the output (see Phase 4). Standard runs:
S="$SKILL_DIR/scripts"; K="brand/<id>"
# WEB — self-contained .html (+ fullpage PNG with --bake)
node "$S/web.mjs" --kit "$K" --kind landing|hero|page --out out/<id>/web \
--headline "…" --subhead "…" --cta "…" --eyebrow "…" [--bake]
# SOCIAL — exact-size card → PNG
node "$S/social.mjs" --kit "$K" --size og|square|story|twitter|<WxH> \
--title "…" --subtitle "…" --kicker "…" --badge "…" [--bg bg-<name>] --bake
# DECK — HTML deck (+ PDF/PPTX). Edit the sample outline, then rerun with --in.
node "$S/deck.mjs" --kit "$K" [--in out/<id>/deck/outline.json] --out out/<id>/deck [--pdf] [--pptx]
# PDF — auto brand-guidelines, or wrap a doc
node "$S/pdf.mjs" --kit "$K" --kind guidelines --out out/<id>
node "$S/pdf.mjs" --kit "$K" --kind doc --in path/to/doc.md --title "…" --out out/<id>
# TOKENS — tokens.css + Tailwind theme/config + tokens.json (+ fonts copy)
node "$S/tokens.mjs" --kit "$K" --out out/<id>/tokens
# COPY — scaffold a voice-locked message, then AUTHOR it (creative, below)
node "$S/copy.mjs" --kit "$K" --kind taglines|launch-post|tweet-thread|landing-copy|ad-variations|email|ui-microcopy \
--topic "…" --out out/<id>/copy
# VIDEO — assemble a /make-video brief from the kit, then hand off
node "$S/video-brief.mjs" --kit "$K" --platform tiktok|reels|shorts|youtube|square \
--story "…" --duration 30 --out out/<id>/video/brief.json
The creative parts (yours to author — scripts scaffold, you supply taste):
- web / social headlines & body — write real, specific copy in the brand voice; never ship lorem. Deploy a
signature device or the punctuation signature where it lands naturally. The --eyebrow/--kicker/--badge slots are opt-in — populate them only when the kit's signature devices include a label/pill device; otherwise omit the flag.
- deck outline — when
--in is omitted, deck.mjs writes outline.sample.json; rewrite it into the real
narrative (cover → sections → content/quote → closing), then rerun with --in.
- copy —
copy.mjs copies a scaffold and injects the brand + the **paths of the editorial voice files to
read. Read editorial/03-VOICE-STORYTELLING.md + 00-EDITORIAL-LINE.md + 04-LLM-PLAYBOOK.md + voice/voice.lock.json — plus editorial/EXEMPLARS.md (the ✅/❌ calibration pairs) when present, and for ui-microcopy also editorial/05-MICROCOPY.md (the kit's own per-element formulas) — fill the {{SLOT}} markers in the brand voice, then run the scaffold's VALIDATE** checklist (on-voice · no AI-slop / no banned words · claims true · length fits channel · signature used).
- video —
video-brief.mjs wires style.design_md (the brand's visual source of truth) + brand.json +
the voice lock + editorial into a brief, then prints /make-video <brief>. Hand off; /make-video adopts design.md verbatim and editorial/ for motion + voice.
Phase 4 — Verify + report
- Render-check every visual deliverable (open the
.html, or the baked PNG/PDF, via /browse or
playwright): fonts load (no system fallback), it reads as the same identity as the brand board, color comes only from the kit's palette, the logo is crisp, the background sits behind content. Fix what you see.
- Anti-slop gate (visual, against the kit's
craft/anti-slop.md): no eyebrow pill unless it is a kit
signature device; no default 3-up card row — feature count/layout follows the brand board (2–4 allowed); no gradient-wash hero unless accentMode is gradient; no glassmorphism.
- Determinism for bakes: re-bake and confirm byte-stability; grep generated HTML for no
Math.random /
Date.now / infinite gradient animation — and for slop tells: font-family Inter|Space Grotesk|Geist|Instrument Serif|Roboto|Arial (normalize spaces/hyphens before matching), hex #6366f1|#8b5cf6|#7c3aed, backdrop-filter.
- Conformance lint (post-render — verify the finished deliverable back against the kit; closes the loop
the creation-side gates leave open). Check and print a short pass / revisions report: - Fonts — every font-family used is a kit face (⊆ ctx.fonts), no system fallback, no banned default. - Colors — every hex/color used is in the kit palette (⊆ ctx.palette roles + gradient), no stray hue. - Contrast — text over its background clears WCAG AA (≥ 4.5:1 body, ≥ 3:1 large/UI); flag any pair below. - Banned terms absent — zero hits on the kit lexicon prohibited[] + the anti-slop verbal list (buzzwords, "It's not X. It's Y.", "Find Your …") across all copy in the deliverable. - Visual anti-slop — zero G1 hits (eyebrow pill / 3-card row / gradient-wash / glassmorphism / sparkle glyph). - Voice matches the exemplars — when the kit ships editorial/EXEMPLARS.md, read its ✅/❌ pairs and check the deliverable's copy sits on the ✅ side of each annotated rule. - Multi-script text — when the kit declares non-Latin languages, carry the Noto fallback chain documented in the kit's fonts.css into every rendered font-family stack (no tofu). If anything fails, fix it and re-lint — don't ship with open revisions.
- Report: the kit used, each deliverable + its path, the surfaces you chose, and the next hop (e.g. for
video, the exact /make-video command; for tokens, which file to import). Include a "Brand constraints applied" line — 2–5 bullets naming the exact spec fields that shaped this deliverable (e.g. "palette.accents.focal #… → CTA", "fonts.display … → headline", "signatureDevices … → hero label", "voice.lock mode … → error tone", "logo.clearSpace … → header padding") so the user sees the trace.
Render-safety contract (every generated asset obeys)
- Self-contained by default — fonts inlined as data-URI woff2 (
faceCSS(ctx,{mode:'inline'})), logo inlined
as SVG (logoSvg), background inlined as data-URI PNG (bgUri). The opened file needs no network. (Use --link/copied assets only for a multi-file site where bundle size matters.)
- Theme purely from variables —
:root{ rootVars(ctx) } then var(--bg/--fg/--acc/--panel/--line/--grad) +
font-family:var(--fd|--fm|--fh). No hardcoded hex or font name → any kit themes the same template.
- Motion (if any): transform/opacity only, finite, no
Math.random/Date.now. Deliverables are
screenshot/print targets — static-first.
- Bakes are CPU raster (
--disable-gpu, sRGB), fonts awaited, animations frozen → repeatable.
- Naming + size budgets — name outputs by a slugged scheme
<kind>-<brand-id>[-variant].<ext>
(e.g. og-acme-launch.png, landing-acme.html) so a folder of deliverables self-describes. Keep bakes in budget: PNG ≤ 1 MB recommended, 5 MB hard max; SVG ≤ 500 KB. Over budget → compress to slot (re-bake at the target size, not a giant canvas scaled down).
- No live CSS filters on photos in baked surfaces — bake the grade into the raster instead. Chromium
rasterizes a filter:/backdrop-filter element to a lossless bitmap, which bloats the PDF/PNG far past budget and is non-deterministic across GPUs. Apply color grades/LUTs to the source image, then embed the already-graded raster. (Live filters are fine in .html you'll never bake.)
Asking questions (office-hours discipline — self-contained)
When you must ask, use AskUserQuestion and frame each as a decision brief: a short title; 1–3 plain sentences on what's being decided; one option marked (recommended) with a one-line reason; 2–4 options each with a real upside + downside. If AskUserQuestion is unavailable, render the same brief as prose ("reply with a letter") and STOP. Never silently auto-decide a creative call (which surface, platform/size, voice direction).
How a generator reads the kit (for authoring/extending)
All scripts import the shared loader + helpers from $SKILLDIR/assets/brand.mjs (resolveKit, rootVars, faceCSS, fontsCss, logoSvg, pickLogo, dataUri, bgUri, abs, copyInto, slug, parseArgs) and the rasteriser from _bake.mjs (screenshot, pdf). brandContext paths are kit-relative; ctx.dir is absolute; read kit files via abs(ctx, rel). A new surface = a new scripts/<surface>.mjs + (optionally) assets/<surface>/*.tmpl.html with {{TOKEN}} markers — nothing else to wire.
File map (a /use-brand run)
out/<id>/
web/ landing|hero|page.html (+ .png with --bake)
social/ <id>-<size>.html (+ <id>-<size>.png with --bake)
deck/ deck.html · outline.json (or outline.sample.json) (+ deck.pdf / deck.pptx)
copy/ <kind>.md (scaffold → you author in voice)
tokens/ tokens.css · theme.css · tailwind.config.cjs · tokens.json · fonts/ · README.md
video/ brief.json (→ /make-video)
brand-guidelines.pdf (+ guidelines.html) # pdf --kind guidelines
brand/<id>/brandContext.json # normalized contract (load-kit)