cc-figma-component
Back to list

nvillapiano/cc-figma-component

Cc Figma Component

GitHub

Generate variable-bound Figma component sets from component-contract definitions after the token collections exist.

65 installsSystemsFrontendArchitecture0 demos

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.

---



…

More from nvillapiano