Read Figma .fig files without Figma or its API. Pure Python 3.14, no
dependencies: decode the whole document to JSON, find frames, print a subtree
with texts and geometry, render a frame to HTML. The kiwi decoder mirrors
evanw/kiwi byte for byte. Docs below are in
Russian; commands and field names are the same in any language.
Чтение файлов Figma .fig без Figma и без API: узлы документа в JSON, поиск
кадров, дерево с текстами и размерами, отрисовка кадра в HTML для сверки
глазами. Чистый Python 3.14 (нужен встроенный compression.zstd), без
зависимостей.
Зачем: макет лежит файлом («Save local copy»), доступа к проекту в Figma нет, а размеры, отступы, цвета и тексты нужно снимать точно, а не на глаз по PNG.
python readfig.py "макет.fig" canvas.json # ~1 мин на 380 МБ: 47 619 узлов, 4 200 блобов
python fig.py find "Каталог" # кадры, секции и символы по подстроке в имени
python fig.py tree 706:38090 3 # поддерево: тип, guid, имя, x,y, размер, текст
python render.py "макет.fig" 706:38090 frame.html # кадр в HTML (картинки вшиты)
python test_kiwi.py # проверка декодера на известных байтахfig.py и render.py читают canvas.json из текущей папки или из переменной
FIG_CANVAS. render.py берёт картинки из самого .fig, поэтому ему нужен и он.
HTML открывается браузером напрямую. Для просмотра целиком на узком экране:
document.body.style.zoom = innerWidth / 1920.
Проект задуман так, чтобы агент (Claude Code, Codex и т. п.) мог снять макет сам, без человека с Figma:
python readfig.py макет.fig canvas.json— один раз, дальше работать с JSON.python fig.py find "<часть имени экрана>"— найти кадр; у одинаковых имён смотреть путь: «Прототип» часто пустая заготовка, настоящее — в «Дизайне» или «Верстке».python fig.py tree <guid> 4— точные размеры, отступы, тексты, какие символы вставлены. Цифры брать отсюда, а не с картинки.python render.py макет.fig <guid> frame.htmlи скриншот — посмотреть, как это выглядит целиком.
Весь документ — плоский список словарей в canvas.json["nodes"]: его можно
разбирать своим кодом (import fig даёт N, BY[guid], KIDS[guid],
path(), line(), svg_path()).
.fig из «Save local copy» — zip: canvas.fig, thumbnail.png, meta.json,
images/<sha1> (картинки заливок по хешу).
canvas.fig:
"fig-kiwi" 8 байт
версия uint32 LE
кусок 0 uint32 LE длина + kiwi-схема (raw deflate)
кусок 1 uint32 LE длина + сообщение (zstd, если начинается
с 28 B5 2F FD, иначе raw deflate)
Схема самоописательна (формат kiwi Эвана
Уоллеса, сооснователя Figma), поэтому декодер универсальный: сначала читает
схему, потом по ней — сообщение типа Message. Чтение значений повторяет
js/bb.ts и js/binary.ts из kiwi один в один:
uint— varint до 5 байт, результат uint32;int— он же зигзагом;uint64/int64— varint, девятый байт берётся целиком;float— 0 одним байтом, иначе 4 байта LE с экспонентой, сдвинутой в младшие биты (bits = (bits << 23) | (bits >>> 9));string— UTF-8 до нулевого байта;byte[]— длина varint + байты;- встроенные типы в схеме — отрицательные:
~индексв[bool, byte, int, uint, float, string, int64, uint64]; - struct — поля подряд; message — пары «номер поля + значение» до нуля.
В Message: nodeChanges — плоский список всех узлов (дерево собирается по
parentIndex.guid, порядок детей — parentIndex.position), blobs — байтовые
данные, на которые узлы ссылаются номером.
- текст —
textData.characters;fillPaintsу TEXT — цвет букв, не фон; - позиция —
transform.m02/m12относительно родителя, размер —size; - картинка —
fillPaints[].image.hash→ файлimages/<hex>в zip; кадрирование (imageScaleModeSTRETCH — это CROP из API, и TILE) —fillPaints[].transform: точка картинки в пикселях → узел =scale(w,h) · T⁻¹ · scale(1/imgW, 1/imgH); - инстанс —
symbolData.symbolID(мастер) иsymbolData.symbolOverrides(переопределённые тексты/заливки поguidPath; ключ —overrideKeyузла, если есть, иначеguid); оверрайд с путём на сам мастер красит корень; - контуры векторов —
fillGeometry[]/strokeGeometry[]:commandsBlob— номер вblobs. Команда — байт, аргументы float32 LE:0Z,1M x y,2L x y,3Q x1 y1 x y,4C x1 y1 x2 y2 x y;windingRule—NONZERO/ODD.
render.py — чтобы посмотреть, а не для пиксель-в-пиксель: не рисует тени и
размытие, повороты узлов, перестроение auto-layout у растянутых инстансов,
смешанные стили внутри одного текста. Цифры (отступы, размеры, радиусы, цвета)
снимать через fig.py tree, а не с картинки.
MIT — см. LICENSE. Формат kiwi и его эталонная реализация — MIT, © Evan Wallace; здесь независимая реализация на Python.
- kiwi: https://github.com/evanw/kiwi (
js/bb.ts,js/binary.ts) - контейнер: https://openpencil.dev/reference/file-format
- геометрия и кадрирование картинок: https://github.com/open-pencil/open-pencil
(
packages/core/src/io/formats/svg/paths.ts,packages/core/src/canvas/fills.ts)