Skip to content

Open Pencil vs Penpot: Comparación de arquitectura y rendimiento

¿Por qué comparar? OpenPencil existe porque las plataformas de diseño cerradas controlan lo que es posible. Entender las diferencias arquitectónicas muestra lo que una alternativa abierta y local-first puede hacer diferente.

Renderer WASM de Penpot

Penpot 2.x incluye un renderer Rust/Skia WASM (render-wasm/v1) activable vía flags del servidor o el parámetro URL ?wasm=true. El renderer SVG antiguo sigue siendo el predeterminado. Esta página cubre ambos.

1. Escala y tamaño del código

MétricaOpen PencilPenpot
LOC total~26.000~299.000
Archivos fuente~143~2.900
LenguajesTypeScript, VueClojure, ClojureScript, Rust, JS, SQL, SCSS
Motor de renderizado~3.200 LOC (TS, 10 Dateien)22.000 LOC (Rust/Skia WASM)
Código UI~4.500 LOC~175.000 LOC (CLJS + SCSS)
BackendNinguno (local-first)32.600 LOC + 151 archivos SQL
Ratio LOC~11×

Open Pencil es ~11× más pequeño — y ese es el punto. No es una simplificación; es una arquitectura fundamentalmente diferente.

2. Arquitectura

Open Pencil: cliente monolítico

┌─────────────────────────────────┐
│         Tauri (shell nativo)    │
│  ┌───────────────────────────┐  │
│  │  Vue 3 + TypeScript       │  │
│  │  ┌─────────┐ ┌──────────┐│  │
│  │  │  Editor  │ │  Kiwi    ││  │
│  │  │  Store   │ │  Codec   ││  │
│  │  └────┬─────┘ └──────────┘│  │
│  │       │                    │  │
│  │  ┌────▼────────────────┐  │  │
│  │  │  Scene Graph (TS)    │  │  │
│  │  │  Map<string, Node>   │  │  │
│  │  └────┬────────────────┘  │  │
│  │       │                    │  │
│  │  ┌────▼────┐ ┌──────────┐│  │
│  │  │  Skia   │ │  Yoga    ││  │
│  │  │CanvasKit│ │  Layout  ││  │
│  │  │  (WASM) │ │  (WASM)  ││  │
│  │  └─────────┘ └──────────┘│  │
│  └───────────────────────────┘  │
└─────────────────────────────────┘

Todo en un proceso. Sin servidor, sin base de datos, sin Docker. El grafo de escena es un Map<string, SceneNode> plano en TypeScript. El renderizado llama a Skia CanvasKit directamente desde TS. El layout es Yoga WASM llamado síncronamente.

Penpot: cliente-servidor distribuido

┌───────────────────────────────────────────────────────┐
│                    Docker Compose                      │
│  ┌──────────────┐  ┌─────────────┐  ┌──────────────┐ │
│  │   Frontend    │  │   Backend   │  │   Exporter   │ │
│  │  ClojureScript│  │   Clojure   │  │  (Chromium)  │ │
│  │  shadow-cljs  │  │   JVM       │  │              │ │
│  │  ┌─────────┐ │  │  ┌────────┐ │  └──────────────┘ │
│  │  │render-  │ │  │  │Postgres│ │                    │
│  │  │wasm     │ │  │  │Valkey  │ │  ┌──────────────┐ │
│  │  │(Rust→   │ │  │  │ MinIO  │ │  │   MCP        │ │
│  │  │ Skia    │ │  │  └────────┘ │  │   Server     │ │
│  │  │ WASM)   │ │  │             │  └──────────────┘ │
│  │  └─────────┘ │  │             │                    │
│  └──────────────┘  └─────────────┘                    │
└───────────────────────────────────────────────────────┘

Mínimo 5+ servicios. PostgreSQL para persistencia, Redis (Valkey) para pub/sub y caché, MinIO para almacenamiento de assets, un backend JVM, un exportador Node.js (Chromium headless), más el frontend ClojureScript.

Veredicto: Arquitectura

La arquitectura de proceso único de Open Pencil elimina: latencia de red entre frontend y backend, overhead de serialización/deserialización en los límites de servicios, complejidad de orquestación de contenedores y overhead de consultas de base de datos.

3. Pipeline de renderizado

Open Pencil: TS → CanvasKit WASM (directo)

