每日一个开源项目(第137篇):Penpot - 真正开源的设计协作工具,SVG 原生格式消灭设计-开发鸿沟

引言

"Figma 的问题不是功能不好,是你的设计数据不属于你,设计师和开发者之间永远隔着一道翻译层。"

这是"每日一个开源项目"系列的第137篇文章 。今天的主角是 Penpot------一个用 Clojure/ClojureScript 全栈构建的开源设计协作工具。

2022 年,Figma 宣布以 200 亿美元被 Adobe 收购,设计圈开始认真讨论开源替代方案。Penpot 在那之后迎来了增长,但它的核心思路早在 Kaleidos 创立它的时候就确定了:设计工具应该是开放的,设计数据应该是标准格式的,设计和开发之间不应该存在翻译层。

三个"应该",对应三个真正的工程决策:MPL-2.0 开源协议 + Docker 自托管,SVG 作为原生存储格式,设计属性直接映射 CSS(Grid、Flex、字体、间距)。

你将学到什么

  • SVG 原生格式的含义:为什么这是消灭设计-开发鸿沟的关键
  • CSS 映射设计属性:Grid/Flex 布局工具如何与 CSS 对齐
  • Clojure/ClojureScript 全栈选型的逻辑
  • Docker Compose 自托管的部署结构
  • 实时协作的 WebSocket 架构
  • 设计系统(组件、色板、文本样式)的完整支持
  • 与 Figma 的本质差异:不是功能对比,是哲学对比

前置知识

  • 使用过设计工具(Figma、Sketch 或类似工具)
  • 了解 SVG 格式的基本概念
  • 了解 CSS Flexbox 和 Grid 的基本用法

项目背景

项目简介

Penpot 是一个基于 Web 的开源设计和原型协作平台,作为 Figma/Sketch 的开源替代品构建。它的核心技术决定是:以 SVG 作为原生存储格式,设计属性与 CSS 规范对齐。

这两个决定的含义是:

  1. 导出的设计文件是标准 SVG,可以在任何支持 SVG 的工具里打开和编辑
  2. 设计师在 Penpot 里设置的 Flex 布局、Grid 布局、间距属性,和开发者在 CSS 里写的属性是同一套语言

设计师和开发者之间的"翻译工作"(把 Figma 的约束系统手动转换成 CSS 数值)在这个架构下大幅缩短。

项目由西班牙数字产品工作室 Kaleidos 创建并开源,现在由 Penpot 团队持续维护,有商业化托管版本(penpot.app)和可自托管的社区版本。

作者/团队介绍

  • 组织: Kaleidos / Penpot Team
  • 技术栈: Clojure(后端)+ ClojureScript(前端)+ PostgreSQL
  • License: Mozilla Public License 2.0(MPL-2.0)
  • 官网: penpot.app

项目数据

  • ⭐ GitHub Stars: 35,000+
  • 🍴 Forks: 1,700+
  • 📄 License: MPL-2.0
  • 🌐 支持语言:西班牙语、英语、多语言社区贡献

主要功能

核心作用

css 复制代码
传统设计工具链(Figma 模式):
设计师在 Figma 中设计
    ↓
导出 PDF/PNG 或使用 Figma Dev Mode
    ↓
开发者手动读取:字体大小、颜色、间距、Flex 对齐方式...
    ↓
在 CSS 中重新写一遍

Penpot 模式:
设计师在 Penpot 中设计(属性直接是 CSS 属性)
    ↓
开发者查看面板,看到的直接是 CSS Grid/Flex 属性
    ↓
复制 CSS 片段或直接理解样式规则

使用场景

  1. 团队设计协作:多人实时编辑同一文件,无需 Figma 订阅,适合预算有限或数据安全要求高的团队
  2. 企业私有化部署:金融、医疗等对数据主权有要求的行业,Docker 自托管在内网运行
  3. 设计系统管理:组件库、色板、文本样式、图标集,组织设计规范
  4. 原型交互设计:添加过渡动画、交互流程,输出可点击原型
  5. 设计-开发协作:CSS 原生属性让前端开发者直接读取设计意图,减少沟通成本
  6. 开源项目的设计资产:设计文件可以像代码一样开源、协作、版本管理

快速开始

Docker Compose 自托管(推荐方式)

bash 复制代码
# 下载官方 docker-compose 配置
wget https://raw.githubusercontent.com/penpot/penpot/main/docker/images/docker-compose.yaml

# 启动(包含后端、前端、PostgreSQL、Redis、邮件服务)
docker compose -p penpot -f docker-compose.yaml up -d

访问 http://localhost:9001,注册第一个账号(默认为管理员)。

核心环境变量

bash 复制代码
# docker-compose.yaml 中的关键配置
PENPOT_FLAGS=enable-registration enable-login-with-password
PENPOT_DATABASE_URI=postgresql://penpot/penpot
PENPOT_REDIS_URI=redis://redis/0

