Pascal 编辑器

pascalorg/editor 访问 GitHub ↗
🔤 TypeScript ★ 20936 ⑂ 0 weekly #9 (+2953) 抓取 2026-08-04

一句话简介

一款面向 3D 场景构建的开源可视化编辑器,基于 TypeScript 开发,支持场景编辑、对象管理与实时预览。

标签

  • 可视化编辑器
  • 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(类型判别字段)、parentIdvisible,以及可选的相机与元数据。节点层级为:Site → Building → Level → Wall/Slab/Ceiling/Roof/Zone/Scan/Guide,其中 Wall、Ceiling 可挂载 Item。存储采用扁平字典 Record<id, Node>,父子关系通过 parentIdchildren 数组维护。

场景注册中心

sceneRegistry 将节点 ID 映射到对应的 Three.js 对象,并按类型分组。渲染器通过 useRegistry(node.id, 'wall', ref) 注册引用,使系统可在不遍历场景图的前提下直接访问 3D 对象。

节点渲染器

SceneRendererNodeRenderer 按类型分发到 BuildingRendererLevelRendererWallRenderer 等具体组件。渲染器先创建占位几何,再由 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:clickitem:enterzone:context-menugrid:click 等事件,载荷包含节点、坐标与法线等信息。spatialGridManager 提供 canPlaceOnFloorcanPlaceOnWallgetSlabElevationAt 等 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…