# OpenPencil vs Penpot: сравнение архитектуры и производительности Зачем сравнивать? OpenPencil существует, потому что закрытые дизайн-платформы ограничивают возможности. Понимание архитектурных различий показывает, что может предложить открытая, локальная альтернатива. ::: info WASM-рендерер Penpot Penpot 2.x включает Rust/Skia WASM рендерер (`render-wasm/v1`), который можно включить через серверные флаги или параметр `?wasm=true` в URL. Старый SVG-рендерер остаётся по умолчанию. На этой странице рассматриваются оба варианта. ::: ## 1. Масштаб и размер кодовой базы | Метрика | OpenPencil | Penpot | |--------|-------------|--------| | Всего строк кода | **~26 000** | **~299 000** | | Файлов исходного кода | ~143 | ~2 900 | | Языки | TypeScript, Vue | Clojure, ClojureScript, Rust, JS, SQL, SCSS | | Движок рендеринга | ~3 200 строк (TS, 10 файлов) | 22 000 строк (Rust/Skia WASM) | | UI-код | ~4 500 строк | ~175 000 строк (CLJS + SCSS) | | Бэкенд | Нет (локальный подход) | 32 600 строк + 151 SQL-файл | | Соотношение LOC | **1×** | **~11×** | OpenPencil **примерно в 11 раз меньше** — и в этом вся суть. Это не упрощение, а принципиально другая архитектура. ## 2. Архитектура ### OpenPencil: монолитный клиент ``` ┌─────────────────────────────────┐ │ Tauri (native shell) │ │ ┌───────────────────────────┐ │ │ │ Vue 3 + TypeScript │ │ │ │ ┌─────────┐ ┌──────────┐│ │ │ │ │ Editor │ │ Kiwi ││ │ │ │ │ Store │ │ Codec ││ │ │ │ └────┬─────┘ └──────────┘│ │ │ │ │ │ │ │ │ ┌────▼────────────────┐ │ │ │ │ │ Scene Graph (TS) │ │ │ │ │ │ Map │ │ │ │ │ └────┬────────────────┘ │ │ │ │ │ │ │ │ │ ┌────▼────┐ ┌──────────┐│ │ │ │ │ Skia │ │ Yoga ││ │ │ │ │CanvasKit│ │ Layout ││ │ │ │ │ (WASM) │ │ (WASM) ││ │ │ │ └─────────┘ └──────────┘│ │ │ └───────────────────────────┘ │ └─────────────────────────────────┘ ``` **Всё в одном процессе.** Без сервера, без базы данных, без Docker. Граф сцены — плоская `Map` в TypeScript. Рендеринг вызывает Skia CanvasKit напрямую из TS. Макет — Yoga WASM, вызываемый синхронно. ### Penpot: распределённый клиент-сервер ``` ┌───────────────────────────────────────────────────────┐ │ Docker Compose │ │ ┌──────────────┐ ┌─────────────┐ ┌──────────────┐ │ │ │ Frontend │ │ Backend │ │ Exporter │ │ │ │ ClojureScript│ │ Clojure │ │ (Chromium) │ │ │ │ shadow-cljs │ │ JVM │ │ │ │ │ │ ┌─────────┐ │ │ ┌────────┐ │ └──────────────┘ │ │ │ │render- │ │ │ │Postgres│ │ │ │ │ │wasm │ │ │ │Valkey │ │ ┌──────────────┐ │ │ │ │(Rust→ │ │ │ │ MinIO │ │ │ MCP │ │ │ │ │ Skia │ │ │ └────────┘ │ │ Server │ │ │ │ │ WASM) │ │ │ │ └──────────────┘ │ │ │ └─────────┘ │ │ │ │ │ └──────────────┘ └─────────────┘ │ └───────────────────────────────────────────────────────┘ ``` **Минимум 5+ сервисов.** PostgreSQL для хранения, Redis (Valkey) для pub/sub и кеширования, MinIO для хранения ассетов, JVM-бэкенд, Node.js экспортёр (headless Chromium для серверного рендеринга), плюс ClojureScript фронтенд. Для разработки требуется Docker Compose с настроенной сетью. ### Вердикт: архитектура Однопроцессная архитектура OpenPencil устраняет: - Сетевую задержку между фронтендом и бэкендом - Накладные расходы на сериализацию/десериализацию на границах сервисов - Сложность оркестрации контейнеров - Накладные расходы на запросы к базе данных при каждой операции Архитектура Penpot оптимизирована для **многопользовательских серверных развёртываний**. OpenPencil оптимизирован для **мгновенной локальной производительности**. ## 3. Конвейер рендеринга ### OpenPencil: TS → CanvasKit WASM (напрямую) ```typescript // renderer.ts — прямые вызовы CanvasKit из TypeScript renderSceneToCanvas(canvas, graph, pageId) { // Итерируем узлы, строим Skia paths/paints, рисуем this.fillPaint.setColor(...) canvas.drawRRect(rrect, this.fillPaint) } ``` - **1 пересечение границы:** TS → WASM (CanvasKit) - Граф сцены живёт в JS-куче — без сериализации для рендеринга - ~3 200 строк рендерера (разбит на 10 специализированных файлов: scene, overlays, fills, strokes, shapes, effects, rulers, labels) ### Penpot: JS (скомпилированный из CLJS) → Rust WASM → Skia Penpot 2.x включает Rust/Skia WASM рендерер (`render-wasm/v1`), опционально включаемый через серверные флаги или `?wasm=true`. При включении фигуры рендерятся через: ``` ClojureScript (скомпилированный в JS) → декомпозиция в примитивы + бинарная упаковка в линейную память WASM → Rust WASM (через Emscripten C FFI) → skia-safe (Rust-биндинги Skia) → Skia (WebGL) ``` При отключении (по умолчанию) фигуры рендерятся как SVG DOM-дерево через React/Reagent — каждая фигура является DOM-элементом. - **1 пересечение границы** (JS → WASM), как и у OpenPencil — но с явными накладными расходами на сериализацию: UUID разбиваются на 4×u32, трансформации на 6×f32, заливки/обводки упаковываются в бинарный формат, базовые свойства группируются в 104-байтную структуру на фигуру - Тайловая система рендеринга с областями интереса - 11 отдельных поверхностей рендеринга (заливки, обводки, тени и т.д.) - Глобальное мутабельное состояние через паттерн `unsafe { STATE.as_mut() }` - 22 000 строк Rust-движка рендеринга Тайловая система Penpot (`TileViewbox`, `TileTextureCache`, `TILE_SIZE_MULTIPLIER`) предварительно рендерит тайлы вокруг области видимости и кеширует текстуры (до 1024 записей). OpenPencil перерисовывает всю область видимости каждый кадр, потому что CanvasKit, вызываемый напрямую из TS, достаточно быстр и не нуждается в тайлинге. ### Вердикт: рендеринг | Аспект | OpenPencil | Penpot | |--------|-------------|--------| | Граница JS→WASM | Напрямую (TS-объекты) | Бинарная упаковка (104-байтная структура) | | Модель рендеринга | Немедленная/полная перерисовка | Тайловое кеширование | | Управление поверхностями | 1 поверхность | 11 поверхностей | | Расход памяти | Низкий (без кеша тайлов) | Высокий (кеш на 1024 тайла) | | Сложность кода | ~3 200 строк (10 файлов) | 22 000 строк | | Unsafe-код | Нет | `unsafe` глобальное состояние | Когда WASM-рендерер Penpot включён, оба проекта используют Skia через JS→WASM. OpenPencil вызывает CanvasKit напрямую с TS-объектами. Penpot декомпозирует данные ClojureScript в бинарно упакованные структуры, записывает их в линейную память WASM и рендерит через 22 000-строчный Rust-движок. При отключённом WASM (по умолчанию) Penpot рендерит фигуры как SVG DOM-дерево. Для малых и средних документов прямой путь через CanvasKit быстрее. Тайловая система Penpot может выигрывать на очень больших канвасах (100K+ фигур), где видна лишь малая область — но накладные расходы значительны. ## 4. Граф сцены и модель данных ### OpenPencil ```typescript // Плоская карта, O(1) поиск nodes: Map // 29 типов узлов из Kiwi-схемы Figma // ~390 полей на NodeChange (совместимо с Figma) ``` - TypeScript-интерфейсы со строгой типизацией - GUID соответствуют формату Figma `sessionID:localID` - Прямой доступ к свойствам — без слоёв косвенности ### Penpot ```clojure ;; 20+ файлов определений типов в common/src/app/common/types/ ;; shapes_builder.cljc, shapes_helpers.cljc ;; Отдельные системы типов для: color, component, container, fills, ;; grid, modifiers, objects_map, page, path и т.д. ``` - Данные распределены по `common/` (49 600 строк .cljc) - Отдельные модули геометрии для flex-макета (~6 файлов), grid-макета (~5 файлов), ограничений, границ, углов, эффектов - Валидация схем в рантайме (Malli) - Данные должны пересекать границу CLJS→Rust для рендеринга ### Вердикт: модель данных OpenPencil использует проверенную схему Figma (194 определения Kiwi) напрямую в TypeScript — без преобразований. Penpot поддерживает собственную систему типов в Clojure/ClojureScript/Rust, требующую ручной синхронизации между всеми тремя. ## 5. Движок макетов ### OpenPencil: Yoga WASM (314 строк) ```typescript import Yoga from 'yoga-layout' // Прямое сопоставление: поля Figma stack* → свойства Yoga flex const root = Yoga.Node.create() root.setFlexDirection(FlexDirection.Row) root.calculateLayout() applyYogaLayout(graph, frame, yogaRoot) ``` 314 строк всего. Синхронно, внутри процесса. ### Penpot: двойная реализация 1. **ClojureScript** (common): `flex_layout/` (6 файлов), `grid_layout/` (5+ файлов) — собственные реализации 2. **Rust WASM**: `flex_layout.rs` (741 строка), `grid_layout.rs` (843 строки) — реализовано с нуля Penpot поддерживает **два независимых движка макетов** (CLJS и Rust), которые должны давать идентичные результаты. ### Вердикт: макет OpenPencil делегирует проверенной библиотеке (Yoga, используется React Native на миллиардах устройств) в 314 строках. Penpot поддерживает ~3 000+ строк собственного кода макета, дублированного на двух языках. ## 6. Формат файлов и совместимость с Figma ### OpenPencil - **Нативный бинарный формат Kiwi** — та же сериализация, что использует Figma внутри - Прямой импорт файлов `.fig` через извлечённый Kiwi-кодек (2 178 строк схемы + 551 строка кодека) - Поддержка вставки из буфера обмена Figma (чтение бинарного Kiwi из буфера обмена) - Совместимость на уровне протокола с мультиплеерным протоколом Figma ### Penpot - **ZIP-архив** (файлы `.penpot`), содержащий JSON-манифесты, JSON-данные по файлам, бинарные ассеты и миниатюры (формат v3) - SVG используется для рендеринга по умолчанию и экспорта (опциональный WASM-рендерер доступен) - Нет нативного импорта `.fig` - Три версии формата (v1 legacy Transit, v2, v3 JSON-in-ZIP) с системой миграции ### Вердикт: формат файлов OpenPencil имеет значительное преимущество — он может читать файлы Figma нативно и даже вставлять данные из буфера обмена Figma. Penpot требует ручного экспорта/импорта и не может открывать файлы `.fig`. ## 7. Управление состоянием и отмена ### OpenPencil ```typescript // 110 строк — паттерн обратных команд class UndoManager { apply(entry: UndoEntry) { entry.forward(); this.undoStack.push(entry) } undo() { entry.inverse(); this.redoStack.push(entry) } } ``` 110 строк. Forward/inverse замыкания, захватывающие минимальное состояние. Поддержка группировки для многоэтапных операций. ### Penpot Управление состоянием использует Potok (Redux-подобная библиотека для ClojureScript atoms). События реализуют `UpdateEvent` (чистое state→state) или `WatchEvent` (побочные эффекты через RxJS). Отмена хранит обратные векторы изменений (максимум 50 записей), с транзакциями для группировки быстрых изменений и авто-истечением через 20 секунд. ### Вердикт: состояние Подход OpenPencil проще и с меньшими накладными расходами. Подход Penpot больше подходит для совместной работы (изменения сериализуемы), но ценой сложности. ## 8. Опыт разработчика | Метрика | OpenPencil | Penpot | |--------|-------------|--------| | Настройка среды | `bun install && bun dev` | Docker Compose + JVM + Node + Rust toolchain | | Горячая перезагрузка | Vite HMR (~50мс) | shadow-cljs (секунды) | | Проверка типов | TypeScript (строгий) | В рантайме (схемы Malli) | | Время сборки | <5с (Vite) | Минуты (запуск JVM + компиляция CLJS + Rust WASM) | | Порог первого вклада | Низкий (TS/Vue) | Высокий (Clojure + Rust + Docker) | | Десктоп | Tauri v2 (~5 МБ) | Н/Д (только браузер) | | Пул разработчиков | Огромный (TS/Vue) | Крошечный (ClojureScript + Rust) | ## 9. Характеристики производительности | Сценарий | OpenPencil | Penpot | |----------|-------------|--------| | Холодный старт | <2с (загрузка WASM) | 10с+ (сервер + клиент + WASM) | | Задержка операций | <1мс (в процессе) | 10-50мс (сетевой round-trip) | | Кадр рендеринга | Прямой вызов Skia | CLJS→JS→WASM FFI→Skia | | Базовый расход памяти | ~50 МБ (вкладка браузера) | ~300 МБ+ (JVM + Postgres + Valkey + браузер) | | Работа офлайн | Полная (локальный подход) | Нет (зависимость от сервера) | | Рендеринг 10K фигур | Один проход, без кеширования | Тайловый с 11 поверхностями | ## 10. В чём Penpot лучше 1. **Серверная совместная работа** — централизованное многопользовательское редактирование с WebSockets, учётными записями и контролем доступа (OpenPencil использует P2P через Trystero + Yjs — без сервера, но и без контроля доступа или сохранения за пределами сессии) 2. **Экспорт PDF** — headless Chromium для серверного PDF-рендеринга (OpenPencil экспортирует SVG, но пока не PDF) 3. **Система плагинов** — полный API плагинов с изолированным выполнением 4. **Дизайн-токены** — нативная поддержка дизайн-токенов 5. **Макет CSS Grid** — собственная реализация (OpenPencil ждёт Yoga Grid) 6. **Самостоятельный хостинг** — развёртывание на Docker для команд 7. **Зрелость** — годы использования в продакшене, проверенный масштабированием ## 11. Скриптинг и расширяемость OpenPencil поставляется с [командой `eval`](/programmable/cli/scripting), предоставляющей Figma-совместимый Plugin API для headless-скриптинга — пакетные операции, автоматизированное тестирование и ИИ-модификации работают без GUI. Кроме того, **90 ИИ-инструментов** доступны через встроенный чат, MCP-сервер (stdio + HTTP) и CLI — охватывающие чтение, создание, модификацию, структуру, переменные, векторные пути, анализ (цвета/типографика/отступы/кластеры), сравнение, булевые операции и упорядочивание. Penpot имеет систему плагинов с изолированным выполнением, но без headless-скриптинга или интеграции MCP. ## Итоги | Аспект | Лидер | Почему | |-----------|--------|-----| | **Простота архитектуры** | OpenPencil | Один процесс vs 5+ сервисов | | **Производительность рендеринга** | OpenPencil | Прямой CanvasKit vs SVG DOM (по умолчанию) или бинарно упакованный WASM | | **Поддерживаемость кода** | OpenPencil | ~26K строк на 1 языке vs 299K на 4+ языках | | **Совместимость с Figma** | OpenPencil | Нативный Kiwi-кодек vs отсутствие поддержки .fig | | **Онбординг разработчиков** | OpenPencil | TS/Vue vs Clojure/Rust/Docker | | **Десктоп** | OpenPencil | Нативный Tauri vs только браузер | | **Движок макетов** | OpenPencil | Yoga (проверенный) vs собственная двойная реализация | | **Совместная работа** | Ничья | Penpot: серверная с контролем доступа; OpenPencil: P2P через Trystero + Yjs, без хостинга | | **Самостоятельный хостинг** | Penpot | Docker-ready vs только десктоп | | **Зрелость экосистемы** | Penpot | Годы продакшена vs ранняя стадия | OpenPencil архитектурно легче — однопроцессный CanvasKit-рендерер в ~26K строках TypeScript, совместимый с Figma по дизайну. Penpot — полноценная платформа с ~299K строками на Clojure, ClojureScript, Rust и SCSS, плюс парк Docker-сервисов. Оба предлагают совместную работу в реальном времени (с разными архитектурами: P2P vs сервер). Penpot имеет экосистему плагинов и серверный экспорт PDF; OpenPencil имеет Figma-совместимый headless-скриптинг, **90 ИИ/MCP инструментов**, экспорт SVG и нативное десктоп-приложение.