A Figma plugin that converts websites, HTML/CSS, local files, web archives and emails into fully editable, layered Figma designs — Auto Layout frames, real text, native styles, variables and vector paths. Never a flat screenshot.
It exists because AI produces designs as HTML, and there was no good way to get that back into the tool designers actually work in.
A personal case study, published for review rather than reuse. It is the whole plugin: the conversion pipeline, the layer-tree contract between the browser and the Figma sandbox, and the build that inlines the UI into a single file.
It is not a published Figma Community plugin, and it isn't maintained for other people. Load it as a development plugin if you want to see it run.
├── manifest.json Figma plugin manifest
├── code.js / ui.html build artifacts — generated, marked linguist-generated
├── scripts/build-ui.mjs bundles src/ui/* and inlines it into ui.html
├── src/
│ ├── types.ts the layer-tree contract (UI ⇄ sandbox)
│ ├── code/ plugin sandbox, TypeScript
│ │ ├── main.ts messaging and import flow
│ │ ├── slides.ts deck detection → one native SlideNode per section
│ │ ├── builders.ts layer tree → Figma nodes
│ │ ├── fonts.ts font-stack resolution, fallback, substitution report
│ │ ├── variables.ts variable collections + binding
│ │ └── styles.ts, paint.ts
│ └── ui/ plugin UI, bundled into ui.html
│ ├── convert.js rendered-DOM walker → layer tree
│ ├── gradients.js CSS gradient parser → Figma gradient data
│ ├── formats.js .mhtml / .eml / .zip → inlined HTML
│ └── images.js rasterisation and SVG helpers
└── test-fixtures/ generated fixtures for the format parsers
src/ui/convert.js is the argument of the project. It walks the rendered DOM rather
than parsing source, so it reads computed styles — which is the only way flex becomes Auto
Layout, backdrop-filter becomes a Figma background blur, and a Tailwind page arrives with
its spacing intact.
src/code/fonts.ts honours the full CSS font stack instead of taking the first name and
giving up. System keywords are skipped, each real family is tried in order at the nearest
installed weight, and the post-import report only names a font when nothing in its stack
was available. Most import tools fail here and produce a wall of Inter.
src/code/variables.ts collects colour, type-scale and spacing tokens from the design
and binds fills to them, so editing one variable restyles the whole import. That turns a
one-way conversion into something a designer can actually keep working in.
src/code/slides.ts detects a slide deck — a stack of uniformly sized sections — and
produces one native Figma slide per section, unpacking the self-unpacking bundle format
first and naming each slide from its authored label.
Symbol glyphs are the detail I'm most pleased with. Short symbol-only text (▶ ✓ ♪ ⌛) renders through system fonts no Figma font reproduces, so it's rasterised 1:1 from the browser's own rendering. Real text stays text.
Grids with explicit placement import absolutely positioned; only auto-flow grids become
Auto Layout. Inline emphasis inside a paragraph flattens to the paragraph's style.
conic-gradient is approximated. Cross-origin images that block CORS are skipped.
TypeScript · esbuild · the Figma Plugin API. One runtime dependency (fflate, for archives).
ui.html must be a single self-contained file, which is why the UI is bundled and inlined
rather than served.
npm install && npm run build
# Figma desktop → Plugins → Development → Import plugin from manifest…All rights reserved. Published for review, not for reuse — see LICENSE.
Third-party libraries and the Figma trademark: see NOTICE.md.