Pascal Editor 是什么:浏览器里的开源 3D 建筑编辑器,与它自带的建模 MCP 服务器

2026-08-05

本文基于 Pascal Editor 仓库 commit 64dca3d(2026-08-04)梳理,该项目仍在高频迭代,具体行为以仓库 https://github.com/pascalorg/editor 最新代码与文档为准。

如果你是做 AI 工程的,这个仓库里最该看的不是那个 3D 编辑器,而是 packages/mcp:它把「造一栋房子」这件事,拆成了一组带 Zod 校验、带撤销重做、带碰撞检查的 MCP 工具。 换句话说,它给出了一个不太常见的样本——一个有强几何约束、有层级不变量的专业领域,是怎么被整理成 Agent 能安全调用的工具面的。编辑器本身反而是这套设计的验证场。

先做一件必须做的事:这里说的 Pascal Editor,是 GitHub 上 pascalorg/editor 这个开源 3D 建筑编辑器项目,和 Pascal 编程语言没有任何关系,也和压强单位帕斯卡没有关系。下文提到「Pascal」时,一律指这个建筑编辑器项目。许可证是 MIT,版权行写的是 Copyright (c) 2026 Pascal Group Inc.。

站内已有几篇相邻的文章,分工是这样的:想知道 MCP 协议本身怎么回事,看 MCP 协议是什么;想横向看有哪些开源 AI 工具值得用,看 开源 AI 工具盘点;想比较各家 Agent 平台的开源实现,看 开源 Agent 平台。本篇不重复这些,只做一件事:把 Pascal 这一个具体仓库摊开,让你判断它值不值得你花一个下午。

一、它解决的问题:3D 建模这件事,鼠标交互一直是唯一入口

传统建模软件里,画一堵墙、开一扇门、铺一层楼板,都得靠人在视口里点、拖、吸附。这套交互对熟练用户很高效,但它有个结构性后果:模型的「构造过程」没有可编程接口,你没法让程序按一段文字描述把房子搭出来。

Pascal 的做法是把场景本身设计成纯数据。仓库 README 这样定位自己:一个用 React Three Fiber 和 WebGPU 构建的 3D 建筑编辑器。React Three Fiber 是把 Three.js 场景写成 React 组件的适配层,WebGPU 是浏览器里新一代的图形接口。但对 AI 工程师更关键的是它的数据侧:所有几何都由「节点」描述,节点是一堆扁平的普通对象,几何是渲染时算出来的派生物。

节点的基类在 README 里写得很清楚,每个节点有 idtypeparentIdvisible,外加可选的 camerametadata。节点之间有一套建筑语义上的层级关系:Site(场地)下面挂 Building(建筑),Building 下面挂 Level(楼层),Level 下面才是 Wall(墙)、Slab(楼板,就是你站的那层水平结构)、Ceiling(吊顶)、Roof(屋面)、Zone(房间区域)等等;门窗(Item)挂在墙上,灯具挂在吊顶上。

这些节点不是嵌套树,而是存在一个扁平字典里(Record<id, Node>),父子关系靠 parentIdchildren 数组表达。这个选择对 Agent 很友好——你要改一堵墙的厚度,不需要在树里递归定位,直接按 id 取。

二、仓库长什么样:一张分工表

仓库是 Turborepo 管理的 monorepo,用 Bun 做包管理。根目录下 apps/ 有 2 个应用,packages/ 有 9 个包。整个仓库受 Git 版本控制的文件有 2508 个(git ls-files | wc -l 数出来的)。各包的体量差得很开,按同样口径数:packages/nodes 733 个文件,packages/editor 445 个,packages/core 233 个,packages/mcp 152 个,packages/viewer 107 个。

