Agent skill

Figma From Code Build Screens

by bitovi in bitovi/ai-enablement-prompts

Subagent for figma-from-code Phase 4. An agent skill from bitovi/ai-enablement-prompts.

MITAuto-check passedAgent Workflows

Install Figma From Code Build Screens

skills CLI
$ npx skills add bitovi/ai-enablement-prompts --skill figma-from-code-build-screens -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install bitovi/ai-enablement-prompts figma-from-code-build-screens --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/bitovi/ai-enablement-prompts.git skills-src && mkdir -p .claude/skills && cp -r skills-src/plugins/figma-from-code/skills/figma-from-code/8-build-screens .claude/skills/figma-from-code-build-screens && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
figma-from-code-build-screens
GitHub stars
121
Token cost
~11k tokens
SKILL.md length
3,496 words
Files
2
Skills in repo
40
Repo updated
First seen
Licence
MIT

At a glance

Subagent for figma-from-code Phase 4. An agent skill from bitovi/ai-enablement-prompts.

  • Works in 8 steps: Verify all components exist… → Analyze the Screen → Build the Screen in Figma → …
  • Tasks that involve Subagents
  • SKILL.md covers When to Use, Required Inputs, Pre-Existing Screens Rule and Execution Mode, plus 7 more sections
  • Calls node and curl; reaches figma.com

What it does

Figma From Code Build Screens is an agent skill from bitovi/ai-enablement-prompts. Subagent for figma-from-code Phase 4. Builds full-page screen frames in Figma by composing built component instances into 1440×900 layouts. Validates each screen against app screenshots and iterates up to 3 fix passes.

Its SKILL.md is about 11k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `README.md`).

It sits in Agent Workflows, covering Subagents. It works with Figma. The repository describes itself as: Prompts Bitovi uses for software development. The licence is MIT.

When your agent uses it

  • Tasks that involve Subagents

Example prompts

  • “/figma-from-code-build-screens”

Workflow steps

8 steps, taken from the step headings in SKILL.md.

  1. Verify all components exist (prerequisite gate)
  2. Analyze the Screen
  3. Build the Screen in Figma
  4. Screenshot the Figma Result
  5. Compare Against App Screenshot
  6. Fix Loop (Up to 3 Iterations)
  7. Write figma-screen.json tracking file
  8. Return Result

What it can do on your machine

Read from SKILL.md and the folder at commit df229b1. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • node
    • curl

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • figma.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Figma From Code Build Screens loads about 11k tokens when it runs. Until then it costs about 62 tokens; SKILL.md has 3,496 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~62
When it runs · the whole SKILL.md, loaded when a task matches
~11k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from bitovi/ai-enablement-prompts at commit df229b1, republished under its MIT licence (© bitovi). 3,496 words, ~10,634 tokens.

Download SKILL.mdSave it as .claude/skills/figma-from-code-build-screens/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
figma-from-code-build-screens
description
Subagent for figma-from-code Phase 4. Builds full-page screen frames in Figma by composing built component instances into 1440×900 layouts. Validates each screen against app screenshots and iterates up to 3 fix passes.
model
claude-sonnet-4-5

Skill: Build Screens (Phase 4)

Builds full-page screen frames in Figma by composing built component instances into screenBodySize layouts (default 1440x900). Each screen assembles navigation, list panels, and detail/form panels using instances of components already created in Phase 3, then validates them visually against an app screenshot — iterating up to 3 fix passes to converge on visual fidelity.

All Figma MCP tools (use_figma, get_screenshot, etc.) are available. This skill runs its entire workflow — analyze, build, screenshot, compare, fix — inline when dispatched by the orchestrator.

When to Use

  • When figma-from-code reaches Phase 4
  • Standalone to rebuild screen layouts after component changes
  • To add new screens after adding pages to the app

Required Inputs

