Pascal Editor:基于 WebGPU 的开源 3D 建筑编辑器技术解析
一个采用现代 Web 技术栈构建的高性能建筑可视化与编辑平台
项目概述
Pascal Editor 是由 pascalorg 组织开发的开源 3D 建筑编辑器,旨在提供一个无需本地安装、完全基于浏览器的建筑设计与可视化解决方案。该项目采用 WebGPU 渲染技术结合 React Three Fiber 构建三维场景,实现了接近原生应用的渲染性能与交互体验。
| 项目属性 | 数据 |
|---|---|
| GitHub Stars | 11,683 |
| Forks | 1,479 |
| 主要语言 | TypeScript(占比 98.6%) |
| 当前版本 | v0.5.1 |
| 许可证 | MIT License |
| 官方网站 | editor.pascal.app |
| 源码仓库 | github.com/pascalorg/editor |
技术架构
Monorepo 项目结构
项目采用 Turborepo 管理的 Monorepo 架构,实现模块化设计与职责分离:
editor/
├── apps/
│ └── editor/ # Next.js 16 应用层
├── packages/
│ ├── core/ # @pascal-app/core
│ └── viewer/ # @pascal-app/viewer
└── tooling/ # 构建工具链配置
模块职责划分:
| 模块 | 职责范围 |
|---|---|
@pascal-app/core |
节点 Schema 定义(Zod)、场景状态管理(Zustand)、几何生成系统、空间查询、事件总线 |
@pascal-app/viewer |
React Three Fiber 3D 渲染组件、默认相机/控制器、后处理特效 |
apps/editor |
UI 组件、交互工具、编辑器特定系统、选择管理器 |
这种架构设计支持核心包的独立发布与复用,开发者可通过 npm 引入渲染引擎或核心逻辑构建定制化应用。
技术栈概览
| 类别 | 技术选型 | 版本 |
|---|---|---|
| 前端框架 | React + Next.js | 19 / 16 |
| 3D 渲染 | Three.js + WebGPU Renderer | - |
| 3D 抽象层 | React Three Fiber + Drei | - |
| 状态管理 | Zustand + Zundo(undo/redo) | - |
| 数据验证 | Zod Schema | - |
| 几何运算 | three-bvh-csg(CSG Boolean) | - |
| 构建工具 | Turborepo + Bun | 2.8.15 / 1.3.0 |
| 代码规范 | Biome | 2.4.6 |
核心技术概念
1. 节点模型(Node Schema)
节点是场景数据的基本单元,所有节点类型均继承 BaseNode:
typescript
interface BaseNode {
id: string // 自动生成,类型前缀(如 "wall_abc123")
type: string // 类型鉴别器
parentId: string | null // 父节点引用
visible: boolean // 可见性控制
camera?: Camera // 可选相机位置
metadata?: JSON // 扩展元数据
}
节点层级结构:
Site(场地)
└── Building(建筑)
└── Level(楼层)
├── Wall → Item(门、窗附属)
├── Slab(地板)
├── Ceiling → Item(灯具附属)
├── Roof(屋顶)
├── Zone(功能区域)
├── Scan(3D 扫描参考)
└── Guide(2D 参考图)
节点存储采用 扁平字典结构 (Record<id, Node>),而非嵌套树形结构。父子关系通过 parentId 与 children 数组定义,简化了遍历与查询操作。
2. 场景状态管理
场景由 Zustand Store 管理,集成持久化与时间旅行(undo/redo)中间件:
typescript
interface SceneState {
nodes: Record<string, AnyNode> // 全部节点
rootNodeIds: string[] // 顶层节点(Site)
dirtyNodes: Set<string> // 待更新节点集合
createNode(node, parentId): void
updateNode(id, updates): void
deleteNode(id): void
}
中间件配置:
- Persist Middleware:自动持久化至 IndexedDB,排除瞬态节点
- Temporal Middleware(Zundo):50 步历史记录,支持撤销/重做
3. 场景注册表(Scene Registry)
注册表维护节点 ID 与 Three.js Object3D 的映射,实现高效的空间对象查询:
typescript
interface SceneRegistry {
nodes: Map<string, Object3D> // ID → 3D Object
byType: {
wall: Set<string>
item: Set<string>
zone: Set<string>
// ... 按类型分组
}
}
渲染器通过 useRegistry Hook 注册引用:
tsx
const ref = useRef<Mesh>(null!)
useRegistry(node.id, 'wall', ref)
此机制允许系统直接访问 3D 对象,无需遍历场景图。
4. 系统(Systems)
系统是运行于渲染循环(useFrame)中的 React 组件,负责几何生成与变换更新。系统仅处理被标记为"脏"的节点。
核心系统列表:
| 系统 | 功能描述 |
|---|---|
WallSystem |
墙壁几何生成,含斜接处理与门窗 CSG 切割 |
SlabSystem |
基于多边形的地板几何生成 |
CeilingSystem |
天花板几何生成 |
RoofSystem |
屋顶几何生成 |
ItemSystem |
物品定位(墙壁、天花板、地板附着点计算) |
LevelSystem |
楼层可见性控制与垂直定位(堆叠/爆炸/单层模式) |
处理流程:
typescript
useFrame(() => {
for (const id of dirtyNodes) {
const obj = sceneRegistry.nodes.get(id)
const node = useScene.getState().nodes[id]
updateGeometry(obj, node) // 更新几何与变换
dirtyNodes.delete(id) // 清除脏标记
}
})
5. 脏节点机制(Dirty Nodes)
节点变更时自动加入 dirtyNodes 集合,系统在每帧检查并仅对脏节点执行几何重建:
typescript
// 自动标记:createNode/updateNode/deleteNode 触发脏标记
useScene.getState().updateNode(wallId, { thickness: 0.2 })
// → wallId 加入 dirtyNodes
// → WallSystem 下一帧重建几何
// → wallId 从 dirtyNodes 移除
此增量更新策略避免了全量重建的计算开销,显著提升性能。
6. 事件总线(Event Bus)
组件间通信采用基于 mitt 的类型化事件发射器:
typescript
// 节点事件
emitter.on('wall:click', (event: NodeEvent) => { ... })
emitter.on('item:enter', (event: NodeEvent) => { ... })
emitter.on('zone:context-menu', (event: NodeEvent) => { ... })
// 网格事件
emitter.on('grid:click', (event) => { ... })
// 事件载荷结构
interface NodeEvent {
node: AnyNode
position: [number, number, number] // 世界坐标
localPosition: [number, number, number] // 局部坐标
normal?: [number, number, number] // 法向量
stopPropagation: () => void
}
7. 空间网格管理器(Spatial Grid Manager)
提供碰撞检测与放置验证接口:
typescript
spatialGridManager.canPlaceOnFloor(levelId, position, dimensions, rotation)
spatialGridManager.canPlaceOnWall(wallId, t, height, dimensions)
spatialGridManager.getSlabElevationAt(levelId, x, z)
工具层调用此接口验证物品放置位置合法性,并计算地板高程。
数据流架构
用户交互(click, drag)
↓
Tool Handler 处理
↓
useScene.createNode() / updateNode()
↓
节点更新 → React 重渲染 NodeRenderer → useRegistry 注册 3D Object
↓
脏节点标记 → System 检测(useFrame) → 几何重建 → 清除脏标记
编辑器扩展架构
编辑器层在 Viewer 基础上扩展以下能力:
工具系统
| 工具 | 功能 |
|---|---|
| SelectTool | 选择与操控 |
| WallTool | 墙壁绘制 |
| ZoneTool | 区域创建 |
| ItemTool | 家具/设备放置 |
| SlabTool | 地板绘制 |
选择管理器
支持层级化导航的选择策略:
Site → Building → Level → Zone → Items
每层级定义独立的 hover/click 行为策略。
Store 分层
| Store | 模块 | 职责 |
|---|---|---|
useScene |
@pascal-app/core |
场景数据(节点、层级、CRUD) |
useViewer |
@pascal-app/viewer |
视图状态(选择、楼层模式、相机) |
useEditor |
apps/editor |
编辑器状态(工具、面板、偏好) |
功能清单
已实现
- 墙壁绘制:点击拖拽绘制,自动斜接处理
- 门窗放置:CSG Boolean 切割生成真实开口
- 区域划分:功能区域标记
- 家具/灯具定位:3D 物品库,支持墙/天花板/地板附着
- 多楼层管理:堆叠/爆炸/单层三种显示模式
- 撤销/重做:Zundo 实现 50 步历史记录
- 数据持久化:IndexedDB 自动保存
项目状态
当前版本 v0.5.1(2026年4月),处于活跃开发阶段:
- 27 个开放 Issue
- 持续的 Commit 活动
- npm 包定期发布
- Discord 社区运营
快速开始
开发环境搭建
bash
# 克隆仓库
git clone https://github.com/pascalorg/editor.git
# 安装依赖
bun install
# 启动开发服务器(含包监视模式)
bun dev
# 访问 http://localhost:3000
注意 :运行 bun dev 需在根目录执行,确保包监视器启动,实现 packages/core 与 packages/viewer 的热重载。
生产构建
bash
# 全量构建
turbo build
# 单包构建
turbo build --filter=@pascal-app/core
npm 包使用
bash
npm install @pascal-app/core # 核心逻辑
npm install @pascal-app/viewer # 3D 渲染引擎
关键文件路径
| 路径 | 内容 |
|---|---|
packages/core/src/schema/ |
Zod 节点类型定义 |
packages/core/src/store/use-scene.ts |
场景状态 Store |
packages/core/src/hooks/scene-registry/ |
3D 对象注册表 Hook |
packages/core/src/systems/ |
几何生成系统 |
packages/viewer/src/components/renderers/ |
节点渲染器组件 |
packages/viewer/src/components/viewer/ |
Viewer 主组件 |
apps/editor/components/tools/ |
编辑器工具组件 |
apps/editor/store/ |
编辑器状态管理 |
适用场景分析
推荐应用场景
| 场景 | 适用性 |
|---|---|
| 建筑/室内概念设计 | 快速草图,无需专业 CAD 许可成本 |
| 房地产交互展示 | 户型图 3D 可视化,增强营销体验 |
| 游戏关卡原型 | 建筑/室内场景快速搭建 |
| Web 3D 技术学习 | 现代 React + Three.js 架构参考 |
| 开源贡献实践 | 前沿 WebGPU 项目参与 |
当前局限
| 局限 | 说明 |
|---|---|
| 施工图纸输出 | 缺乏精确标注与规范合规性 |
| 大型建筑场景 | 性能与功能边界尚未验证 |
| CAD 导出 | 暂不支持导出至其他 CAD 格式 |
技术亮点总结
-
WebGPU 先行者:首批大规模采用 WebGPU 的开源 3D 项目,浏览器渲染性能突破传统 WebGL 限制
-
架构设计规范:Monorepo 模块分离、Zustand 状态分层、脏节点增量更新,体现工程化思维
-
CSG 几何运算 :
three-bvh-csg实现真实布尔切割,门窗开口具有物理真实性而非视觉遮蔽 -
React Three Fiber 声明式 3D:Three.js 对象生命周期由 React 管理,代码可维护性显著提升
-
开源生态贡献:核心包 npm 发布,支持社区复用与二次开发
参考资源
| 资源 | 链接 |
|---|---|
| 官方网站 | editor.pascal.app |
| GitHub 仓库 | github.com/pascalorg/editor |
| npm @pascal-app/core | npmjs.com/package/@pascal-app/core |
| npm @pascal-app/viewer | npmjs.com/package/@pascal-app/viewer |
| Discord 社区 | discord.gg/SaBRA9t2 |
| Twitter/X | @pascal_app |