openpencil/packages/pen-figma
Kayshen-X c4e5359596 docs: drop op export from CLI docs and clarify pen-mcp usage
The `op export` command was removed in 0.7.x but the README still
advertised it (#116). The pen-mcp README also documented an
`npx @zseven-w/pen-mcp` quick-start that never worked because the
package ships TypeScript source against workspace-only deps with no
`bin` entry (#117).

- Strip `op export` references from all 15 root and 15 cli READMEs
- Sync AGENTS.md, CLAUDE.md, apps/cli/CLAUDE.md to match the codegen-
  pipeline reality (no standalone export command anymore)
- Rewrite pen-mcp README's quick-start: explain the package ships as
  part of the OpenPencil app and external clients connect over HTTP

Closes #116
Closes #117
2026-04-26 19:20:14 +08:00
..
src V0.7.2-bugfix (#109) 2026-04-14 21:42:56 +08:00
CLAUDE.md V0.7.1 (#102) 2026-04-13 21:30:23 +08:00
LICENSE V0.7.1 (#102) 2026-04-13 21:30:23 +08:00
package.json docs: drop op export from CLI docs and clarify pen-mcp usage 2026-04-26 19:20:14 +08:00
README.md V0.7.1 (#102) 2026-04-13 21:30:23 +08:00
tsconfig.json V0.5.0 (#67) 2026-03-22 09:44:04 +08:00

@zseven-w/pen-figma

Figma .fig file parser and converter for OpenPencil. Import Figma designs directly into the OpenPencil document model — binary file parsing, multi-page support, clipboard paste, and full style conversion.

Install

npm install @zseven-w/pen-figma
# or
bun add @zseven-w/pen-figma

Overview

This package handles the complete pipeline from Figma's proprietary binary format to OpenPencil's PenDocument:

.fig binary → Kiwi schema decode → FigmaNodeChange[] → tree building → PenNode[] → PenDocument

It supports:

  • Binary .fig files (Kiwi schema + zstd/zip compression)
  • Figma clipboard HTML (copy from Figma → paste in OpenPencil)
  • All node types: frames, groups, components, instances, shapes, text, vectors, images
  • Full style conversion: fills, strokes, effects, gradients, auto-layout, typography

Usage

Parse a .fig file

import { parseFigFile, figmaAllPagesToPenDocument } from '@zseven-w/pen-figma';

const buffer = await fs.readFile('design.fig');
const figFile = parseFigFile(buffer);
const document = figmaAllPagesToPenDocument(figFile);

console.log(`Imported ${document.pages?.length} pages`);

Single page import

import { parseFigFile, getFigmaPages, figmaToPenDocument } from '@zseven-w/pen-figma';

const figFile = parseFigFile(buffer);
const pages = getFigmaPages(figFile);

// Import just the first page
const document = figmaToPenDocument(figFile, pages[0]);

Clipboard paste

Detect and convert Figma clipboard data (when users copy from Figma and paste into OpenPencil):

import {
  isFigmaClipboardHtml,
  extractFigmaClipboardData,
  figmaClipboardToNodes,
} from '@zseven-w/pen-figma';

document.addEventListener('paste', (e) => {
  const html = e.clipboardData?.getData('text/html');
  if (html && isFigmaClipboardHtml(html)) {
    const data = extractFigmaClipboardData(html);
    const nodes = figmaClipboardToNodes(data);
    // Insert nodes into document...
  }
});

Convert individual nodes

For lower-level access (e.g., incremental sync):

import { figmaNodeChangesToPenNodes } from '@zseven-w/pen-figma';

const penNodes = figmaNodeChangesToPenNodes(figmaNodeChanges, options);

Icon resolution

Register an icon lookup function for converting Figma component instances to icon nodes:

import { setIconLookup } from '@zseven-w/pen-figma';

setIconLookup((name) => {
  // Return SVG path data for the icon name, or null
  return iconRegistry[name]?.path ?? null;
});

Image resolution

Resolve embedded image blob references to data URLs:

import { resolveImageBlobs } from '@zseven-w/pen-figma';

const images = resolveImageBlobs(figFile);
// Map<blobHash, dataURL>

Conversion Coverage

Node Types

Figma Type PenNode Type Notes
FRAME frame With auto-layout, constraints, clip content
GROUP group Preserves child transforms
COMPONENT frame Marked as reusable
INSTANCE frame Resolved with overrides
RECTANGLE rectangle Corner radius (uniform + per-corner)
ELLIPSE ellipse Arc support
LINE line Stroke properties
TEXT text Rich text with styled segments
VECTOR path Complex paths, boolean ops, stars, polygons
IMAGE image Embedded or referenced

Styles

Figma Style Conversion
Solid fills PenFill with solid type
Linear gradients PenFill with gradient stops + angle
Radial gradients PenFill with center + radius
Image fills PenFill with image source
Strokes PenStroke with cap, join, dash
Drop shadows PenEffect shadow
Inner shadows PenEffect inner shadow
Blur PenEffect blur
Auto-layout layout, gap, padding, justifyContent, alignItems
Text styles fontSize, fontWeight, fontFamily, lineHeight, letterSpacing
Rich text StyledTextSegment[] with per-run styles

API Reference

Function Description
parseFigFile(buffer) Parse binary .fig file → FigmaDecodedFile
figmaAllPagesToPenDocument(file) Convert all pages → PenDocument
figmaToPenDocument(file, page) Convert single page → PenDocument
getFigmaPages(file) List available pages
figmaNodeChangesToPenNodes(changes) Convert raw node changes → PenNode[]
isFigmaClipboardHtml(html) Detect Figma clipboard data
extractFigmaClipboardData(html) Extract base64 .fig from clipboard HTML
figmaClipboardToNodes(data) Convert clipboard data → PenNode[]
resolveImageBlobs(file) Resolve image references → data URLs
setIconLookup(fn) Register icon name → SVG path resolver

License

MIT