jrpease/throughline/token-builder

Claude Code and agent skill by jrpease/throughline

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

Build a two-tier (primitive + semantic) design token system as Figma variables — color ramps, spacing, type scale, radius, shadows — with light/dark or brand modes, using one collection per category per tier. Use this when the user wants to create design tokens, design variables, a color system, a type scale, a spacing system, or 'build my tokens' in Figma. Also trigger when the user mentions primitives and semantic tokens, variable collections, design system foundations, or modes/themes in Fig…

Install

npx vskill@latest install jrpease/throughline/token-builder

SKILL.md

Token builder

Critical collection rule: this system uses one collection per category per tier — never one giant Primitives + one giant Semantic. Color, spacing, typography, radius, and border each get their own primitive collection and their own semantic collection. This is non-negotiable: modes (Light/Dark, Desktop/Mobile) belong to a collection, so mixing categories in one collection forces unrelated variables to share the same mode axis.
Model tip (#3): building a coherent token system (ramps, type scale, modes,
primitive→semantic aliasing) is reasoning-heavy. It runs on your session model —
Sonnet is a solid default; Opus helps for large or multi-mode systems. See the
model guide in the plugin README.

Creates a two-tier design token system as Figma variables. Each tier is split into one collection per category (color, spacing, type, radius, border) so every category owns its own modes — see Step 1 for why. Within a collection, Figma variables are grouped with / and omit the category prefix (the collection already carries it); the sync layer later derives the dotted logical name (color.gray.50) by prefixing the collection's category.

  • Primitives — raw values with no meaning attached: gray/50, space/4

in their category's primitive collection. The full palette of possible values.

  • Semantic — meaning-bearing tokens that alias onto primitives:

bg/default → {gray/50}, text/primary → {gray/900}. This is the layer the rest of the system consumes.

The power of two tiers: change a primitive once and every semantic token referencing it updates automatically, which cascades through sheets, components, and synced code. Preserving these aliases (not flattening them) is what makes runtime theming work later, so always create semantic tokens as references to primitives, never as copied literal values.

Prerequisites

This skill needs a live Figma connection. Read the manifest (${CLAUDE_PLUGIN_ROOT}/references/manifest-schema.md for the schema) and check figma.connected. Then do a cheap liveness read to confirm the connection is actually live right now. If it isn't, say so plainly and offer to run the figma-environment-setup skill first: "Figma isn't connected yet — want me to set that up? It's a one-time thing." Don't proceed until Figma is reachable.

The plugin writes to Figma through Console MCP. If figma.mechanism holds anything other than console-mcp, say that value is no longer supported and offer figma-environment-setup to reset it. With Console MCP, prefer figma_execute to create variables in scripted loops rather than one tool call per variable — this is dramatically more token-efficient for the potentially hundreds of primitives across modes.

Scripting via `figma_execute`: see ${CLAUDE_PLUGIN_ROOT}/references/figma-scripting.md for the shared gotchas — the single-bridge-instance preflight (concurrent writes corrupt the file), the dynamic-page async APIs (synchronous document-wide getters like getLocalVariableCollections and setters like figma.currentPage = / node.textStyleId = throw — use getLocalVariableCollectionsAsync, setCurrentPageAsync, setTextStyleIdAsync, …), the resize() axis-lock trap, and why large WRAP grids time out. For a simple verification read, prefer the dedicated figma_get_variables tool (it handles dynamic-page correctly and resolves aliases with resolveAliases: true) over a hand-written script.

Execution model — sequential architect → figma-executor with model routing. If your host supports subagent dispatch, plan the token architecture once with one architect dispatch (deep tier) — it reads existing Figma state and emits a transcription-grade spec in stable identifiers (collection/variable names, never nodeIds) — then build the variables with figma-executor dispatches (balanced tier), strictly sequentially: preflight figma_get_status and never run two Figma-touching subagents at once (the single bridge is concurrency-1). Each executor finalizes by build-verify-then-replace with a programmatic read-back (figma_get_variables, not a screenshot); gate the result with a reviewer pass. Keep the human checkpoint between tiers (the PAUSE in Steps 2–4) — subagents run continuously within a tier, but you pause for the human between them. Route per ${CLAUDE_PLUGIN_ROOT}/references/agent-routing.md; never parallelize Figma work. If your host has no subagent dispatch, build and verify each tier inline, sequentially, as the steps below describe. Inline, run the active-file preflight in ${CLAUDE_PLUGIN_ROOT}/references/figma-scripting.md before the first write and again before replacing anything — the executor's file check does not come with you.

Step 1 — Brainstorm the structure (before building anything)

Run the protocol in ${CLAUDE_PLUGIN_ROOT}/references/brainstorm-before-build.md. First establish the intake mode (generative / descriptive / import) per that reference — it changes how much you generate versus preserve. In import mode, do not stop at a 1:1 transcription of what the user fed you (a brand guide or marketing site is almost always a partial system): after preserving and organizing their values, run the completeness pass from that reference — diff against the full-system model and proactively propose the missing pieces (tonal ramps, neutral ramp, state colors, dark mode, semantic roles, elevation/radius scales) as a preserve-first, opt-in menu derived from their existing values. Then lock the structure with the user, in readable chunks:

  • Seeds and direction — capture what the user actually has: brand color(s),

