blog.dopana

Back

Most architectural design tools are either expensive proprietary software (Revit, ArchiCAD) or limited web tools. Pascal Editor is neither — it’s an open-source 3D building editor built with modern web technologies, specifically React Three Fiber and WebGPU, designed for creating and sharing architectural projects in the browser.

What is Pascal Editor?#

Pascal Editor is a 3D building editor developed by PascalOrg. It’s a Turborepo monorepo with a sophisticated architecture that separates concerns across five packages:

  • @pascal-app/core — Node schemas, scene state (Zustand), registry contracts, spatial queries, and event bus
  • @pascal-app/viewer — 3D rendering via React Three Fiber, shared render systems, camera/controls, and post-processing
  • @pascal-app/editor — Editing tools, panels, selection, and direct-manipulation UI
  • @pascal-app/nodes — Built-in registry plugin with node definitions, renderers, geometry, and systems
  • @pascal-app/ui — Shared UI components

The editor runs as a Next.js 16 application with React 19, using WebGPU for rendering and Bun as the package manager.

Core Architecture#

Node-Based Scene Graph#

Everything in Pascal Editor is a node. All nodes extend a base type:

BaseNode {
  id: string       // Auto-generated with type prefix
  type: string     // Discriminator for type-safe handling
  parentId: string | null
  visible: boolean
  camera?: Camera  // Optional saved camera position
  metadata?: JSON  // Arbitrary metadata
}
typescript

Nodes form a hierarchy:

Site
└── Building
    └── Level
        ├── Wall → Item (doors, windows)
        ├── Slab
        ├── Ceiling → Item (lights)
        ├── Roof
        ├── Zone
        ├── Scan (3D reference)
        └── Guide (2D reference)
text

The smart part: nodes are stored in a flat dictionary (Record<id, Node>), not a nested tree. Parent-child relationships are maintained via parentId and children arrays, making lookups fast and state management straightforward.

State Management with Zustand#

Each package has its own Zustand store:

StorePackageResponsibility
useScene@pascal-app/coreScene data: nodes, CRUD, undo/redo (50-step history via Zundo), persisted to IndexedDB
useViewer@pascal-app/viewerViewer state: selection, level display modes
useEditorapps/editorEditor state: active tool, panel states, preferences

Dirty Node System#

When a node changes, it’s marked as dirty. Systems check the dirty set each frame and only recompute geometry for affected nodes. This is how Pascal Editor achieves real-time performance in the browser:

// Automatic: createNode, updateNode, deleteNode mark nodes dirty
useScene.getState().updateNode(wallId, { thickness: 0.2 })
// → wallId added to dirtyNodes
// → WallSystem regenerates geometry next frame
typescript

Systems Architecture#

Systems are React components running in the render loop (useFrame) that update geometry and transforms:

SystemResponsibility
WallSystemGenerates wall geometry with mitering and CSG cutouts for doors/windows
SlabSystemGenerates floor geometry from polygons
CeilingSystemGenerates ceiling geometry
RoofSystemGenerates roof geometry
ItemSystemPositions items on walls, ceilings, or floors
LevelSystemHandles level visibility and positioning (stacked/exploded/solo)

Scene Registry#

The registry maps node IDs to their Three.js objects for fast lookup — no scene graph traversal needed:

sceneRegistry = {
  nodes: Map<id, Object3D>,
  byType: { wall: Set<id>, item: Set<id>, zone: Set<id>, ... }
}
typescript

Spatial Grid Manager#

Handles collision detection and placement validation — used by item placement tools to validate positions and calculate slab elevations.

Event Bus#

A typed event emitter (mitt) handles inter-component communication for node interactions, grid clicks, and context menus.

Editing Tools#

The editor provides a toolbar with specialized tools:

  • SelectTool — Selection and manipulation with hierarchical navigation (Site → Building → Level → Zone → Items)
  • WallTool — Draw walls with mitering and cutouts
  • ZoneTool — Create functional zones
  • ItemTool — Place furniture, fixtures, doors, windows
  • SlabTool — Create floor slabs

Plugin System#

Pascal Editor is extensible via plugins. A plugin ships node kinds (schema, 3D/2D rendering, placement tools, inspector parametrics) and left-rail panels through the same manifest as built-ins.

There’s even a worked example: pascalorg/plugin-trees — a standalone plugin with procedural trees, flowers, grass, and a presets panel.

Technology Stack#

LayerTechnology
FrameworkReact 19 + Next.js 16
3D RenderingThree.js (WebGPU renderer) + React Three Fiber + Drei
StateZustand + Zundo (undo/redo) + IndexedDB persistence
ValidationZod
Geometrythree-bvh-csg (Boolean operations)
MonorepoTurborepo
Package ManagerBun

Getting Started#

# Clone and install
git clone https://github.com/pascalorg/editor
cd editor
bun install

# Start development server (hot reload for all packages)
bun dev
# Opens http://localhost:3002
bash

For production:

turbo build
bash

Using Published Packages#

You can use Pascal Editor’s components in your own projects:

npm install @pascal-app/core @pascal-app/viewer @pascal-app/editor @pascal-app/nodes
bash
import { loadPlugin } from '@pascal-app/core'
import { builtinPlugin } from '@pascal-app/nodes'
await loadPlugin(builtinPlugin)
typescript

Why Pascal Editor Matters#

Most open-source 3D editors are either game engines (Godot, Three.js playgrounds) or generic CAD tools. Pascal Editor is purpose-built for architectural design — with wall mitering, slab generation, level management, and door/window cutouts built in.

Its WebGPU renderer means it can handle complex building models in the browser with real-time performance. And its plugin architecture means it can grow from a building editor into a full architectural design platform.

For developers, it’s also a masterclass in React Three Fiber architecture — showing how to structure stores, systems, renderers, and plugins in a real-world 3D application.

References#