Figma Plugin Writer
/install figma-plugin-writer
Figma Plugin Writer
Write plugin code (code.js) to automate design in Figma files. After updating the code, notify the user to run the plugin.
Prerequisites
The user must provide:
- Plugin directory — folder containing
code.jsandmanifest.json - Code file — typically
code.js - Target Figma file — optional, for context
Workflow
- Receive design requirements from the user
- Write plugin code to
code.js - Notify user:
Plugins → Development → \x3Cplugin-name> - Iterate based on feedback
API Reference
Font Loading (required before creating text)
await figma.loadFontAsync({ family: "Inter", style: "Regular" });
await figma.loadFontAsync({ family: "Inter", style: "Medium" });
await figma.loadFontAsync({ family: "Inter", style: "Semi Bold" });
await figma.loadFontAsync({ family: "Inter", style: "Bold" });
Frame (Container)
var frame = figma.createFrame();
frame.name = "MyFrame";
frame.resize(width, height);
frame.cornerRadius = 12;
frame.fills = [{ type: "SOLID", color: { r: 1, g: 1, b: 1 } }];
frame.x = 0;
frame.y = 0;
Text
var text = figma.createText();
text.characters = "Hello World";
text.fontSize = 16;
text.fontName = { family: "Inter", style: "Regular" };
text.fills = [{ type: "SOLID", color: { r: 0, g: 0, b: 0 } }];
Rectangle
var rect = figma.createRectangle();
rect.resize(100, 50);
rect.fills = [{ type: "SOLID", color: { r: 0.9, g: 0.2, b: 0.2 } }];
rect.cornerRadius = 8;
Nesting Nodes
frame.appendChild(text);
parentPage.appendChild(frame);
Drop Shadow
frame.effects = [{
type: "DROP_SHADOW",
color: { r: 0, g: 0, b: 0, a: 0.1 },
offset: { x: 0, y: 4 },
radius: 12,
spread: 0,
visible: true,
blendMode: "NORMAL",
}];
Stroke
frame.strokes = [{ type: "SOLID", color: { r: 0.8, g: 0.8, b: 0.8 } }];
frame.strokeWeight = 1;
Text Alignment
text.textAlignHorizontal = "CENTER"; // LEFT | CENTER | RIGHT | JUSTIFIED
text.textAlignVertical = "CENTER"; // TOP | CENTER | BOTTOM
Auto Layout (inside Frame)
frame.layoutMode = "VERTICAL"; // or "HORIZONTAL"
frame.primaryAxisAlignItems = "CENTER"; // MIN | CENTER | MAX | SPACE_BETWEEN
frame.counterAxisAlignItems = "CENTER";
frame.paddingTop = 16;
frame.paddingBottom = 16;
frame.paddingLeft = 16;
frame.paddingRight = 16;
frame.itemSpacing = 8;
Page Navigation
var pages = figma.root.children;
var targetPage = pages[pages.length - 1];
await figma.setCurrentPageAsync(targetPage);
Clear Page Content
var old = targetPage.children.slice();
for (var i = 0; i \x3C old.length; i++) {
old[i].remove();
}
Viewport
figma.viewport.scrollAndZoomIntoView([frame]);
Notifications
figma.notify("Done!", { timeout: 3000 });
figma.notify("ERROR: " + e.message, { timeout: 10000 });
Page Info
var pages = figma.root.children;
var count = pages.length;
var pageName = pages[0].name;
Code Template
async function main() {
try {
// 1. Load fonts
await figma.loadFontAsync({ family: "Inter", style: "Regular" });
await figma.loadFontAsync({ family: "Inter", style: "Bold" });
// 2. Get target page
var pages = figma.root.children;
var target = pages[pages.length - 1];
await figma.setCurrentPageAsync(target);
// 3. Clear old content
var old = target.children.slice();
for (var i = 0; i \x3C old.length; i++) old[i].remove();
// 4. Create design...
var frame = figma.createFrame();
frame.name = "Screen";
frame.resize(375, 812);
frame.fills = [{ type: "SOLID", color: { r: 1, g: 1, b: 1 } }];
frame.x = 0;
frame.y = 0;
target.appendChild(frame);
// 5. Done
figma.viewport.scrollAndZoomIntoView([frame]);
figma.notify("Design complete!", { timeout: 3000 });
} catch (e) {
figma.notify("ERROR: " + e.message, { timeout: 10000 });
}
}
main();
Pitfalls & Gotchas
documentAccess: "dynamic-page" Mode
If manifest.json has "documentAccess": "dynamic-page":
- ❌
figma.currentPage = page→ ✅await figma.setCurrentPageAsync(page) - ❌
figma.getNodeById()→ ✅await figma.getNodeByIdAsync() - ❌
figma.closePlugin()→ ✅await figma.closePluginAsync()
Error Handling
- Always wrap code in
try-catch - Show errors via
figma.notify("ERROR: " + e.message, { timeout: 10000 }) - Do not use emoji in text content (font may not support the glyph)
- Do not call
figma.closePlugin()automatically (let user close manually)
Free Tier Limits
- Max 3 Pages — do not create new Pages
- Work within existing Pages (clear and rebuild)
Fonts
- Default: Inter (built into Figma)
- Supported styles: "Regular", "Medium", "Semi Bold", "Bold"
- Colors use
{ r, g, b }format with 0-1 range
Iteration Pattern
On each design iteration:
- Clear old elements:
page.children.slice().forEach(c => c.remove()) - Recreate design with changes
- Notify user to re-run the plugin
- Make sure OpenClaw is installed (local or Docker)
- Run the install command in chat:
/install figma-plugin-writer - After installation, invoke the skill by name or use
/figma-plugin-writer - Provide required inputs per the skill's parameter spec and get structured output
What is Figma Plugin Writer?
自动生成和更新 Figma 插件的 code.js 以创建和修改设计元素,用户更新代码后需手动运行插件执行。 It is an AI Agent Skill for Claude Code / OpenClaw, with 343 downloads so far.
How do I install Figma Plugin Writer?
Run "/install figma-plugin-writer" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.
Is Figma Plugin Writer free?
Yes, Figma Plugin Writer is completely free, licensed under MIT-0. You can download, install and use it at no cost.
Which platforms does Figma Plugin Writer support?
Figma Plugin Writer is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).
Who created Figma Plugin Writer?
It is built and maintained by Zoe Addamssance (@zerozlw); the current version is v1.0.0.