Skip to content

Commit 251ccdc

Browse files
committed
wip
1 parent e21bd84 commit 251ccdc

4 files changed

Lines changed: 43 additions & 26 deletions

File tree

skills/figma.md

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ description: >
1212

1313
Translate Figma designs built with the [Windows UI Kit (Community)](https://www.figma.com/design/t7yLwpMUOWJSYt5ahz3ROC/Windows-UI-kit--Community-) into Reactor C# code. This skill provides the mapping tables and rules the agent applies during code generation.
1414

15+
**Goal: Pixel-accurate reproduction.** Every dimension, gap, margin, padding, and position value from Figma must be used exactly as specified — no rounding, no substitution. The generated app should match the Figma design pixel-for-pixel. Where `design.md` recommends flexible sizing (MinWidth) or 4px grid rounding for hand-written code, those rules are overridden here — Figma translation uses exact values.
16+
1517
**Prerequisites:**
1618
- A Figma MCP server must be configured (e.g., `figma-developer-mcp`) for URL-based extraction. See [spec 033](../docs/specs/033-figma-to-reactor.md) for the full workflow architecture.
1719

@@ -75,21 +77,30 @@ Pass the full URL to the Figma MCP tool — the server handles node scoping.
7577
| `layoutMode` | `VERTICAL` | `VStack(gap, children)` |
7678
| `layoutMode` | `HORIZONTAL` | `HStack(gap, children)` |
7779
| `itemSpacing` | `N` | Gap parameter: `VStack(N, ...)` or `HStack(N, ...)` |
78-
| `paddingTop/Right/Bottom/Left` | uniform `P` | Wrap in `Border(VStack(...)).Padding(P)` |
79-
| `paddingTop/Right/Bottom/Left` | mixed | Wrap in `Border(VStack(...)).Padding(left, top, right, bottom)` |
80+
| `paddingTop/Right/Bottom/Left` | all equal `P` | `.Padding(P)` on the wrapping `Border` |
81+
| `paddingTop/Right/Bottom/Left` | symmetric (h≠v) | `.Padding(vertical, horizontal)` on the wrapping `Border` |
82+
| `paddingTop/Right/Bottom/Left` | mixed | `.Padding(left: L, top: T, right: R, bottom: B)` on the wrapping `Border` |
8083

8184
**Important:** `VStack` and `HStack` do not support `.Padding()` — only `Border` and control-based elements do. Always wrap the stack in a `Border` when padding is needed. Use `.Margin()` when the spacing is between the element and its siblings rather than internal padding.
8285

86+
**Margin overloads:**
87+
- `.Margin(uniform)` — all four sides equal
88+
- `.Margin(vertical, horizontal)` — top/bottom share one value, left/right share another
89+
- `.Margin(left: L, top: T, right: R, bottom: B)` — use named args for per-side values
90+
8391
### Sizing
8492

8593
| Figma Sizing Mode | Reactor Output |
8694
|---|---|
87-
| Fixed width/height | `.MinWidth(N)` / `.MinHeight(N)` (prefer over fixed `.Width(N)` / `.Height(N)` for text scaling) |
95+
| Fixed width | `.Width(N)` — use the **exact** pixel value from Figma |
96+
| Fixed height | `.Height(N)` — use the **exact** pixel value from Figma |
97+
| Fixed width + height | `.Size(W, H)` — shorthand for both |
8898
| Hug contents | No explicit size (natural sizing) |
8999
| Fill container | `.HAlign(HorizontalAlignment.Stretch)` |
90-
| Min/max constraints | `.MinWidth(N)` / `.MaxWidth(N)` |
100+
| Fill container (vertical) | `.VAlign(VerticalAlignment.Stretch)` |
101+
| Min/max constraints | `.MinWidth(N)` / `.MaxWidth(N)` / `.MinHeight(N)` / `.MaxHeight(N)` |
91102

92-
Prefer `MinWidth`/`MinHeight` over fixed `Width`/`Height` on controls and text containers — fixed sizes clip content at larger text scales.
103+
**Pixel-accuracy rule:** When Figma specifies a fixed width or height, always use the **exact** value via `.Width(N)` / `.Height(N)` / `.Size(W, H)`. Do NOT substitute `MinWidth`/`MinHeight` for fixed dimensions — that produces different layout behavior. Only use `MinWidth`/`MinHeight` when the Figma node explicitly has min/max constraints.
93104

94105
### Alignment
95106

@@ -117,15 +128,16 @@ Prefer `MinWidth`/`MinHeight` over fixed `Width`/`Height` on controls and text c
117128

118129
Always set `HorizontalContentAlignment = Stretch` on vertical scroll regions to prevent content from collapsing. Place headers and footers outside the ScrollView so they remain fixed.
119130

120-
### Spacing Grid Rule
131+
### Spacing Rule
121132

122-
Round all spacing values to the **4px grid**: 4, 8, 12, 16, 20, 24, 32, 40, 48.
123-
124-
If a Figma value is not on the grid (e.g., 15px), round to nearest grid value (16px) and add a comment:
133+
Use the **exact** pixel values from Figma for all spacing, gaps, margins, and padding. Do NOT round to a grid. Pixel-accurate reproduction is the goal.
125134

126135
```csharp
127-
// Note: Figma spacing was 15px, rounded to 16px (4px grid)
128-
VStack(16, children)
136+
// Figma says itemSpacing = 13 → use 13, not 12 or 16
137+
VStack(13, children)
138+
139+
// Figma says padding top=18, left=24 → use exact values
140+
Border(content).Padding(left: 24, top: 18)
129141
```
130142

131143
## Control Mapping
@@ -444,7 +456,7 @@ Note: `dotnet watch` does not maintain MCP/devtools sessions across rebuilds. Us
444456
3. **Follow design.md best practices** — all generated code must comply with the `design.md` skill rules. Key requirements:
445457
- Use `.ApplyStyle()` or Reactor text factories (`Caption()`, `SubHeading()`, `Heading()`) for typography — not raw `FontSize`/`FontWeight` (§4).
446458
- `VStack`/`HStack` do not support `.Padding()` — wrap in `Border` (§5).
447-
- Prefer `MinWidth`/`MinHeight` over fixed `Width`/`Height` on controls and text containers (§5).
459+
- Use `.Width(N)` / `.Height(N)` / `.Size(W, H)` for fixed Figma dimensions. Only use `MinWidth`/`MinHeight` when Figma explicitly sets min/max constraints (§5).
448460
- Use `.HAlign()` / `.VAlign()` for alignment — not `.HorizontalAlignment()` / `.VerticalAlignment()` (§5).
449461
- Set `HorizontalContentAlignment = Stretch` on vertical `ScrollView` (§5).
450462
- Add `.AutomationName()` on icon-only interactive controls; use `.AccessibilityHidden()` on decorative icons (§7).
@@ -453,7 +465,7 @@ Note: `dotnet watch` does not maintain MCP/devtools sessions across rebuilds. Us
453465
- Use `SymbolThemeFontFamily` for icon font glyphs (§4).
454466
- For circular elements, derive radius from size (`size / 2`) instead of hardcoded values (§5).
455467
4. **Use Theme tokens first** — follow the token resolution ladder strictly. No hex on themed surfaces.
456-
5. **Round to 4px grid**all spacing values must be multiples of 4.
468+
5. **Use exact pixel values**do NOT round spacing, margins, padding, gaps, widths, or heights. Use the exact values from Figma for pixel-accurate output.
457469
6. **Use theme resources for corner radii**`ControlCornerRadius` (4px) and `OverlayCornerRadius` (8px). Do not hardcode number values.
458470
7. **Emit TODO for unknowns** — never silently skip or guess. Every unmapped element gets a placeholder with the Figma node ID.
459471
8. **One Component per top-level frame** — each major Figma frame becomes a Reactor Component class.

src/Reactor.Cli/Program.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,6 @@
8383
{
8484
return Microsoft.UI.Reactor.Cli.Figma.FigmaCommand.Run(args.Skip(1).ToArray());
8585
}
86-
}
8786

