Figma Plugin Writer
by @zerozlw
自动生成和更新 Figma 插件的 code.js 以创建和修改设计元素,用户更新代码后需手动运行插件执行。
clawhub install figma-plugin-writer📖 About This Skill
name: figma-plugin-writer description: Write Figma plugin code to automate UI design in Figma files. Activate when user wants to create UI mockups, design systems, app screens, or visual prototypes directly in Figma via plugin code. NOT for: Figma API REST calls, file management, or commenting.
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:
1. Plugin directory — folder containing code.js and manifest.json
2. Code file — typically code.js
3. Target Figma file — optional, for context
Workflow
1. Receive design requirements from the user
2. Write plugin code to code.js
3. Notify user: Plugins → Development →
4. 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 < 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 < 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
try-catchfigma.notify("ERROR: " + e.message, { timeout: 10000 })figma.closePlugin() automatically (let user close manually)Free Tier Limits
Fonts
{ r, g, b } format with 0-1 rangeIteration Pattern
On each design iteration:
1. Clear old elements: page.children.slice().forEach(c => c.remove())
2. Recreate design with changes
3. Notify user to re-run the plugin
⚙️ Configuration
The user must provide:
1. Plugin directory — folder containing code.js and manifest.json
2. Code file — typically code.js
3. Target Figma file — optional, for context