WF2Des โ How to Use
Summary
WF2Des turns a wireframe frame into a native Figma design, built from your project's own
registered components and design tokens.
It does not draw new UI: it decides which registered component each part of the wireframe
should become, keeps the wireframe's layout and copy, and assembles the result in your file.
Prerequisites
Everything happens inside the Figma plugin. Before generating anything:
1. Sign in
Sign in with your Plabs account. The plugin needs a project selected โ a design is always generated into a project's registry and rules.
2. Open the file that holds your design system
The components the generator picks from must live in the same Figma file as the wireframe. If a component cannot be found in the open file, it cannot be placed.
3. Have the boards ready
Two kinds of board are read during setup:
| Board | What it holds |
|---|---|
| Component boards | The design system's component sets โ buttons, form fields, headers, cards |
| Guideline boards | The written rules โ colours, typography, spacing, per-component usage |
One-time setup
Open the Setup tab. Both steps read your canvas selection, so select the board frames first.
1. Component library
Select the component boards, then Review sync โ Confirm sync.
The run reports four steps: Resolve โ Sweep โ Register โ Save. It reads every component set on the selected boards and records its variants, text slots, sizes and publish keys.
Note
After the sync reports Completed, a second pass captures variant details directly from Figma. It walks every node on the selected boards, so on a large library it legitimately takes minutes โ the panel shows a live node count while it works. The sync result is already saved; the capture only enriches it.
Check it worked: open What's in the registry โ it lists what was registered, by board.
2. Design-rule boards
Select the guideline boards, then Review upload โ Confirm upload.
The run reports Render โ Extract โ Merge โ Save, and produces a new revision of the ruleset. Earlier revisions are kept: open Current rules & history to see colours, typography and spacing, and Revert to any previous revision.
Generating a design
Open the Generate tab.
- Select exactly one frame on the canvas โ the wireframe you want to convert. The plugin refuses a multi-selection or a non-frame node, and says which.
- Optionally set a Screen id. Leave it blank and one is derived from the frame name.
- Press Generate design.
The run reports four steps: Trigger โ Parse โ Assemble โ Build. Parse and assemble happen on the server; build happens in your file. You can press Stop watching (run continues) at any point โ the run continues server-side and you can re-attach later.
When it finishes you get Total / Placed / Unmatched.
Reading the result
| What you see | What it means |
|---|---|
| Placed | Built from a registered component, with the wireframe's own text placed into its slots |
| Unmatched | Nothing in the registry fitted. Rendered as a dashed orange box so the gap is visible, never silently skipped |
| A dashed box where the wireframe had a picture | Should not happen โ real images are copied from the wireframe automatically. If you see one, the source node had no image fill |
| Text that wrapped onto more lines than the wireframe | Expected. Your design system's font is not the wireframe's, so the design is taller |
The output is one frame, built as a single undo step โ press undo once to remove it entirely. Re-generating the same wireframe replaces its previous output rather than stacking a copy beside it.
If something goes wrong
"Attached to a run already in progressโฆ"
A run for this same frame is still open. Wait for it to finish โ only one run per wireframe can be
active at a time. A run that never completes blocks new ones until it is cancelled.
"select exactly one frame" / "selected node is not a frame"
The wireframe must be a single FRAME. A group or a multi-selection is refused.
Everything comes out as dashed boxes
The registry is empty for this project, or the wrong file is open. Run the component sync first and
check What's in the registry.
A component is placed but shows the wrong variant
The registry knows the component but not which variant to use. Re-run the component sync so the
variant capture records each variant's own contents.
The plugin shows a stale state after an update
Close and reopen the plugin โ the UI is bundled, so a reload picks up the current build.
What it does not do
Stated plainly, so the output is read correctly:
- It does not invent components. Anything the design system has no component for stays unmatched.
- It does not restyle your wireframe's structure. Layout, order and copy are preserved by design โ if the wireframe is wrong, the design will be faithfully wrong.
- It does not replace design review. Confidence and flags mark what to check, not what is correct.
Local Operations and Evaluation
WF2Des converts a registered Figma wireframe into native Figma nodes using the
project's component library and design rules. This section covers local operation,
diagnosis, and model evaluation. Run commands from the guinness-ai-v2 root.
Prerequisites
- Copy
apps/wf2des/.env.exampletoapps/wf2des/.env.devand configure Figma OAuth (preferred) orFIGMA_PAT, plus the required model-provider credentials. - Start the local backend/harness, LocalStack on port
4566, and the populated Mongo instance on port27019. - Run
uv synconce.
Process queued jobs
# Terminal 1: generation queue
uv run python -u apps/wf2des/scripts/consume_local.py
# Terminal 2: onboarding, component, and actual-render review events
LOCAL_SQS_QUEUE_URL=http://localhost:4566/000000000000/wf2des-events \
LOCAL_SQS_VISIBILITY_TIMEOUT=1800 uv run python -u apps/wf2des/scripts/consume_local.py
Both bridges are required for the complete local plugin flow. The first handles generation; the
second handles registration, sweeps, captures, and the post-placement visual review. Add --once
to either command to drain currently available messages and exit. These are mutating
production-path runs: they consume SQS messages, read Figma, call configured models, write
Mongo/S3, and send the local status webhook. The bridge
checks source mtimes before each message and stops when its loaded worker code is stale.
Restart it after code changes.
Safe inspection and replay
| Command | Use | Mutation and cost |
|---|---|---|
uv run python apps/wf2des/scripts/inspect_local.py 1 7 |
Inspect collection counts and tenant-scoped records | Read-only |
uv run python apps/wf2des/scripts/replay_generation.py RUN_ID --output-dir /tmp/wf2des-replay |
Reassemble with the original run's pinned source, components, rules, models, and prompt version | Local files only; no DB/S3/webhook/ledger mutation; model calls may cost money |
uv run python apps/wf2des/scripts/replay_generation.py RUN_ID --stored --output-dir /tmp/wf2des-replay |
Export the stored result without reassembly | Local files only; no model call |
uv run python apps/wf2des/scripts/review_render.py --help |
Evaluate explicit source/output PNG evidence with the production render reviewer | Local files only; no DB/S3/queue/Figma mutation; review model may cost money |
Replay preserves the original pins. Supplying a new source manifest is an experiment, not a replay of the original generation, and its output must be labeled accordingly.
Registry maintenance
| Command | Use | Mutation and cost |
|---|---|---|
uv run python apps/wf2des/scripts/sweep_components.py "FIGMA_URL" 7 |
Run the deterministic REST sweep into local design_component records |
Mutates local Mongo and snapshot files; no LLM |
uv run python apps/wf2des/scripts/classify_slot_roles.py --org 1 --project 7 --dry-run |
Preview content-vs-placeholder classifications | No write; incurs model cost for unclassified strings |
uv run python apps/wf2des/scripts/classify_slot_roles.py --org 1 --project 7 |
Persist classifications | Updates project_figma_file.slot_roles; incurs model cost |
uv run python apps/wf2des/scripts/tag_component_semantics.py --org 1 --project 7 |
Preview missing semantic tags | No registry write; may incur model cost |
uv run python apps/wf2des/scripts/tag_component_semantics.py --org 1 --project 7 --apply |
Persist component/variant visual semantics | Mutates component registry; incurs vision-model cost |
Model configuration
Production defaults use openai:gpt-5.4 for matching and whole-screen review and
openai:gpt-5.4-mini for vision ingestion. Model IDs are provider-prefixed and pinned
at parse time. Direct Anthropic uses an anthropic:... model and ANTHROPIC_API_KEY.
OpenRouter uses the OpenAI-compatible transport, OPENAI_BASE_URL=https://openrouter.ai/api/v1,
an OpenRouter token in OPENAI_API_KEY, and a model such as
openai:anthropic/claude-sonnet-4.6. Set SCREEN_REVIEW_REASONING_EFFORT=none for
non-GPT review models.
ab_model_test.py is a paid evaluation tool that writes local output under
workspace/ab/; it is not part of production processing.
Failure behavior
Exhausted credits, invalid credentials/access, and unavailable configured models cannot be repaired by redelivery. The worker records a failed artifact/manifest and exposes a safe error to the client. Ordinary rate limits and provider 5xx errors remain retryable and are returned to SQS for redelivery.
The plugin records materialization diagnostics separately. The supported event values are
name_fallback, ordinal_fallback, build_error, font_fallback, prop_rejected,
unmatched, and preserved.