typescript
// renderer.ts — llamadas directas a CanvasKit desde TypeScript
renderSceneToCanvas(canvas, graph, pageId) {
  this.fillPaint.setColor(...)
  canvas.drawRRect(rrect, this.fillPaint)
}
  • 1 cruce de límite: TS → WASM (CanvasKit)
  • El grafo de escena vive en el heap JS — sin serialización para renderizar
  • 1.646 LOC de renderer total

Penpot: JS (compilado de CLJS) → Rust WASM → Skia

ClojureScript (compilado a JS)
  → descomponer a primitivas + empaquetar en binario en memoria lineal WASM
  → Rust WASM (vía Emscripten C FFI)
  → skia-safe (bindings Rust de Skia)
  → Skia (WebGL)

Cuando está deshabilitado (predeterminado), las formas se renderizan como un árbol DOM SVG. Cuando está habilitado, usa un sistema de renderizado basado en tiles con 11 superficies separadas y caché de hasta 1024 entradas.

Veredicto: Renderizado

AspectoOpen PencilPenpot
Límite JS→WASMDirecto (objetos TS)Empaquetado binario (104 bytes por forma)
Modelo de renderizadoInmediato/redibujado completoCaché por tiles
Gestión de superficies1 superficie11 superficies
Overhead de memoriaBajo (sin caché de tiles)Alto (1024 entradas caché)
Complejidad de código1.646 LOC22.000 LOC
Código inseguroNingunoEstado global unsafe

4. Grafo de escena y modelo de datos

Open Pencil

typescript
// Mapa plano, búsqueda O(1)
nodes: Map<string, SceneNode>
// 29 tipos de nodo del esquema Kiwi de Figma
// ~390 campos por NodeChange (compatible con Figma)
  • Interfaces TypeScript con tipos estrictos
  • GUIDs coinciden con el formato sessionID:localID de Figma
  • Acceso directo a propiedades — sin capas de indirección

Penpot

  • Datos distribuidos en common/ (49.600 LOC de .cljc)
  • Módulos de geometría separados para flex layout, grid layout, constraints, bounds, esquinas, efectos
  • Validación de esquema en runtime (Malli)
  • Los datos deben cruzar el límite CLJS→Rust para renderizado

Veredicto: Modelo de datos

Open Pencil reutiliza el esquema probado de Figma (194 definiciones Kiwi) directamente en TypeScript — cero traducción. Penpot mantiene su propio sistema de tipos a través de Clojure/ClojureScript/Rust, requiriendo sincronización manual entre los tres.

5. Motor de layout

Open Pencil: Yoga WASM (314 LOC)

typescript
import Yoga from 'yoga-layout'
const root = Yoga.Node.create()
root.setFlexDirection(FlexDirection.Row)
root.calculateLayout()
applyYogaLayout(graph, frame, yogaRoot)

314 líneas total. Síncrono, en proceso.

Penpot: Implementación dual

  1. ClojureScript (common): flex_layout/ (6 archivos), grid_layout/ (5+ archivos)
  2. Rust WASM: flex_layout.rs (741 LOC), grid_layout.rs (843 LOC)

Penpot mantiene dos motores de layout independientes que deben producir resultados idénticos.

Veredicto: Layout

Open Pencil delega en una librería probada (Yoga, usada por React Native en miles de millones de dispositivos) en 314 líneas. Penpot mantiene ~3.000+ LOC de código de layout personalizado duplicado.

6. Formato de archivo y compatibilidad con Figma

Open Pencil

  • Formato binario Kiwi nativo — misma serialización que usa Figma internamente
  • Import directo de archivos .fig vía codec Kiwi extraído (2.178 LOC esquema + 551 LOC codec)
  • Soporte de pegado desde el portapapeles de Figma
  • Compatible con el protocolo multiplayer de Figma

Penpot

  • Archivo ZIP (.penpot) con manifiestos JSON y assets binarios
  • Sin import nativo de .fig
  • Tres versiones de formato con sistema de migración

Veredicto: Formato de archivo

Open Pencil tiene una ventaja significativa — puede leer archivos Figma nativamente y pegar datos del portapapeles de Figma.

7. Gestión de estado y deshacer

Open Pencil