font(s), aesthetic words (modern, rounded, dense, comfortable), reference images/URLs, or an existing token set to import. In generative mode, this is the seed you expand from; in import mode, this is the set you organize.

  • Color ramps — which hues (e.g. gray, brand primary, success, warning,

danger), and how many steps each (a 50–900 ramp of ~10 steps is a sensible default). In generative mode, derive a full tonal ramp and harmonized supporting families from the user's seed color(s).

  • Modes — does the system need light + dark? Brand variants? Density? This

is high-impact and shapes everything downstream (it determines how many values each variable holds and how the sync layer emits themes), so brainstorm it carefully. Default: light + dark.

  • Spacing scale — base unit and steps (e.g. 4px base: 0, 1, 2, 3, 4, 6, 8,

12, 16, 24...). Default to a 4px-based scale; "dense" pulls it tighter, "comfortable" looser.

  • Type scale — font families, the size ramp, weights, line-heights. In

generative mode, propose complementary font pairings from the user's seed font. Default to a modular scale.

  • Radius / border / shadow scales as needed. "Rounded" → larger radius

scale.

  • Primitive naming convention — the single most important decision, because

the semantic tier aliases onto these names and renaming later breaks every alias. Lock it explicitly. In Figma, name variables without the category prefix (the collection supplies it) and group with /: e.g. gray/50, space/4, radius/md inside their category's primitive collection. The sync layer derives the dotted logical identity (e.g. color.gray.50) by prefixing the collection's category. Keep names neutral and semantic — never framework-specific (don't name a token --background to match shadcn; the adapter renames per framework later). Figma is framework-agnostic; the adapter absorbs all framework-specific shaping.

  • Tiers — default to two-tier (primitive + semantic). Only raise the

option of a third component tier if the user signals multi-brand, white-labeling, or a very large/robust component library — for a single-brand project it adds complexity without payoff, so don't even surface it. If the user opts in, component tokens alias onto semantic tokens (e.g. bg/primary → {bg/emphasis}).

  • Collection structure — two tiers, but **one collection per category per

tier, never one giant `Primitives` + one giant `Semantic`. In Figma a mode axis (Light/Dark, Desktop/Mobile, Brand) belongs to the *collection*, so every variable in a collection is forced to share its modes. Putting `space` in the same collection as `color` drags spacing into Light/Dark, which is meaningless. Default layout (single-brand): private primitive collections `_Color/Primitive`, `_Typography/Primitive`, `_Radius/Primitive`, `_Border/Primitive`, and a public** Spacing/Primitive; published semantic collections Color/Semantic (Light/Dark), Spacing/Semantic, Typography/Semantic, Radius/Semantic, Border/Semantic. Privacy is the leading-_ prefix. size/icon/* lives in Spacing/Primitive; don't create a Sizing collection unless control heights/avatars become real tokens.

  • Multi-brand — keep two axes in two collections so they don't multiply.

Brand lives on _Color/Primitive (modes = Brand A, Brand B = raw palettes); Theme lives on Color/Semantic (modes = Light, Dark). A frame sets both independently and Figma resolves bg/default(Light) → {gray/50} → Brand A's gray. This keeps each collection ≤2 modes — under the Figma Professional cap of 4 modes/collection. (Brand-on-primitive assumes brands differ in raw palette, same role mapping; if a brand needs a different mapping, it also becomes a mode on Color/Semantic.)

Show the proposed full structure back to the user and get sign-off before creating anything.

The structural-consistency rule (prevents the "different every time" problem)

Every token concern gets both a primitive and a semantic collection, even when the semantic tier is a 1:1 passthrough today. A dimensional semantic tier (Spacing/Semantic, Radius/Semantic, Border/Semantic) is justified by a plausible future mode axis — e.g. adding Desktop/Mobile to spacing later — which only works if the semantic collection already exists to carry that axis. Building every concern the same way is also what makes the output consistent run-to-run instead of an arbitrary guess about which categories to duplicate.

The one guardrail: consistency does not license invented roles. Semantic names must be real usage roles (inset/md, width/focus, text/primary), never just renamed primitive steps (space/12, width/1). A passthrough role with a meaningful name is fine; a fake role nobody applies is not. If you can't name a genuine role for a category, give it semantic roles that map to actual usage rather than mirroring the primitive scale step-for-step.

Step 1.5 — Brownfield: refine existing variables in place (don't rebuild)

If this is a retrofit (tokens.intakeMode: "retrofit", or the file already has variables), do not create a fresh set on top of the old one. Refine what exists, in place. Read `${CLAUDE_PLUGIN_ROOT}/references/brownfield-retrofit.md` first — guardrail 3 is the whole point of this branch.

The hard rule (guardrail 3): rename and realign variables in place to preserve their Figma IDs. Never delete-and-recreate — every binding (a populated file can have thousands) references the variable id, so recreating under the same name still unbinds everything. A rename keeps the id; a delete+create does not.

The refine loop:

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
79
Repository forks
11
7-day trend score
0

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/jrpease/throughline/token-builder/badge)](https://verified-skill.com/skills/jrpease/throughline/token-builder)

Something wrong with this skill or its page? Tell us.