Skip to content

Open Pencil vs Penpot : Comparaison d'architecture et de performances

Pourquoi comparer ? OpenPencil existe parce que les plateformes de design fermées contrôlent ce qui est possible. Comprendre les différences architecturales montre ce qu'une alternative ouverte et local-first peut faire différemment.

Renderer WASM de Penpot

Penpot 2.x inclut un renderer Rust/Skia WASM (render-wasm/v1) activable via les flags du serveur ou le paramètre URL ?wasm=true. Le renderer SVG reste le défaut. Cette page couvre les deux.

1. Échelle et taille du code

MétriqueOpen PencilPenpot
LOC total~26 000~299 000
Fichiers source~143~2 900
LangagesTypeScript, VueClojure, ClojureScript, Rust, JS, SQL, SCSS
Moteur de rendu~3 200 LOC (TS, 10 plików)22 000 LOC (Rust/Skia WASM)
Code UI~4 500 LOC~175 000 LOC (CLJS + SCSS)
BackendAucun (local-first)32 600 LOC + 151 fichiers SQL
Ratio LOC~11×

Open Pencil est ~11× plus petit — et c'est tout l'intérêt. Ce n'est pas une simplification ; c'est une architecture fondamentalement différente.

2. Architecture

Open Pencil : Client monolithique

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

Tout dans un seul processus. Pas de serveur, pas de base de données, pas de Docker.

Penpot : Client-serveur distribué

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

Minimum 5+ services. PostgreSQL, Redis (Valkey), MinIO, un backend JVM, un exporteur Node.js (Chromium headless), plus le frontend ClojureScript.

Verdict : Architecture

L'architecture monoprocessus d'Open Pencil élimine : la latence réseau, l'overhead de sérialisation aux frontières de services, la complexité d'orchestration de conteneurs et l'overhead de requêtes base de données.

3. Pipeline de rendu

Open Pencil : TS → CanvasKit WASM (direct)

typescript
renderSceneToCanvas(canvas, graph, pageId) {
  this.fillPaint.setColor(...)
  canvas.drawRRect(rrect, this.fillPaint)
}
  • 1 franchissement de frontière : TS → WASM (CanvasKit)
  • Le graphe de scène vit dans le heap JS — pas de sérialisation pour le rendu
  • 1 646 LOC de renderer au total

Penpot : JS (compilé depuis CLJS) → Rust WASM → Skia

ClojureScript (compilé en JS)
  → décomposer en primitives + empaqueter en binaire en mémoire linéaire WASM
  → Rust WASM (via Emscripten C FFI)
  → skia-safe (bindings Rust Skia)
  → Skia (WebGL)

Quand désactivé (défaut), les formes sont rendues comme un arbre DOM SVG. Quand activé, système de rendu par tuiles avec 11 surfaces et cache de 1024 entrées.

Verdict : Rendu

AspectOpen PencilPenpot
Frontière JS→WASMDirect (objets TS)Empaquetage binaire (104 octets par forme)
Modèle de renduImmédiat/redessin completCache par tuiles
Gestion des surfaces1 surface11 surfaces
Overhead mémoireFaible (pas de cache tuiles)Élevé (1024 entrées cache)
Complexité du code1 646 LOC22 000 LOC
Code unsafeAucunÉtat global unsafe

4. Graphe de scène et modèle de données

Open Pencil

typescript
nodes: Map<string, SceneNode>
// 29 types de nœuds du schéma Kiwi de Figma
// ~390 champs par NodeChange (compatible Figma)
  • Interfaces TypeScript avec types stricts
  • GUIDs au format sessionID:localID de Figma

Penpot

  • Données réparties dans common/ (49 600 LOC de .cljc)
  • Validation de schéma au runtime (Malli)
  • Les données doivent traverser la frontière CLJS→Rust pour le rendu

Verdict : Modèle de données

Open Pencil réutilise le schéma éprouvé de Figma directement en TypeScript — zéro traduction. Penpot maintient son propre système de types à travers trois langages.

5. Moteur 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()

314 lignes au total. Synchrone, dans le processus.

Penpot : Double implémentation

Penpot maintient deux moteurs de layout indépendants (CLJS et Rust) qui doivent produire des résultats identiques. ~3 000+ LOC de code layout personnalisé dupliqué.

Verdict : Layout