InputDescriptionSource
screenNamePascalCase name (e.g., CasesPage, CreateCasePage)Route → PascalCase conversion
routeURL path on the dev server (e.g., /cases, /cases/new)component-map.json → routes
pageSourceFilePath to the page's .tsx sourceComponent source discovery
fileKeyFigma file keyState ledger or caller
screensFrameIdNode ID of the Screens container to append intostate.json → figmaNodes
appScreenshotPath to the app screenshot PNG.temp/figma-from-code/screenshots/screens/{name}/app.png
textContentExtracted text JSON from the live page.temp/figma-from-code/screenshots/screens/{name}/text.json
keyComponentsTop-level components rendered on the route + their descendantscomponent-map.json → tree
builtComponentsMap of {componentName: nodeId} for all components built in Phase 3state.json → builtComponents
preExistingScreensImmutable snapshot of screen frames that existed in Figma BEFORE this orchestrator run startedstate.json → preExistingScreens (Phase 0a snapshot)
screenshotDirDirectory for saving Figma screenshots and diff artifacts.temp/figma-from-code/screenshots/screens/{name}/
Optional Inputs
InputDescription
computedStylesResolved CSS values from computed-styles.json (produced by inspect-styles.js against the page root). Authoritative for colors, spacing, typography on screen chrome (the page's own elements, not its component children)
screenBodySizeBody dimensions read from state.json → screenBodySize if the project uses a non-default screen size (default 1440x900)

Config placeholders like {pagesRoot} resolve from state.json → config (fields: devServerUrl, devServerStart, sourceDir, componentsRoot, pagesRoot, cssPath, tailwindConfigPath, iconLibrary, skillRoot).


Pre-Existing Screens Rule

Before doing any work that resolves to a node ID in preExistingScreens, stop. That node existed in Figma before this run; modifying it (rebuild, resize, delete + recreate, restructure) requires explicit user authorization.

Concretely:

  • If screenName itself maps to a node in preExistingScreens and the caller's intent is to rebuild that node: write a result file with "status": "needs_authorization" and "preExistingTouched": ["<name>"], then return. Do not call use_figma to delete, replace, resize, or restyle the existing node. Building a fresh screen with the same name into the same screensFrameId is also a modification (creates a duplicate the orchestrator must reconcile) — don't do it without authorization.
  • Instancing a component that is itself in preExistingComponents is fine — that's reuse, not modification.
  • The fix-loop in Step 5 must never edit a node in preExistingScreens. If the comparison says you need to, escalate to the orchestrator instead.

This rule overrides Steps 2–5 of the workflow when in conflict.


Execution Mode

The orchestrator dispatches one subagent per screen. Each subagent runs the entire workflow (Steps 1–7) independently — analyze, build via use_figma, screenshot via get_screenshot, compare, fix loop, and return results.

The subagent writes its result to .temp/figma-from-code/build-results/screens/{screenName}.json. The orchestrator collects results after all subagents complete using collect-screen-results.js.

Screens can run in parallel — they only instantiate (not modify) already-built Phase 3 components.

Agent Prompt Template

The orchestrator dispatches one agent per screen. Send all agents in a single message so they run in parallel.

Build a Figma screen frame by composing built component instances, then validate visually.

Follow this skill's workflow (all 7 steps):
0. Verify all referenced components exist in builtComponents
1. FIRST study the app screenshot to understand what the default view shows,
   THEN analyze the page source — only include components visible in the screenshot.
   Exclude components behind conditional branches (ternaries, state guards, URL params)
   and portal-rendered overlays (Dialog, Sheet, etc.) that aren't visible by default.
2. Build the screen in Figma via use_figma (`screenBodySize` frame, default 1440x900)
3. Screenshot the result via get_screenshot
4. Structural check (content must match), then sizing check, then pixel diff
5. If mismatch, diagnose and fix (up to 3 iterations)
6. Write figma-screen.json tracking file
7. Write results to .temp/figma-from-code/build-results/screens/{screenName}.json

Inputs:
- Screen name: {screenName}
- Route: {route}
- Page source file: {pageSourceFile}
- Figma file key: {fileKey}
- Screens frame node ID: {screensFrameId}
- App screenshot: .temp/figma-from-code/screenshots/screens/{screenName}/app.png
- Text content: .temp/figma-from-code/screenshots/screens/{screenName}/text.json
- Screenshot dir: .temp/figma-from-code/screenshots/screens/{screenName}/
- Built components (for instance reuse): .temp/figma-from-code/builtComponents.json
- Pre-existing screens (DO NOT MODIFY): {JSON.stringify(preExistingScreens)}

Read plugins/figma-from-code/skills/figma-from-code/8-build-screens/SKILL.md for the full workflow,
fixSizing() function, variant resolution, and common pitfalls.

Workflow

Step 0    Prereqs       Verify all referenced components exist in builtComponents
Step 1    Analyze       Study appScreenshot first, then read page source; filter out non-default conditional branches
Step 2    Build         Create the screen frame in Figma via use_figma
Step 3    Screenshot    Capture the Figma result via get_screenshot
Step 4    Compare       Structural check + sizing sanity check + pixel diff against the app screenshot
Step 5    Fix Loop      If mismatch, diagnose and fix (up to 3 iterations)
Step 6    Track         Write figma-screen.json into the page folder
Step 7    Return        Report result with node ID, match score, and any remaining issues

Step 0: Verify all components exist (prerequisite gate)

Before building any screen, verify that every component referenced by the screen exists in builtComponents from state.json.

Identify the screen's key components from component-map.json → tree (the top-level components on that route and all their descendants). Check each one against builtComponents. Also check every icon imported by the page source (e.g., Icon/Check).

If any component or icon is missing from builtComponents:

STOP — do not proceed to Step 1. Return immediately with a rejection result:

json
{
  "screenName": "CasesPage",
  "status": "rejected",
  "reason": "missing_components",
  "missingComponents": ["CaseDetails", "MenuList"],
  "missingIcons": ["Icon/Trash"],
  "availableComponents": ["AppHeader", "Sidebar", "Button"]
}

Write this to .temp/figma-from-code/build-results/screens/{screenName}.json so the orchestrator can see what's missing.

Standalone (no orchestrator) — if the caller is the user directly, surface the rejection in the conversation and ask how to proceed. Don't fall back to inlining the missing components, building stubs, or downgrading the build into "best effort" — those produce a different artifact than the skill is supposed to produce. The right options are: (a) build the missing components first via plugins/figma-from-code/skills/figma-from-code/7-build-component/SKILL.md, (b) abandon the screen, or (c) get explicit user authorization to deviate.

Only proceed to Step 1 if every required component and icon is confirmed present.


Step 1: Analyze the Screen

Before writing any use_figma code, analyze all inputs to plan the screen structure.

Pre-flight: dev server is required for Step 1f (live inspection). Step 1f — inspecting the rendered page in a browser via inspect-styles.js — is the authoritative source for colors, spacing, and layout on the page chrome (the elements the page itself renders, outside of component children). Do not silently skip it. If you don't already have a dev server URL (from the orchestrator state ledger, project memory, or the caller's arguments), pause and ask the user for one before proceeding past Step 1. Only skip Step 1f if the user explicitly says no dev server is available.

