2026-03-03 09:57:17 +00:00
# `open-pencil eval` — Figma-ähnliche Plugin-API für Headless-Skripting
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
## Übersicht
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
`bun open-pencil eval <file> --code '<js>'` führt JavaScript gegen eine `.fig` -Datei mit einem Figma-kompatiblen `figma` -Globalobjekt aus. Dies ermöglicht Headless-Skripting, Batch-Operationen, KI-Werkzeug-Ausführung und Tests — alles ohne die GUI.
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
Das `figma` -Objekt spiegelt Figmas Plugin-API-Oberfläche so nah wie möglich, sodass vorhandenes Figma-Plugin-Wissen und Code-Snippets direkt übertragbar sind.
2026-03-03 09:46:35 +00:00
```bash
2026-03-03 09:57:17 +00:00
# Frame erstellen, Auto-Layout setzen, Kinder hinzufügen
2026-03-03 09:46:35 +00:00
bun open-pencil eval design.fig --code '
const frame = figma.createFrame()
frame.name = "Card"
frame.resize(300, 200)
frame.layoutMode = "VERTICAL"
frame.itemSpacing = 12
frame.paddingTop = frame.paddingBottom = 16
frame.paddingLeft = frame.paddingRight = 16
frame.fills = [{ type: "SOLID", color: { r: 1, g: 1, b: 1 } }]
const title = figma.createText()
title.characters = "Hello World"
title.fontSize = 24
frame.appendChild(title)
return { id: frame.id, name: frame.name }
'
2026-03-03 09:57:17 +00:00
# Knoten abfragen
2026-03-03 09:46:35 +00:00
bun open-pencil eval design.fig --code '
const buttons = figma.currentPage.findAll(n => n.type === "FRAME" & & n.name.includes("Button"))
return buttons.map(b => ({ id: b.id, name: b.name, w: b.width, h: b.height }))
'
2026-03-03 09:57:17 +00:00
# Von stdin lesen (für mehrzeilige Skripte / Piping)
2026-03-03 09:46:35 +00:00
cat transform.js | bun open-pencil eval design.fig --stdin
2026-03-03 09:57:17 +00:00
# Änderungen zurückschreiben
2026-03-03 09:46:35 +00:00
bun open-pencil eval design.fig --code '...' --write
bun open-pencil eval design.fig --code '...' -o modified.fig
```
2026-03-03 09:57:17 +00:00
## Architektur
2026-03-03 09:46:35 +00:00
```
┌──────────────────────────────────────────────────────┐
│ CLI: `open-pencil eval <file> --code '...'` │
│ ↓ │
│ loadDocument(file) → SceneGraph │
│ ↓ │
2026-03-03 09:57:17 +00:00
│ FigmaAPI(sceneGraph) → `figma` Proxy-Objekt │
2026-03-03 09:46:35 +00:00
│ ↓ │
│ AsyncFunction('figma', wrappedCode)(figmaProxy) │
│ ↓ │
2026-03-03 09:57:17 +00:00
│ Ergebnis als JSON / agentfmt ausgeben │
│ optional: saveDocument(file) bei --write │
2026-03-03 09:46:35 +00:00
└──────────────────────────────────────────────────────┘
```
2026-03-03 09:57:17 +00:00
### Schlüsselklassen
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
| Klasse | Ort | Rolle |
|--------|-----|-------|
| `FigmaAPI` | `packages/core/src/figma-api.ts` | Proxy-Objekt, das `figma.*` -Methoden gegen `SceneGraph` implementiert |
| `FigmaNode` | `packages/core/src/figma-api.ts` | Proxy, der `SceneNode` mit Figma-ähnlichem Eigenschaftszugriff umhüllt |
| `eval` -Befehl | `packages/cli/src/commands/eval.ts` | CLI-Befehl: Dokument laden, API erstellen, Code ausführen |
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
### Warum in `@open-pencil/core`?
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
Die `FigmaAPI` -Klasse lebt in core (nicht CLI), weil:
- **KI-Werkzeuge nutzen sie wieder** — das Chat-Panels `render` -Werkzeug kann JSX über dieselbe API ausführen
- **Testskripte** — Unit-Tests können die API für Fixture-Setup verwenden
- **Keine DOM-Abhängigkeiten** — läuft headless in Bun
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
## CLI-Befehl
2026-03-03 09:46:35 +00:00
```
2026-03-03 09:57:17 +00:00
bun open-pencil eval < file > [optionen]
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
Argumente:
file .fig-Datei zum Bearbeiten
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
Optionen:
--code, -c Auszuführender JavaScript-Code (hat Zugriff auf `figma` -Global)
--stdin Code von stdin statt --code lesen
--write, -w Änderungen in die Eingabedatei zurückschreiben
-o, --output In eine andere Datei schreiben
--json Ergebnis als JSON ausgeben (Standard für Nicht-TTY)
--quiet, -q Ausgabe unterdrücken, nur Datei schreiben
2026-03-03 09:46:35 +00:00
```
2026-03-03 09:57:17 +00:00
### Ausführungsmodell
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
1. `.fig` laden → `SceneGraph`
2. `FigmaAPI(graph)` erstellen → `figma` -Proxy
3. Benutzercode in async-Funktion verpacken: `return (async () => { <code> })()`
4. Mit `figma` als einzigem Argument ausführen
5. Rückgabewert ausgeben (JSON oder agentfmt)
6. Bei `--write` oder `-o` : `SceneGraph` zurück in `.fig` serialisieren
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
### Rückgabewert-Formatierung
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
- `undefined` / `void` → keine Ausgabe
- Primitive → direkt ausgeben
- Objekte/Arrays → `JSON.stringify(result, null, 2)` oder agentfmt-Tabellen
- `FigmaNode` → serialisiert als `{ id, type, name, x, y, width, height, fills, ... }`
- Arrays von `FigmaNode` → als Liste serialisiert
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
## `FigmaAPI` — Phasenweise Implementierung
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
Die vollständige API-Referenz mit Phasen (Core, Komponenten, Variablen, Stile) und Eigenschafts-Mapping finden Sie in der [englischen Version ](/eval-command ).
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
### Phase 1: Core
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
Deckt ~80% realer Plugin-Skripte ab. Enthält: Dokument & Seite, Knotenerstellung, Knoteneigenschaften, Baumoperationen, Auto-Layout, Text, Kontur und Export.
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
### Phase 2: Komponenten & Instanzen
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
`figma.createComponent()` , `combineAsVariants()` , `createInstance()` , `detachInstance()` , `mainComponent` .
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
### Phase 3: Variablen
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
`figma.variables.getLocalVariables()` , `createVariable()` , `createVariableCollection()` , `setBoundVariable()` .
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
### Phase 4: Stile & Erweitert
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
Paint/Text/Effekt-Stile, Boolesche Operationen, JSX-Renderer.
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
## Gemeinsam mit KI-Werkzeugen
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
Die `FigmaAPI` -Klasse ist **dieselbe API-Oberfläche** , die KI-Werkzeuge verwenden. Dies stellt sicher, dass CLI-Skripte und KI-Werkzeuge identisch funktionieren.
2026-03-03 09:46:35 +00:00
2026-03-03 09:57:17 +00:00
## Dateilayout
2026-03-03 09:46:35 +00:00
```
packages/core/src/
2026-03-03 09:57:17 +00:00
figma-api.ts # FigmaAPI-Klasse + FigmaNode-Proxy
2026-03-03 09:46:35 +00:00
packages/cli/src/commands/
2026-03-03 09:57:17 +00:00
eval.ts # CLI-Befehl
2026-03-03 09:46:35 +00:00
```