8887
Console.Error.WriteLine($"Unknown option: {args[0]}");
8988
Console.Error.WriteLine();

tools/figma-plugin/dist/ui.html

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,16 @@
207207
var csproj = getCsprojPath();
208208
var name = getProjectName();
209209

210-
var skillRef = 'Read skills/figma.md for Figma-to-Reactor control mapping, theme tokens, typography, and layout rules. Read skills/design.md for WinUI design best practices. Match every dimension, gap, and padding value exactly from the Figma design for pixel-accurate output.';
210+
var skillRef = 'Read skills/figma.md for Figma-to-Reactor control mapping, theme tokens, typography, and layout rules. Read skills/design.md for WinUI design best practices. Use exact pixel values from Figma for all widths, heights, gaps, margins, and padding — do NOT round to a grid or substitute MinWidth/MinHeight for fixed dimensions. The goal is pixel-to-pixel accuracy with the Figma design.';
211211
var watchCmd = 'dotnet run --project src/Reactor.Cli -- figma watch "' + url + '" --interval 10';
212-
var watchLoop = ' After the initial sync, start a live watch loop: run `' + watchCmd +
213-
'` in a background shell. It emits JSON events to stdout when the Figma file changes.' +
212+
var runCmd = 'dotnet run --project ' + csproj;
213+
var watchLoop = ' After the initial sync, start the app with `' + runCmd +
214+
'` in a background shell. Then start a live watch loop: run `' + watchCmd +
215+
'` in another background shell. It emits JSON events to stdout when the Figma file changes.' +
214216
' When you see an event with "event":"changed", re-fetch the design via get_figma_data MCP tool for file key ' + (frameInfo.fileKey || '') + ' node ' + (frameInfo.nodeId || '') +
215217
', diff it against the current code, and apply only the changes needed.' +
218+
' After editing the code, stop the running app process and relaunch it with `' + runCmd + '` so the changes are visible.' +
219+
' Do NOT rely on dotnet watch hot reload — always restart the app after edits.' +
216220
' Keep this loop running — do NOT exit after the first sync. You are a live sync agent.';
217221