1-pre. Screenshot-first composition (MANDATORY)

Before reading source code, look at appScreenshot (app.png). This screenshot shows the ACTUAL default view of the page as rendered in the browser with no user interaction. It is the ground truth for what the screen should look like.

Study the screenshot and identify:

  • Which regions are visible (sidebar, main content area, detail panels, headers, footers)
  • Whether the main content area shows populated data or an empty/placeholder state (e.g., "No case selected", "Select an item")
  • Which component instances are actually rendered vs hidden by conditional logic
  • Whether any overlays, dialogs, or menus are open (they should not be in the default state)

The source code analysis in Steps 1a–1b must MATCH what the screenshot shows, not the full component tree from the JSX. If the source code contains components behind conditional branches that are not visible in the screenshot, those components must be excluded from composition.

1a. Identify the page composition

Read the page source file and determine:

  • Layout direction: Is the page root a vertical stack (flex-col), horizontal row (flex, flex-row), or a grid (grid)?
  • Sizing: Screens are always fixed at screenBodySize (default 1440x900; read from state.json → screenBodySize). The outermost screen frame is primaryAxisSizingMode='FIXED' and counterAxisSizingMode='FIXED'. Capture this explicitly — Step 4a verifies it.
  • Container children: What is the top-level region structure? Typical pages have: top nav (full width), sidebar (fixed width), main content (fill), or a hero + sections stack. Identify each region and which built component instance lives there.
  • Spacing: gap-* classes on the page root map to itemSpacing. p-*, px-*, py-* map to padding.
  • Background: bg-* class on the page root. Resolve through CSS variables if needed (see Step 1g of plugins/figma-from-code/skills/figma-from-code/7-build-component/step-1-analyze.md for the full chain).
1b. Identify component instances (default state only)

Walk the page source JSX and list component references, but only include components visible in the default state (as shown in appScreenshot from Step 1-pre).

For each included component:

  • Map it to builtComponents[name] — that's the node ID to instantiate
  • Note the variant props passed in code (e.g., <Button variant="primary" size="lg">) — these resolve to a specific variant inside the component set
  • Note any sizing classes applied at the call site (className="w-full", className="flex-1") — these translate to layoutSizingHorizontal='FILL' etc. on the instance
tsx
// Source has: <Sidebar className="w-64" />
// builtComponents has: { "Sidebar": "230:5" }
// → Instantiate Sidebar at fixed width 256 inside the page frame
Conditional rendering analysis

When walking the JSX, identify and handle conditional patterns:

  1. Ternary expressions (condition ? <A /> : <B />): Determine which branch is visible when the page first loads with no user interaction and no URL params beyond the base route. Cross-reference with appScreenshot — only include the branch that matches.

    tsx
    // Example: {id ? <CaseDetails /> : <EmptyState />}
    // If appScreenshot shows "No case selected" → include EmptyState, EXCLUDE CaseDetails
  2. URL-param-gated components: For components guarded by useParams() values (e.g., id ? <Detail /> : <Fallback />), use the param-absent branch as default since the screen captures the base route.

  3. State-hook-gated components: Components behind useState(false) or useState(null) guards are hidden by default — exclude them.

    tsx
    // Example: const [isOpen, setIsOpen] = useState(false);
    // {isOpen && <Modal />}  → EXCLUDE Modal from default screen
  4. Logical AND guards ({flag && <C />}): Exclude unless the guard's initial value is truthy.

DO NOT compose components from non-default conditional branches. Those belong in separate screen variants if the pipeline supports them.

Portal-rendered overlay exclusion

Portal-rendered overlays — Dialog, Sheet, ConfirmationDialog, DropdownMenu, Popover, Drawer, AlertDialog, Tooltip, etc. — are NEVER visible in the default resting state. Exclude them from screen composition unless the appScreenshot explicitly shows them open.

These components are already handled by the component-level State axis in Phase 3 (see 7-build-component/step-1-analyze.md → "Conditional rendering of overlays"). Do not duplicate them in the screen frame.

1c. Identify icon usage on the page chrome

If the page renders any Lucide icons directly (not via a child component), map each to its builtComponents entry (Icon/{Name}) and size from the className. See Step 1c of plugins/figma-from-code/skills/figma-from-code/7-build-component/step-1-analyze.md for the size mapping table.

1d. Plan text content

Use textContent (from text.json) for any text the page itself renders (page titles, section headings, empty states). Never use generic placeholders. Text rendered inside a component instance is handled by that component's own master — don't try to override it from the screen.

1e. Identify pre-existing screen conflicts

Check whether screenName is in preExistingScreens. If yes — apply the Pre-Existing Screens Rule above and stop.

1f. Inspect the live page in Playwright

Before building, inspect the actual rendered page in the browser to capture computed styles on the page chrome. This provides ground-truth values for the page-level background, padding, and layout — more reliable than inferring from Tailwind classes alone.

Run inspect-styles.js against the page root selector on the dev server:

bash
node {skillRoot}/scripts/inspect-styles.js \
  "{devServerUrl}/{route}" \
  --selector "[data-page='{ScreenName}'], main, #root > div" \
  --output ".temp/figma-from-code/screenshots/screens/{ScreenName}/"

This produces:

FileContents
computed-styles.jsonResolved CSS properties on the page root (background, padding, layout direction, gap), the element's class list, and layoutContext (viewport, offsetWidth/Height)

How to use the outputs:

Use exact padding and gap values to set Figma properties — these are the authoritative values for the page chrome. For colors, the computed RGB values are authoritative for what the color is, but not for how to apply it: reverse-match each one against the variable index first (node {skillRoot}/scripts/resolve-color.js 'rgb(...)' --context fill) and bind the matched variable (see §2e). Hardcode the RGB only when the match is "none".

Dev server is required — don't silently skip this step.

See Step 1g of plugins/figma-from-code/skills/figma-from-code/7-build-component/step-1-analyze.md for the full decision tree: orchestrator-dispatched vs standalone vs auto/non-interactive, how to derive selectors, and when escalation to the user is required.


Step 2: Build the Screen in Figma

2a. Create the screen frame
javascript
// use_figma
const screensFrame = figma.getNodeById('{screensFrameId}');
screensFrame.layoutWrap = 'WRAP';
screensFrame.counterAxisSpacing = 80;

const screen = figma.createFrame();
screen.name = '{screenName}';
screen.resize(1440, 900); // or screenBodySize values
screen.layoutMode = '{VERTICAL or HORIZONTAL}'; // from page root direction
screen.primaryAxisSizingMode = 'FIXED';
screen.counterAxisSizingMode = 'FIXED';
screen.itemSpacing = { gapValue };
screen.paddingTop = { pt };
screen.paddingBottom = { pb };
screen.paddingLeft = { pl };
screen.paddingRight = { pr };
screen.fills = [{ type: 'SOLID', color: { ...pageBackground } }];
// Bind the background variable when §2e reverse-match found one (it almost always does):
// screen.setBoundVariable('fills', 0, await figma.variables.getVariableByIdAsync('{backgroundVariableId}'));
screen.clipsContent = true;

// ... add region frames and component instances (Step 2b) ...

screensFrame.appendChild(screen); // do NOT set x/y — wrap layout positions it
return JSON.stringify({ name: screen.name, id: screen.id });
2b. Add component instances

For each component identified in Step 1b:

javascript
const comp = figma.getNodeById(builtComponents['{ComponentName}']);

// If component is a COMPONENT_SET, resolve the target variant
let master = comp;
if (comp.type === 'COMPONENT_SET') {
  const targetProps = { Variant: 'primary', Size: 'regular' }; // from source props
  master =
    comp.children.find((child) =>
      Object.entries(targetProps).every(
        ([k, v]) => child.variantProperties?.[k]?.toLowerCase() === v.toLowerCase()
      )
    ) ?? comp.children[0];
}

const instance = master.createInstance();
// Apply call-site sizing classes
if (callSiteHasWFull) instance.layoutSizingHorizontal = 'FILL';
if (callSiteHasFlex1) instance.layoutSizingHorizontal = 'FILL';
if (callSiteHasHFull) instance.layoutSizingVertical = 'FILL';
parent.appendChild(instance);
2c. Add region frames for nested layout

When the page source nests multiple components inside a layout container (e.g., a sidebar + main content row), create a region frame:

javascript
const row = figma.createFrame();
row.layoutMode = 'HORIZONTAL';
row.primaryAxisSizingMode = 'FIXED';
row.counterAxisSizingMode = 'FIXED';
row.layoutSizingHorizontal = 'FILL';
row.layoutSizingVertical = 'FILL';
row.itemSpacing = 0;
row.fills = [];
// ... append child instances ...
screen.appendChild(row);
2d. Tailwind-to-Figma mapping

Read {skillRoot}/7-build-component/figma-utils.md for the canonical fixSizing() definition and the Tailwind→Figma mapping table.

2e. Resolving page background colors

When the page root uses semantic colors (bg-background, bg-muted), resolve and bind the Figma variable — page chrome colors are exactly the colors that should stay coupled to tokens. The reverse-match-before-hardcode rule from 7-build-component/step-2-build.md §2e Step 0 applies to screens too:

  1. Resolve the class or the computed RGB from computed-styles.json (Step 1f) via the lookup CLI:
    bash
    node {skillRoot}/scripts/resolve-color.js 'bg-background' --context fill
    # or, from computed styles:
    node {skillRoot}/scripts/resolve-color.js 'rgb(255, 255, 255)' --context fill
  2. On match: "exact" or "tolerance", set the fill then bind: screen.setBoundVariable('fills', 0, await figma.variables.getVariableByIdAsync('{id}')).
  3. Only on match: "none", hardcode the RGB from computed-styles.json.

(If tailwindConfigPath is null in state, class-based lookups still work — the CLI falls back to stripping known prefixes and matching CSS variable names directly.)


Step 3: Screenshot the Figma Result

get_screenshot(fileKey, screenFrameId)

Save to {screenshotDir}/figma.png:

bash
curl -sL "{image_url}" -o "{screenshotDir}/figma.png"

Step 4: Compare Against App Screenshot

4-pre. Structural match check (run BEFORE sizing or pixel checks)

Before running any automated comparison, visually inspect both app.png and figma.png side by side. Check whether the two images show the same content structure:

  • Do both show the same regions filled with the same type of content (list, detail, empty state)?
  • Does one show an empty state ("No case selected") while the other shows a populated detail view?
  • Are there overlays, dialogs, or menus visible in the Figma screenshot that don't appear in the app screenshot?
  • Are there entire sections present in one but missing in the other?

