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.
Files changed (34) hide show
  1. package/README.md +133 -0
  2. package/bin/install.js +328 -0
  3. package/knowledge/README.md +62 -0
  4. package/knowledge/css-strategy.md +973 -0
  5. package/knowledge/design-to-code-assets.md +855 -0
  6. package/knowledge/design-to-code-layout.md +929 -0
  7. package/knowledge/design-to-code-semantic.md +1085 -0
  8. package/knowledge/design-to-code-typography.md +1003 -0
  9. package/knowledge/design-to-code-visual.md +1145 -0
  10. package/knowledge/design-tokens-variables.md +1261 -0
  11. package/knowledge/design-tokens.md +960 -0
  12. package/knowledge/figma-api-devmode.md +894 -0
  13. package/knowledge/figma-api-plugin.md +920 -0
  14. package/knowledge/figma-api-rest.md +742 -0
  15. package/knowledge/figma-api-variables.md +848 -0
  16. package/knowledge/figma-api-webhooks.md +876 -0
  17. package/knowledge/payload-blocks.md +1184 -0
  18. package/knowledge/payload-figma-mapping.md +1210 -0
  19. package/knowledge/payload-visual-builder.md +1004 -0
  20. package/knowledge/plugin-architecture.md +1176 -0
  21. package/knowledge/plugin-best-practices.md +1206 -0
  22. package/knowledge/plugin-codegen.md +1313 -0
  23. package/package.json +31 -0
  24. package/skills/README.md +103 -0
  25. package/skills/audit-plugin/SKILL.md +244 -0
  26. package/skills/build-codegen-plugin/SKILL.md +279 -0
  27. package/skills/build-importer/SKILL.md +320 -0
  28. package/skills/build-plugin/SKILL.md +199 -0
  29. package/skills/build-token-pipeline/SKILL.md +363 -0
  30. package/skills/ref-html/SKILL.md +290 -0
  31. package/skills/ref-layout/SKILL.md +150 -0
  32. package/skills/ref-payload-block/SKILL.md +415 -0
  33. package/skills/ref-react/SKILL.md +222 -0
  34. package/skills/ref-tokens/SKILL.md +347 -0
@@ -0,0 +1,150 @@
1
+ ---
2
+ name: ref-layout
3
+ description: "Reference: Interpret Figma Auto Layout properties and generate correct CSS Flexbox. Use this skill when the user has Figma Auto Layout JSON data (layoutMode, sizing modes, alignment, spacing, wrap, constraints) and needs the corresponding CSS Flexbox output with accurate sizing mode handling."
4
+ ---
5
+
6
+ @knowledge/design-to-code-layout.md
7
+
8
+ ## Objective
9
+
10
+ Interpret Figma Auto Layout properties from node data and produce correct, production-grade CSS Flexbox. This skill handles the full pipeline: container detection, flex direction, alignment mapping, sizing modes (FIXED/HUG/FILL), gap and padding, wrap mode, min/max constraints, absolute positioning, non-Auto-Layout frames, and responsive multi-frame merging.
11
+
12
+ ## Input
13
+
14
+ The user provides Figma node data as `$ARGUMENTS`. This may be:
15
+
16
+ - Raw Figma REST API JSON (a node or subtree with Auto Layout properties)
17
+ - Extracted Auto Layout properties (layoutMode, primaryAxisAlignItems, counterAxisAlignItems, itemSpacing, padding, layoutSizingHorizontal, layoutSizingVertical, layoutWrap, etc.)
18
+ - A description of the Figma Auto Layout configuration in plain language
19
+ - A screenshot or paste of Figma's design panel showing layout settings
20
+
21
+ If the input is incomplete, ask the user for the missing properties before generating CSS. At minimum you need: `layoutMode`, child sizing modes, and spacing.
22
+
23
+ ## Process
24
+
25
+ Follow these steps in order. Consult `knowledge/design-to-code-layout.md` for all mapping tables and edge cases.
26
+
27
+ ### Step 1: Detect Container Type
28
+
29
+ - Check if the node has `layoutMode` set to `HORIZONTAL` or `VERTICAL` (Auto Layout container).
30
+ - If `layoutMode` is `NONE` or absent, treat as non-Auto-Layout frame. Use absolute positioning with constraints (see Section 7 of the layout knowledge module).
31
+ - If the node is a `GROUP`, use absolute positioning with coordinate adjustment (subtract group position for child coordinates).
32
+
33
+ ### Step 2: Map Container Properties
34
+
35
+ For Auto Layout containers, generate the base flex properties:
36
+
37
+ - `layoutMode: HORIZONTAL` -> `display: flex; flex-direction: row;`
38
+ - `layoutMode: VERTICAL` -> `display: flex; flex-direction: column;`
39
+ - `primaryAxisAlignItems` -> `justify-content` (MIN/CENTER/MAX/SPACE_BETWEEN)
40
+ - `counterAxisAlignItems` -> `align-items` (MIN/CENTER/MAX/BASELINE)
41
+ - Container sizing: `primaryAxisSizingMode` and `counterAxisSizingMode` determine if the container itself has explicit dimensions or hugs content.
42
+
43
+ ### Step 3: Map Gap and Padding
44
+
45
+ - `itemSpacing` -> CSS `gap` (NOT padding -- this is spacing BETWEEN children)
46
+ - `counterAxisSpacing` -> only applies when `layoutWrap: WRAP`. Maps to `row-gap` or `column-gap` depending on direction.
47
+ - When both primary and counter gaps are equal, use `gap` shorthand. When different, use separate `row-gap` and `column-gap`.
48
+ - `paddingTop/Right/Bottom/Left` -> CSS `padding` with shorthand optimization.
49
+ - If any spacing or padding value has a variable binding, generate `var()` reference. External library variables get pixel fallbacks.
50
+
51
+ ### Step 4: Handle Sizing Modes (CRITICAL)
52
+
53
+ This is the most error-prone step. For EACH child in the Auto Layout parent:
54
+
55
+ 1. Determine which axis is PRIMARY (same as parent flex-direction) and which is COUNTER.
56
+ - Parent `HORIZONTAL` -> horizontal = primary, vertical = counter
57
+ - Parent `VERTICAL` -> vertical = primary, horizontal = counter
58
+
59
+ 2. PRIMARY AXIS sizing:
60
+ - `FILL` -> `flex-grow: 1; flex-basis: 0;` (BOTH required -- never omit `flex-basis: 0`)
61
+ - `FIXED` -> `flex-shrink: 0;` + explicit dimension from bounds
62
+ - `HUG` -> omit sizing CSS, let content determine size
63
+
64
+ 3. COUNTER AXIS sizing:
65
+ - `FILL` -> `align-self: stretch;`
66
+ - `FILL` + max constraint on counter dimension -> `width: 100%` / `height: 100%` + `max-width`/`max-height` (NOT `align-self: stretch`)
67
+ - `FIXED` -> explicit dimension from bounds
68
+ - `HUG` -> omit, let content determine size
69
+
70
+ 4. Check for `layoutAlign` overrides on individual children -> `align-self`
71
+
72
+ ### Step 5: Handle Wrap Mode
73
+
74
+ - `layoutWrap: WRAP` -> `flex-wrap: wrap;`
75
+ - `counterAxisAlignContent` -> `align-content` (AUTO -> `flex-start`, SPACE_BETWEEN -> `space-between`)
76
+ - Counter axis gap becomes relevant only in wrap mode.
77
+
78
+ ### Step 6: Handle Min/Max Constraints
79
+
80
+ - `minWidth` (if > 0) -> `min-width`
81
+ - `maxWidth` (if < Infinity) -> `max-width`
82
+ - `minHeight` (if > 0) -> `min-height`
83
+ - `maxHeight` (if < Infinity) -> `max-height`
84
+ - These apply to both containers and children.
85
+
86
+ ### Step 7: Handle Absolute Children
87
+
88
+ - If any child has `layoutPositioning: ABSOLUTE`, add `position: relative` to the parent.
89
+ - Absolute children get `position: absolute` with offset values from constraints.
90
+ - These children do not participate in flex flow or gap distribution.
91
+
92
+ ### Step 8: Responsive Multi-Frame (if applicable)
93
+
94
+ If multiple frames represent breakpoints (detected via `#mobile`/`#tablet`/`#desktop` suffix or variant properties):
95
+
96
+ - Smallest frame provides base styles (no media query).
97
+ - Larger frames contribute override styles in `@media (min-width: ...)` blocks.
98
+ - Only emit properties that differ from the base.
99
+ - Reset layout properties (`align-self: auto`, `flex-grow: 0`, `flex-shrink: 1`, `flex-basis: auto`) when they exist in base but not in the larger breakpoint.
100
+ - Transform fixed pixel widths in responsive overrides to `width: 100%; max-width: Npx` for fluid behavior.
101
+
102
+ ## Output
103
+
104
+ Generate CSS with explanatory comments showing the Figma-to-CSS mapping:
105
+
106
+ ```css
107
+ /* Container: layoutMode=HORIZONTAL, primaryAxis=SPACE_BETWEEN, counterAxis=CENTER */
108
+ .component-name {
109
+ display: flex;
110
+ flex-direction: row;
111
+ justify-content: space-between;
112
+ align-items: center;
113
+ gap: 16px; /* itemSpacing: 16 */
114
+ padding: 24px 16px; /* paddingTop/Bottom: 24, paddingLeft/Right: 16 */
115
+ }
116
+
117
+ /* Child: sizingH=FILL (primary), sizingV=HUG (counter) */
118
+ .component-name__content {
119
+ flex-grow: 1;
120
+ flex-basis: 0;
121
+ }
122
+
123
+ /* Child: sizingH=FIXED (primary, 200px), sizingV=FILL (counter) */
124
+ .component-name__sidebar {
125
+ width: 200px;
126
+ flex-shrink: 0;
127
+ align-self: stretch;
128
+ }
129
+ ```
130
+
131
+ When variable bindings are present, use CSS custom properties:
132
+
133
+ ```css
134
+ .component-name {
135
+ gap: var(--spacing-md); /* Variable: spacing/md */
136
+ padding: var(--spacing-lg, 24px); /* External variable with fallback */
137
+ }
138
+ ```
139
+
140
+ ### Output Checklist
141
+
142
+ Before returning CSS, verify:
143
+
144
+ - [ ] Every FILL on primary axis has BOTH `flex-grow: 1` AND `flex-basis: 0`
145
+ - [ ] STRETCH only appears on counter axis (never primary)
146
+ - [ ] `itemSpacing` maps to `gap`, not padding
147
+ - [ ] GROUP children use absolute positioning with adjusted coordinates
148
+ - [ ] FILL counter-axis + max constraint uses `width: 100%`/`height: 100%` instead of `align-self: stretch`
149
+ - [ ] Responsive overrides include layout property resets where needed
150
+ - [ ] Variable references use `var()` with fallbacks for external library variables
@@ -0,0 +1,415 @@
1
+ ---
2
+ name: ref-payload-block
3
+ description: "Reference: Map a Figma component to a PayloadCMS block definition with config, renderer, types, and CSS Module. Use this skill when the user has a Figma component (JSON data, component description, or REST API node) and needs a complete PayloadCMS block implementation following the container-first architecture."
4
+ ---
5
+
6
+ @knowledge/payload-blocks.md
7
+ @knowledge/payload-figma-mapping.md
8
+ @knowledge/payload-visual-builder.md
9
+ @knowledge/css-strategy.md
10
+
11
+ ## Objective
12
+
13
+ Map a Figma component to a complete PayloadCMS block implementation: a block config (`.ts`), a React renderer (`.tsx`), TypeScript types, and a CSS Module (`.module.css`). The skill uses multi-signal confidence scoring to identify the correct block type from the 18-type catalog, maps component properties to PayloadCMS fields, generates container nesting rules, and produces CSS that follows the three-layer architecture (Tailwind layout + CSS Custom Properties tokens + CSS Modules visual skin).
14
+
15
+ ## Input
16
+
17
+ The user provides Figma component data as `$ARGUMENTS`. This may be:
18
+
19
+ - **Figma REST API JSON** -- A component or component set node with properties, variants, children, fills, text content
20
+ - **Plugin API extracted data** -- Component properties, variant details, child nodes
21
+ - **Component description** -- Plain language description of the Figma component (structure, properties, variants, content)
22
+ - **Screenshot or design spec** -- Visual reference of the component with noted properties
23
+
24
+ If the input is insufficient, ask for:
25
+ - Component name and variant properties
26
+ - Child element structure (text nodes, images, buttons, nested components)
27
+ - Layout mode (Auto Layout direction, spacing, padding)
28
+ - Visual properties (colors, border radius, shadows)
29
+
30
+ ## Process
31
+
32
+ Follow these steps in order. Consult the referenced knowledge modules for all mapping rules, field types, and architectural patterns.
33
+
34
+ ### Step 1: Analyze Figma Component Structure
35
+
36
+ Identify the component's structure and classify its elements:
37
+
38
+ - **Root node**: component boundary, layout mode (Auto Layout direction), dimensions
39
+ - **Variant properties**: boolean toggles, enum options (size, style, impact level)
40
+ - **Text layers**: heading text, body text, labels, captions
41
+ - **Image fills/frames**: background images, thumbnails, avatars, icons
42
+ - **Interactive children**: button instances, link text, form inputs
43
+ - **Nested component instances**: child components that may map to separate blocks
44
+ - **Layout structure**: spacing, padding, alignment, wrap mode
45
+ - **Visual properties**: fills, strokes, effects, corner radius
46
+
47
+ ### Step 2: Determine Block Type via Confidence Scoring
48
+
49
+ Consult `knowledge/payload-figma-mapping.md` Section 2 for the complete decision tree.
50
+
51
+ Apply multi-signal confidence scoring using two complementary strategies:
52
+
53
+ **Name-based detection (higher priority):**
54
+ - Check if component/frame name contains recognized keywords: hero, card, button, nav, accordion, tabs, stat, testimonial, carousel, cta, media, video, form, etc.
55
+
56
+ **Structure-based detection (fallback for generic names):**
57
+ - Analyze children, dimensions, properties, and layout patterns against block type heuristics
58
+
59
+ **18-type block catalog:**
60
+
61
+ | Block Type | Slug | Key Signals |
62
+ |-----------|------|-------------|
63
+ | Hero | `hero` | Full-width, bg image/color, large heading, CTA buttons |
64
+ | Card | `card` | Bounded width, image + heading + body, optional CTA, radius/shadow |
65
+ | Button | `button` | Small dimensions, bg fill, single text label, radius |
66
+ | Navigation | `subnavigation` | Horizontal layout, multiple link children, compact |
67
+ | Accordion | `accordion` | Vertical layout, repeating header + content, toggle icon |
68
+ | Tabs | `tabs` | Tab bar + content panel, active/inactive states |
69
+ | Stats | `stats` | Large numeric text, label below, compact |
70
+ | Testimonial | `testimonial` | Quote text, author info, optional avatar |
71
+ | Carousel | `carousel` | Horizontal overflow, nav dots/arrows, card children |
72
+ | CallToAction | `callToAction` | Full-width, strong background, title + description |
73
+ | Media | `media` | Single image, no text children |
74
+ | Video | `video` | Play button overlay, 16:9 ratio, thumbnail |
75
+ | Form | `form` | Input fields, submit button, labels |
76
+ | RichText | `richText` | Primarily text content, styled segments |
77
+ | Container | `container` | Auto Layout wrapper containing block-type children |
78
+ | Grid | `grid` | Grid-like child layout, uniform child sizes |
79
+ | Code | `code` | Code/monospace content |
80
+ | StickyCTA | `stickyCTA` | Fixed/sticky positioning, compact CTA |
81
+
82
+ **Confidence thresholds:**
83
+ - 0.9+ -- Auto-map, high confidence
84
+ - 0.8-0.89 -- Auto-map, flag for optional review
85
+ - 0.7-0.79 -- Moderate confidence, flag for human review
86
+ - Below 0.7 -- Require human confirmation
87
+
88
+ Report the matched block type and confidence score to the user.
89
+
90
+ ### Step 3: Map Component Properties to Block Fields
91
+
92
+ Consult `knowledge/payload-figma-mapping.md` Section 3 and `knowledge/payload-blocks.md` Section 2.
93
+
94
+ Apply these property-to-field mapping rules:
95
+
96
+ | Figma Property Type | PayloadCMS Field Type | Mapping Rule |
97
+ |--------------------|----------------------|--------------|
98
+ | Text layer (heading) | `richText` (Lexical) | Extract text content into Lexical document structure |
99
+ | Text layer (single line) | `text` | Direct string mapping |
100
+ | Boolean variant | `checkbox` | `true`/`false` toggle |
101
+ | Enum variant (2-4 options) | `radio` | Radio buttons with variant option values |
102
+ | Enum variant (5+ options) | `select` | Dropdown with variant option values |
103
+ | Instance swap slot | `relationship` or `blocks` | Reference to another block type or media |
104
+ | Image fill / image frame | `upload` with `relationTo: 'media'` | Image upload field via `imageFields` factory |
105
+ | Color property | Token reference | Map to CSS Custom Property, not a hardcoded color field |
106
+ | Number property | `number` | Numeric input for dimensions, counts |
107
+ | URL/link text | `group` with link fields | Link group factory (type, url, label, newTab) |
108
+ | Button instance(s) | `array` of link groups | Button/CTA array using `linkGroup` factory |
109
+
110
+ **Field organization follows tab-based pattern:**
111
+ 1. **Content tab** (named `content`): richText, text fields, arrays of content items
112
+ 2. **Media/Image tab**: image upload fields via `imageFields` factory
113
+ 3. **CTA tab**: button/link groups when the block has call-to-action elements
114
+ 4. **Settings tab** (unnamed): className, layoutMeta, type/variant selection, HTML tag
115
+
116
+ ### Step 4: Map Variants to CVA Configuration
117
+
118
+ If the component has enum variants that affect visual presentation (e.g., size: sm/md/lg, style: primary/secondary, impact: high/medium/low):
119
+
120
+ - Map variant property name to block settings field (radio or select)
121
+ - Generate CVA (class-variance-authority) configuration for the renderer:
122
+
123
+ ```typescript
124
+ import { cva } from 'class-variance-authority';
125
+
126
+ const heroVariants = cva(styles.hero, {
127
+ variants: {
128
+ type: {
129
+ highImpact: styles['hero--high-impact'],
130
+ mediumImpact: styles['hero--medium-impact'],
131
+ lowImpact: styles['hero--low-impact'],
132
+ },
133
+ },
134
+ defaultVariants: {
135
+ type: 'highImpact',
136
+ },
137
+ });
138
+ ```
139
+
140
+ ### Step 5: Handle Container Nesting
141
+
142
+ Consult `knowledge/payload-blocks.md` and `knowledge/payload-figma-mapping.md` Section 4.
143
+
144
+ **Maximum nesting: 2 levels** (Container > NestedContainer).
145
+
146
+ - If the Figma component contains structural wrappers around other block-type children, map outer wrapper to `Container` and inner wrappers to a restricted nested container.
147
+ - Container block uses the `blocks` field type to hold child blocks.
148
+ - Map Figma Auto Layout properties to Container settings:
149
+ - `layoutMode: HORIZONTAL` --> `settings.layout = 'row'`
150
+ - `layoutMode: VERTICAL` --> `settings.layout = 'col'`
151
+ - `primaryAxisAlignItems` --> `settings.justifyContent` (Tailwind utility string)
152
+ - `counterAxisAlignItems` --> `settings.alignItems` (Tailwind utility string)
153
+ - `itemSpacing` --> `settings.gap` (snap to nearest option)
154
+ - Settings are stored as Tailwind utility class strings (Layer 1 of CSS architecture).
155
+
156
+ **Nesting rules:**
157
+ - Container (level 1) can contain any block type including NestedContainer
158
+ - NestedContainer (level 2) can contain content blocks but NOT another container
159
+ - Never nest deeper than 2 levels -- flatten if the Figma structure goes deeper
160
+
161
+ ### Step 6: Configure Lexical Rich Text
162
+
163
+ Consult `knowledge/payload-blocks.md` for Lexical configuration patterns.
164
+
165
+ Restrict Lexical editor features based on block type:
166
+
167
+ | Block Type | Lexical Features Allowed |
168
+ |-----------|------------------------|
169
+ | Hero | Heading (h1-h2), paragraph, bold, italic, link, text color |
170
+ | Card | Heading (h3-h4), paragraph, bold, italic, link |
171
+ | RichText | Full feature set (all headings, lists, blockquote, code, media) |
172
+ | Button | None (use `text` field, not richText) |
173
+ | Stats | Heading (h2-h3), paragraph, bold |
174
+ | Testimonial | Paragraph, bold, italic |
175
+ | CallToAction | Heading (h2-h3), paragraph, bold, italic, link |
176
+ | Default | Paragraph, bold, italic, link |
177
+
178
+ ### Step 7: Generate Block Config
179
+
180
+ Produce the PayloadCMS block config `.ts` file:
181
+
182
+ ```typescript
183
+ import { Block } from 'payload';
184
+ import { imageFields } from '@/admin/fields/imageFields';
185
+ import { linkGroup } from '@/admin/fields/linkGroup';
186
+ import { settingTabs } from './settingTabs';
187
+
188
+ export const Hero: Block = {
189
+ slug: 'hero',
190
+ labels: {
191
+ singular: 'Hero',
192
+ plural: 'Heroes',
193
+ },
194
+ fields: [
195
+ {
196
+ type: 'tabs',
197
+ tabs: [
198
+ {
199
+ label: 'Content',
200
+ name: 'content',
201
+ fields: [
202
+ {
203
+ name: 'richText',
204
+ type: 'richText',
205
+ label: false,
206
+ // Lexical config with restricted features
207
+ },
208
+ ...linkGroup({ appearances: ['default', 'outline'] }),
209
+ ],
210
+ },
211
+ {
212
+ label: 'Media',
213
+ fields: [...imageFields()],
214
+ },
215
+ settingTabs,
216
+ ],
217
+ },
218
+ ],
219
+ };
220
+ ```
221
+
222
+ **Config conventions:**
223
+ - Export as named constant matching block name (PascalCase)
224
+ - Use `slug` in camelCase
225
+ - Organize fields in tabs (Content, Media, CTA, Settings)
226
+ - Use field factories (`imageFields`, `linkGroup`, `layoutMeta`) for reusable patterns
227
+ - Settings tab fields are stored at block root (no `name` on the tab)
228
+
229
+ ### Step 8: Generate React Renderer
230
+
231
+ Produce the renderer `.tsx` file:
232
+
233
+ ```tsx
234
+ import React from 'react';
235
+ import styles from './Hero.module.css';
236
+ import { RichText } from '@/components/RichText';
237
+ import { Media } from '@/components/Media';
238
+ import { CMSLink } from '@/components/Link';
239
+ import type { HeroBlock } from './types';
240
+
241
+ export function HeroRenderer({ block }: { block: HeroBlock }) {
242
+ const { content, image, settings } = block;
243
+
244
+ return (
245
+ <section
246
+ className={`flex flex-col items-center justify-center gap-6 p-8 ${styles.hero} ${styles[`hero--${settings?.type}`] || ''}`}
247
+ >
248
+ {image?.image && (
249
+ <div className={`absolute inset-0 ${styles.hero__media}`}>
250
+ <Media resource={image.image} fill />
251
+ </div>
252
+ )}
253
+ <div className={`relative z-10 flex flex-col items-center gap-4 ${styles.hero__content}`}>
254
+ {content?.richText && <RichText data={content.richText} />}
255
+ {content?.buttonGroup?.length > 0 && (
256
+ <div className="flex gap-4">
257
+ {content.buttonGroup.map((btn, i) => (
258
+ <CMSLink key={i} {...btn.link} />
259
+ ))}
260
+ </div>
261
+ )}
262
+ </div>
263
+ </section>
264
+ );
265
+ }
266
+ ```
267
+
268
+ **Renderer conventions:**
269
+ - Named export (not default) with `{BlockName}Renderer` naming
270
+ - Tailwind classes for layout (Layer 1)
271
+ - CSS Module classes for visual styling (Layer 3)
272
+ - CSS Custom Properties consumed via CSS Module (Layer 2)
273
+ - Null-safe access for all optional fields
274
+ - Semantic HTML elements based on block type
275
+
276
+ ### Step 9: Generate CSS Module
277
+
278
+ Produce the `.module.css` file following the three-layer architecture:
279
+
280
+ ```css
281
+ /* Hero Block — Visual Skin (Layer 3) */
282
+ /* Layout handled by Tailwind in JSX */
283
+ /* Tokens consumed from tokens.css (Layer 2) */
284
+
285
+ .hero {
286
+ background-color: var(--color-surface);
287
+ min-height: 60vh;
288
+ position: relative;
289
+ overflow: hidden;
290
+ }
291
+
292
+ .hero--highImpact {
293
+ min-height: 80vh;
294
+ }
295
+
296
+ .hero--mediumImpact {
297
+ min-height: 60vh;
298
+ }
299
+
300
+ .hero--lowImpact {
301
+ min-height: 40vh;
302
+ }
303
+
304
+ .hero__media {
305
+ opacity: 0.3;
306
+ }
307
+
308
+ .hero__content {
309
+ max-width: 48rem;
310
+ text-align: center;
311
+ }
312
+
313
+ .hero__content h1,
314
+ .hero__content h2 {
315
+ color: var(--color-text-primary);
316
+ font-family: var(--font-heading);
317
+ }
318
+
319
+ .hero__content p {
320
+ color: var(--color-text-secondary);
321
+ font-size: var(--text-lg);
322
+ }
323
+ ```
324
+
325
+ **CSS Module rules:**
326
+ - Only visual properties (colors, backgrounds, borders, effects, typography skin)
327
+ - All color values via `var()` references to CSS Custom Properties (never hardcoded)
328
+ - BEM-style naming within the module (flat: `.block__element`, never `.block__element__sub`)
329
+ - Variant modifiers as `.block--variant` classes
330
+ - Layout (flexbox, gap, padding, sizing) stays in Tailwind classes in JSX
331
+
332
+ ### Step 10: Generate TypeScript Types
333
+
334
+ ```typescript
335
+ import type { Media as MediaType } from '@/payload-types';
336
+
337
+ export interface HeroBlock {
338
+ blockType: 'hero';
339
+ content?: {
340
+ richText?: any; // Lexical root node
341
+ buttonGroup?: Array<{
342
+ link: {
343
+ type: 'reference' | 'custom';
344
+ url?: string;
345
+ reference?: { relationTo: 'pages'; value: string };
346
+ label: string;
347
+ newTab?: boolean;
348
+ appearance?: 'default' | 'outline';
349
+ };
350
+ }>;
351
+ };
352
+ image?: {
353
+ image?: string | MediaType;
354
+ };
355
+ settings?: {
356
+ type?: 'highImpact' | 'mediumImpact' | 'lowImpact';
357
+ className?: string;
358
+ layoutMeta?: {
359
+ marginTop?: string;
360
+ marginBottom?: string;
361
+ paddingTop?: string;
362
+ paddingBottom?: string;
363
+ };
364
+ };
365
+ }
366
+ ```
367
+
368
+ ## Output
369
+
370
+ Generate four files for the mapped block:
371
+
372
+ ### 1. `config.ts` -- PayloadCMS Block Definition
373
+
374
+ - Block slug, labels, tab-based field organization
375
+ - Field factories for reusable patterns (imageFields, linkGroup, layoutMeta)
376
+ - Lexical editor restricted per block type
377
+ - Settings fields with variant options stored as Tailwind utility strings
378
+
379
+ ### 2. `Renderer.tsx` -- React Renderer Component
380
+
381
+ - Named export with `{BlockName}Renderer` naming
382
+ - Tailwind layout classes in JSX (Layer 1)
383
+ - CSS Module visual classes from companion `.module.css` (Layer 3)
384
+ - Null-safe field access
385
+ - Semantic HTML elements
386
+
387
+ ### 3. `{BlockName}.module.css` -- CSS Module
388
+
389
+ - Visual skin only (colors, backgrounds, effects, typography overrides)
390
+ - All values via `var()` CSS Custom Property references (Layer 2)
391
+ - BEM naming (flat hierarchy, no deep nesting)
392
+ - Variant modifier classes
393
+
394
+ ### 4. `types.ts` -- TypeScript Interfaces
395
+
396
+ - Block interface with `blockType` discriminant
397
+ - Optional fields for all non-required content
398
+ - Proper Media and reference types
399
+
400
+ ### Output Checklist
401
+
402
+ Before returning the block implementation, verify:
403
+
404
+ - [ ] Block type matches with stated confidence score
405
+ - [ ] Container nesting does not exceed 2 levels
406
+ - [ ] Settings fields use Tailwind utility class strings (not raw CSS values)
407
+ - [ ] Lexical editor features are restricted appropriately for the block type
408
+ - [ ] Field factories are used for reusable patterns (not duplicated field definitions)
409
+ - [ ] CSS Module contains only visual properties (no layout)
410
+ - [ ] All color values use `var()` references (no hardcoded colors)
411
+ - [ ] BEM class names are flat (never `block__element__sub`)
412
+ - [ ] Renderer handles null/undefined for all optional fields
413
+ - [ ] Tab organization follows convention: Content, Media, CTA, Settings
414
+ - [ ] Block slug is camelCase and unique
415
+ - [ ] Variant mapping uses CVA pattern when applicable