Skip to content

feat: wireframe designer, Satori rendering, and Copy to Figma#24

Merged
trmquang93 merged 7 commits intomainfrom
feat/satori-wireframe-figma-export
Apr 4, 2026
Merged

feat: wireframe designer, Satori rendering, and Copy to Figma#24
trmquang93 merged 7 commits intomainfrom
feat/satori-wireframe-figma-export

Conversation

@trmquang93
Copy link
Copy Markdown
Collaborator

Summary

  • Satori rendering — replaces Puppeteer in the MCP server with Satori (Vercel's HTML-to-SVG engine). No Chrome binary required; renders ~50ms vs ~2s. MCP screens now produce clean native SVG alongside the PNG, stored as screen.svgContent.
  • Built-in wireframe designer — new W toolbar button opens a full-screen SVG canvas editor. Drag components (rect, button, input, nav-bar, tab-bar, etc.) from a palette, edit properties in the right panel, and click Done to render a PNG. Interactive components auto-generate hotspots.
  • Copy to Figma — right-click any MCP screen or wireframe → Copy for Figma to clipboard-copy the SVG, or Download SVG. Paste in Figma to get editable vector layers.

Changes

  • mcp-server: SatoriRenderer replaces HtmlRenderer; bundles Inter font; @resvg/resvg-js marked external in esbuild config; font assets copied to dist/assets/ at build time
  • src/constants.js: FILE_VERSION 12 → 13; adds WIREFRAME_GRID_SIZE, WIREFRAME_VIEWPORT_WIDTH/HEIGHT
  • src/hooks/useWireframeEditor.js: component CRUD, undo/redo (ref-based), grid snap
  • src/components/wireframe/: WireframeEditor, ComponentPalette, PropertyPanel
  • src/utils/wireframeToSvg.js, wireframeRenderer.js, wireframeDefaults.js: SVG generation and PNG rendering
  • src/utils/copyToFigma.js: clipboard copy + SVG file download
  • src/utils/importFlow.js: backfills svgContent, sourceHtml, wireframe for v1–12 files
  • src/pages/docs/userGuide.md: new Wireframe Designer and Copy to Figma sections

Test plan

  • npm test — 358 tests pass
  • npm run build — clean production build
  • MCP: cd mcp-server && node --input-type=module test with SatoriRenderer renders PNG + SVG
  • MCP bundle: npm run build in mcp-server/ produces dist/index.js + dist/assets/ fonts
  • Open existing v12 .drawd file — loads without errors, new fields default to null
  • Click Draw Wireframe → place components → resize → edit text/fill → click Done → screen shows PNG
  • Re-open wireframe editor — components preserved
  • Right-click MCP screen with svgContent → Copy for Figma → paste in Figma shows editable vectors
  • Right-click wireframe screen → Copy for Figma → paste in Figma shows editable vectors

Replace Puppeteer with Satori (Vercel) in the MCP server for HTML-to-PNG
rendering. Satori produces clean native SVG alongside the PNG, eliminating
the Chrome binary requirement and reducing render time from ~2s to ~50ms.

Add a built-in wireframe designer that lets users sketch screens directly
in Drawd using a drag-and-drop component palette (rect, button, input,
nav-bar, tab-bar, and more). Wireframes render to PNG via the browser canvas
and store their component schema for re-editing.

Both MCP screens (via Satori) and wireframe screens export to Figma as
editable SVG vector layers via right-click → Copy for Figma or Download SVG.

Details:
- mcp-server: SatoriRenderer replaces HtmlRenderer; returns svgString +
  pngBuffer; bundles Inter font; esbuild marks @resvg/resvg-js external
- File version bumped 12 → 13; screens gain svgContent, sourceHtml, wireframe
- useWireframeEditor hook: full undo/redo, grid snapping, component CRUD
- WireframeEditor: SVG canvas with drag/resize, keyboard shortcuts, auto-
  hotspot generation from interactive components
- copyToFigma utility: clipboard SVG copy + SVG file download
- Backward compat: importFlow.js backfills new fields for v1–12 files
- Docs: updated user guide with wireframe designer and Figma export sections
Satori requires every element with multiple children to have an explicit
display property — default block/inline layout does not exist. Add
injectMissingDisplay() to auto-inject display:flex;flex-direction:column
on div/section/header/footer/main/nav elements whose style lacks a
display declaration.

Also improve create_screen and update_screen_image tool descriptions to
clearly document Satori's rendering constraints for AI agent callers.
- Add copyScreensForFigma() combining multiple screen SVGs into one
  document using <g translate> per screen, preserving canvas-relative
  positions scaled to SVG coordinate space
- Add prefixSvgIds() to prevent ID collisions (gradients, patterns)
  when merging multiple SVGs into a single document
- Wire prepareSvgForFigma() into copyScreenForFigma() and
  downloadScreenSvg() so single-screen exports also get gradient fixes
- Context menu shows "Copy N Screens for Figma" when right-clicking
  within a multi-screen selection; falls back to "Copy for Figma" for
  single screens
- Toast message adapts: "3 screens copied — paste in Figma" vs
  "SVG copied — paste in Figma"
- Import generateId from utils instead of redefining locally
- Fix drag undo: snapshot pre-drag (captureDragSnapshot) instead of
  post-drag (commitMove), making drag/resize operations undoable
- Remove unused moveComponent from useWireframeEditor API
- Remove redundant selectedComp re-derivation; use hook's selectedComponent
- Skip getBoundingClientRect on mousemove when no drag/resize is active
- Fix button fill default in ComponentShape to match wireframeToSvg (#333333)
- Collapse dead ternary in renderText (both branches were identical)
- Use WIREFRAME_VIEWPORT_WIDTH/HEIGHT constants and deduplicate onAddWireframe
- Reuse downloadZip from zipBuilder in downloadScreenSvg
- Add _autoSave() to FlowState and call it after every mutation (addScreen,
  updateScreen, deleteScreen, addHotspot, addConnection, etc.) so changes
  are written to disk immediately without an explicit save_flow call
- Add filePath as a required parameter to all non-file tools via withFilePath()
  in server.js; the request handler auto-loads the file on the first call
  so Claude never needs a separate open_flow call to establish session context
- Update screen-tools HTML description with Figma-compatibility rules
- Add api script to mcp-server/package.json
- Add copyScreensForFigmaEditable() using fig-kiwi to write Figma's native
  binary clipboard format; pasted screens arrive as editable frames with fills,
  text nodes, and corner radii rather than flat SVG vectors
- Add htmlToFigmaNodes, figmaClipboard, figKiwiWriter, diffPayload utilities
  and figmaSchema.json to support the conversion pipeline
- Add "Copy as Editable" context menu entry in CanvasArea for wireframe screens
- Flash canvas items that were mutated by an MCP tool call (mcpFlashIds +
  CSS keyframe animations in ScreenNode, StickyNote, ConnectionLines)
- Push undo snapshot before applying MCP payloads so MCP edits are undoable
- Add MCP HTTP API server (mcp-server/src/api-server.js) and top-level api.js
- Add figma-plugin/ reference files for clipboard format reverse-engineering
- Add test coverage for figKiwiWriter, figmaClipboard, copyToFigma,
  wireframeToSvg, and useWireframeEditor
Single-line text nodes (height < 1.5× lineHeight) now use WIDTH_AND_HEIGHT
auto-resize so Figma never re-flows them regardless of font metric differences.
Multi-line text gets a +1px width buffer in layoutSize.x to absorb per-character
drift. Text widths are ceiled to avoid sub-pixel rounding.

Text inside non-auto-layout visual containers (badges, pills) is now positioned
at (paddingLeft, paddingTop) instead of (0, 0), and its width is reduced by
horizontal padding — fixing labels like "VIP" and "Nóng" overlapping their frame
edges and wrapping.
@trmquang93 trmquang93 merged commit 11fecef into main Apr 4, 2026
1 check failed
@github-actions github-actions bot deleted the feat/satori-wireframe-figma-export branch April 4, 2026 07:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant