Pascal 编辑器
一句话简介
一款面向 3D 场景构建的开源可视化编辑器,基于 TypeScript 开发,支持场景编辑、对象管理与实时预览。
标签
适用应用场景
- 3D 场景搭建与编辑
- 游戏关卡设计
- 虚拟场景原型制作
- 建筑可视化预览
README 中文摘要
项目概述
Pascal Editor 是一个基于 React Three Fiber 与 WebGPU 的 3D 建筑编辑器,采用 Turborepo 单仓多包架构,将核心逻辑、渲染运行时、编辑工具与节点定义分离,便于扩展与复用。
安装与快速上手
安装发布包,并在挂载 <Viewer> 之前加载内置插件:
npm install @pascal-app/core @pascal-app/viewer @pascal-app/editor @pascal-app/nodes
import { loadPlugin } from '@pascal-app/core'
import { builtinPlugin } from '@pascal-app/nodes'
await loadPlugin(builtinPlugin)
// 之后即可在 React 中渲染 <Viewer /> 组件
仓库架构
主要包含以下包:
- @pascal-app/core:节点 schema(Zod 定义)、场景状态(Zustand)、注册中心契约、空间查询与事件总线。
- @pascal-app/viewer:基于 R3F 的 3D 渲染运行时、共享渲染系统、默认相机/控制器与后处理。
- @pascal-app/editor:编辑工具、面板、选择管理以及直接操作 UI。
- @pascal-app/nodes:内置注册插件,提供节点定义、渲染器、几何与系统。
- apps/editor:基于 Next.js 的独立编辑器宿主应用。
设计原则是 viewer 负责带默认配置的渲染,editor 在其之上叠加交互能力。
状态管理
每个包维护独立的 Zustand Store:
- useScene(core):管理节点数据、根节点 ID、脏节点集合与 CRUD;通过 Zundo 支持撤销/重做,并持久化到 IndexedDB。
- useViewer(viewer):管理当前选中(建筑/楼层/区域)、楼层显示模式(堆叠/爆炸/独立)以及相机模式。
- useEditor(apps/editor):管理当前工具、结构层可见性、面板状态与编辑器偏好。
// 在 React 组件中订阅
const nodes = useScene((state) => state.nodes)
const levelId = useViewer((state) => state.selection.levelId)
const activeTool = useEditor((state) => state.tool)
// 在回调或 system 中直接访问
useScene.getState().nodes[id]
useViewer.getState().setSelection({ levelId: 'level_123' })
核心概念
节点模型
所有节点继承自 BaseNode,包含 id(按类型前缀自动生成,如 wall_abc123)、type(类型判别字段)、parentId、visible,以及可选的相机与元数据。节点层级为:Site → Building → Level → Wall/Slab/Ceiling/Roof/Zone/Scan/Guide,其中 Wall、Ceiling 可挂载 Item。存储采用扁平字典 Record<id, Node>,父子关系通过 parentId 与 children 数组维护。
场景注册中心
sceneRegistry 将节点 ID 映射到对应的 Three.js 对象,并按类型分组。渲染器通过 useRegistry(node.id, 'wall', ref) 注册引用,使系统可在不遍历场景图的前提下直接访问 3D 对象。
节点渲染器
SceneRenderer → NodeRenderer 按类型分发到 BuildingRenderer、LevelRenderer、WallRenderer 等具体组件。渲染器先创建占位几何,再由 System 在下一帧填充实际数据。
System 与脏节点
System 是运行在 useFrame 中的 React 组件,负责根据脏节点更新几何与变换。WallSystem 处理墙体斜接与门窗 CSG 挖洞;SlabSystem/CeilingSystem/RoofSystem 生成楼板、天花板与屋顶;ItemSystem 将物件贴附到墙、顶或地板上并计算高程。
useFrame(() => {
for (const id of dirtyNodes) {
const obj = sceneRegistry.nodes.get(id)
const node = useScene.getState().nodes[id]
updateGeometry(obj, node)
dirtyNodes.delete(id)
}
})
事件总线与空间网格
基于 mitt 的类型化事件总线支持 wall:click、item:enter、zone:context-menu、grid:click 等事件,载荷包含节点、坐标与法线等信息。spatialGridManager 提供 canPlaceOnFloor、canPlaceOnWall、getSlabElevationAt 等 API,用于放置校验与高程计算。
编辑器扩展
编辑工具集包括 Select、Wall、Zone、Item 与 Slab 工具。选择管理器沿 Site → Building → Level → Zone → Items 层级导航,每层独立处理悬停与点击。系统层面另有 ZoneSystem 控制可见性,并提供节点聚焦的自定义相机控制。
插件机制
编辑器通过统一的 Plugin 清单暴露扩展点,插件可注册节点 schema、3D/2D 渲染器、放置工具、Inspector 参数面板以及左侧栏面板,无需使用内部私有 API。可参考 pascalorg/plugin-trees 作为起点。
技术栈
React 19、Next.js 16、Three.js(WebGPU)、React Three Fiber + Drei、Zustand、Zod、Zundo、three-bvh-csg、Turborepo、Bun。
开发与构建
# 在仓库根目录安装依赖并启动开发服务(启用所有包的 watch 模式)
bun install
bun dev
# 访问 http://localhost:3002
# 生产构建
turbo build
turbo build --filter=@pascal-app/core
# 发布
turbo build --filter=@pascal-app/core --filter=@pascal-app/viewer
npm publish --workspace=@pascal-app/core --access public
npm publish --workspace=@pascal-app/viewer --access public
注意:务必在根目录运行
bun dev,否则 packages 的监听不会生效,编辑packages/core/src/或packages/viewer/src/时无法热更新。
摘要更新于 2026-07-29 00:30:20
· 原文 13304 字符
· md5 6d79da526016…