Open Pencil délègue à Yoga (utilisé par React Native sur des milliards d'appareils) en 314 lignes.

6. Format de fichier et compatibilité Figma

Open Pencil

  • Format binaire Kiwi natif — même sérialisation que Figma
  • Import direct .fig, collage depuis le presse-papiers Figma
  • Compatible avec le protocole multiplayer de Figma

Penpot

  • Archive ZIP (.penpot) avec manifestes JSON et assets binaires
  • Pas d'import natif .fig
  • Trois versions de format avec système de migration

Verdict : Format de fichier

Open Pencil a un avantage significatif — il peut lire les fichiers Figma nativement et coller les données du presse-papiers Figma.

7. Gestion d'état et annulation

Open Pencil

typescript
// 110 LOC — patron de commande inverse
class UndoManager {
  apply(entry) { entry.forward(); this.undoStack.push(entry) }
  undo() { entry.inverse(); this.redoStack.push(entry) }
}

110 lignes. Closures forward/inverse avec état minimal.

Penpot

Gestion d'état via Potok (bibliothèque Redux-like pour atomes ClojureScript). Undo stocke des vecteurs de changements inverses (max 50 entrées), avec auto-expiration après 20 secondes.

8. Expérience développeur

MétriqueOpen PencilPenpot
Setup devbun install && bun devDocker Compose + JVM + Node + Rust
Rechargement à chaudVite HMR (~50ms)shadow-cljs (secondes)
Vérification de typesTypeScript (strict)Runtime (schémas Malli)
Temps de build<5s (Vite)Minutes (JVM + CLJS + Rust WASM)
Barrière première contributionBasse (TS/Vue)Haute (Clojure + Rust + Docker)
DesktopTauri v2 (~5Mo)N/A (navigateur uniquement)
Bassin de recrutementMassif (devs TS/Vue)Petit (ClojureScript + Rust)

9. Caractéristiques de performance

ScénarioOpen PencilPenpot
Démarrage à froid<2s (chargement WASM)10s+ (serveur + client + WASM)
Latence d'opération<1ms (dans le processus)10-50ms (aller-retour réseau)
Frame de renduAppel Skia directCLJS→JS→WASM FFI→Skia
Mémoire de base~50Mo (onglet navigateur)~300Mo+ (JVM + Postgres + Valkey + navigateur)
Capacité hors ligneComplète (local-first)Aucune (dépend du serveur)
Rendu 10K formesUne passe, sans cachePar tuiles avec 11 surfaces

10. Ce que Penpot fait mieux

  1. Collaboration serveur — édition multi-utilisateurs centralisée avec WebSockets, comptes et contrôle d'accès
  2. Export PDF serveur — service d'export Chromium headless pour PDF (Open Pencil exporte déjà en SVG nativement)
  3. Système de plugins — API complète avec exécution sandboxée
  4. Tokens de design — support natif des design tokens
  5. CSS Grid layout — implémentation personnalisée (Open Pencil attend Yoga Grid)
  6. Self-hosting — déploiement Docker pour les équipes
  7. Maturité — années d'utilisation en production

11. Scripting et extensibilité

OpenPencil inclut une commande eval offrant une API Plugin compatible Figma pour le scripting headless. De plus, 90 outils IA sont disponibles via le chat intégré, le serveur MCP (stdio + HTTP) et le CLI. Penpot a un système de plugins avec exécution sandboxée mais pas d'API de scripting headless ni d'intégration MCP.

Résumé

DimensionGagnantPourquoi
Simplicité architecturaleOpen PencilUn processus vs 5+ services
Performance de renduOpen PencilCanvasKit direct vs SVG DOM (défaut) ou WASM empaqueté
Maintenabilité du codeOpen Pencil~26K LOC en 1 langage vs 299K en 4+
Compatibilité FigmaOpen PencilCodec Kiwi natif vs pas de support .fig
Onboarding développeurOpen PencilTS/Vue vs Clojure/Rust/Docker
Expérience desktopOpen PencilTauri natif vs navigateur uniquement
Moteur de layoutOpen PencilYoga (éprouvé) vs double implémentation
CollaborationÉgalitéPenpot : serveur avec contrôle d'accès ; Open Pencil : P2P via Trystero + Yjs
Self-hostingPenpotPrêt Docker vs desktop uniquement
Maturité écosystèmePenpotAnnées de production vs stade précoce

Open Pencil est architecturalement plus léger — un renderer CanvasKit monoprocessus en ~26K LOC TypeScript, compatible Figma par conception. Penpot est une plateforme full-stack avec ~299K LOC. Open Pencil a le scripting headless, 90 outils AI/MCP, export SVG et une app desktop native.

Released under the MIT License.