figma-code-agent 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +133 -0
- package/bin/install.js +328 -0
- package/knowledge/README.md +62 -0
- package/knowledge/css-strategy.md +973 -0
- package/knowledge/design-to-code-assets.md +855 -0
- package/knowledge/design-to-code-layout.md +929 -0
- package/knowledge/design-to-code-semantic.md +1085 -0
- package/knowledge/design-to-code-typography.md +1003 -0
- package/knowledge/design-to-code-visual.md +1145 -0
- package/knowledge/design-tokens-variables.md +1261 -0
- package/knowledge/design-tokens.md +960 -0
- package/knowledge/figma-api-devmode.md +894 -0
- package/knowledge/figma-api-plugin.md +920 -0
- package/knowledge/figma-api-rest.md +742 -0
- package/knowledge/figma-api-variables.md +848 -0
- package/knowledge/figma-api-webhooks.md +876 -0
- package/knowledge/payload-blocks.md +1184 -0
- package/knowledge/payload-figma-mapping.md +1210 -0
- package/knowledge/payload-visual-builder.md +1004 -0
- package/knowledge/plugin-architecture.md +1176 -0
- package/knowledge/plugin-best-practices.md +1206 -0
- package/knowledge/plugin-codegen.md +1313 -0
- package/package.json +31 -0
- package/skills/README.md +103 -0
- package/skills/audit-plugin/SKILL.md +244 -0
- package/skills/build-codegen-plugin/SKILL.md +279 -0
- package/skills/build-importer/SKILL.md +320 -0
- package/skills/build-plugin/SKILL.md +199 -0
- package/skills/build-token-pipeline/SKILL.md +363 -0
- package/skills/ref-html/SKILL.md +290 -0
- package/skills/ref-layout/SKILL.md +150 -0
- package/skills/ref-payload-block/SKILL.md +415 -0
- package/skills/ref-react/SKILL.md +222 -0
- package/skills/ref-tokens/SKILL.md +347 -0
|
@@ -0,0 +1,973 @@
|
|
|
1
|
+
# Layered CSS Architecture
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Authoritative reference for the layered CSS strategy used in Figma design-to-code generation. Documents how generated CSS properties are distributed across three layers -- Tailwind CSS utilities for structural layout, CSS Custom Properties for design tokens, and CSS Modules for component-specific visual styling -- to produce maintainable, overridable, production-grade CSS output. Encodes production patterns for token extraction, CSS generation, token consumption, and CSS Modules isolation.
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
Reference this module when you need to:
|
|
10
|
+
|
|
11
|
+
- Decide which CSS layer a generated property should belong to (Tailwind, Custom Property, or CSS Module)
|
|
12
|
+
- Understand how the three CSS layers compose without specificity conflicts
|
|
13
|
+
- Configure Tailwind to reference design tokens from CSS Custom Properties
|
|
14
|
+
- Structure CSS Module files for component-scoped visual styles
|
|
15
|
+
- Implement token consumption patterns with `var()` and fallback values
|
|
16
|
+
- Handle responsive CSS using mobile-first media queries with Tailwind prefixes
|
|
17
|
+
- Support light/dark themes through CSS Custom Properties and mode selectors
|
|
18
|
+
- Choose between separate CSS files (reset.css, tokens.css, styles.css) or merged output
|
|
19
|
+
- Understand how the five design-to-code modules feed into the CSS generation pipeline
|
|
20
|
+
- Implement Visual Builder token aliasing for plugin isolation
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Content
|
|
25
|
+
|
|
26
|
+
### 1. Three-Layer Architecture Overview
|
|
27
|
+
|
|
28
|
+
Generated CSS is distributed across three layers, each with a distinct responsibility and specificity level. This separation ensures that layout structure, design tokens, and visual skin can be modified independently.
|
|
29
|
+
|
|
30
|
+
#### Layer Summary
|
|
31
|
+
|
|
32
|
+
| Layer | Technology | Responsibility | Specificity |
|
|
33
|
+
|-------|-----------|----------------|-------------|
|
|
34
|
+
| 1. Layout Bones | Tailwind CSS classes | Flexbox, gap, padding, margin, sizing, positioning, responsive breakpoints | Zero (utility classes at `@layer utilities`) |
|
|
35
|
+
| 2. Design Tokens | CSS Custom Properties | Colors, font sizes, font families, spacing values, radii, shadows, transitions | Defined on `:root` (zero selector specificity for the variables themselves) |
|
|
36
|
+
| 3. Visual Skin | CSS Modules | Component-specific backgrounds, borders, effects, color assignments, overrides | Scoped to component (hashed class names prevent leaking) |
|
|
37
|
+
|
|
38
|
+
#### Why Three Layers
|
|
39
|
+
|
|
40
|
+
The three-layer approach solves three problems that single-strategy CSS cannot:
|
|
41
|
+
|
|
42
|
+
1. **Tailwind alone** cannot handle design-specific visual styles (exact color assignments, shadow compositions, gradient definitions) without excessive arbitrary values that defeat the utility-class purpose.
|
|
43
|
+
|
|
44
|
+
2. **CSS Custom Properties alone** cannot provide structural layout utilities efficiently. Repeating `display: flex; flex-direction: column; gap: var(--spacing-md)` on every container is verbose when `flex flex-col gap-4` achieves the same result.
|
|
45
|
+
|
|
46
|
+
3. **CSS Modules alone** cannot share design tokens across components without importing a shared file or duplicating values. Token changes would require editing every module file.
|
|
47
|
+
|
|
48
|
+
The three layers compose naturally: Tailwind handles the predictable structural patterns, Custom Properties provide the shared design language, and CSS Modules apply the unique visual identity per component.
|
|
49
|
+
|
|
50
|
+
#### How the Layers Compose
|
|
51
|
+
|
|
52
|
+
```html
|
|
53
|
+
<!-- Layer 1: Tailwind classes handle layout -->
|
|
54
|
+
<div class="flex flex-col gap-4 p-6 w-full">
|
|
55
|
+
<!-- Layer 3: CSS Module class handles visual skin -->
|
|
56
|
+
<div class="card">
|
|
57
|
+
<h2 class="card__title">Welcome</h2>
|
|
58
|
+
<p class="card__body">Content here</p>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```css
|
|
64
|
+
/* Layer 2: tokens.css — design tokens at :root */
|
|
65
|
+
:root {
|
|
66
|
+
--color-neutral-100: #f5f5f5;
|
|
67
|
+
--color-neutral-800: #333333;
|
|
68
|
+
--color-primary: #1a73e8;
|
|
69
|
+
--radius-lg: 12px;
|
|
70
|
+
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Layer 3: Card.module.css — visual skin consuming tokens */
|
|
74
|
+
.card {
|
|
75
|
+
background-color: var(--color-neutral-100);
|
|
76
|
+
border: 1px solid var(--color-neutral-300);
|
|
77
|
+
border-radius: var(--radius-lg);
|
|
78
|
+
box-shadow: var(--shadow-md);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.card__title {
|
|
82
|
+
color: var(--color-neutral-800);
|
|
83
|
+
font-size: var(--text-2xl);
|
|
84
|
+
font-weight: var(--font-bold);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
### 2. Layer 1: Tailwind CSS (Layout Bones)
|
|
91
|
+
|
|
92
|
+
Tailwind CSS handles all structural layout properties. These are the mechanical, pattern-based properties that determine how elements are arranged, sized, and spaced -- not how they look visually.
|
|
93
|
+
|
|
94
|
+
#### Properties That Belong in Tailwind
|
|
95
|
+
|
|
96
|
+
| CSS Property | Tailwind Class | Source in Figma |
|
|
97
|
+
|-------------|---------------|-----------------|
|
|
98
|
+
| `display: flex` | `flex` | Auto Layout container |
|
|
99
|
+
| `flex-direction: column` | `flex-col` | `layoutMode: VERTICAL` |
|
|
100
|
+
| `flex-direction: row` | `flex-row` | `layoutMode: HORIZONTAL` |
|
|
101
|
+
| `justify-content: center` | `justify-center` | `primaryAxisAlignItems: CENTER` |
|
|
102
|
+
| `justify-content: space-between` | `justify-between` | `primaryAxisAlignItems: SPACE_BETWEEN` |
|
|
103
|
+
| `align-items: center` | `items-center` | `counterAxisAlignItems: CENTER` |
|
|
104
|
+
| `align-items: flex-start` | `items-start` | `counterAxisAlignItems: MIN` |
|
|
105
|
+
| `gap: 16px` | `gap-4` | `itemSpacing: 16` |
|
|
106
|
+
| `padding: 24px` | `p-6` | `padding: { top: 24, right: 24, bottom: 24, left: 24 }` |
|
|
107
|
+
| `padding: 16px 24px` | `py-4 px-6` | Mixed padding values |
|
|
108
|
+
| `flex-grow: 1; flex-basis: 0` | `flex-1` | `layoutSizingHorizontal: FILL` (primary axis) |
|
|
109
|
+
| `flex-shrink: 0` | `shrink-0` | `layoutSizingHorizontal: FIXED` (primary axis) |
|
|
110
|
+
| `align-self: stretch` | `self-stretch` | `layoutSizingVertical: FILL` (counter axis) |
|
|
111
|
+
| `width: 100%` | `w-full` | FILL on counter axis |
|
|
112
|
+
| `flex-wrap: wrap` | `flex-wrap` | `layoutWrap: WRAP` |
|
|
113
|
+
| `position: relative` | `relative` | Parent of absolute children |
|
|
114
|
+
| `position: absolute` | `absolute` | `layoutPositioning: ABSOLUTE` |
|
|
115
|
+
| `overflow: hidden` | `overflow-hidden` | Clip content |
|
|
116
|
+
| `min-width: 200px` | `min-w-[200px]` | `minWidth: 200` |
|
|
117
|
+
| `max-width: 800px` | `max-w-[800px]` | `maxWidth: 800` |
|
|
118
|
+
|
|
119
|
+
#### When NOT to Use Tailwind
|
|
120
|
+
|
|
121
|
+
Tailwind should NOT be used for visual design properties:
|
|
122
|
+
|
|
123
|
+
- **Colors** -- `bg-blue-500` creates a tight coupling to Tailwind's color palette. Use CSS Custom Properties so colors can be changed via tokens without touching HTML.
|
|
124
|
+
- **Shadows** -- `shadow-lg` uses Tailwind's built-in shadow, not the design's specific shadow. Use token-referenced `box-shadow` in CSS Modules.
|
|
125
|
+
- **Border radius** -- Design-specific radii should reference tokens (`var(--radius-lg)`), not Tailwind's radius scale.
|
|
126
|
+
- **Font sizes** -- Use token-referenced `font-size` (`var(--text-lg)`) to maintain consistency with the design's type scale.
|
|
127
|
+
- **Specific spacing values** -- When a spacing value maps to a design token (from Figma Variables or threshold-promoted), use `var(--spacing-md)` instead of `gap-4`.
|
|
128
|
+
|
|
129
|
+
**Exception:** When Tailwind is configured to reference CSS Custom Properties in its theme (see Section 2.1), Tailwind classes like `gap-md` or `text-lg` can safely reference tokens.
|
|
130
|
+
|
|
131
|
+
#### 2.1 Tailwind Theme Integration with Design Tokens
|
|
132
|
+
|
|
133
|
+
Tailwind's theme can be configured to reference CSS Custom Properties, bridging Layer 1 and Layer 2:
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
// tailwind.config.js
|
|
137
|
+
export default {
|
|
138
|
+
theme: {
|
|
139
|
+
extend: {
|
|
140
|
+
colors: {
|
|
141
|
+
primary: 'var(--color-primary)',
|
|
142
|
+
secondary: 'var(--color-secondary)',
|
|
143
|
+
neutral: {
|
|
144
|
+
100: 'var(--color-neutral-100)',
|
|
145
|
+
300: 'var(--color-neutral-300)',
|
|
146
|
+
800: 'var(--color-neutral-800)',
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
spacing: {
|
|
150
|
+
xs: 'var(--spacing-xs)',
|
|
151
|
+
sm: 'var(--spacing-sm)',
|
|
152
|
+
md: 'var(--spacing-md)',
|
|
153
|
+
lg: 'var(--spacing-lg)',
|
|
154
|
+
xl: 'var(--spacing-xl)',
|
|
155
|
+
},
|
|
156
|
+
borderRadius: {
|
|
157
|
+
sm: 'var(--radius-sm)',
|
|
158
|
+
md: 'var(--radius-md)',
|
|
159
|
+
lg: 'var(--radius-lg)',
|
|
160
|
+
full: 'var(--radius-full)',
|
|
161
|
+
},
|
|
162
|
+
fontSize: {
|
|
163
|
+
xs: 'var(--text-xs)',
|
|
164
|
+
sm: 'var(--text-sm)',
|
|
165
|
+
base: 'var(--text-base)',
|
|
166
|
+
lg: 'var(--text-lg)',
|
|
167
|
+
xl: 'var(--text-xl)',
|
|
168
|
+
'2xl': 'var(--text-2xl)',
|
|
169
|
+
},
|
|
170
|
+
boxShadow: {
|
|
171
|
+
sm: 'var(--shadow-sm)',
|
|
172
|
+
md: 'var(--shadow-md)',
|
|
173
|
+
lg: 'var(--shadow-lg)',
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
With this configuration, `gap-md` resolves to `gap: var(--spacing-md)`, which in turn resolves to the actual pixel value defined in the `:root` tokens. This allows Tailwind classes to be token-aware without hardcoding values.
|
|
181
|
+
|
|
182
|
+
#### Tailwind v4 Configuration
|
|
183
|
+
|
|
184
|
+
The reference project uses Tailwind v4 via `@tailwindcss/postcss`:
|
|
185
|
+
|
|
186
|
+
```js
|
|
187
|
+
// postcss.config.mjs
|
|
188
|
+
const config = {
|
|
189
|
+
plugins: {
|
|
190
|
+
'@tailwindcss/postcss': {},
|
|
191
|
+
},
|
|
192
|
+
}
|
|
193
|
+
export default config
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Tailwind v4 automatically detects CSS custom properties and can use them as utility values without explicit theme configuration, reducing the need for manual theme extension.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
### 3. Layer 2: CSS Custom Properties (Design Tokens)
|
|
201
|
+
|
|
202
|
+
CSS Custom Properties serve as the design tokens bridge -- the shared vocabulary of colors, spacing, typography, radii, shadows, and transitions that all components reference. Tokens are defined once in `:root` and consumed everywhere via `var()`.
|
|
203
|
+
|
|
204
|
+
#### Token Placement at `:root`
|
|
205
|
+
|
|
206
|
+
All design tokens are defined on the `:root` selector, making them globally available:
|
|
207
|
+
|
|
208
|
+
```css
|
|
209
|
+
:root {
|
|
210
|
+
/* Colors */
|
|
211
|
+
--color-primary: #1a73e8;
|
|
212
|
+
--color-secondary: #5f6368;
|
|
213
|
+
--color-neutral-100: #f5f5f5;
|
|
214
|
+
--color-neutral-800: #333333;
|
|
215
|
+
--color-success: #34a853;
|
|
216
|
+
--color-warning: #fbbc04;
|
|
217
|
+
--color-error: #ea4335;
|
|
218
|
+
|
|
219
|
+
/* Spacing */
|
|
220
|
+
--spacing-1: 4px;
|
|
221
|
+
--spacing-2: 8px;
|
|
222
|
+
--spacing-3: 12px;
|
|
223
|
+
--spacing-4: 16px;
|
|
224
|
+
--spacing-6: 24px;
|
|
225
|
+
--spacing-8: 32px;
|
|
226
|
+
|
|
227
|
+
/* Typography */
|
|
228
|
+
--font-primary: 'Inter', sans-serif;
|
|
229
|
+
--font-mono: 'Roboto Mono', monospace;
|
|
230
|
+
--text-sm: 14px;
|
|
231
|
+
--text-base: 16px;
|
|
232
|
+
--text-lg: 18px;
|
|
233
|
+
--text-xl: 24px;
|
|
234
|
+
--text-2xl: 32px;
|
|
235
|
+
--font-regular: 400;
|
|
236
|
+
--font-medium: 500;
|
|
237
|
+
--font-bold: 700;
|
|
238
|
+
|
|
239
|
+
/* Border Radii */
|
|
240
|
+
--radius-sm: 4px;
|
|
241
|
+
--radius-md: 8px;
|
|
242
|
+
--radius-lg: 12px;
|
|
243
|
+
--radius-full: 9999px;
|
|
244
|
+
|
|
245
|
+
/* Shadows */
|
|
246
|
+
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
247
|
+
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
248
|
+
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
|
249
|
+
|
|
250
|
+
/* Transitions */
|
|
251
|
+
--transition-fast: 150ms ease;
|
|
252
|
+
--transition-normal: 200ms ease;
|
|
253
|
+
--transition-slow: 300ms ease;
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
#### Category Naming Conventions
|
|
258
|
+
|
|
259
|
+
The recommended category prefixes for auto-detected tokens:
|
|
260
|
+
|
|
261
|
+
| Category | Prefix | Examples |
|
|
262
|
+
|----------|--------|---------|
|
|
263
|
+
| Colors | `--color-*` | `--color-primary`, `--color-neutral-800`, `--color-error` |
|
|
264
|
+
| Spacing | `--spacing-*` | `--spacing-1`, `--spacing-4`, `--spacing-8` |
|
|
265
|
+
| Font sizes | `--text-*` | `--text-sm`, `--text-base`, `--text-2xl` |
|
|
266
|
+
| Font families | `--font-*` | `--font-primary`, `--font-mono` |
|
|
267
|
+
| Font weights | `--font-*` | `--font-bold`, `--font-medium`, `--font-regular` |
|
|
268
|
+
| Border radii | `--radius-*` | `--radius-sm`, `--radius-md`, `--radius-full` |
|
|
269
|
+
| Shadows | `--shadow-*` | `--shadow-sm`, `--shadow-md`, `--shadow-lg` |
|
|
270
|
+
| Transitions | `--transition-*` | `--transition-fast`, `--transition-normal` |
|
|
271
|
+
|
|
272
|
+
#### The `--token-*` Double-Prefix Pattern
|
|
273
|
+
|
|
274
|
+
Some projects add a `--token-` prefix to all design tokens. This serves two purposes: (1) clearly distinguishes design tokens from other CSS custom properties, and (2) enables the Visual Builder's token aliasing pattern.
|
|
275
|
+
|
|
276
|
+
```css
|
|
277
|
+
/* tokens.css */
|
|
278
|
+
:root {
|
|
279
|
+
--token-color-primary: #3b82f6;
|
|
280
|
+
--token-spacing-md: 16px;
|
|
281
|
+
--token-radius-lg: 12px;
|
|
282
|
+
--token-font-size-base: 18px;
|
|
283
|
+
--token-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
The `--token-` prefix is a project convention, not a requirement. Some projects use bare category prefixes (`--color-*`), others use `--token-color-*`. Both are valid approaches.
|
|
288
|
+
|
|
289
|
+
#### Token Fallback Pattern
|
|
290
|
+
|
|
291
|
+
When consuming tokens in CSS Module rules, always include a raw fallback value. This ensures the styles work even if the token definition is missing (e.g., during development, or when tokens are loaded asynchronously):
|
|
292
|
+
|
|
293
|
+
```css
|
|
294
|
+
/* With fallback — safe for all environments */
|
|
295
|
+
background-color: var(--token-color-primary, #3b82f6);
|
|
296
|
+
border-radius: var(--token-radius-lg, 12px);
|
|
297
|
+
padding: var(--token-spacing-lg, 24px);
|
|
298
|
+
|
|
299
|
+
/* Without fallback — only safe when token is guaranteed to be defined */
|
|
300
|
+
background-color: var(--color-primary);
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
**When to omit fallbacks:** For tokens defined in the same project's `tokens.css` that is guaranteed to be loaded before component styles. Fallbacks can be omitted for local Figma Variables (tokens defined in the same file). External library variables always include fallbacks.
|
|
304
|
+
|
|
305
|
+
> For details on token extraction, naming algorithms, and promotion thresholds, see `design-tokens.md`.
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
### 4. Layer 3: CSS Modules (Visual Skin)
|
|
310
|
+
|
|
311
|
+
CSS Modules provide component-scoped visual styles. These are the Figma-specific visual properties that give each component its unique appearance -- backgrounds, borders, shadows, color assignments, typography styling.
|
|
312
|
+
|
|
313
|
+
#### Component-Scoped Styles
|
|
314
|
+
|
|
315
|
+
Each component gets its own CSS Module file. Class names are locally scoped (hashed at build time), preventing style leaking between components:
|
|
316
|
+
|
|
317
|
+
```css
|
|
318
|
+
/* Card.module.css */
|
|
319
|
+
.card {
|
|
320
|
+
background-color: var(--color-neutral-100);
|
|
321
|
+
border: 1px solid var(--color-neutral-300);
|
|
322
|
+
border-radius: var(--radius-lg);
|
|
323
|
+
box-shadow: var(--shadow-md);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
.card__title {
|
|
327
|
+
color: var(--color-neutral-800);
|
|
328
|
+
font-size: var(--text-2xl);
|
|
329
|
+
font-weight: var(--font-bold);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.card__body {
|
|
333
|
+
color: var(--color-neutral-800);
|
|
334
|
+
font-size: var(--text-base);
|
|
335
|
+
line-height: 1.6;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.card__cta {
|
|
339
|
+
background-color: var(--color-primary);
|
|
340
|
+
color: var(--color-neutral-100);
|
|
341
|
+
border-radius: var(--radius-sm);
|
|
342
|
+
font-weight: var(--font-medium);
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
#### BEM Naming Within Modules
|
|
347
|
+
|
|
348
|
+
CSS Module class names follow BEM conventions with flat hierarchy (no deeper than `block__element`):
|
|
349
|
+
|
|
350
|
+
```css
|
|
351
|
+
/* Block */
|
|
352
|
+
.hero { }
|
|
353
|
+
|
|
354
|
+
/* Elements */
|
|
355
|
+
.hero__inner { }
|
|
356
|
+
.hero__content { }
|
|
357
|
+
.hero__title { }
|
|
358
|
+
.hero__buttons { }
|
|
359
|
+
.hero__button { }
|
|
360
|
+
|
|
361
|
+
/* Modifiers (via composes or separate classes) */
|
|
362
|
+
.heroContainerHigh { min-height: 400px; }
|
|
363
|
+
.heroContainerMedium { min-height: 300px; }
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
> For BEM naming conventions and flat hierarchy rules, see `design-to-code-semantic.md`.
|
|
367
|
+
|
|
368
|
+
#### Token Consumption Pattern
|
|
369
|
+
|
|
370
|
+
CSS Module rules consume tokens via `var()` references. The module never defines its own token values -- it only references tokens from Layer 2:
|
|
371
|
+
|
|
372
|
+
```css
|
|
373
|
+
/* CORRECT: Module consumes tokens */
|
|
374
|
+
.card {
|
|
375
|
+
background-color: var(--token-color-bg, #ffffff);
|
|
376
|
+
border-radius: var(--token-radius-lg, 12px);
|
|
377
|
+
box-shadow: var(--token-shadow-sm, 0 1px 3px rgba(0, 0, 0, 0.1));
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/* WRONG: Module defines its own values (bypasses token system) */
|
|
381
|
+
.card {
|
|
382
|
+
background-color: #ffffff;
|
|
383
|
+
border-radius: 12px;
|
|
384
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
#### File Organization (Per-Block Modules)
|
|
389
|
+
|
|
390
|
+
The recommended approach organizes CSS Modules by block type, with each block in its own file under `src/styles/blocks/`:
|
|
391
|
+
|
|
392
|
+
```
|
|
393
|
+
src/styles/
|
|
394
|
+
tokens.css # Layer 2: shared design tokens
|
|
395
|
+
blocks/
|
|
396
|
+
accordion.module.css # Layer 3: per-block visual skin
|
|
397
|
+
button.module.css
|
|
398
|
+
callToAction.module.css
|
|
399
|
+
card.module.css
|
|
400
|
+
container.module.css
|
|
401
|
+
hero.module.css
|
|
402
|
+
media.module.css
|
|
403
|
+
richText.module.css
|
|
404
|
+
stats.module.css
|
|
405
|
+
testimonial.module.css
|
|
406
|
+
video.module.css
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
Each module imports `tokens.css` to ensure token definitions are available:
|
|
410
|
+
|
|
411
|
+
```css
|
|
412
|
+
@import '../tokens.css';
|
|
413
|
+
|
|
414
|
+
.card {
|
|
415
|
+
background-color: var(--token-color-bg, #ffffff);
|
|
416
|
+
/* ... */
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
#### Visual Builder Token Aliasing
|
|
421
|
+
|
|
422
|
+
The Visual Builder plugin creates a CSS isolation boundary using `contain: content` and `isolation: isolate`. Within this boundary, tokens are aliased from `--token-*` to `--vb-*` to prevent interference with the Payload CMS admin panel's styles:
|
|
423
|
+
|
|
424
|
+
```css
|
|
425
|
+
/* visualCanvas.module.css */
|
|
426
|
+
.visualCanvas {
|
|
427
|
+
all: revert;
|
|
428
|
+
contain: content;
|
|
429
|
+
isolation: isolate;
|
|
430
|
+
|
|
431
|
+
/* Token aliasing: VB tokens reference project tokens with fallbacks */
|
|
432
|
+
--vb-color-primary: var(--token-color-primary, #3b82f6);
|
|
433
|
+
--vb-spacing-md: var(--token-spacing-md, 16px);
|
|
434
|
+
--vb-radius-md: var(--token-radius-md, 8px);
|
|
435
|
+
/* ... full aliasing for all token categories */
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
This pattern enables:
|
|
440
|
+
|
|
441
|
+
1. **Plugin portability** -- The Visual Builder works in any project regardless of whether `--token-*` variables are defined (fallbacks kick in)
|
|
442
|
+
2. **Admin isolation** -- `contain: content` prevents Payload admin styles from bleeding into the visual canvas
|
|
443
|
+
3. **Single source of truth** -- Projects define tokens once in `tokens.css`; the Visual Builder automatically picks them up via the alias chain
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
### 5. Property Placement Decision Tree
|
|
448
|
+
|
|
449
|
+
For any CSS property generated from a Figma node, this decision tree determines which layer it belongs to. This is the core routing logic for the CSS generation pipeline.
|
|
450
|
+
|
|
451
|
+
```
|
|
452
|
+
For each CSS property on a GeneratedElement:
|
|
453
|
+
|
|
454
|
+
1. IS IT A STRUCTURAL LAYOUT PROPERTY?
|
|
455
|
+
(display, flex-direction, justify-content, align-items, gap,
|
|
456
|
+
flex-grow, flex-basis, flex-shrink, flex-wrap, align-self,
|
|
457
|
+
align-content, position, width/height from sizing modes,
|
|
458
|
+
min-width, max-width, min-height, max-height, overflow)
|
|
459
|
+
|
|
460
|
+
YES → Layer 1: Tailwind utility class
|
|
461
|
+
Rationale: Layout is mechanical and pattern-based.
|
|
462
|
+
Tailwind's utility classes express these concisely.
|
|
463
|
+
|
|
464
|
+
2. IS THE RAW VALUE A PROMOTED DESIGN TOKEN?
|
|
465
|
+
(color resolves to var(--color-*),
|
|
466
|
+
spacing resolves to var(--spacing-*),
|
|
467
|
+
font-size resolves to var(--text-*),
|
|
468
|
+
font-family resolves to var(--font-*),
|
|
469
|
+
font-weight resolves to var(--font-*),
|
|
470
|
+
border-radius resolves to var(--radius-*),
|
|
471
|
+
box-shadow resolves to var(--shadow-*))
|
|
472
|
+
|
|
473
|
+
YES → Layer 2: CSS Custom Property reference in the value
|
|
474
|
+
The token is DEFINED in :root, CONSUMED in the CSS Module rule.
|
|
475
|
+
Rationale: Tokens are the shared design language. Centralizing
|
|
476
|
+
them enables theme changes without touching component styles.
|
|
477
|
+
|
|
478
|
+
3. IS IT A COMPONENT-SPECIFIC VISUAL STYLE?
|
|
479
|
+
(background-color, background-image, border, border-color,
|
|
480
|
+
border-radius, box-shadow, color, opacity, filter,
|
|
481
|
+
backdrop-filter, mix-blend-mode, text-decoration,
|
|
482
|
+
transition, transform)
|
|
483
|
+
|
|
484
|
+
YES → Layer 3: CSS Module rule
|
|
485
|
+
The property is placed in the component's .module.css file.
|
|
486
|
+
If the value is a token, the rule uses var(--token-*).
|
|
487
|
+
If the value is not a token, the raw value is used inline.
|
|
488
|
+
|
|
489
|
+
4. IS IT PADDING OR GAP WITH A TOKEN VALUE?
|
|
490
|
+
|
|
491
|
+
YES → Layer 1 if using Tailwind theme integration:
|
|
492
|
+
class="gap-md p-lg" (where md/lg map to token vars)
|
|
493
|
+
YES → Layer 3 if not using Tailwind theme integration:
|
|
494
|
+
gap: var(--spacing-md); padding: var(--spacing-lg);
|
|
495
|
+
Rationale: Padding and gap are layout properties but can also
|
|
496
|
+
carry token values. The choice depends on Tailwind configuration.
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
#### Property-to-Layer Reference Table
|
|
500
|
+
|
|
501
|
+
| Property Category | Example Properties | Layer | Method |
|
|
502
|
+
|------------------|--------------------|-------|--------|
|
|
503
|
+
| Flex container | `display`, `flex-direction`, `justify-content`, `align-items`, `flex-wrap`, `align-content` | 1 (Tailwind) | Utility classes |
|
|
504
|
+
| Flex child | `flex-grow`, `flex-basis`, `flex-shrink`, `align-self` | 1 (Tailwind) | Utility classes |
|
|
505
|
+
| Spacing | `gap`, `padding`, `margin` | 1 or 3 | Tailwind if standard; Module if token-bound |
|
|
506
|
+
| Sizing | `width`, `height`, `min-width`, `max-width` | 1 (Tailwind) | Utility classes |
|
|
507
|
+
| Positioning | `position`, `top`, `right`, `bottom`, `left`, `z-index` | 1 (Tailwind) | Utility classes |
|
|
508
|
+
| Overflow | `overflow`, `text-overflow` | 1 (Tailwind) | Utility classes |
|
|
509
|
+
| Background | `background-color`, `background-image`, `background-size` | 3 (Module) | CSS rule with `var()` |
|
|
510
|
+
| Border | `border`, `border-color`, `border-width` | 3 (Module) | CSS rule with `var()` |
|
|
511
|
+
| Border radius | `border-radius` | 3 (Module) | CSS rule with `var()` |
|
|
512
|
+
| Shadow | `box-shadow` | 3 (Module) | CSS rule with `var()` |
|
|
513
|
+
| Color | `color` | 3 (Module) | CSS rule with `var()` |
|
|
514
|
+
| Typography | `font-family`, `font-size`, `font-weight`, `line-height` | 3 (Module) | CSS rule with `var()` |
|
|
515
|
+
| Text | `text-align`, `text-transform`, `white-space`, `letter-spacing` | 3 (Module) | CSS rule |
|
|
516
|
+
| Opacity | `opacity` | 3 (Module) | CSS rule |
|
|
517
|
+
| Blend modes | `mix-blend-mode`, `background-blend-mode` | 3 (Module) | CSS rule |
|
|
518
|
+
| Filters | `filter`, `backdrop-filter` | 3 (Module) | CSS rule |
|
|
519
|
+
| Transitions | `transition` | 3 (Module) | CSS rule with `var()` |
|
|
520
|
+
|
|
521
|
+
---
|
|
522
|
+
|
|
523
|
+
### 6. Specificity Management
|
|
524
|
+
|
|
525
|
+
The three layers compose without specificity conflicts because each layer operates at a different specificity level.
|
|
526
|
+
|
|
527
|
+
#### Specificity by Layer
|
|
528
|
+
|
|
529
|
+
| Layer | Selector Type | Specificity | Example |
|
|
530
|
+
|-------|-------------|-------------|---------|
|
|
531
|
+
| 1. Tailwind | Utility class | `0-1-0` (single class) | `.flex` |
|
|
532
|
+
| 2. Tokens | `:root` pseudo-class | `0-1-0` (for definition) | `:root { --color-primary: #1a73e8 }` |
|
|
533
|
+
| 3. CSS Module | Hashed class | `0-1-0` (single class) | `.card_abc123` |
|
|
534
|
+
|
|
535
|
+
#### Why Conflicts Do Not Occur
|
|
536
|
+
|
|
537
|
+
1. **Tailwind vs Modules** -- Tailwind handles layout properties. Modules handle visual properties. They target different CSS properties on the same element, so they do not compete.
|
|
538
|
+
|
|
539
|
+
2. **Tokens vs Modules** -- Tokens define variables on `:root`. Modules consume those variables via `var()`. They do not target the same selectors or properties.
|
|
540
|
+
|
|
541
|
+
3. **Tailwind vs Tokens** -- When Tailwind is configured with token references in its theme, Tailwind utilities resolve to `var()` values. This is composition, not conflict.
|
|
542
|
+
|
|
543
|
+
#### Potential Conflict: Padding and Gap
|
|
544
|
+
|
|
545
|
+
The one area where Layers 1 and 3 could conflict is spacing properties (padding, gap). If a Tailwind class sets `gap: 16px` and a CSS Module rule also sets `gap: var(--spacing-md)`, the Module rule wins due to source order (Modules are loaded after Tailwind utilities).
|
|
546
|
+
|
|
547
|
+
**Resolution:** Choose one layer for spacing. Either:
|
|
548
|
+
- Use Tailwind for all spacing (with token-aware theme configuration)
|
|
549
|
+
- Use CSS Module rules for all spacing (when token substitution is needed)
|
|
550
|
+
|
|
551
|
+
Do not mix both layers for the same spacing property on the same element.
|
|
552
|
+
|
|
553
|
+
#### Tailwind `@layer` Ordering
|
|
554
|
+
|
|
555
|
+
Tailwind v4 uses CSS `@layer` to establish baseline ordering:
|
|
556
|
+
|
|
557
|
+
```
|
|
558
|
+
@layer base; /* Resets, element defaults */
|
|
559
|
+
@layer components; /* Component styles (CSS Modules go here) */
|
|
560
|
+
@layer utilities; /* Tailwind utilities (highest CSS layer priority) */
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
By default, Tailwind utilities override component styles. This means a Tailwind class on an element will override the same property set by a CSS Module. This is generally desirable for layout overrides but requires awareness when both layers target the same property.
|
|
564
|
+
|
|
565
|
+
---
|
|
566
|
+
|
|
567
|
+
### 7. Responsive Strategy
|
|
568
|
+
|
|
569
|
+
#### Mobile-First Breakpoint Ordering
|
|
570
|
+
|
|
571
|
+
All responsive CSS uses a mobile-first approach: base styles target the smallest viewport, and larger viewports are handled through `min-width` media queries.
|
|
572
|
+
|
|
573
|
+
| Breakpoint | min-width | CSS |
|
|
574
|
+
|------------|-----------|-----|
|
|
575
|
+
| `mobile` | _(base)_ | No media query (base styles) |
|
|
576
|
+
| `tablet` | 768px | `@media (min-width: 768px)` |
|
|
577
|
+
| `desktop` | 1024px | `@media (min-width: 1024px)` |
|
|
578
|
+
|
|
579
|
+
This matches both responsive frame merging (see `design-to-code-layout.md` Section 8) and Figma Variables breakpoint mode detection.
|
|
580
|
+
|
|
581
|
+
#### Figma Variables Mode to Media Query Mapping
|
|
582
|
+
|
|
583
|
+
When Figma variable collections use breakpoint modes (detected by mode names like "mobile", "tablet", "desktop"), the pipeline renders mode-aware `:root` overrides inside media queries:
|
|
584
|
+
|
|
585
|
+
```css
|
|
586
|
+
/* Base: mobile values (default mode) */
|
|
587
|
+
:root {
|
|
588
|
+
--spacing-lg: 16px;
|
|
589
|
+
--text-xl: 20px;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/* Tablet overrides */
|
|
593
|
+
@media (min-width: 768px) {
|
|
594
|
+
:root {
|
|
595
|
+
--spacing-lg: 24px;
|
|
596
|
+
--text-xl: 24px;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/* Desktop overrides */
|
|
601
|
+
@media (min-width: 1024px) {
|
|
602
|
+
:root {
|
|
603
|
+
--spacing-lg: 32px;
|
|
604
|
+
--text-xl: 28px;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
This approach means component styles automatically respond to viewport changes without any media queries of their own -- the token values change, and all `var()` references resolve to the new values.
|
|
610
|
+
|
|
611
|
+
#### Tailwind Responsive Prefixes
|
|
612
|
+
|
|
613
|
+
For layout properties in Layer 1, use Tailwind's responsive prefixes:
|
|
614
|
+
|
|
615
|
+
```html
|
|
616
|
+
<div class="flex flex-col md:flex-row gap-3 md:gap-6 lg:gap-8 p-4 md:p-6 lg:p-8">
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
| Prefix | Breakpoint | CSS |
|
|
620
|
+
|--------|-----------|-----|
|
|
621
|
+
| _(none)_ | All | Base styles |
|
|
622
|
+
| `sm:` | 640px | `@media (min-width: 640px)` |
|
|
623
|
+
| `md:` | 768px | `@media (min-width: 768px)` |
|
|
624
|
+
| `lg:` | 1024px | `@media (min-width: 1024px)` |
|
|
625
|
+
| `xl:` | 1280px | `@media (min-width: 1280px)` |
|
|
626
|
+
|
|
627
|
+
#### CSS Module Responsive Patterns
|
|
628
|
+
|
|
629
|
+
For visual properties in Layer 3 that need responsive behavior beyond what token media queries provide:
|
|
630
|
+
|
|
631
|
+
```css
|
|
632
|
+
/* Card.module.css */
|
|
633
|
+
.card {
|
|
634
|
+
border-radius: var(--radius-md);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
@media (min-width: 768px) {
|
|
638
|
+
.card {
|
|
639
|
+
border-radius: var(--radius-lg);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
```
|
|
643
|
+
|
|
644
|
+
This is less common because most responsive visual changes are handled through token mode overrides at the `:root` level. Module-level media queries are only needed for structural visual changes (e.g., adding/removing a border on desktop, changing an element's background pattern).
|
|
645
|
+
|
|
646
|
+
> For responsive frame matching and style diffing algorithms, see `design-to-code-layout.md` Section 8.
|
|
647
|
+
|
|
648
|
+
---
|
|
649
|
+
|
|
650
|
+
### 8. Theme Support
|
|
651
|
+
|
|
652
|
+
#### Light/Dark Theme via CSS Custom Properties
|
|
653
|
+
|
|
654
|
+
Themes are implemented by redefining token values under different selectors. The component styles remain unchanged -- they reference tokens via `var()`, and the resolved values change based on the active theme.
|
|
655
|
+
|
|
656
|
+
**Media query approach (automatic, based on OS preference):**
|
|
657
|
+
|
|
658
|
+
```css
|
|
659
|
+
:root {
|
|
660
|
+
--color-bg: #ffffff;
|
|
661
|
+
--color-text: #1a1a1a;
|
|
662
|
+
--color-border: #e0e0e0;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
@media (prefers-color-scheme: dark) {
|
|
666
|
+
:root {
|
|
667
|
+
--color-bg: #1a1a1a;
|
|
668
|
+
--color-text: #ffffff;
|
|
669
|
+
--color-border: #404040;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
**Data attribute approach (manual toggle, JavaScript-controlled):**
|
|
675
|
+
|
|
676
|
+
```css
|
|
677
|
+
:root,
|
|
678
|
+
[data-theme="light"] {
|
|
679
|
+
--color-bg: #ffffff;
|
|
680
|
+
--color-text: #1a1a1a;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
[data-theme="dark"] {
|
|
684
|
+
--color-bg: #1a1a1a;
|
|
685
|
+
--color-text: #ffffff;
|
|
686
|
+
}
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
The pipeline generates both approaches when theme mode collections are detected: the `prefers-color-scheme` media query for automatic theme detection, and the `[data-theme]` selector for manual control.
|
|
690
|
+
|
|
691
|
+
#### Figma Variables Theme Mode Mapping
|
|
692
|
+
|
|
693
|
+
When a Figma variable collection has a "theme" mode type (detected by mode names containing "light" or "dark"), the pipeline maps the default mode (light) to `:root` and non-default modes to both `prefers-color-scheme` and `[data-theme]` selectors:
|
|
694
|
+
|
|
695
|
+
```
|
|
696
|
+
Collection: "Theme"
|
|
697
|
+
Mode "Light" (default) → :root { }
|
|
698
|
+
Mode "Dark" → @media (prefers-color-scheme: dark) { :root { } }
|
|
699
|
+
[data-theme="dark"] { }
|
|
700
|
+
```
|
|
701
|
+
|
|
702
|
+
> For the full Figma Variables multi-mode theming patterns, see `figma-api-variables.md`.
|
|
703
|
+
|
|
704
|
+
#### Brand Theming
|
|
705
|
+
|
|
706
|
+
For multi-brand themes, use class-based selectors:
|
|
707
|
+
|
|
708
|
+
```css
|
|
709
|
+
.brand-a {
|
|
710
|
+
--color-primary: #0066ff;
|
|
711
|
+
--font-primary: 'Inter', sans-serif;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
.brand-b {
|
|
715
|
+
--color-primary: #ff3366;
|
|
716
|
+
--font-primary: 'Poppins', sans-serif;
|
|
717
|
+
}
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
Components reference `var(--color-primary)` and automatically adopt the active brand's values.
|
|
721
|
+
|
|
722
|
+
---
|
|
723
|
+
|
|
724
|
+
### 9. Export Formats
|
|
725
|
+
|
|
726
|
+
The generation pipeline supports multiple CSS export structures depending on the project's needs.
|
|
727
|
+
|
|
728
|
+
#### Separate Files (Recommended for Projects)
|
|
729
|
+
|
|
730
|
+
When `separateTokens: true`, the export produces three independent CSS files:
|
|
731
|
+
|
|
732
|
+
| File | Content | Layer |
|
|
733
|
+
|------|---------|-------|
|
|
734
|
+
| `reset.css` | Universal CSS reset (box-sizing, margin, padding, image defaults) | Pre-layer |
|
|
735
|
+
| `tokens.css` | `:root` block with CSS Custom Properties, media queries for modes | Layer 2 |
|
|
736
|
+
| `styles.css` | Component class rules (BEM-named) | Layer 3 |
|
|
737
|
+
|
|
738
|
+
Import order matters:
|
|
739
|
+
|
|
740
|
+
```html
|
|
741
|
+
<link rel="stylesheet" href="reset.css">
|
|
742
|
+
<link rel="stylesheet" href="tokens.css">
|
|
743
|
+
<link rel="stylesheet" href="styles.css">
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
#### Merged Output (Default for Preview)
|
|
747
|
+
|
|
748
|
+
When `separateTokens: false`, tokens are merged into `styles.css`:
|
|
749
|
+
|
|
750
|
+
| File | Content |
|
|
751
|
+
|------|---------|
|
|
752
|
+
| `reset.css` | Universal CSS reset |
|
|
753
|
+
| `styles.css` | Tokens (`:root` block) + component class rules |
|
|
754
|
+
|
|
755
|
+
#### SCSS Export
|
|
756
|
+
|
|
757
|
+
For SCSS consumers, the pipeline generates a parallel file structure using SCSS conventions:
|
|
758
|
+
|
|
759
|
+
| File | Content | Notes |
|
|
760
|
+
|------|---------|-------|
|
|
761
|
+
| `_reset.scss` | Reset rules | Underscore prefix = SCSS partial |
|
|
762
|
+
| `_variables.scss` | `$variable` declarations | `--color-primary` becomes `$color-primary` |
|
|
763
|
+
| `_mixins.scss` | Empty placeholder | For project-specific mixins |
|
|
764
|
+
| `styles.scss` | `@import` statements + component rules | Entry point with var() converted to $variable |
|
|
765
|
+
|
|
766
|
+
**SCSS variable conversion:**
|
|
767
|
+
|
|
768
|
+
```scss
|
|
769
|
+
// _variables.scss (generated from tokens)
|
|
770
|
+
$color-primary: #1a73e8;
|
|
771
|
+
$spacing-4: 16px;
|
|
772
|
+
$text-lg: 18px;
|
|
773
|
+
$font-bold: 700;
|
|
774
|
+
$shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
775
|
+
|
|
776
|
+
// styles.scss (generated from component styles)
|
|
777
|
+
@import 'variables';
|
|
778
|
+
@import 'reset';
|
|
779
|
+
@import 'mixins';
|
|
780
|
+
|
|
781
|
+
.card {
|
|
782
|
+
background-color: $color-neutral-100;
|
|
783
|
+
border-radius: $radius-lg;
|
|
784
|
+
box-shadow: $shadow-md;
|
|
785
|
+
}
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
The conversion replaces `var(--name)` with `$name` and `--name: value` with `$name: value`.
|
|
789
|
+
|
|
790
|
+
#### HTML Document Export
|
|
791
|
+
|
|
792
|
+
For standalone preview, the pipeline generates a complete HTML document with embedded CSS:
|
|
793
|
+
|
|
794
|
+
```html
|
|
795
|
+
<!DOCTYPE html>
|
|
796
|
+
<html lang="en">
|
|
797
|
+
<head>
|
|
798
|
+
<style>
|
|
799
|
+
@import url('https://fonts.googleapis.com/css2?family=...');
|
|
800
|
+
/* CSS reset */
|
|
801
|
+
/* tokens :root block */
|
|
802
|
+
/* component styles */
|
|
803
|
+
</style>
|
|
804
|
+
</head>
|
|
805
|
+
<body>
|
|
806
|
+
<!-- generated HTML -->
|
|
807
|
+
</body>
|
|
808
|
+
</html>
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
The ordering within the `<style>` block is: font imports, reset, tokens, component styles.
|
|
812
|
+
|
|
813
|
+
> For details on the SCSS rendering pipeline, see `design-tokens.md`.
|
|
814
|
+
|
|
815
|
+
---
|
|
816
|
+
|
|
817
|
+
### 10. Integration with Design-to-Code Pipeline
|
|
818
|
+
|
|
819
|
+
The five design-to-code modules feed into the CSS strategy at specific integration points.
|
|
820
|
+
|
|
821
|
+
#### Pipeline Flow
|
|
822
|
+
|
|
823
|
+
```
|
|
824
|
+
Figma Node Tree
|
|
825
|
+
↓
|
|
826
|
+
[Extraction Phase]
|
|
827
|
+
↓
|
|
828
|
+
ExtractedNode tree
|
|
829
|
+
↓
|
|
830
|
+
┌─────────────────────────────┐
|
|
831
|
+
│ Token Collection & Promotion │ ← design-tokens.md
|
|
832
|
+
│ (colors, spacing, typography,│
|
|
833
|
+
│ effects, Figma Variables) │
|
|
834
|
+
└──────────────┬──────────────┘
|
|
835
|
+
↓
|
|
836
|
+
TokenLookup map
|
|
837
|
+
↓
|
|
838
|
+
┌─────────────────────────────┐
|
|
839
|
+
│ Generation Phase │
|
|
840
|
+
│ ├─ layout.md → Layer 1 │ Flex container/child → Tailwind classes
|
|
841
|
+
│ ├─ visual.md → Layer 3 │ Fills, strokes, effects → CSS Module rules
|
|
842
|
+
│ ├─ typography.md → Layer 3 │ Font props → CSS Module rules with var()
|
|
843
|
+
│ ├─ assets.md → HTML │ Vector/image → <img> tags
|
|
844
|
+
│ └─ semantic.md → HTML │ Tags, BEM classes, ARIA attributes
|
|
845
|
+
└──────────────┬──────────────┘
|
|
846
|
+
↓
|
|
847
|
+
GeneratedOutput
|
|
848
|
+
┌──────┼──────┐
|
|
849
|
+
↓ ↓ ↓
|
|
850
|
+
HTML CSS Tokens
|
|
851
|
+
↓ ↓
|
|
852
|
+
Layer 3 Layer 2
|
|
853
|
+
(styles.css) (tokens.css)
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
#### How Each Module Contributes
|
|
857
|
+
|
|
858
|
+
**`design-to-code-layout.md`** produces layout CSS that maps to Layer 1 (Tailwind classes):
|
|
859
|
+
- `display: flex` → `flex`
|
|
860
|
+
- `flex-direction: column` → `flex-col`
|
|
861
|
+
- `gap: 16px` → `gap-4` (or `gap: var(--spacing-4)` if token-bound)
|
|
862
|
+
- Responsive frame merging → `md:flex-row lg:gap-8`
|
|
863
|
+
|
|
864
|
+
**`design-to-code-visual.md`** produces visual CSS that maps to Layer 3 (CSS Module rules):
|
|
865
|
+
- `background-color: var(--color-primary)` (via token lookup)
|
|
866
|
+
- `box-shadow: var(--shadow-md)` (via token lookup)
|
|
867
|
+
- `border-radius: var(--radius-lg)` (via token lookup)
|
|
868
|
+
- Raw values when no token match: `border: 1px solid #e0e0e0`
|
|
869
|
+
|
|
870
|
+
**`design-to-code-typography.md`** produces typography CSS that maps to Layer 3:
|
|
871
|
+
- `font-family: var(--font-primary)` (via token lookup)
|
|
872
|
+
- `font-size: var(--text-lg)` (via token lookup)
|
|
873
|
+
- `font-weight: var(--font-bold)` (via token lookup)
|
|
874
|
+
- `line-height: 1.50` (always raw, not tokenized)
|
|
875
|
+
|
|
876
|
+
**`design-to-code-assets.md`** produces HTML elements (not CSS):
|
|
877
|
+
- Vector containers → `<img src="icon.svg">`
|
|
878
|
+
- Image fills → `<img>` or `background-image` CSS in Module
|
|
879
|
+
|
|
880
|
+
**`design-to-code-semantic.md`** produces HTML structure:
|
|
881
|
+
- Semantic tags → `<section>`, `<nav>`, `<h2>`, `<button>`
|
|
882
|
+
- BEM class names → `.card`, `.card__title`, `.card__body`
|
|
883
|
+
- ARIA attributes → `aria-label`, `role`
|
|
884
|
+
|
|
885
|
+
#### Token Lookup During Generation
|
|
886
|
+
|
|
887
|
+
The `TokenLookup` is built from promoted tokens before generation begins. During CSS generation, each raw value is checked against the lookup map. If a match is found, the `var()` reference is used instead of the raw value:
|
|
888
|
+
|
|
889
|
+
```
|
|
890
|
+
Raw value: #1a73e8
|
|
891
|
+
→ lookupColor(lookup, "#1a73e8")
|
|
892
|
+
→ Returns: "var(--color-primary)" (if token exists)
|
|
893
|
+
→ Returns: "#1a73e8" (if no token match)
|
|
894
|
+
```
|
|
895
|
+
|
|
896
|
+
This substitution happens transparently during the generation of visual and typography styles. Layout properties are not token-substituted (they go to Tailwind).
|
|
897
|
+
|
|
898
|
+
> For the complete token lookup system, including Figma Variable priority over auto-detected tokens, see `design-tokens.md`.
|
|
899
|
+
|
|
900
|
+
#### Complete Example: All Three Layers
|
|
901
|
+
|
|
902
|
+
A card component with all three layers working together:
|
|
903
|
+
|
|
904
|
+
```html
|
|
905
|
+
<!-- Layer 1: Tailwind for layout -->
|
|
906
|
+
<section class="flex flex-col gap-6 p-6 max-w-md">
|
|
907
|
+
<!-- Layer 3: CSS Module for visual skin -->
|
|
908
|
+
<div class="card">
|
|
909
|
+
<img class="card__image" src="./assets/photo.png" alt="Team photo">
|
|
910
|
+
<div class="flex flex-col gap-3 p-4">
|
|
911
|
+
<h3 class="card__title">Meet the Team</h3>
|
|
912
|
+
<p class="card__body">Our talented people make the difference.</p>
|
|
913
|
+
<a class="card__cta" href="#">Learn More</a>
|
|
914
|
+
</div>
|
|
915
|
+
</div>
|
|
916
|
+
</section>
|
|
917
|
+
```
|
|
918
|
+
|
|
919
|
+
```css
|
|
920
|
+
/* Layer 2: tokens.css */
|
|
921
|
+
:root {
|
|
922
|
+
--color-primary: #1a73e8;
|
|
923
|
+
--color-neutral-100: #f5f5f5;
|
|
924
|
+
--color-neutral-800: #333333;
|
|
925
|
+
--text-lg: 18px;
|
|
926
|
+
--text-2xl: 32px;
|
|
927
|
+
--font-bold: 700;
|
|
928
|
+
--radius-lg: 12px;
|
|
929
|
+
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/* Layer 3: Card.module.css */
|
|
933
|
+
.card {
|
|
934
|
+
background-color: var(--color-neutral-100);
|
|
935
|
+
border-radius: var(--radius-lg);
|
|
936
|
+
box-shadow: var(--shadow-md);
|
|
937
|
+
overflow: hidden;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
.card__title {
|
|
941
|
+
font-size: var(--text-2xl);
|
|
942
|
+
font-weight: var(--font-bold);
|
|
943
|
+
color: var(--color-neutral-800);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
.card__body {
|
|
947
|
+
font-size: var(--text-lg);
|
|
948
|
+
color: var(--color-neutral-800);
|
|
949
|
+
line-height: 1.60;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
.card__cta {
|
|
953
|
+
background-color: var(--color-primary);
|
|
954
|
+
color: var(--color-neutral-100);
|
|
955
|
+
border-radius: var(--radius-sm);
|
|
956
|
+
padding: 8px 16px;
|
|
957
|
+
font-weight: var(--font-bold);
|
|
958
|
+
}
|
|
959
|
+
```
|
|
960
|
+
|
|
961
|
+
---
|
|
962
|
+
|
|
963
|
+
## Cross-References
|
|
964
|
+
|
|
965
|
+
- **`design-tokens.md`** -- Token extraction pipeline, threshold-based promotion, naming conventions, CSS/SCSS/Tailwind rendering. Defines the tokens consumed by Layer 2.
|
|
966
|
+
- **`design-tokens-variables.md`** -- Figma Variables deep dive: mode detection and classification, variable resolution chains, mode-aware CSS rendering, fallback strategies, scope-to-CSS-property mapping. The Variables-to-Token-to-CSS bridge.
|
|
967
|
+
- **`figma-api-variables.md`** -- Variables API endpoints, variable data model, multi-mode theming patterns. The source data for Figma Variable tokens.
|
|
968
|
+
- **`design-to-code-layout.md`** -- Auto Layout to Flexbox mapping that produces Layer 1 (Tailwind) output. Responsive multi-frame pattern with mobile-first media queries.
|
|
969
|
+
- **`design-to-code-visual.md`** -- Visual property extraction that produces Layer 3 (CSS Module) output. Color token integration with HSL naming, variable binding resolution.
|
|
970
|
+
- **`design-to-code-typography.md`** -- Typography extraction that produces Layer 3 output. Font family/size/weight token lookup during generation.
|
|
971
|
+
- **`design-to-code-assets.md`** -- Asset management for image and vector export. Asset references appear in HTML (`<img src>`) and CSS Module rules (`background-image`).
|
|
972
|
+
- **`design-to-code-semantic.md`** -- Semantic HTML generation that provides the element structure. BEM class naming used by Layer 3 CSS Modules. Three-layer architecture overview (Section 9).
|
|
973
|
+
- **`payload-blocks.md`** -- PayloadCMS block system that consumes all three CSS layers. Container blocks store Tailwind utility classes (Layer 1), block CSS Modules reference `--token-*` custom properties (Layer 2), and each block has a dedicated CSS Module for scoped visual styles (Layer 3). The three-layer architecture serves this block system directly.
|