Generate variable-bound Figma component sets from component-contract definitions after the token collections exist.
Real-world examples not captured yet
This skill shows a gallery of live HTML demos (CDN libraries welcome — GSAP, Three.js, etc.) rendered inline via srcdoc.
Skill markdown
# cc-figma-component — Component Contracts Component Skill
Generate Figma component sets from component contracts. This skill reads a contract, derives component-scoped (Tier 3) tokens, and builds a fully variable-bound component set in Figma.
**Prerequisites — load these skills first:**
- `figma-use` — Plugin API syntax rules (mandatory before every `use_figma` call)
- `figma-generate-library` — Design system workflow and component creation patterns
- `cc-figma-tokens` must have been run — `Primitives` and `Semantic` collections must exist in the target Figma file
**Always pass `skillNames: "cc-figma-component"` when calling `use_figma` as part of this skill.**
---
## Global Rules
### Frame sizing defaults to HUG
**Every frame created by this skill must have both sizing properties set to `'HUG'` immediately after creation — no exceptions.**
```js
node.layoutSizingHorizontal = 'HUG';
node.layoutSizingVertical = 'HUG';
```
This applies to: the base component frame, every variant duplicate, the Generation Notes frame, and any other frame created during the run. Never rely on Figma's default — it sets new frames to `FIXED` at 100px, which produces portrait-aspect components regardless of padding values. Only deviate from HUG when a slot child's `figma.sizing` is explicitly set to `"fixed"` in the contract. In that case use the contract's `figma.width` and `figma.height` values directly:
```js
if (child.figma?.sizing === 'fixed') {
node.layoutSizingHorizontal = 'FIXED';
node.layoutSizingVertical = 'FIXED';
node.resize(child.figma.width, child.figma.height);
}
```
This is the only legitimate exception to the HUG default.
---
## 1. Configuration
Before anything else, read `.component-contracts` from the project root. Never output `FIGMA_ACCESS_TOKEN` in any response.
```
FIGMA_ACCESS_TOKEN=... # never output this value
FIGMA_FILE_KEY=... # use for all use_figma calls
TOKENS_DIR=... # root directory of token files
CONTRACTS_DIR=... # root directory of contract files
```
---
## 2. Contract Structure
A component contract is a JSON file at `{CONTRACTS_DIR}/{id}.contract.json`. Read it fully before planning anything.
Key sections used by this skill:
**`tokens`** — defines the component's Tier 3 token bindings, organized by category:
```json
{
"tokens": {
"color": {
"background.primary": "brand.500",
"text.primary": "neutral.0",
"border.secondary": "brand.500"
},
"spacing": {
"padding.x.sm": "space.sm",
"padding.y.sm": "space.xs"
},
"typography": {
"label.size": "textSize.sm",
"label.weight": "weight.semibold"
},
"border": {
"radius": "radius.md",
"width": "border.width.sm"
},
"motion": {
"transition": "duration.fast"
}
}
}
```
**`props`** — defines the component's variant axes (e.g. `variant`, `size`, `state`)
**`a11y`** — accessibility requirements (ARIA roles, keyboard behavior)
**`platforms`** — target platforms (web, ios, android)
---
## 3. Tier 3 Token Derivation
Component-scoped (Tier 3) tokens are derived from the contract's `tokens` section — they are NOT stored as a separate file. Derive them at runtime using these rules:
### Naming convention
```
--ds-{componentId}-{role}-{qualifier}
```
Where:
- `componentId` — the contract's `id` field (e.g. `button`, `accordion`)
- `role` — the Figma-aligned role name (see role translation table below)
- `qualifier` — derived from the Semantic alias name in the contract value
### Role translation table
| Contract category + key prefix | CSS/Figma role |
|-------------------------------|----------------|
| `color.background.*` | `fill` |
| `color.text.*` | `text` |
| `color.border.*` | `border` |
| `color.focus.*` | `focus` |
| `spacing.*` | `spacing` |
| `typography.*` | `typography` |
| `border.radius` | `border` (as `border-radius`) |
| `border.width` | `border` (as `border-width`) |
| `motion.*` | `transition` |
### Qualifier derivation
The qualifier comes from the Semantic alias value in the contract, with the scale suffix dropped:
```
"background.primary": "brand.500" → qualifier = "brand" → --ds-button-fill-brand
"background.primary.hover": "brand.600" → qualifier = "brand-hover"
"text.primary": "neutral.0" → qualifier = "neutral-0"
```
State suffixes (`hover`, `active`, `focus`, `disabled`) are appended after the qualifier:
```
--ds-button-fill-brand-hover
--ds-button-fill-brand-active
```
### Semantic variable lookup
Each Tier 3 token must bind to the corresponding Semantic variable in Figma. Look up the variable by name:
```
contract value "brand.500" → Semantic variable named "brand/500"
contract value "space.sm" → Semantic variable named "space/sm"
contract value "radius.md" → Semantic variable named "radius/md"
```
If a Semantic variable is not found, stop and report the missing variable to the user before proceeding.
---
…