If the two images show fundamentally different content — not just styling differences, but different components or states entirely — flag as structural_mismatch. This indicates the composition in Step 1b included wrong conditional branches and the screen must be rebuilt, not patched.

A structural_mismatch overrides any pixel score. Do not accept a high match percentage as valid when the content is visibly different — structural similarity in shared chrome (headers, sidebars) can inflate pixel scores even when the main content area is completely wrong.

json
"comparison": {
  "structuralCheck": {
    "verdict": "pass" | "structural_mismatch",
    "issues": ["Figma shows case detail view but app shows empty state 'No case selected'"]
  }
}

If structural_mismatch: enter Step 5 fix loop, but the fix is to re-run Step 1b with stricter screenshot-informed filtering, not to patch colors or spacing.

Show full SKILL.md (1,410 more words)Show less
4a. Sizing sanity check (run BEFORE the pixel compare)

A pixel diff against app.png can pass even when the screen is built much smaller than 1440x900 — most commonly when the outermost frame collapsed to hug content. Run this check first; it is independent of the screenshot.

Inspect the built screen (use_figma) and read its top-level frame:

javascript
const node = figma.getNodeById('{screenNodeId}');
const built = {
  w: Math.round(node.width),
  h: Math.round(node.height),
  primaryAxisSizingMode: node.primaryAxisSizingMode,
  counterAxisSizingMode: node.counterAxisSizingMode,
  layoutMode: node.layoutMode,
};

Compare against the expected screen body size (default 1440x900, or screenBodySize from state):

CheckPass criteriaFlag if …
Widthbuilt.w === expectedW ± 2pxOff by more than 2px
Heightbuilt.h === expectedH ± 2pxOff by more than 2px
Sizing modesprimaryAxisSizingMode === 'FIXED' AND counterAxisSizingMode === 'FIXED'Either is 'AUTO'
Layout modeSet ('VERTICAL' or 'HORIZONTAL')'NONE' — children won't auto-layout
Top-level region countMatches the page source structure (e.g., 2 for nav + body, 3 for header + sidebar row + footer)Region count differs from source
Fill childrenAny child whose call-site has flex-1 / w-full has layoutSizingHorizontal='FILL'Source says fill, built says hug

If any check fails, treat this as a size_mismatch discrepancy and feed it into Step 5 alongside (or before) the pixel diff results. Do not declare a match based on pixel score alone if the sizing check failed — pixel match against a too-small app.png is a false positive.

Record the sizing check result in the eventual result file:

json
"comparison": {
  "sizingCheck": {
    "verdict": "pass" | "fail",
    "issues": ["counterAxisSizingMode='AUTO' (expected FIXED)", "built height 412 (expected 900)"],
    "builtSize": {"w": 1440, "h": 412},
    "expectedSize": {"w": 1440, "h": 900}
  },
  "matchPct": 95.26,
  ...
}
4b. Pixel diff comparison

Run the pixel diff comparison:

bash
node {skillRoot}/scripts/compare.js \
  "{screenshotDir}/app.png" \
  "{screenshotDir}/figma.png" \
  "{screenshotDir}/"

This produces:

  • diff.png — red pixels mark differences, matching pixels dimmed
  • comparison.json — { matchPct, borderMatchPct, verdict, borderVerdict }

Verdict thresholds (combined with Step 4a result):

  • 4a passed AND matchPct >= 88% AND borderMatchPct >= 80% → match (done)
  • 4a failed (regardless of pixel score) → size_mismatch (needs fixing — fix sizing first, then re-screenshot, then re-run 4a + 4b)
  • 4a passed AND matchPct 72-88% or borderMatchPct < 80% → minor_diff (needs fixing)
  • 4a passed AND matchPct < 72% → mismatch (needs fixing)

Screen thresholds are slightly more lenient than component thresholds because screens contain many instances whose internal pixels are already validated at the component level — a small per-instance drift compounds across the page.

A passing pixel verdict alone is NOT enough — 4a must also pass. Otherwise the build is silently wrong-sized and the validation phase will reject it later.

If no app screenshot exists (appScreenshot is null), skip pixel comparison — but still run Step 4a. Report no_app_reference only if 4a also passes; otherwise report size_mismatch.


Step 5: Fix Loop (Up to 3 Iterations)

If the verdict is minor_diff, mismatch, or size_mismatch, enter the fix loop.

Per-iteration process

5a. Diagnose the discrepancy

Use all five inputs together to identify specific differences:

  1. Step 4a sizing check result — if it failed, address sizing FIRST. A wrong-sized screen will mask everything else and will re-fail validation later.
  2. Read diff.png — red regions show exactly where pixels differ
  3. Read app.png — what the screen should look like
  4. Read figma.png — what was actually built
  5. Read page source .tsx — Tailwind classes reveal intended values

Cross-reference to identify the exact Figma properties that need correction. Common screen-level discrepancy patterns:

SymptomLikely CauseFix
4a failed (frame collapsed to hug)Outermost frame has *SizingMode='AUTO'node.primaryAxisSizingMode='FIXED'; node.counterAxisSizingMode='FIXED'; node.resizeWithoutConstraints(1440, 900). Order matters — modes before resize.
4a failed (region didn't fill width)Child region missing layoutSizingHorizontal='FILL'Set child.layoutSizingHorizontal='FILL' (and Vertical if appropriate)
Sidebar / header in wrong positionLayout direction wrong, or x/y manually set inside auto-layoutSet screen.layoutMode correctly; remove any manual x/y assignments
Component instance shows wrong variantTargeted the wrong variant during Step 2binstance.setProperties({ Variant: 'secondary' }) or recreate from correct master
Whole page shifted by ~24pxWrong padding on the screen frameAdjust paddingTop/Bottom/Left/Right
Background color wrongWrong fill on the screen frameAdjust screen.fills — prefer computed-styles.json resolved RGB
Two components touching where source has gapWrong itemSpacing on the parent regionSet region.itemSpacing to match source gap-* class
Missing region (e.g., footer absent)Region frame not created during Step 2cAdd the missing region with its children
Component appears tiny in the cornerInstance added before auto-layout was set, or appended to wrong parentRe-parent the instance; verify screen.layoutMode is set before appending children
Screen positioned at wrong x/y inside Screens frameManual x/y set despite screensFrame.layoutWrap='WRAP'Remove x/y assignments — let the wrap layout position it

5b. Apply the fix via use_figma

Write a targeted fix — change only the properties identified in diagnosis:

javascript
// use_figma — fix specific property
const node = figma.getNodeById('{nodeId}');
node.primaryAxisSizingMode = 'FIXED';
node.counterAxisSizingMode = 'FIXED';
node.resizeWithoutConstraints(1440, 900);
fixSizing(node, { exemptRoot: true }); // root stays FIXED, descendants may auto
return 'fixed';

5c. Re-screenshot and re-compare

get_screenshot(fileKey, screenFrameId)

Save to {screenshotDir}/figma.png (overwrite previous).

bash
node {skillRoot}/scripts/compare.js \
  "{screenshotDir}/app.png" \
  "{screenshotDir}/figma.png" \
  "{screenshotDir}/"

5d. Evaluate and continue or stop

  • If verdict is now match → exit loop, report as fixed
  • If verdict improved but still minor_diff, mismatch, or size_mismatch → continue to next iteration
  • If iteration count reaches 3 → exit loop, report remaining issues
Structural audit (run before first comparison if issues suspected)
javascript
// use_figma
function auditScreen(node) {
  const issues = [];
  if (node.layoutMode === 'NONE') {
    issues.push({ type: 'no_layout_mode', node: node.id, name: node.name });
  }
  if (node.primaryAxisSizingMode === 'AUTO' || node.counterAxisSizingMode === 'AUTO') {
    issues.push({ type: 'screen_not_fixed', node: node.id });
  }
  for (const child of node.children) {
    if (child.x !== 0 && child.parent?.layoutMode && child.parent.layoutMode !== 'NONE') {
      issues.push({ type: 'manual_xy_in_autolayout', node: child.id });
    }
  }
  return issues;
}
const node = figma.getNodeById('{screenNodeId}');
return JSON.stringify(auditScreen(node));

Fix structural issues before screenshotting — manual x/y inside an auto-layout parent causes silent layout drift, and missing layoutMode collapses all children to (0,0).


Step 6: Write figma-screen.json tracking file

Write a tracking record to the page's source folder so the codebase has a durable link back to the Figma screen node.

Path: Resolve from pageSourceFile. If the page is {pagesRoot}/CasesPage.tsx, write to {pagesRoot}/CasesPage.figma-screen.json. If pages live in a folder ({pagesRoot}/CasesPage/index.tsx), write to {pagesRoot}/CasesPage/figma-screen.json.

Schema:

json
{
  "fileKey": "{figmaFileKey}",
  "nodeId": "{screenFrameId}",
  "url": "https://figma.com/design/{fileKey}?node-id={nodeIdWithDashes}",
  "screenName": "CasesPage",
  "route": "/cases",
  "createdAt": "2026-05-15T14:32:00Z",
  "updatedAt": "2026-05-15T14:32:00Z"
}

Read-then-write semantics:

  1. If figma-screen.json already exists at the target path: parse it, preserve the existing createdAt, and refresh nodeId, url, updatedAt (and screenName/route if they changed) with current values.
  2. If it does not exist: write a fresh file with createdAt and updatedAt both set to the current ISO 8601 UTC timestamp.

Failure handling: if the write fails (permission, missing parent path that can't be created), log the failure and continue — do not fail the build. Surface the failure in the Step 7 return result under a trackingFile field with { written: false, error: "..." } so the orchestrator can report it.


Step 7: Return Result

Return a structured result for the caller:

json
{
  "screenName": "CasesPage",
  "nodeId": "600:1",
  "route": "/cases",
  "comparison": {
    "matchPct": 92.4,
    "borderMatchPct": 86.0,
    "verdict": "match",
    "iterations": 1,
    "fixes": ["counterAxisSizingMode AUTO -> FIXED, resize to 1440x900"],
    "sizingCheck": {
      "verdict": "pass",
      "builtSize": { "w": 1440, "h": 900 },
      "expectedSize": { "w": 1440, "h": 900 }
    }
  },
  "figmaScreenshot": ".temp/figma-from-code/screenshots/screens/CasesPage/figma.png",
  "trackingFile": {
    "written": true,
    "path": "{pagesRoot}/CasesPage.figma-screen.json"
  }
}

If no app screenshot was available:

json
{
  "screenName": "EmptyStatePage",
  "nodeId": "600:9",
  "route": "/empty",
  "comparison": {
    "verdict": "no_app_reference",
    "matchPct": null,
    "iterations": 0,
    "sizingCheck": {
      "verdict": "pass",
      "builtSize": { "w": 1440, "h": 900 },
      "expectedSize": { "w": 1440, "h": 900 }
    }
  }
}

If rejected for missing components:

json
{
  "screenName": "CasesPage",
  "status": "rejected",
  "reason": "missing_components",
  "missingComponents": ["CaseDetails"]
}
Aggregate output

Across all screens, write .temp/figma-from-code/build-screens.json:

json
{
  "screens": [
    {
      "name": "CasesPage",
      "nodeId": "600:1",
      "verdict": "match",
      "matchPct": 92.4,
      "iterations": 1
    }
  ],
  "failed": [],
  "rejected": []
}

fixSizing() — for descendants, not the screen root

Read {skillRoot}/7-build-component/figma-utils.md for the canonical fixSizing() definition and the Tailwind→Figma mapping table.

The screen frame itself must stay FIXED on both axes (screenBodySize, default 1440x900). Descendant frames may need fixSizing() to release height locks introduced by resize() calls. Call it with { exemptRoot: true } to preserve the root frame's FIXED sizing while releasing descendants.

Call fixSizing(screen, { exemptRoot: true }) after composition — the root stays at FIXED screenBodySize (default 1440x900) while descendants are released to grow with content.


Common Pitfalls

PitfallPrevention
Screen frame collapses to hug contentSet primaryAxisSizingMode='FIXED' and counterAxisSizingMode='FIXED' BEFORE resize(1440, 900)
Children stacked at (0,0)screen.layoutMode not set — children need an auto-layout parent to position
Screen positioned at hardcoded x/y inside Screens frameUse screensFrame.layoutWrap='WRAP' + appendChild; never set x/y
Wrong component variant renderedResolve COMPONENT_SET to the specific variant matching source props before createInstance()
Sidebar appears as a thin stripForgot layoutSizingVertical='FILL' on the sidebar instance
Page background missingSet screen.fills to the resolved page-root background, or [] if transparent
Manual padding inside an auto-layout childUse parent itemSpacing for gaps, child padding* for insets — never manual x offsets
fixSizing() collapsed the screen to hugAlways pass { exemptRoot: true } when calling fixSizing on the screen frame
Modifying a pre-existing screen without authorizationCheck preExistingScreens in Step 1e before building
Wrong-text inside component instanceDon't override component instance text from the screen — the component master owns its text
Screen shows non-default conditional branchStudy appScreenshot in Step 1-pre; exclude components behind ternaries/guards that aren't visible
Portal overlay (Dialog, Sheet, etc.) visible on screenPortals are never visible by default — exclude unless appScreenshot explicitly shows them open
High pixel match but fundamentally different contentRun Step 4-pre structural check; don't trust pixel score when content structure differs

Error Handling

ScenarioAction
Component missing from builtComponentsReject the entire build — return status: "rejected" with the missing components list (Step 0)
Icon missing from builtComponentsReject — return status: "rejected" with the missing icon in missingIcons (Step 0)
use_figma failsDiagnose error, fix script, retry once. If it fails again, return screen as failed
use_figma incremental limitSplit the build across multiple use_figma calls. Create the screen frame and regions first, then append instances in follow-up calls
get_screenshot failsRetry once. If still failing, return screen as built but unvalidated
compare.js failsReport comparison error, return the screen with nodeId but no match score
App screenshot missingBuild from source code alone, run Step 4a sizing check, report no_app_reference if 4a passes
Pre-existing screen targetedReturn status: "needs_authorization" with preExistingTouched — do not modify
Dev server unavailable for Step 1fAsk the user (standalone) or flag liveInspection: "skipped_no_dev_server" (auto mode)

Never fail silently. Every error or skip must appear in the returned result.

© bitovi, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file in plugins/figma-from-code/skills/figma-from-code/8-build-screens of bitovi/ai-enablement-prompts.

  • SKILL.md
  • README.md

Open the folder on GitHubat commit df229b1

Compare with similar skills

Figma From Code Build Screens next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Figma From Code Build Screens compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Figma From Code Build Screens this skillbitovi/ai-enablement-prompts121—~11kAutomated safety check: PassMIT
Claude Code Agent Developmentanthropics/claude-plugins-official38k7 repos~2.8kAutomated safety check: PassApache-2.0
Subagent Driven DevelopmentAsvarox/allkaraoke26137 repos~1.2kAutomated safety check: PassNone
Dispatching Parallel Agentsultralisp/ultralisp25840 repos~1.5kAutomated safety check: PassNone
Paseo Advisor Second Opiniongetpaseo/paseo20k1 repos~756Automated safety check: PassCustom licence
Task Observerrebelytics/one-skill-to-rule-them-all3.2k1 repos~11kAutomated safety check: PassCC-BY-4.0

Similar skills

  • Claude Code Agent Development

    anthropics/claude-plugins-official

    Official

    Explains how to write agents for Claude Code plugins: the markdown file with YAML frontmatter, trigger descriptions, model and color settings, and system prompt design.

    38k GitHub starsUsed in 7 repos~2.8k tokens
    Agent WorkflowsAuto-check passed
  • Subagent Driven Development

    Asvarox/allkaraoke

    A skill your agent uses when executing implementation plans with independent tasks in the current session

    261 GitHub starsUsed in 37 repos~1.2k tokens
    Agent WorkflowsAuto-check passed
  • Dispatching Parallel Agents

    ultralisp/ultralisp

    A skill your agent uses when facing 2+ independent tasks that can be worked on without shared state or sequential dependencies

    258 GitHub starsUsed in 40 repos~1.5k tokens
    Agent WorkflowsAuto-check passed
  • Launches one separate agent through Paseo to give a second opinion on the current task, with a self-contained briefing and no permission to edit files.

    20k GitHub starsUsed in 1 repo~756 tokens
    Agent WorkflowsAuto-check passed
  • Task Observer

    rebelytics/one-skill-to-rule-them-all

    Monitors task execution for skill improvement opportunities.

    3.2k GitHub starsUsed in 1 repo~11k tokens
    Agent WorkflowsAuto-check passed
  • O2 Review Loop

    openobserve/openobserve

    Splits a change into planner, coder and independent reviewer roles: you confirm a spec, a subagent implements it, and a separate reviewer checks each round's local WIP commit.

    22k GitHub stars~3.7k tokensUpdated today
    Agent WorkflowsAuto-check passed

More from bitovi/ai-enablement-prompts

All 40 skills in this repo
  • Component Registry

    bitovi/ai-enablement-prompts

    Track reusable UI components and unextracted patterns. An agent skill from bitovi/ai-enablement-prompts.

    121 GitHub stars~597 tokensUpdated 29 days ago
    Auto-check passed
  • Computed Styles

    bitovi/ai-enablement-prompts

    Extract and compare computed CSS styles between a baseline URL and a dev/Storybook URL using Playwright MCP evaluate calls.

    121 GitHub stars~2.4k tokensUpdated 29 days ago
    Auto-check passed
  • Create Plugin

    bitovi/ai-enablement-prompts

    A skill your agent uses when the user asks to "create a plugin", "add a plugin", "make a new plugin", "build a plugin", or wants to package skills into an installable plugin for this marketplace.

    121 GitHub stars~2k tokensUpdated 29 days ago
    Auto-check passed
  • Create React Modlet

    bitovi/ai-enablement-prompts

    Create React components, hooks, or utilities following the modlet pattern.

    121 GitHub stars~2.1k tokensUpdated 29 days ago
    Auto-check passed
  • Create Skill

    bitovi/ai-enablement-prompts

    A skill your agent uses when the user asks to "create a skill", "add a skill", "make a new skill", "build a skill", or wants to automate a repeated workflow into a reusable prompt.

    121 GitHub stars~1.6k tokensUpdated 29 days ago
    Auto-check passed
  • Create Skill

    bitovi/ai-enablement-prompts

    Create new Agent Skills for this project. An agent skill from bitovi/ai-enablement-prompts.

    121 GitHub stars~1.7k tokensUpdated 29 days ago
    Auto-check passed

Works with

Categories

Questions about Figma From Code Build Screens

What does Figma From Code Build Screens do?

Subagent for figma-from-code Phase 4. An agent skill from bitovi/ai-enablement-prompts. Figma From Code Build Screens is an agent skill from bitovi/ai-enablement-prompts. Subagent for figma-from-code Phase 4.

When should I use Figma From Code Build Screens?

Figma From Code Build Screens fits situations like: tasks that involve Subagents.

How do I install Figma From Code Build Screens in Claude Code?

Run `npx skills add bitovi/ai-enablement-prompts --skill figma-from-code-build-screens -a claude-code`. Or copy the skill folder (plugins/figma-from-code/skills/figma-from-code/8-build-screens in bitovi/ai-enablement-prompts) into .claude/skills/figma-from-code-build-screens in your project. Claude Code loads it when a task matches its description.

How do I install Figma From Code Build Screens in Codex?

Run `npx skills add bitovi/ai-enablement-prompts --skill figma-from-code-build-screens -a codex`. Or copy the skill folder (plugins/figma-from-code/skills/figma-from-code/8-build-screens in bitovi/ai-enablement-prompts) into .agents/skills/figma-from-code-build-screens in your project. Codex loads it when a task matches its description.

Can I use Figma From Code Build Screens in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add bitovi/ai-enablement-prompts --skill figma-from-code-build-screens -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/figma-from-code-build-screens, .gemini/skills/figma-from-code-build-screens, .github/skills/figma-from-code-build-screens and .opencode/skills/figma-from-code-build-screens in your project.

What does Figma From Code Build Screens need to run?

Going by SKILL.md and its folder, Figma From Code Build Screens needs the command-line tools its instructions call (node and curl).

Does Figma From Code Build Screens access the network?

SKILL.md names 1 domain. In commands or code: figma.com; the agent is likely to contact it when it follows the instructions. This is read from the text; nothing was executed.

Is Figma From Code Build Screens safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Figma From Code Build Screens use?

Figma From Code Build Screens is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Figma From Code Build Screens use?

About 11k tokens (SKILL.md is roughly 43k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Figma From Code Build Screens?

Skills that share tags, products or a category with Figma From Code Build Screens: Claude Code Agent Development (anthropics/claude-plugins-official, 38k stars), Subagent Driven Development (Asvarox/allkaraoke, 261 stars), Dispatching Parallel Agents (ultralisp/ultralisp, 258 stars) and Paseo Advisor Second Opinion (getpaseo/paseo, 20k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Figma From Code Build Screens?

bitovi (a GitHub organization) maintains it in bitovi/ai-enablement-prompts, which has 121 GitHub stars. The repository holds 40 skills in this directory. The repository was last updated on September 11, 2026.

Source: bitovi/ai-enablement-prompts on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.