How to bring Pencil (.pen) designs into Figma as editable layers
A working method for pen.dev users who need their designs in Figma. No screenshots, no rebuilding.
To get a Pencil design into Figma, export the node from your .pen file as HTML and CSS using Pencil's export_html tool, make sure the referenced images resolve, then import that HTML into Figma with the html2figma plugin. The design arrives as native Figma layers with real text and your original layer names, not as a flattened image. The whole trip takes about two minutes.
Why is it hard to get a Pencil design out of the editor?
Pencil is built on a good idea: your design lives as a .pen file in the repo, your coding agent reads it, and code comes out the other side. Design and code stop drifting apart.
That works right up to the moment someone outside your editor needs to see the design.
A designer wants to iterate on it in the team's Figma library. A client only reviews in Figma. Your design system lives there as published components. The stakeholder who signs off doesn't have Cursor installed and never will.
Pencil handles the inbound direction natively. You can paste from Figma straight onto the canvas. Outbound is where people get stuck. The usual fallback is exporting a PNG and rebuilding the layout by hand in Figma, which throws away every piece of structure the canvas already knows about.
There's a better route, and it takes about two minutes.
What's the trick for exporting Pencil to Figma?
Pencil can export any node as HTML. Figma can import HTML as native layers. So you go through HTML rather than through an image.
Nothing is flattened. Text stays text, frames stay frames, and your layer names survive the trip.
How do I export a .pen node as HTML?
Pencil's MCP server exposes an HTML export. Ask your agent for it directly:
Export the node<node-id>fromdesigns/dashboard.pento./export/dashboard.htmlusing thehtml-cssformat, with layer names included.
Under the hood that calls export_html with these settings, and the settings matter:
| Setting | Use | Why |
|---|---|---|
format |
html-css |
Not html-tailwind. Tailwind output is class names that mean nothing without the Tailwind stylesheet compiled alongside. Plain CSS carries the actual computed values, which is what a converter can read. |
includeLayerNames |
true |
Writes your Pencil layer names into the markup as data attributes, so your Figma layers arrive named instead of as a stack of anonymous frames. |
includeHtmlScaffold |
true |
Gives you a complete, self-contained document rather than a fragment. |
To find the node ID, ask your agent to list the top-level nodes in the file first, or select the frame on the canvas and read the current selection.
Export as html-css, not html-tailwind. A converter reads computed style values. Tailwind class names carry no values on their own, so the design arrives unstyled.
Why are my images missing after the export?
This is the step everyone misses, and it's the reason a first attempt usually comes back with empty boxes where the images should be.
Pencil's HTML export never embeds image assets. It references them with relative paths, pointing at files sitting next to your HTML on disk. Open that file from the filesystem and the images resolve fine locally. Hand the markup to anything that isn't running in that folder and every image is a broken link.
Two ways around it.
Serve the folder locally
From your export directory:
npx serve ./export
You now have a real URL, and the relative paths resolve like they would on any website.
Or inline the assets
If you'd rather move a single file around, have your agent convert the referenced images to base64 data URIs in the exported HTML. Bigger file, zero dependencies, works anywhere.
Serving locally is faster. Inlining is better if you're sending the export to someone else.
Pencil's HTML export never embeds image assets. If you skip this step, the design imports with empty boxes where every image should be.
How do I import the HTML into Figma?
In Figma, run html2figma and give it the export from step 2.
What lands on the canvas:
- Frames with auto layout preserved where the export defined it
- Real text nodes you can edit, not rasterized type
- Fills, strokes, radii and spacing as actual Figma properties
- Layer names carried through from your
.penfile
From there it behaves like anything else in Figma. Attach it to a library, swap in published components, hand it to a designer.
Can I carry my Pencil design tokens across?
If your Pencil file uses variables, they map to CSS custom properties. Ask your agent to dump them before you export:
Get the variables from designs/dashboard.pen.
You'll get your token names with their resolved values. That gives you a reference list for matching the imported design against your existing Figma variables, rather than eyeballing hex codes one at a time.
What doesn't survive the trip?
Being straight about the limits, because a guide that oversells wastes your afternoon:
- Interactions don't survive. Prototype links, hover states and transitions aren't in the HTML export, so they don't reach Figma. Static layout only.
- Components arrive flattened. A
.pencomponent instance comes through as a normal frame, not as a Figma component instance. You'll need to swap it against your library manually if you want it linked. - Complex nesting can drift. Deeply nested layouts sometimes come through with more wrapper frames than you'd draw by hand. Fixable in a minute, but worth expecting.
- It's one-directional. This is an export, not a sync. Change the Figma file and nothing flows back to your
.penfile. Re-export when the design changes.
Should I route through Figma at all?
This is worth doing when the design needs to leave your editor: client review, designer handoff, joining a component library, or documentation for people who don't work in code.
It's not worth doing if the design's next stop is production code. That's the path Pencil already handles natively, and routing through Figma just adds a step.
pen.dev to Figma: common questions
Why export html-css instead of html-tailwind?
Tailwind output is class names that mean nothing without the Tailwind stylesheet compiled alongside it. Plain CSS carries the actual computed values, which is what a converter can read.
Why are my images missing after importing into Figma?
Pencil's HTML export never embeds image assets. It references them with relative paths that point at files sitting next to your HTML on disk, so anything not running in that folder sees broken links. Serve the export folder locally with npx serve ./export, or inline the images as base64 data URIs.
Do Pencil components come through as Figma components?
No. A .pen component instance comes through as a normal frame, not as a Figma component instance. You need to swap it against your library manually if you want it linked.
Does this sync both ways between Pencil and Figma?
No. This is an export, not a sync. Change the Figma file and nothing flows back to your .pen file. Re-export when the design changes.
Do prototype interactions survive the export?
No. Prototype links, hover states and transitions aren't in the HTML export, so they don't reach Figma. The result is static layout only.
How do I find the node ID to export?
Ask your agent to list the top-level nodes in the .pen file first, or select the frame on the canvas and read the current selection.
Can I bring my Pencil design tokens across?
Variables in a Pencil file map to CSS custom properties. Ask your agent to get the variables from the .pen file before exporting, and you get your token names with their resolved values as a reference list for matching against your existing Figma variables.
html2figma is a free Figma plugin that converts HTML and CSS into editable Figma layers. If you use this workflow, let me know what breaks. The failure cases are what I fix first.