Overview
The Pascal Editor SDK is built as a Turborepo monorepo with clear separation of concerns between packages. This architecture enables reusable 3D rendering components while keeping editor-specific functionality isolated.Repository Structure
The monorepo consists of three main packages:Package Responsibilities
@pascal-app/core
- Node schemas (Zod)
- Scene state (Zustand)
- Systems (geometry generation)
- Spatial queries
- Event bus
@pascal-app/viewer
- 3D rendering via React Three Fiber
- Default camera/controls
- Post-processing
- Node renderers
apps/editor
- UI components
- Interactive tools
- Selection management
- Editor-specific systems
Separation of Concerns
The viewer package renders the scene with sensible defaults and can be used standalone. The editor extends it with interactive tools, selection management, and editing capabilities.| Package | Responsibility |
|---|---|
| @pascal-app/core | Node schemas, scene state (Zustand), systems (geometry generation), spatial queries, event bus |
| @pascal-app/viewer | 3D rendering via React Three Fiber, default camera/controls, post-processing |
| apps/editor | UI components, tools, custom behaviors, editor-specific systems |
This separation allows the viewer to be published as a standalone NPM package for rendering Pascal scenes without editing functionality.
State Management
Each package has its own Zustand store for managing state:Core Stores
| Store | Package | Responsibility |
|---|---|---|
useScene | @pascal-app/core | Scene data: nodes, root IDs, dirty nodes, CRUD operations. Persisted to IndexedDB with undo/redo via Zundo. |
useViewer | @pascal-app/viewer | Viewer state: current selection (building/level/zone IDs), level display mode (stacked/exploded/solo), camera mode. |
useEditor | apps/editor | Editor state: active tool, structure layer visibility, panel states, editor-specific preferences. |
Access Patterns
packages/core/src/store/use-scene.ts:40-50
Data Flow
The architecture follows a unidirectional data flow pattern:Flow Example
- User Action: User clicks to create a wall
- Tool Handler: WallTool processes the click
- State Update:
useScene.getState().createNode(wallNode, levelId) - Marking Dirty: Node is automatically added to
dirtyNodesset - Rendering: React renders
<WallRenderer>component - Registration:
useRegistry(node.id, 'wall', ref)registers the mesh - System Processing:
WallSystemdetects dirty wall inuseFrame - Geometry Update: System generates wall geometry with mitering/CSG
- Cleanup: System clears dirty flag
packages/core/src/store/actions/node-actions.ts:5-52
Technology Stack
The SDK is built with modern web technologies:- React 19 + Next.js 16 - UI framework and application layer
- Three.js (WebGPU renderer) - 3D graphics engine
- React Three Fiber + Drei - React renderer for Three.js
- Zustand - State management
- Zod - Schema validation
- Zundo - Undo/redo middleware for Zustand
- three-bvh-csg - Boolean geometry operations (wall cutouts)
- Turborepo - Monorepo management
- Bun - Package manager and runtime
The use of WebGPU provides better performance than WebGL, especially for complex scenes with many nodes and geometry operations.
Scene Registry
The registry maps node IDs to their Three.js objects for fast lookup:useRegistry hook:
packages/core/src/hooks/scene-registry/scene-registry.ts
Publishing Workflow
The core and viewer packages are published to NPM:The editor application is not published to NPM - it’s deployed separately as a Next.js application.