OpenPencil e Penpot: architettura e prestazioni
OpenPencil e Penpot sono strumenti di design open source, ma adottano obiettivi e architetture differenti.
Motore WASM di Penpot
Penpot 2.x include il motore Rust/Skia WASM render-wasm/v1, attivabile tramite opzioni del server o ?wasm=true. Il motore SVG rimane quello predefinito. Il confronto considera entrambe le modalità.
1. Dimensione del codice
| Metrica | OpenPencil | Penpot |
|---|---|---|
| Righe di codice | circa 26.000 | circa 299.000 |
| File sorgente | circa 143 | circa 2.900 |
| Linguaggi | TypeScript, Vue | Clojure, ClojureScript, Rust, JavaScript, SQL, SCSS |
| Motore di rendering | circa 3.200 righe, TypeScript | 22.000 righe, Rust/Skia WASM |
| Interfaccia | circa 4.500 righe | circa 175.000 righe, CLJS e SCSS |
| Server | Nessuno, architettura locale | 32.600 righe e 151 file SQL |
| Rapporto | 1× | circa 11× |
OpenPencil è circa undici volte più piccolo. La differenza dipende soprattutto dall’architettura, non soltanto dal numero di funzioni.
2. Architettura
OpenPencil: un solo processo client
┌─────────────────────────────────┐
│ Tauri native shell │
│ ┌───────────────────────────┐ │
│ │ Vue 3 + TypeScript │ │
│ │ Editor + Kiwi codec │ │
│ │ SceneGraph in TypeScript │ │
│ │ CanvasKit + Yoga WASM │ │
│ └───────────────────────────┘ │
└─────────────────────────────────┘Editor, SceneGraph, codec dei file e motore di rendering vengono eseguiti nello stesso processo. Non servono server, database o Docker. SceneGraph è una Map<string, SceneNode>. TypeScript chiama direttamente CanvasKit e Yoga WASM calcola la disposizione in modo sincrono.
Penpot: piattaforma client-server
┌───────────────────────────────────────────────────────┐
│ Docker Compose │
│ ClojureScript frontend │ Clojure/JVM backend │
│ Rust/Skia WASM │ PostgreSQL, Valkey, MinIO │
│ Chromium exporter │ MCP server │
└───────────────────────────────────────────────────────┘Un’installazione completa di Penpot comprende interfaccia, server JVM, PostgreSQL, Valkey, MinIO e un esportatore basato su Chromium senza interfaccia. L’ambiente di sviluppo richiede Docker Compose, JVM, Node e strumenti Rust.
OpenPencil evita latenza di rete, serializzazione tra servizi, orchestrazione dei contenitori e query al database per le normali operazioni. Penpot è pensato come piattaforma multiutente ospitata su server; OpenPencil privilegia l’editing locale a bassa latenza.
3. Flusso di rendering
OpenPencil: TypeScript → CanvasKit WASM
renderSceneToCanvas(canvas, graph, pageId) {
this.fillPaint.setColor(...)
canvas.drawRRect(rrect, this.fillPaint)
}- Passaggio diretto da TypeScript a WASM.
- SceneGraph rimane nell’heap JavaScript e non viene serializzato prima del rendering.
- Il motore comprende circa 3.200 righe distribuite in moduli specializzati.
Penpot: ClojureScript → Rust WASM → Skia
ClojureScript → JavaScript
→ scomposizione e codifica binaria nella memoria WASM
→ Rust WASM tramite Emscripten C FFI
→ skia-safe
→ Skia/WebGLSenza WASM, ogni forma viene renderizzata come elemento SVG DOM tramite React/Reagent. Con WASM, UUID, trasformazioni, riempimenti e contorni vengono codificati in strutture binarie. Il motore usa cache a riquadri, aree di interesse, undici superfici e stato globale mutabile tramite unsafe.
La cache può conservare fino a 1.024 texture. OpenPencil ridisegna invece l’intera area visibile.
| Aspetto | OpenPencil | Penpot |
|---|---|---|
| JavaScript → WASM | Chiamate dirette con oggetti TypeScript | Strutture binarie |
| Modello | Ridisegno del viewport visibile | Cache a riquadri |
| Superfici | 1 | 11 |
| Cache aggiuntiva | Nessuna | Fino a 1.024 riquadri |
| Dimensione del motore | circa 3.200 righe | 22.000 righe |
| Codice non sicuro | Nessuno | Stato globale tramite unsafe |
Il percorso diretto di CanvasKit richiede meno elaborazione intermedia nei documenti piccoli e medi. La cache di Penpot può essere vantaggiosa oltre 100.000 forme quando è visibile solo una piccola area.
4. SceneGraph e modello dati
nodes: Map<string, SceneNode>OpenPencil offre ricerca per ID in O(1), 29 tipi di oggetto dallo schema Kiwi, circa 390 campi in NodeChange, tipi TypeScript rigorosi e GUID nel formato Figma sessionID:localID.
Penpot mantiene definizioni proprie in Clojure/ClojureScript e Rust. Moduli separati gestiscono colori, componenti, contenitori, riempimenti, griglia, modificatori, pagine e percorsi. Malli convalida gli schemi durante l’esecuzione e i dati di rendering attraversano il confine CLJS → Rust.
5. Motore di disposizione
OpenPencil usa Yoga WASM in modo sincrono:
const root = Yoga.Node.create()
root.setFlexDirection(FlexDirection.Row)
root.calculateLayout()Penpot mantiene implementazioni proprie di Flex e Grid sia in ClojureScript sia in Rust WASM. OpenPencil usa Yoga, compresa una variante con supporto Grid; Penpot mantiene migliaia di righe di codice di disposizione in due linguaggi.
6. Formati e Figma
OpenPencil usa il formato binario Kiwi di Figma, importa direttamente .fig, legge i dati Kiwi dagli appunti ed è compatibile con il protocollo multiplayer di Figma.
Un file .penpot è invece un archivio ZIP con manifesti JSON, dati, risorse binarie e miniature. Penpot non importa .fig in modo nativo e gestisce diverse generazioni del formato tramite migrazioni.
7. Stato e annullamento
OpenPencil usa comandi inversi: le funzioni di applicazione e annullamento conservano solo lo stato necessario e le operazioni possono essere raggruppate.
Penpot usa Potok. UpdateEvent cambia lo stato, WatchEvent esegue gli effetti tramite RxJS e la cronologia conserva vettori inversi, fino a 50 voci, raggruppando le modifiche rapide in transazioni.
8. Sviluppo
| Metrica | OpenPencil | Penpot |
|---|---|---|
| Preparazione | bun install && bun dev | Docker Compose, JVM, Node e Rust |
| Aggiornamento rapido | Vite | shadow-cljs |
| Tipi | TypeScript rigoroso | Schemi Malli durante l’esecuzione |
| Desktop | Tauri v2 | Browser |
| Tecnologie principali | TypeScript e Vue | Clojure, ClojureScript, Rust e Docker |
9. Prestazioni
| Scenario | OpenPencil | Penpot |
|---|---|---|
| Avvio | meno di 2 s con WASM | oltre 10 s per server, client e WASM |
| Operazione comune | Nello stesso processo | Possibile passaggio di rete |
| Fotogramma | Chiamata diretta a Skia | CLJS → JS → WASM FFI → Skia |
| Memoria di base | circa 50 MB nella scheda | JVM, database, cache e browser |
| Senza rete | Completo | Richiede il server |
| 10.000 forme | Una passata | Renderer a riquadri con 11 superfici |
10. Vantaggi di Penpot
- Collaborazione tramite server: account, controllo degli accessi e archiviazione centrale.
- Export PDF: esportatore Chromium dedicato.
- Sistema di plugin: esecuzione isolata e API dei plugin.
- Token di design: supporto integrato.
- CSS Grid: implementazione propria; OpenPencil usa una variante di Yoga con Grid.
- Installazione autonoma: piattaforma di gruppo distribuibile con Docker.
- Maturità: diversi anni di uso in produzione.
11. Script ed estensibilità
Il comando eval fornisce un’API compatibile con i plugin Figma per script senza interfaccia, operazioni in serie e test automatizzati. Chat AI, server MCP e CLI offrono inoltre 90 strumenti per lettura, creazione, modifica, struttura, variabili, tracciati vettoriali, analisi, differenze, operazioni booleane e disposizione.
Penpot offre plugin isolati, ma non un’API equivalente per script senza interfaccia o integrazione MCP.
Riepilogo
| Area | Vantaggio | Motivo |
|---|---|---|
| Semplicità | OpenPencil | Un processo invece di più servizi |
| Rendering | OpenPencil | Percorso CanvasKit diretto |
| Codice | OpenPencil | Circa 26.000 contro 299.000 righe |
| Compatibilità Figma | OpenPencil | Kiwi e .fig nativi |
| Sviluppo | OpenPencil | TypeScript e Vue anziché Clojure, Rust e Docker |
| Applicazione desktop | OpenPencil | Tauri nativo |
| Disposizione | OpenPencil | Yoga anziché due implementazioni proprie |
| Collaborazione | Punti di forza diversi | Penpot: server e accessi; OpenPencil: P2P senza hosting |
| Installazione autonoma | Penpot | Distribuzione Docker |
| Maturità | Penpot | Anni di uso in produzione |
OpenPencil è un editor compatto in un solo processo con CanvasKit e supporto nativo .fig. Penpot è una piattaforma client-server completa con Clojure, ClojureScript, Rust, database e servizi Docker. Entrambi supportano la collaborazione con modelli diversi.