typescript
// 110 LOC — patrón de comando inverso
class UndoManager {
  apply(entry: UndoEntry) { entry.forward(); this.undoStack.push(entry) }
  undo() { entry.inverse(); this.redoStack.push(entry) }
}

110 líneas. Closures forward/inverse que capturan estado mínimo.

Penpot

Gestión de estado usa Potok (librería tipo Redux para átomos ClojureScript). Undo almacena vectores de cambios inversos (máximo 50 entradas), con transacciones y auto-expiración tras 20 segundos.

Veredicto: Estado

El enfoque de Open Pencil es más simple y con menos overhead.

8. Experiencia de desarrollo

MétricaOpen PencilPenpot
Setup de devbun install && bun devDocker Compose + JVM + Node + Rust toolchain
Recarga en calienteVite HMR (~50ms)shadow-cljs (segundos)
Verificación de tiposTypeScript (estricto)Runtime (esquemas Malli)
Tiempo de build<5s (Vite)Minutos (JVM startup + CLJS compile + Rust WASM)
Barrera primera contribuciónBaja (TS/Vue)Alta (Clojure + Rust + Docker)
DesktopTauri v2 (~5MB)N/A (solo navegador)
Pool de contrataciónMasivo (devs TS/Vue)Pequeño (ClojureScript + Rust)

9. Características de rendimiento

EscenarioOpen PencilPenpot
Arranque en frío<2s (carga WASM)10s+ (servidor + cliente + WASM)
Latencia de operación<1ms (en proceso)10-50ms (round-trip red)
Frame de renderLlamada Skia directaCLJS→JS→WASM FFI→Skia
Memoria base~50MB (pestaña navegador)~300MB+ (JVM + Postgres + Valkey + navegador)
Capacidad offlineCompleta (local-first)Ninguna (depende del servidor)
Render 10K formasUna pasada, sin cachéBasado en tiles con 11 superficies

10. Lo que Penpot hace mejor

  1. Colaboración servidor — edición multiusuario centralizada con WebSockets, cuentas y control de acceso
  2. Exportación PDF en servidor — servicio de export Chromium headless para PDF (Open Pencil ya exporta SVG nativamente)
  3. Sistema de plugins — API completa con ejecución sandboxed
  4. Tokens de diseño — soporte nativo de design tokens
  5. CSS Grid layout — implementación propia (Open Pencil espera Yoga Grid)
  6. Self-hosting — despliegue Docker para equipos
  7. Madurez — años de uso en producción, probado a escala

11. Scripting y extensibilidad

OpenPencil incluye un comando eval que proporciona una API de Plugin compatible con Figma para scripting headless. Además, 90 herramientas AI disponibles vía chat integrado, servidor MCP (stdio + HTTP) y CLI. Penpot tiene sistema de plugins con ejecución sandboxed pero sin API de scripting headless ni integración MCP.

Resumen

DimensiónGanadorPor qué
Simplicidad arquitectónicaOpen PencilUn proceso vs 5+ servicios
Rendimiento de renderizadoOpen PencilCanvasKit directo vs SVG DOM (default) o WASM empaquetado
Mantenibilidad del códigoOpen Pencil~26K LOC en 1 lenguaje vs 299K en 4+
Compatibilidad FigmaOpen PencilCodec Kiwi nativo vs sin soporte .fig
Onboarding de desarrolladoresOpen PencilTS/Vue vs Clojure/Rust/Docker
Experiencia desktopOpen PencilTauri nativo vs solo navegador
Motor de layoutOpen PencilYoga (probado) vs implementación dual personalizada
ColaboraciónEmpatePenpot: servidor con control de acceso; Open Pencil: P2P vía Trystero + Yjs, zero hosting
Self-hostingPenpotListo para Docker vs solo desktop
Madurez del ecosistemaPenpotAños de producción vs etapa temprana

Open Pencil es arquitectónicamente más ligero — un renderer CanvasKit de proceso único en ~26K LOC de TypeScript, compatible con Figma por diseño. Penpot es una plataforma full-stack con ~299K LOC. Ambos ofrecen colaboración en tiempo real (P2P vs servidor). Penpot tiene ecosistema de plugins y exportación PDF en servidor; Open Pencil tiene scripting headless compatible con Figma, 90 herramientas AI/MCP, exportación SVG y app desktop nativa.

Released under the MIT License.