# 使用对象存储(可选,默认本地文件系统)
PENPOT_STORAGE_BACKEND=s3
PENPOT_STORAGE_S3_BUCKET=your-bucket

升级

bash 复制代码
docker compose -p penpot -f docker-compose.yaml pull
docker compose -p penpot -f docker-compose.yaml up -d

核心特性

SVG 原生格式

Penpot 的文件格式本质上是结构化的 SVG。这意味着:

  • 不存在专有二进制格式
  • 设计文件可以被任何 SVG 解析器读取
  • 导出即标准格式,无需专用导出插件

CSS 对齐的设计属性

在 Penpot 里,当你设置一个容器的布局时,你操作的概念和 CSS 是一一对应的:

sql 复制代码
Penpot 布局面板          ↔    CSS 等价
────────────────────────────────────────
Flex 布局方向:Row        ↔    flex-direction: row
主轴对齐:Space Between   ↔    justify-content: space-between
交叉轴对齐:Center        ↔    align-items: center
行间距 16px               ↔    row-gap: 16px
内边距 12px               ↔    padding: 12px

Grid 布局同理------Penpot 的 Grid 工具直接暴露 grid-template-columnsgrid-template-rowsgap 等 CSS Grid 概念。

设计系统支持

  • 组件:创建主组件(Main Component),在文件内任意复制为实例(Instance);修改主组件,所有实例自动更新
  • 组件覆写:实例可以在保持组件结构的同时覆写特定属性(文字、颜色)
  • 共享库:把一个文件的资产库(组件、色板、文本样式、图标)共享给团队其他文件
  • 色板系统:项目级别和文件级别的调色板,支持颜色变量
  • 文本样式:定义命名文本样式(H1、Body、Caption),跨文件复用

实时协作

多人同时编辑同一文件:

  • 用户光标实时可见(显示其他协作者位置)
  • 评论系统(在设计稿上添加定点评论,@提及队员)
  • 版本历史(可回滚到历史版本)
  • 文件权限(查看者 / 编辑者分级)

项目详细剖析

Clojure/ClojureScript 全栈

Penpot 是罕见的、在生产中大规模使用 Clojure 全栈的开源项目之一。

markdown 复制代码
后端:Clojure(运行在 JVM)
    ├── HTTP API 服务(RESTful)
    ├── WebSocket 实时协作处理
    ├── 文件存储管理
    └── PostgreSQL 数据访问

前端:ClojureScript(编译到 JavaScript)
    ├── 基于 React 的 UI 渲染(rum 库)
    ├── 画布渲染(SVG-based)
    ├── 状态管理(基于不可变数据结构)
    └── WebSocket 客户端(实时同步)

数据库:PostgreSQL
    ├── 用户、团队、项目数据
    └── 设计文件元数据(文件内容存储为独立格式)

Redis:
    └── 会话管理、实时协作状态

选用 Clojure/ClojureScript 的技术逻辑:

  • 同构数据共享:前后端使用相同的数据结构描述设计文件,减少序列化/反序列化摩擦
  • 不可变数据结构:天然支持撤销/重做历史(Undo/Redo)------每次操作产生新状态,旧状态自动保留
  • 函数式编程:复杂的图形变换(矩阵运算、路径操作)用纯函数表达,测试和推理更容易

SVG 数据模型

Penpot 的设计文件在内部以树状数据结构表示,每个元素对应一个 SVG 节点:

clojure 复制代码
;; 一个矩形元素的内部表示(简化)
{:type :rect
 :id "uuid-xxx"
 :name "Button Background"
 :x 100, :y 200
 :width 200, :height 48
 :fill [{:fill-color "#3355FF" :fill-opacity 1}]
 :r1 8 :r2 8 :r3 8 :r4 8  ; border-radius
 :layout-item-margin {:m1 0 :m2 16 :m3 0 :m4 16}  ; 在父 Flex 容器中的 margin
}

这个数据结构可以直接序列化为 SVG 属性,没有"设计软件内部格式 → 导出格式"的二次转换。

实时协作架构

css 复制代码
客户端 A(设计师)
    │  移动元素操作
    ▼
WebSocket 连接
    │  发送操作(Operation/Transaction)
    ▼
后端 WebSocket 处理器
    │
    ├── 持久化到 PostgreSQL
    │
    ├── 广播给同文件的其他客户端
    │
    └── 客户端 B(另一个设计师)接收 → 应用操作 → 更新本地状态

操作是以"操作类型 + 参数"描述的,不是发送完整文件,而是发送增量变更(类似 CRDT 的思路,但实现更简单)。

原型交互系统

Penpot 的原型交互基于"帧(Frame)→ 帧"的跳转模型:

