instance.detachInstance() turns an instance into a frame that keeps its content, as in Figma, from scripts run through eval. It reuses the graph's shared detach implementation, asserts editability like the proxy's other mutations, and joins the instance surface check against @figma/plugin-typings.
5.1 KiB
| title | description |
|---|---|
| Scripting | Execute JavaScript with a Figma-compatible Plugin API to query, batch-modify, and generate designs. |
Scripting
openpencil eval runs JavaScript against an OpenPencil document with a Figma-compatible figma global. Use it for headless batch edits, inspection, fixture setup, and automation without opening the editor UI.
Basic usage
openpencil eval design.fig -c "return figma.currentPage.children.length"
The -c flag accepts JavaScript. If the code does not start with return, OpenPencil wraps it in an async function and returns the value from that function when present.
openpencil eval design.fig -c "
const frame = figma.createFrame()
frame.name = 'Card'
frame.resize(300, 200)
frame.layoutMode = 'VERTICAL'
frame.itemSpacing = 12
return { id: frame.id, name: frame.name }
"
Query nodes
openpencil eval design.fig -c "
return figma.currentPage
.findAll((node) => node.type === 'FRAME' && node.name.includes('Button'))
.map((button) => ({
id: button.id,
name: button.name,
width: button.width,
height: button.height
}))
"
Modify and save
Use --write / -w to write changes back to the input file:
openpencil eval design.fig -c "
figma.currentPage.children.forEach((node) => {
node.opacity = 0.5
})
" --write
Use --output / -o to write to a new file:
openpencil eval design.fig -c "figma.currentPage.name = 'Updated'" -o updated.fig
Read scripts from stdin
cat transform.js | openpencil eval design.fig --stdin --write
Live app mode
Omit the file path to run against the currently open document in the desktop app:
openpencil eval -c "return figma.currentPage.name"
The desktop app must be running with a document open.
Output
By default, non-TTY output is JSON. Use --json to force JSON output:
openpencil eval design.fig -c "return figma.currentPage.children.map((n) => n.name)" --json
Use --quiet / -q to suppress output when only writing a file.
Supported API surface
The API is intentionally close to Figma's Plugin API, but it maps to OpenPencil's scene graph and file format.
Document and pages
figma.rootfigma.currentPagefigma.currentPage.selectionfigma.getNodeById(id)figma.createPage()
Node creation
figma.createFrame()figma.createRectangle()figma.createEllipse()figma.createText()figma.createLine()figma.createPolygon()figma.createStar()figma.createVector()figma.createComponent()figma.createSection()
Tree operations
node.childrennode.parentnode.appendChild(child)node.insertChild(index, child)node.clone()node.remove()node.findAll(callback?)node.findOne(callback)node.findChild(callback)node.findChildren(callback?)figma.group(nodes, parent)figma.ungroup(node)
Components
figma.createComponentFromNode(node)component.createInstance()instance.mainComponent
Variables
figma.getLocalVariables(type?)figma.getVariableById(id)figma.getLocalVariableCollections()figma.getVariableCollectionById(id)figma.createVariable(name, type, collectionId, value?)figma.setVariableValue(variableId, modeId, value)figma.deleteVariable(id)figma.createVariableCollection(name)figma.deleteVariableCollection(id)figma.bindVariable(nodeId, field, variableId)figma.unbindVariable(nodeId, field)
Properties
Common node properties are readable/writable through the proxy, including:
- Geometry:
x,y,width,height,rotation,resize(width, height) - Appearance:
fills,strokes,effects,opacity,visible,locked,blendMode,clipsContent - Radius:
cornerRadius,topLeftRadius,topRightRadius,bottomRightRadius,bottomLeftRadius - Text:
characters,fontSize,fontName,fontWeight, alignment, line height, letter spacing, style-run helpers - Auto-layout:
layoutMode,primaryAxisAlignItems,counterAxisAlignItems,itemSpacing, padding, sizing, and layout positioning fields - Stroke helpers:
strokeWeight,strokeAlign,dashPattern
Utilities
figma.mixedfigma.createImage(data)figma.loadFontAsync(fontName)no-ops because OpenPencil does not gate text edits on plugin font loadingfigma.listAvailableFontsAsync()returns host-provided fonts when availablefigma.getNodeByIdAsync(id)andinstance.getMainComponentAsync()resolve to the same nodes asfigma.getNodeById(id)andinstance.mainComponent, for scripts written for Figma's dynamic-page modefigma.notify(message)logs a warning in headless modefigma.viewport
Not yet Figma-compatible
These Figma APIs are not exposed as compatible helpers yet:
node.exportAsync()node.setBoundVariable(field, variable)figma.combineAsVariants(components, parent)- Figma style APIs such as
figma.createPaintStyle()/figma.createTextStyle() - Full vector boolean operation parity
Use OpenPencil CLI export commands, core tools, or direct scene-graph helpers where available.