* docs: polish localized documentation - Rewrite Russian documentation for natural terminology and current source parity\n- Continue the Polish editorial pass across guides and SDK references\n- Refresh shared localized SDK API data imports * docs(pl): complete editorial pass - Rewrite the remaining advanced Vue SDK references\n- Refresh the Figma compatibility matrix against the canonical source\n- Align terminology and behavior across every Polish documentation page * docs(de): complete editorial pass - Rewrite German guides, automation docs, and Vue SDK references\n- Restore current AI, export, component, and variable behavior\n- Refresh the Penpot comparison and Figma compatibility matrix * docs(es): complete editorial pass - Rewrite Spanish guides, automation docs, and Vue SDK references\n- Restore current AI, export, component, and variable behavior\n- Refresh the Penpot comparison and Figma compatibility matrix * docs(fr): complete editorial pass - Rewrite French guides, automation docs, and Vue SDK references\n- Restore current AI, export, component, and variable behavior\n- Refresh the Penpot comparison and Figma compatibility matrix * docs: correct localized terminology - Replace unnecessary English prose with natural localized terminology\n- Derive documentation aliases from named directory roots\n- Preserve English only for identifiers, APIs, and exact product terms * docs(it): continue editorial pass - Rewrite Italian user guides and automation documentation\n- Update Vue SDK composables and component references\n- Restore current AI, export, component, and variable behavior * docs(it): complete editorial pass - Finish Italian advanced SDK and reference documentation\n- Refresh the Penpot comparison and Figma compatibility matrix\n- Replace literal machine translations with natural technical prose * docs(pl): refine property panel terminology * docs: refine remaining localized prose - Replace overfitted English prose in Polish feature documentation\n- Rewrite the Russian property-list reference in natural terminology * docs(ru): rewrite Penpot comparison naturally - Replace remaining English prose with natural Russian\n- Preserve code identifiers and library names only where required * docs: rewrite localized feature overviews naturally - Replace avoidable English prose in German, Spanish, and French\n- Keep identifiers and product names unchanged * docs(de): refine property panel terminology * docs: refine Spanish and French SDK terminology * docs(ru): continue full prose audit - Rewrite homepage, setup, navigation, and guide index naturally\n- Restore missing zoom shortcuts * docs(ru): audit user and automation guides - Rewrite selection, collaboration, and automation prose naturally\n- Preserve API identifiers while localizing ordinary terminology * docs(ru): audit CLI inspection and analysis * docs(ru): audit Vue SDK overview and guides * docs(ru): audit Vue SDK API prose - Localize ordinary component and composable terminology\n- Preserve API symbols and code identifiers * docs(ru): audit advanced and gradient API references * docs(ru): finish advanced API prose audit * docs(ru): audit JSX renderer guide * docs(ru): audit CLI export and scripting guides * docs(pl): audit Penpot comparison prose * docs(pl): audit selection and automation guides * docs(pl): audit homepage and variable guides * docs(pl): audit vector, layers, and Pen guides * docs(pl): audit Auto layout and shape guides * docs(pl): audit context menu and export guides * docs(pl): audit JSX and analysis guides * docs(pl): audit AI Chat guide * docs(pl): audit components and CLI inspection * docs(pl): audit scripting and SDK overview prose * docs(pl): audit SDK API indexes * docs(pl): audit SDK component references * docs(pl): audit SDK composable references * docs(ru): refine usePosition terminology * docs(pl): audit advanced SDK references * docs(pl): audit Figma compatibility matrix * docs(pl): finish residual SDK terminology audit * docs(pl): finish component terminology audit * docs(pl): finish SDK guide terminology audit * docs(de): begin full user guide prose audit * docs(de): audit navigation, Pen, and layers guides * docs(de): audit Auto Layout, shapes, menu, and export * docs(de): audit components, text, and vector guides * docs(de): audit variables and automation overview * docs(de): audit AI Chat and collaboration guides * docs(de): audit CLI inspection, analysis, and export * docs(de): audit scripting and JSX guides * docs(de): audit Vue SDK overview and guides * docs(de): audit SDK API indexes * docs(de): audit SDK component references * docs(de): audit SDK composable references * docs(de): audit advanced SDK references * docs(de): audit Penpot comparison prose * docs(de): audit Figma compatibility reference * docs(es): begin full user guide prose audit * docs(es): audit document organization guides * docs(es): audit editing workflow guides * docs(es): audit automation and collaboration prose * docs(es): audit CLI inspection and export guides * docs(es): audit CLI scripting guide * docs(es): audit JSX and feature overview prose * docs(es): audit Penpot comparison prose * docs(es): audit SDK overview and guides * docs(es): begin SDK component reference audit * docs(es): audit SDK navigation component references * docs(es): audit SDK color and layout components * docs(es): begin SDK composable reference audit * docs(es): audit SDK property composable references * docs(es): audit SDK editor composable references * docs(es): begin advanced SDK reference audit * docs(es): audit advanced SDK state references * docs(es): complete advanced SDK reference audit * docs(es): audit Figma compatibility reference * docs(es): complete residual terminology sweep * docs(fr): begin full prose second audit * docs(fr): audit AI and variables prose * docs(fr): audit core user guide prose * docs(fr): audit editing workflow guides * docs(fr): audit CLI and JSX prose * docs(fr): audit Penpot comparison prose * docs(fr): audit SDK overview and guides * docs(fr): begin SDK API reference audit * docs(fr): audit SDK navigation component references * docs(fr): audit SDK color and layout components * docs(fr): begin SDK composable reference audit * docs(fr): audit SDK property composable references * docs(fr): audit editor composables and advanced APIs * docs(fr): audit advanced SDK state references * docs(fr): complete advanced SDK reference audit * docs(fr): audit Figma compatibility reference * docs(fr): complete residual terminology sweep * docs(it): begin full prose second audit * docs(it): audit document workflow guides * docs(it): audit editing and automation prose * docs(it): audit CLI and JSX prose * docs(it): audit Penpot comparison and SDK guides * docs(it): begin SDK API reference audit * docs(it): audit SDK component and state references * docs(it): audit residual SDK references * docs(it): audit Figma compatibility reference * docs(it): complete residual terminology sweep * docs(i18n): verify residual locale terminology
213 lines
11 KiB
Markdown
213 lines
11 KiB
Markdown
# OpenPencil y Penpot: arquitectura y rendimiento
|
||
|
||
OpenPencil y Penpot son herramientas de diseño de código abierto con objetivos y arquitecturas distintos.
|
||
|
||
::: info Renderizador WASM de Penpot
|
||
Penpot 2.x incluye el renderizador Rust/Skia WASM `render-wasm/v1`, que se activa mediante opciones del servidor o `?wasm=true`. El renderizador SVG sigue siendo el predeterminado. La comparación tiene en cuenta ambas opciones.
|
||
:::
|
||
|
||
## 1. Tamaño del código
|
||
|
||
| Métrica | OpenPencil | Penpot |
|
||
|---------|------------|--------|
|
||
| Lines of code | **unas 26.000** | **unas 299.000** |
|
||
| Archivos fuente | unos 143 | unos 2.900 |
|
||
| Lenguajes | TypeScript, Vue | Clojure, ClojureScript, Rust, JavaScript, SQL, SCSS |
|
||
| Renderizador | unas 3.200 líneas, TypeScript | 22.000 líneas, Rust/Skia WASM |
|
||
| Interfaz | unas 4.500 líneas | unas 175.000 líneas, CLJS y SCSS |
|
||
| Servidor | Ninguno, arquitectura local | 32.600 líneas y 151 archivos SQL |
|
||
| Proporción | **1×** | **unas 11×** |
|
||
|
||
OpenPencil es unas once veces más pequeño. La diferencia se debe sobre todo a la arquitectura, no únicamente al número de funciones.
|
||
|
||
## 2. Arquitectura
|
||
|
||
### OpenPencil: un solo proceso cliente
|
||
|
||
```text
|
||
┌─────────────────────────────────┐
|
||
│ Tauri native shell │
|
||
│ ┌───────────────────────────┐ │
|
||
│ │ Vue 3 + TypeScript │ │
|
||
│ │ Editor + Kiwi codec │ │
|
||
│ │ SceneGraph in TypeScript │ │
|
||
│ │ CanvasKit + Yoga WASM │ │
|
||
│ └───────────────────────────┘ │
|
||
└─────────────────────────────────┘
|
||
```
|
||
|
||
Editor, SceneGraph, códec de archivos y renderizador se ejecutan en el mismo proceso. No se necesita servidor, base de datos ni Docker. SceneGraph se almacena como `Map<string, SceneNode>`. TypeScript llama directamente a CanvasKit y Yoga WASM calcula la disposición de forma síncrona.
|
||
|
||
### Penpot: plataforma Client-Server
|
||
|
||
```text
|
||
┌───────────────────────────────────────────────────────┐
|
||
│ Docker Compose │
|
||
│ ClojureScript frontend │ Clojure/JVM backend │
|
||
│ Rust/Skia WASM │ PostgreSQL, Valkey, MinIO │
|
||
│ Chromium exporter │ MCP server │
|
||
└───────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
Un despliegue completo de Penpot incluye interfaz, servidor JVM, PostgreSQL, Valkey, MinIO y un exportador basado en Chromium sin interfaz. El entorno de desarrollo requiere Docker Compose, JVM, Node y las herramientas de Rust.
|
||
|
||
OpenPencil evita latencia de red, serialización entre servicios, coordinación de contenedores y consultas de base de datos en las operaciones habituales. Penpot está pensado como plataforma multiusuario alojada en un servidor; OpenPencil prioriza la edición local con baja latencia.
|
||
|
||
## 3. Proceso de renderizado
|
||
|
||
### OpenPencil: TypeScript → CanvasKit WASM
|
||
|
||
```typescript
|
||
renderSceneToCanvas(canvas, graph, pageId) {
|
||
this.fillPaint.setColor(...)
|
||
canvas.drawRRect(rrect, this.fillPaint)
|
||
}
|
||
```
|
||
|
||
- Paso directo de TypeScript a WASM.
|
||
- SceneGraph permanece en el JavaScript heap y no se serializa antes del Rendering.
|
||
- El renderizador contiene unas 3.200 líneas distribuidas en módulos especializados.
|
||
|
||
### Penpot: ClojureScript → Rust WASM → Skia
|
||
|
||
Con el renderizador WASM activado:
|
||
|
||
```text
|
||
ClojureScript → JavaScript
|
||
→ descomposición y Binary packing en WASM linear memory
|
||
→ Rust WASM mediante Emscripten C FFI
|
||
→ skia-safe
|
||
→ Skia/WebGL
|
||
```
|
||
|
||
Sin WASM, cada Shape se renderiza como SVG DOM element mediante React/Reagent.
|
||
|
||
En modo WASM, cada UUID se divide en cuatro `u32`, cada transformación en seis `f32`, los rellenos y contornos se codifican en binario y las propiedades básicas de una forma ocupan una estructura de 104 bytes. El renderizador usa caché de teselas, áreas de interés, once superficies y estado global mutable mediante `unsafe { STATE.as_mut() }`.
|
||
|
||
El Tile system prepara zonas próximas al Viewport y almacena hasta 1.024 Textures. OpenPencil vuelve a renderizar toda la zona visible.
|
||
|
||
| Aspecto | OpenPencil | Penpot |
|
||
|---------|------------|--------|
|
||
| JavaScript → WASM | Calls directos con objetos TypeScript | Structures codificadas en Binary |
|
||
| Modelo | Render completo del Viewport visible | Tile cache |
|
||
| Surfaces | 1 | 11 |
|
||
| Caché adicional | Sin Tile cache | Hasta 1.024 Tiles |
|
||
| Tamaño del renderizador | unas 3.200 líneas | 22.000 líneas |
|
||
| Código no seguro | Ninguno | Estado global mediante `unsafe` |
|
||
|
||
El Path directo de CanvasKit necesita menos procesamiento intermedio en documentos pequeños y medianos. El Tile system de Penpot puede resultar ventajoso en documentos con más de 100.000 Shapes cuando solo se muestra una zona reducida.
|
||
|
||
## 4. SceneGraph y modelo de datos
|
||
|
||
```typescript
|
||
nodes: Map<string, SceneNode>
|
||
```
|
||
|
||
OpenPencil ofrece:
|
||
|
||
- búsqueda por identificador en O(1);
|
||
- 29 tipos de objeto del esquema Kiwi de Figma;
|
||
- unos 390 campos en `NodeChange`;
|
||
- tipos estrictos de TypeScript;
|
||
- GUID con formato `sessionID:localID` de Figma.
|
||
|
||
Penpot mantiene definiciones de tipos propias en Clojure/ClojureScript y Rust. Módulos distintos gestionan colores, componentes, contenedores, rellenos, Grid, modificadores, páginas y rutas. Malli valida esquemas en tiempo de ejecución y los datos de renderizado cruzan el límite CLJS → Rust.
|
||
|
||
OpenPencil utiliza directamente el esquema Kiwi. Penpot debe mantener sincronizado su modelo entre varios lenguajes.
|
||
|
||
## 5. Motor de disposición
|
||
|
||
OpenPencil usa Yoga WASM de forma síncrona:
|
||
|
||
```typescript
|
||
import Yoga from 'yoga-layout'
|
||
const root = Yoga.Node.create()
|
||
root.setFlexDirection(FlexDirection.Row)
|
||
root.calculateLayout()
|
||
applyYogaLayout(graph, frame, yogaRoot)
|
||
```
|
||
|
||
Penpot mantiene implementaciones propias de Flex y Grid en ClojureScript y Rust WASM. Ambos motores deben producir el mismo resultado.
|
||
|
||
OpenPencil utiliza Yoga, incluida una variante con Grid. Penpot mantiene varios miles de líneas de código propio de disposición en dos lenguajes.
|
||
|
||
## 6. Formatos y Figma
|
||
|
||
### OpenPencil
|
||
|
||
- Formato Binary Kiwi nativo de Figma.
|
||
- Import directo de `.fig`.
|
||
- Paste de Kiwi binary data desde Figma Clipboard.
|
||
- Wire compatibility con Figma Multiplayer protocol.
|
||
|
||
### Penpot
|
||
|
||
- `.penpot` es un ZIP con JSON manifests, Document data, Binary assets y Thumbnails.
|
||
- SVG renderer y Export predeterminados; WASM renderer opcional.
|
||
- Sin Import nativo de `.fig`.
|
||
- Varias Generations del formato con Migration system.
|
||
|
||
OpenPencil lee `.fig` y Figma Clipboard directamente. Penpot necesita una vía de Import o Export separada.
|
||
|
||
## 7. Estado y deshacer
|
||
|
||
OpenPencil usa comandos inversos. Las funciones de avance y retroceso guardan solo el estado necesario; los lotes agrupan varias operaciones.
|
||
|
||
Penpot usa Potok. `UpdateEvent` modifica el estado y `WatchEvent` ejecuta efectos secundarios mediante RxJS. Deshacer almacena vectores de cambios inversos, limita el historial a 50 entradas y agrupa cambios rápidos en transacciones.
|
||
|
||
Los cambios serializables encajan con la colaboración basada en servidor, pero aumentan la complejidad. El enfoque de OpenPencil es más directo para un editor de un solo proceso.
|
||
|
||
## 8. Desarrollo
|
||
|
||
| Métrica | OpenPencil | Penpot |
|
||
|---------|------------|--------|
|
||
| Setup | `bun install && bun dev` | Docker Compose, JVM, Node y Rust |
|
||
| HMR | Vite | shadow-cljs |
|
||
| Types | Strict TypeScript | Malli runtime schemas |
|
||
| Desktop | Tauri v2 | Browser |
|
||
| Tecnologías principales | TypeScript y Vue | Clojure, ClojureScript, Rust y Docker |
|
||
|
||
## 9. Rendimiento
|
||
|
||
| Escenario | OpenPencil | Penpot |
|
||
|-----------|------------|--------|
|
||
| Arranque en frío | menos de 2 s con WASM | más de 10 s para servidor, cliente y WASM |
|
||
| Operación habitual | Dentro de un proceso | Posible recorrido de red |
|
||
| Fotograma | Llamada directa a Skia | CLJS → JS → WASM FFI → Skia |
|
||
| Memoria base | unos 50 MB en la pestaña del navegador | JVM, base de datos, caché y navegador |
|
||
| Sin conexión | Funcionamiento local completo | Requiere servidor |
|
||
| 10.000 formas | Una pasada | Renderizador por teselas con once superficies |
|
||
|
||
## 10. Ventajas de Penpot
|
||
|
||
1. **Colaboración mediante servidor:** cuentas, control de acceso y almacenamiento central a través de WebSockets.
|
||
2. **Exportación PDF:** exportador independiente basado en Chromium.
|
||
3. **Sistema de plugins:** ejecución aislada y API de plugins.
|
||
4. **Variables de diseño:** compatibilidad integrada.
|
||
5. **CSS Grid:** implementación propia; OpenPencil usa una variante de Yoga con Grid.
|
||
6. **Alojamiento propio:** despliegue de una plataforma de equipo mediante Docker.
|
||
7. **Madurez:** varios años de uso en producción.
|
||
|
||
## 11. Scripts y extensibilidad
|
||
|
||
El comando [`eval`](/programmable/cli/scripting) proporciona una API compatible con plugins de Figma para scripts sin interfaz, operaciones por lotes y pruebas automatizadas. Además, el chat con AI, el servidor MCP y la CLI ofrecen 90 herramientas para leer, crear, modificar, estructurar, gestionar variables, editar rutas vectoriales, analizar, comparar, ejecutar operaciones booleanas y ordenar.
|
||
|
||
Penpot ofrece plugins aislados, pero no una API equivalente para scripting sin interfaz ni integración MCP.
|
||
|
||
## Resumen
|
||
|
||
| Área | Ventaja | Motivo |
|
||
|------|---------|--------|
|
||
| Simplicidad | OpenPencil | Un proceso en lugar de varios servicios |
|
||
| Renderizado | OpenPencil | Ruta directa a CanvasKit |
|
||
| Código | OpenPencil | Unas 26.000 frente a 299.000 líneas |
|
||
| Compatibilidad con Figma | OpenPencil | Kiwi y `.fig` nativos |
|
||
| Desarrollo | OpenPencil | TypeScript y Vue frente a Clojure, Rust y Docker |
|
||
| Aplicación de escritorio | OpenPencil | Tauri nativo |
|
||
| Disposición | OpenPencil | Yoga frente a dos implementaciones propias |
|
||
| Colaboración | Ventajas distintas | Penpot: servidor y control de acceso; OpenPencil: P2P sin alojamiento |
|
||
| Alojamiento propio | Penpot | Despliegue con Docker |
|
||
| Madurez del ecosistema | Penpot | Años de uso en producción |
|
||
|
||
OpenPencil es un editor compacto de un solo proceso con renderizador CanvasKit y compatibilidad nativa con `.fig`. Penpot es una plataforma cliente-servidor completa con Clojure, ClojureScript, Rust, bases de datos y servicios Docker. Ambos ofrecen colaboración con modelos diferentes. Penpot tiene un ecosistema de plugins y exportación PDF; OpenPencil ofrece scripting sin interfaz compatible con Figma, 90 herramientas AI/MCP, exportación SVG y una aplicación de escritorio.
|