css 复制代码
页面帧 A(登录页)
    │  点击"登录"按钮
    │  触发器:点击
    │  动画:滑入(右→左,300ms)
    ▼
页面帧 B(首页)

支持的触发器:点击、悬停、鼠标按下、鼠标松开、进入/离开视口 支持的过渡动画:瞬间、溶解、滑入、滑出、弹出 支持的导航动作:跳转帧、叠加帧、替换帧、滚动到元素

这足以表达大多数移动端和 Web 产品的交互流程。

部署架构

完整的 Docker Compose 部署包含:

markdown 复制代码
┌─────────────────────────────────────────┐
│              Nginx (反向代理)             │
│              localhost:9001              │
└──────┬──────────────┬────────────────────┘
       │              │
       ▼              ▼
┌──────────┐    ┌──────────────┐
│ Frontend │    │   Backend    │
│ (静态文件) │    │  (Clojure)  │
│  :3449   │    │    :6060     │
└──────────┘    └──────┬───────┘
                       │
         ┌─────────────┼──────────────┐
         ▼             ▼              ▼
    ┌─────────┐  ┌──────────┐  ┌──────────┐
    │Postgres │  │  Redis   │  │  文件存储  │
    │  :5432  │  │  :6379   │  │(本地/S3) │
    └─────────┘  └──────────┘  └──────────┘

与 Figma 的本质差异

维度 Penpot Figma
数据所有权 完全自托管,数据在你的服务器 数据在 Figma/Adobe 云端
文件格式 SVG 原生,可用标准工具打开 专有 .fig 格式
CSS 映射 设计属性直接对应 CSS 概念 需要 Dev Mode 翻译
价格 自托管免费;云托管有免费层 免费层受限;专业版订阅
插件生态 社区插件,规模较小 成熟庞大的插件生态
性能 浏览器 SVG 渲染,极大文件稍慢 原生渲染引擎,性能更优
多人协作 支持,WebSocket 实现 支持,成熟度更高
版本历史 支持 支持(更完善)
技术开放性 完全开源,可二次开发 闭源,无法二次开发

Figma 在插件生态、渲染性能、高级协作功能上仍有优势。Penpot 的优势在于数据主权、CSS 对齐的开发者友好性、以及作为开源项目的可扩展性。


项目地址与资源

官方资源

相关资源

  • Docker Hub 镜像:penpotapp/backendpenpotapp/frontend
  • 贡献指南:CONTRIBUTING.md(项目仓库内)

总结

Penpot 的核心论点是:设计工具的问题不是功能不够,而是数据不开放、格式不标准、设计和开发之间存在永久的翻译层。

SVG 原生格式和 CSS 对齐的属性系统,是这个论点的直接技术回答。一个前端开发者打开 Penpot 的检查面板,看到的 flex-direction: rowgap: 16pxborder-radius: 8px 不需要任何翻译------这就是 CSS,他直接写就好了。

Clojure/ClojureScript 的全栈选型是一个有趣的工程决策:不可变数据结构天然支持 Undo/Redo,同构数据模型减少前后端摩擦,函数式编程让复杂图形变换可测试。这些好处对于设计工具这类交互密集的应用来说实实在在。

对于需要数据私有化的企业、预算有限的团队、或者重视设计-开发一体化工作流的团队,Penpot 是目前开源设计工具里产品完成度最高、工程架构最清晰的选项。


探索 PrimeSkills ------ 精选 AI Agent 与技能的市场,每一个都经过真实企业工作流验证,去掉浮夸,留下真正有用的。

欢迎访问我的个人主页,发现更多有价值的见解和有趣的产品。

相关推荐
nuIl1 小时前
实现一个 Coding Agent(7):Skills
前端·agent·cursor
nuIl1 小时前
实现一个 Coding Agent(8):会话持久化与多会话
前端·agent·cursor
jt君424263 小时前
React Native JSI 深入剖析 — 第 5 部分中文技术整理:用 HostObject 把 C++ 类暴露给 JavaScript
前端·react native
胡萝卜术3 小时前
滑动窗口最大值:从暴力到单调队列,层层优化全解析
前端·javascript·面试
fluffyox3 小时前
Notion 的公式栏里,藏着一台虚拟机——逆向 + 用 600 行 JS 复刻它的编译器与栈式 VM
前端
kyriewen4 小时前
2026 年了,这 6 个 npm 包可以卸载了——浏览器原生 API 已经能替代
前端·javascript·npm
Csvn6 小时前
Monorepo 迁移血泪史:从 Multi-Repo 到 Turborepo,这 3 个坑我帮你踩完了
前端
星栈7 小时前
Dioxus 多页面怎么做:`dioxus-router`、嵌套路由、`Outlet` 和页面组织,一篇给你讲顺
前端·rust·前端框架
用户987409238877 小时前
用 Remotion + edge-tts 打造中文教学视频全自动流水线
前端