组成部分它负责什么仓库位置你什么时候会碰到它
core节点 schema、场景状态(Zustand store)、注册表契约、空间查询、事件总线。AGENTS.md 明确写它「不含 Three.js」packages/core想搞清 Agent 到底在改什么数据结构时
viewer独立的 3D 画布:渲染器、viewer 系统、相机与后期处理packages/viewer只想把模型嵌进自己页面展示时
editor编辑工具与 UI 组件,被独立应用和嵌入方复用packages/editor想做二次开发的编辑界面时
nodes内置节点定义、渲染器、几何与系统,以插件形式装载packages/nodes想加一种新构件(比如自定义家具)时
mcpMCP 服务器与场景存储适配层packages/mcp你来这个仓库的主要理由
独立应用Next.js 宿主,把 viewer + editor + 工具拼成完整编辑器apps/editor本地跑起来看效果时
架构文档分层规则、节点 schema、渲染器、系统、工具、选择管理等专题页wiki/architecture/,共 20 个 Markdown 文件(含索引 README.md改动前必读,AGENTS.md 里点名了哪类改动读哪页

三个细节值得单独说。

一是 packages/nodes/src/ 下面有 46 个子目录(ls -d packages/nodes/src/*/ | wc -l),绝大多数是一种构件:wallslabdoorwindowstairroof-segmentsolar-panelduct-segmentpipe-trapstructural-grid……还有 shared 这类共享目录。这个粒度说明它想覆盖的不只是「四面墙一个屋顶」,暖通风管、给排水管件、结构柱网(承重柱按固定间距排成的那套网格,也是整套图纸的定位基准)都在里面。

二是仓库根目录同时存在 AGENTS.mdCLAUDE.mdGEMINI.md 三份 Agent 约定文件。AGENTS.md 自己交代了:CLAUDE.mdGEMINI.md.github/copilot-instructions.md 都是它的符号链接,Codex 直接读原文件。它还把可复用工作流放在 .agents/skills/<name>/SKILL.md,目前有 open-prreview-architecture 两个,并通过符号链接同时暴露成 .claude/skills/.cursor/skills/.codex/skills/。这是一种「一份真相、多家宿主」的组织方式,值得直接抄。

三是上面那张表只写了 apps/editor 一个应用,但 apps/ 下其实是两个。另一个是 apps/ifc-converter,对应的纯逻辑包是 packages/ifc-converter,它的 README 交代得很清楚:接收一段 IFC 字节流,按 core 的 schema 吐出 { nodes, rootNodeIds, stats },不碰 DOM 也不碰 React,界面部分单独放在应用里。IFC 是建筑信息模型领域用来跨软件交换模型的开放文件格式,各家建模软件都能导入导出;把它单独切成一个无依赖的转换包,意味着「从别人的模型导进来」和「渲染出来」是两条互不牵连的路。对做 Agent 的人来说这条支线也有用——它给出了一个把外部行业数据映射成这套节点字典的现成参照。

三、MCP 服务器:Agent 是怎么造房子的

packages/mcp/README.md 把这一层说得很直白:这个服务器在 Bun 里无头运行,不需要浏览器、WebGPU、React,也不依赖外部数据库服务。它把编辑器 UI 用的那套场景变更操作,原样暴露成 MCP 的 tools、resources、prompts。

工具面的分层很清晰。 一类是只读查询:get_scene 取全量场景图,get_node / describe_node 取单个节点,find_nodes 按类型或父节点筛,list_levelsget_level_summaryget_wallsget_zones 分别给出楼层、墙、房间的摘要,measure 算两个节点间距离和面积。这一组的价值在于给 Agent 提供「便宜的上下文」——不必每次把整棵场景图塞进对话。

一类是语义化的建造工具,粒度明显高于「创建一个节点」:create_room 接一个多边形,一次性生成区域、楼板、吊顶和四周的墙,返回各自 id 和面积;create_story_shell 从一个轮廓生成整层的外壳;create_stair_between_levels 建一段直跑楼梯,同时在目标楼板或下层吊顶上开一个矩形洞口;create_roof 建屋面容器和屋面段;add_door / add_window 用参数化方式往墙上加门窗;furnish_room 按房间类型往多边形里摆家具。

还有一类是底层与运维工具:create_levelcreate_wallplace_itemcut_openingset_zoneduplicate_leveldelete_node 是细粒度写入;apply_patch 接一批 create/update/delete/move,先做校验和 dry-run 再提交;undo / redo 走时间旅行历史;export_json 序列化;validate_sceneverify_scenecheck_collisions 分别做 schema 校验、高层布局检查和重叠检测。另外还有两个视觉工具,analyze_floorplan_image 从平面图图片里提墙和房间,analyze_room_photo 从房间照片里提近似尺寸和固定装置。

这里要提醒一句:packages/mcp/README.md 的那张工具表并不等于服务器实际注册的全部工具。代码里 packages/mcp/src/tools/scene-lifecycle/ 还单独放着一组项目生命周期工具——create_project 建项目、load_scene 载入已保存的场景、save_scene 存草稿或检查点、get_project_status 查当前项目状态。这一组在 README 表里没有条目,却是实时联动那条链路上绕不开的。所以判断工具面够不够用,别只扫 README,packages/mcp/src/tools/ 这个目录才是权威清单。

资源与提示这层也别跳过。 资源里 pascal://scene/current 给 JSON 快照,pascal://scene/current/summary 给人读的 Markdown 摘要,pascal://catalog/items 给内置家具目录,pascal://constraints/{levelId} 给某层的楼板轮廓和墙多边形当规划上下文。最有意思的是那份写给 Agent 的施工说明书。README 的资源表里它叫 pascal://agent/guide,但代码里这个 URI 已经被标成 legacy,新名字是 pascal://agent-guide,两个 URI 返回同一份内容——照 README 抄配置不会出错,但你要是按 URI 做缓存键,得知道有两个。这份说明书直接规定了动作顺序(先 create_room,再 add_dooradd_window,最后 furnish_room)、坐标约定(X/Z 是平面轴、Y 是竖直方向、单位是米),甚至写了一条经验规则:每扇门两侧留大约 0.65 米净空——净空就是家具不能侵占、供人通行的空白区域。它还专门列了一节收尾检查,其中 verify_scene.hasIssues 应为 false,否则要向用户解释剩余问题;get_project_status.nodeCount 则被写成必须大于 0。措辞上这两条强度不同,一条是「应当」,一条是「必须」,抄进自己的 Agent 提示词时别一刀切。

提示模板有三个:from_brief 把一段散文需求(README 举的例子是「80 平米两居室」)转成一串递进的 apply_patch 调用;iterate_on_feedback 要求用最小改动满足反馈;renovation_from_photos 把视觉工具和变更工具串起来出改造方案。

它和编辑器怎么联动。 通过 MCP 保存的场景落在本地 SQLite 数据库 ~/.pascal/data/pascal.db,可用 PASCAL_DATA_DIR 换目录、PASCAL_DB_PATH 指定确切文件。当编辑器和 MCP 服务器共用同一个 PASCAL_DATA_DIR 时,MCP 的写入会持久化并记进一个本地 scene_events 事件流,编辑器页面用 SSE 订阅 /api/scenes/:id/events,于是浏览器标签页能实时看到 Agent 在改什么。每次变更前会做版本校验,如果浏览器或另一个 MCP 进程先写了新版本,工具会返回 live_sync_version_conflict,此时要重新 load_scene

四、边界与代价:这个设计放弃了什么

真诚地说清楚这块,比列工具清单更有用。

几何是渲染期算的,无头模式下不重算。 packages/mcp/README.md 的限制章节写得很坦白:墙体斜接(相邻两堵墙交角处的接缝处理)、楼板三角化(把一个平面多边形切成一堆三角形,显卡才画得出来)、门窗洞口的 CSG 布尔运算(用实体减实体挖出洞的运算)、屋顶与楼梯生成,这些系统跑在编辑器的 React hooks 里。无头模式不会重新生成派生几何,只保证节点数据完全可操作。需要真几何的消费方,得在浏览器宿主里跑 @pascal-app/viewer

export_glb 是明确的未实现。 它会抛 not_implemented,理由是 GLB 导出依赖 Three.js 渲染器,无头环境下代价太大。所以「让 Agent 生成一个能直接丢进游戏引擎的模型文件」这条路,在当前 MCP 层是走不通的,你只能拿 export_json

视觉工具依赖宿主能力。 两个 analyze 工具需要 MCP 宿主支持 sampling(createMessage),不支持的客户端会拿到结构化的 sampling_unavailable 错误。选宿主前先确认这点。

资产 URL 有浏览器绑定。 core 的 loadAssetUrl / saveAsset 是浏览器专属的,引用 asset://<id> 的条目在 Node 里解析不了,需要外部可用时得改成绝对 URL 或 data: URL。

内置目录是刻意做小的。 README 说这是为了不让 MCP 包依赖编辑器 UI 包,宿主应用可以自己暴露更丰富的目录。也就是说,你想要什么风格的家具,多半得自己接。

还有个观测性上的小坑: 无头模式下没有渲染器消费 dirtyNodes(待更新节点集合),它会一直累积,需要时得调 bridge.flushDirty() 排空。

安全代价必须摆在明面上。 这个服务器会在你机器上跑起来,会读写 ~/.pascal/data/pascal.db 这个本地文件,Agent 通过工具能创建、修改、删除、级联删除场景里的任何节点——delete_nodecascade 参数。默认走 stdio;开 HTTP 时(pascal-mcp --http --port 8787)如果绑非 loopback 地址,代码里强制要求提供 PASCAL_MCP_HTTP_TOKENauthToken,否则直接拒绝启动,这个约束在 packages/mcp/src/transports/http.ts 里。视觉工具会按你给的图片 URL 发起出网请求,仓库为此单独写了 packages/mcp/src/lib/safe-fetch.ts:拦截回环地址、链路本地地址(含云厂商元数据地址 169.254.169.254)、私有网段和非 http(s) 协议,重定向手动跟随并对每一跳重新做同样检查,还支持用 PASCAL_ALLOWED_ASSET_ORIGINS 收窄到白名单。这个文件的注释里写明了动因:早前几个视觉工具直接裸调 fetch(url),构成了一个 SSRF 通道。关于这类判断的通用框架,可以参考 MCP 的安全边界

五、上手与避坑清单

跑起来这一步,别在子目录里起服务。 README 明确要求从仓库根目录执行 bun dev,原因是根目录才会启动各个包的 watcher,你改 packages/core/src/packages/viewer/src/ 才能热更新。在子包里单独起,改了代码没反应,你会以为是缓存问题。默认端口 3002。

Docker 部署时不要重映射端口。 SETUP.md 里有一条很容易踩的坑:docker compose up -d 后编辑器在 3000 端口,必须保持容器端口是 3000,因为 /scenes 页面通过一个只有 NEXT_PUBLIC_APP_URL 能覆盖的 base URL 请求自己的 API,而 Next 会在构建期把这个值内联进去——把端口改成别的,页面直接返回 500。自托管到别的域名时,要显式设 MINT_PASCAL_HOST_ORIGIN。数据落在 pascal-data 卷里,docker compose down 不会丢。

编辑器和 MCP 要指向同一个数据目录,否则「Agent 建了但我看不见」。 两边都设 PASCAL_DATA_DIR 指同一个路径。这是实时联动生效的前提。不过「明明工具返回成功,浏览器里空空如也」的原因不止这一个——草稿与已发布版本没对上也会这样。agent-guide 资源为此单独写了一节排查步骤,不预设病因:先调 get_project_status,把 publishedVersionlatestVersionbrowserVisibleVersionnodeCountgraphHash 五个值比一遍。如果图不空而浏览器是空的,说明问题出在会话绑定而不是数据目录,重新调一次 get_project_status 再存一次草稿即可;如果 nodeCount 本身就是 0,那才轮到去查两边的 PASCAL_DATA_DIR 是不是指到了两个地方。这个「先量再判」的次序,比任何一条经验法则都省时间。

别用外部工具算好坐标直接灌进来。 MCP 的 README 用了一整节讲坐标约定,也点明了陷阱:场景是右手系,X 和 Z 构成地面、Y 向上,长度是米、旋转是弧度并存成 Euler [x, y, z]。你传的每个二维点都是楼层局部的地面坐标 [x, z],第二个分量是世界 Z(进深),不是「上」。而按「Y 轴朝北、俯视看」习惯画出来的布局——地形测量、正北朝上的场地图、二维绘图库都是这个习惯——灌进来会整体转过一个角度。README 给的验证办法是:先放一张按已知锚点缩放好的参考底图(guide 节点,就是垫在场景底下的二维参考图),比对是否对齐,再决定你这边要补多少旋转或镜像。

墙上附着的坐标是墙局部坐标,不是平面坐标。 门窗存的 position[0],以及 place_item 目标是墙时的 position[0],都是沿墙方向的米数;附着在墙上的旋转也是墙局部的。这个和平面坐标混起来用,结果就是门跑到墙外面去。

并发写入要准备好冲突分支。 只要你同时开着浏览器编辑,就可能撞上 live_sync_version_conflict。别在 Agent 侧写重试循环硬顶,正确做法是重新 load_scene 再继续。

优先用语义工具,不要手搓节点图。 agent-guide 里把这条写成了两句并列的规则:语义工具优先于原始图补丁;除非没有对应的语义工具,否则不要手写节点图。原因不难理解——语义工具封装了这个领域的不变量(楼层归属、开洞同步、支撑面选举),手写 patch 很容易造出 schema 合法但建筑上讲不通的模型。想系统地理解怎么把 MCP 接进日常工具链,可以看 MCP 配置教程

六、接下来读哪个文件

给一条最短路径。想快速判断这套工具面是否够用,直接从 packages/mcp/README.md 的工具表往下扫,重点看 Limitations 那一节,很多决策在那里就能拍板。想理解 Agent 到底在改什么,读根目录 README.md 的 Core Concepts,尤其是节点层级和脏节点那两小节。想动手改代码,先读 AGENTS.md 的 Layer Boundaries,再按它的指引去 wiki/architecture/ 找对应页——比如加节点类型要读 node-schemas.mdrenderers.mdsystems.md,动选择逻辑要读 selection-managers.md。想把它当宿主嵌进自己的 Agent 框架,packages/mcp/examples/embed-in-agent.ts 是可编译的最短样例。

最后留一个自检清单,用来判断这个仓库对你有没有用:你需要的是可编程的建筑模型数据、还是可直接渲染的几何?你的宿主支持 sampling 吗?你能接受几何在无头环境不重算吗?三个问题都答完,再决定要不要投入时间。

这个系列的其余文章

这篇是总览。想往下挖,按下面两条线走:先让 Agent 调起来,或者直接读代码

上手与使用

结构与机制

全部文章也汇总在 Pascal Editor 开源专题。另一个「垂直领域 Agent」的样本在金融方向,工具层与风控层的切法完全不同:Vibe-Trading 是什么:HKUDS 这个开源交易 Agent 项目的工程全景与边界

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。