Commit 11fecef
authored
feat: wireframe designer, Satori rendering, and Copy to Figma (#24)
* feat: add wireframe designer, Satori rendering, and Copy to Figma export
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
* fix(mcp): inject missing display:flex for Satori compatibility
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.
* feat: add multi-screen Copy for Figma support
- 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"
* fix: code quality cleanup for wireframe/Satori PR
- 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
* fix(mcp): auto-save mutations and require filePath on all tools
- 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
* feat: add editable Figma clipboard export and MCP visual feedback
- 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
* fix: prevent text wrapping and misalignment in editable Figma export
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.
---------
Co-authored-by: Quang Tran <16215255+trmquang93@users.noreply.github.com>1 parent 9f6a759 commit 11fecef
57 files changed
Lines changed: 64162 additions & 54 deletions
File tree
- figma-plugin
- mcp-server
- assets
- src
- figma-export
- renderer
- tools
- src
- components
- wireframe
- hooks
- pages/docs
- utils
- __fixtures__
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
26 | 26 | | |
27 | 27 | | |
28 | 28 | | |
| 29 | + | |
29 | 30 | | |
30 | 31 | | |
31 | 32 | | |
| |||
Large diffs are not rendered by default.
0 commit comments