218222
var prompt;
@@ -221,7 +225,7 @@
221225
' using mur --create ' + name +
222226
', then translate this Figma design into it: ' + url +
223227
'. ' + skillRef +
224-
' After generating the code, run: dotnet watch run --project ' + csproj + '.' +
228+
' After generating the code, launch the app with `' + runCmd + '`.' +
225229
watchLoop;
226230
} else {
227231
if (!csproj) {
@@ -234,7 +238,6 @@
234238
' Apply only the changes needed to bring the code in sync with the design — update text, spacing, sizing, colors, and layout to match.' +
235239
' Do not regenerate from scratch unless the structure has fundamentally changed.' +
236240
' ' + skillRef +
237-
' Make sure dotnet watch run --project ' + csproj + ' is running.' +
238241
watchLoop;
239242
}
240243

@@ -253,7 +256,7 @@
253256
function copyRunCmd() {
254257
var csproj = getCsprojPath();
255258
if (csproj) {
256-
copyToClipboard('dotnet watch run --project ' + csproj);
259+
copyToClipboard('dotnet watch --non-interactive run --project ' + csproj);
257260
showToast('Copied — paste in terminal');
258261
}
259262
}

tools/figma-plugin/src/ui.html

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,16 @@
207207
var csproj = getCsprojPath();
208208
var name = getProjectName();
209209

210-
var skillRef = 'Read skills/figma.md for Figma-to-Reactor control mapping, theme tokens, typography, and layout rules. Read skills/design.md for WinUI design best practices. Match every dimension, gap, and padding value exactly from the Figma design for pixel-accurate output.';
210+
var skillRef = 'Read skills/figma.md for Figma-to-Reactor control mapping, theme tokens, typography, and layout rules. Read skills/design.md for WinUI design best practices. Use exact pixel values from Figma for all widths, heights, gaps, margins, and padding — do NOT round to a grid or substitute MinWidth/MinHeight for fixed dimensions. The goal is pixel-to-pixel accuracy with the Figma design.';
211211
var watchCmd = 'dotnet run --project src/Reactor.Cli -- figma watch "' + url + '" --interval 10';
212-
var watchLoop = ' After the initial sync, start a live watch loop: run `' + watchCmd +
213-
'` in a background shell. It emits JSON events to stdout when the Figma file changes.' +
212+
var runCmd = 'dotnet run --project ' + csproj;
213+
var watchLoop = ' After the initial sync, start the app with `' + runCmd +
214+
'` in a background shell. Then start a live watch loop: run `' + watchCmd +
215+
'` in another background shell. It emits JSON events to stdout when the Figma file changes.' +
214216
' When you see an event with "event":"changed", re-fetch the design via get_figma_data MCP tool for file key ' + (frameInfo.fileKey || '') + ' node ' + (frameInfo.nodeId || '') +
215217
', diff it against the current code, and apply only the changes needed.' +
218+
' After editing the code, stop the running app process and relaunch it with `' + runCmd + '` so the changes are visible.' +
219+
' Do NOT rely on dotnet watch hot reload — always restart the app after edits.' +
216220
' Keep this loop running — do NOT exit after the first sync. You are a live sync agent.';
217221

218222
var prompt;
@@ -221,7 +225,7 @@
221225
' using mur --create ' + name +
222226
', then translate this Figma design into it: ' + url +
223227
'. ' + skillRef +
224-
' After generating the code, run: dotnet watch run --project ' + csproj + '.' +
228+
' After generating the code, launch the app with `' + runCmd + '`.' +
225229
watchLoop;
226230
} else {
227231
if (!csproj) {
@@ -234,7 +238,6 @@
234238
' Apply only the changes needed to bring the code in sync with the design — update text, spacing, sizing, colors, and layout to match.' +
235239
' Do not regenerate from scratch unless the structure has fundamentally changed.' +
236240
' ' + skillRef +
237-
' Make sure dotnet watch run --project ' + csproj + ' is running.' +
238241
watchLoop;
239242
}
240243

@@ -253,7 +256,7 @@
253256
function copyRunCmd() {
254257
var csproj = getCsprojPath();
255258
if (csproj) {
256-
copyToClipboard('dotnet watch run --project ' + csproj);
259+
copyToClipboard('dotnet watch --non-interactive run --project ' + csproj);
257260
showToast('Copied — paste in terminal');
258261
}
259262
}

0 commit comments

Comments
 (0)