pascalorg/editorPublic

Open-source 3D architectural editor with a local CLI, MCP tools, and practical workflows for humans and AI agents.

AI summary: A 3D spatial building editor leveraging React Three Fiber and WebGPU for architectural design.

Stars
24.6K
+206 today
Forks
3K
Watchers
131
Open issues
20
Open PRs
34
Contributors
~51
Commits
1.7K
Branches
241

TypeScriptMITCreated Oct 16, 2025Last push 1d agoLatest release v1.0.3+294 stars this week+2.7K this month

Quick answers

What is editor?
A 3D spatial building editor leveraging React Three Fiber and WebGPU for architectural design.
What does editor do?
Pascal Editor is a specialized 3D architectural and spatial building tool designed around modern web technologies like React Three Fiber and WebGPU. It provides a local runtime environment for declaratively editing complex 3D structures and scenes directly within an application via a Turborepo monorepo architecture. The tool includes a standalone Node.js CLI that provisions a persistent local installation, selects collision-free loopback ports, and manages projects via a local database without requiring repository cloning. Additionally, it features an integrated, authenticated Model Context Protocol (MCP) service running in the background to seamlessly facilitate AI agent interactions.
Who is editor for?
Frontend developers, 3D artists, and spatial computing engineers building applications that require high-performance, editable 3D environments. It assumes familiarity with React, WebGPU, and Node.js tooling.
How do I get started with editor?
npx @pascal-app/cli editor
How popular is editor on GitHub?
pascalorg/editor has 24,575 stars and 3,039 forks on GitHub, and gained 294 stars in the last 7 days.
What license does editor use?
pascalorg/editor is released under the MIT license.

Star history

since Jul 29, 2026
010K20KJul 2026Aug 2026Sep 2026Oct 2026
24.6K stars as of Oct 3, 2026. Measured daily since Jul 29, 2026; GitHub no longer exposes earlier star timestamps.

Contribution activity

commits per day, last 52 weeks
SepOctNovDecJanFebMarAprMayJunJulAugSepMonWedFri2025-09-27: 0 commits2025-09-28: 0 commits2025-09-29: 0 commits2025-09-30: 0 commits2025-10-01: 0 commits2025-10-02: 0 commits2025-10-03: 0 commits2025-10-04: 0 commits2025-10-05: 0 commits2025-10-06: 0 commits2025-10-07: 0 commits2025-10-08: 0 commits2025-10-09: 0 commits2025-10-10: 0 commits2025-10-11: 0 commits2025-10-12: 0 commits2025-10-13: 0 commits2025-10-14: 0 commits2025-10-15: 0 commits2025-10-16: 0 commits2025-10-17: 0 commits2025-10-18: 0 commits2025-10-19: 0 commits2025-10-20: 0 commits2025-10-21: 0 commits2025-10-22: 0 commits2025-10-23: 0 commits2025-10-24: 0 commits2025-10-25: 0 commits2025-10-26: 0 commits2025-10-27: 0 commits2025-10-28: 0 commits2025-10-29: 0 commits2025-10-30: 0 commits2025-10-31: 0 commits2025-11-01: 0 commits2025-11-02: 0 commits2025-11-03: 0 commits2025-11-04: 0 commits2025-11-05: 0 commits2025-11-06: 0 commits2025-11-07: 0 commits2025-11-09: 0 commits2025-11-10: 0 commits2025-11-11: 0 commits2025-11-12: 0 commits2025-11-13: 0 commits2025-11-14: 0 commits2025-11-15: 0 commits2025-11-16: 0 commits2025-11-17: 0 commits2025-11-18: 0 commits2025-11-19: 0 commits2025-11-20: 0 commits2025-11-21: 0 commits2025-11-22: 0 commits2025-11-23: 0 commits2025-11-24: 0 commits2025-11-25: 0 commits2025-11-26: 0 commits2025-11-27: 0 commits2025-11-28: 0 commits2025-11-29: 0 commits2025-11-30: 0 commits2025-12-01: 0 commits2025-12-02: 0 commits2025-12-03: 0 commits2025-12-04: 0 commits2025-12-05: 0 commits2025-12-06: 0 commits2025-12-07: 0 commits2025-12-08: 0 commits2025-12-09: 0 commits2025-12-10: 0 commits2025-12-11: 0 commits2025-12-12: 0 commits2025-12-13: 0 commits2025-12-14: 0 commits2025-12-15: 0 commits2025-12-16: 0 commits2025-12-17: 0 commits2025-12-18: 0 commits2025-12-19: 0 commits2025-12-20: 0 commits2025-12-21: 0 commits2025-12-22: 0 commits2025-12-23: 0 commits2025-12-24: 0 commits2025-12-25: 0 commits2025-12-26: 0 commits2025-12-27: 0 commits2025-12-28: 0 commits2025-12-29: 0 commits2025-12-30: 0 commits2025-12-31: 0 commits2026-01-01: 0 commits2026-01-02: 0 commits2026-01-03: 0 commits2026-01-04: 0 commits2026-01-05: 0 commits2026-01-06: 0 commits2026-01-07: 0 commits2026-01-08: 0 commits2026-01-09: 0 commits2026-01-10: 0 commits2026-01-11: 0 commits2026-01-12: 0 commits2026-01-13: 0 commits2026-01-14: 6 commits2026-01-15: 4 commits2026-01-16: 5 commits2026-01-17: 4 commits2026-01-18: 4 commits2026-01-19: 6 commits2026-01-20: 3 commits2026-01-21: 14 commits2026-01-22: 7 commits2026-01-23: 6 commits2026-01-24: 0 commits2026-01-25: 0 commits2026-01-26: 14 commits2026-01-27: 11 commits2026-01-28: 8 commits2026-01-29: 15 commits2026-01-30: 14 commits2026-01-31: 0 commits2026-02-01: 0 commits2026-02-02: 10 commits2026-02-03: 6 commits2026-02-04: 2 commits2026-02-05: 9 commits2026-02-06: 3 commits2026-02-07: 2 commits2026-02-08: 0 commits2026-02-09: 11 commits2026-02-10: 10 commits2026-02-11: 16 commits2026-02-12: 7 commits2026-02-13: 0 commits2026-02-14: 0 commits2026-02-15: 0 commits2026-02-16: 8 commits2026-02-17: 10 commits2026-02-18: 29 commits2026-02-19: 13 commits2026-02-20: 11 commits2026-02-21: 0 commits2026-02-22: 0 commits2026-02-23: 10 commits2026-02-24: 13 commits2026-02-25: 15 commits2026-02-26: 9 commits2026-02-27: 9 commits2026-02-28: 3 commits2026-03-01: 1 commit2026-03-02: 7 commits2026-03-03: 3 commits2026-03-04: 11 commits2026-03-05: 7 commits2026-03-06: 10 commits2026-03-07: 0 commits2026-03-08: 0 commits2026-03-09: 0 commits2026-03-10: 10 commits2026-03-11: 9 commits2026-03-12: 0 commits2026-03-13: 1 commit2026-03-14: 0 commits2026-03-15: 0 commits2026-03-16: 1 commit2026-03-17: 0 commits2026-03-18: 0 commits2026-03-19: 0 commits2026-03-20: 2 commits2026-03-21: 1 commit2026-03-22: 0 commits2026-03-23: 0 commits2026-03-24: 5 commits2026-03-25: 6 commits2026-03-26: 10 commits2026-03-27: 0 commits2026-03-28: 2 commits2026-03-29: 1 commit2026-03-30: 9 commits2026-03-31: 3 commits2026-04-01: 0 commits2026-04-02: 2 commits2026-04-03: 0 commits2026-04-04: 0 commits2026-04-05: 1 commit2026-04-06: 2 commits2026-04-07: 3 commits2026-04-08: 1 commit2026-04-09: 3 commits2026-04-10: 0 commits2026-04-11: 0 commits2026-04-12: 0 commits2026-04-13: 3 commits2026-04-14: 3 commits2026-04-15: 7 commits2026-04-16: 15 commits2026-04-17: 11 commits2026-04-18: 16 commits2026-04-19: 7 commits2026-04-20: 9 commits2026-04-21: 10 commits2026-04-22: 4 commits2026-04-23: 2 commits2026-04-24: 8 commits2026-04-25: 2 commits2026-04-26: 1 commit2026-04-27: 9 commits2026-04-28: 9 commits2026-04-29: 7 commits2026-04-30: 5 commits2026-05-01: 6 commits2026-05-02: 0 commits2026-05-03: 0 commits2026-05-04: 5 commits2026-05-05: 6 commits2026-05-06: 5 commits2026-05-07: 5 commits2026-05-08: 2 commits2026-05-09: 4 commits2026-05-10: 11 commits2026-05-11: 3 commits2026-05-12: 6 commits2026-05-13: 5 commits2026-05-14: 44 commits2026-05-15: 46 commits2026-05-16: 1 commit2026-05-17: 0 commits2026-05-18: 15 commits2026-05-19: 17 commits2026-05-20: 7 commits2026-05-21: 6 commits2026-05-22: 2 commits2026-05-23: 0 commits2026-05-24: 0 commits2026-05-25: 0 commits2026-05-26: 2 commits2026-05-27: 5 commits2026-05-28: 4 commits2026-05-29: 5 commits2026-05-30: 0 commits2026-05-31: 0 commits2026-06-01: 1 commit2026-06-02: 8 commits2026-06-03: 10 commits2026-06-04: 1 commit2026-06-05: 4 commits2026-06-06: 4 commits2026-06-07: 10 commits2026-06-08: 11 commits2026-06-09: 12 commits2026-06-10: 12 commits2026-06-11: 2 commits2026-06-12: 1 commit2026-06-13: 0 commits2026-06-14: 4 commits2026-06-15: 11 commits2026-06-16: 14 commits2026-06-17: 25 commits2026-06-18: 9 commits2026-06-19: 6 commits2026-06-20: 0 commits2026-06-21: 0 commits2026-06-22: 2 commits2026-06-23: 12 commits2026-06-24: 12 commits2026-06-25: 23 commits2026-06-26: 12 commits2026-06-27: 11 commits2026-06-28: 1 commit2026-06-29: 3 commits2026-06-30: 0 commits2026-07-01: 1 commit2026-07-02: 2 commits2026-07-03: 0 commits2026-07-04: 0 commits2026-07-05: 0 commits2026-07-06: 3 commits2026-07-07: 1 commit2026-07-08: 10 commits2026-07-09: 9 commits2026-07-10: 1 commit2026-07-11: 0 commits2026-07-12: 0 commits2026-07-13: 2 commits2026-07-14: 2 commits2026-07-15: 4 commits2026-07-16: 2 commits2026-07-17: 3 commits2026-07-18: 2 commits2026-07-19: 13 commits2026-07-20: 2 commits2026-07-21: 5 commits2026-07-22: 4 commits2026-07-23: 10 commits2026-07-24: 6 commits2026-07-25: 0 commits2026-07-26: 0 commits2026-07-27: 2 commits2026-07-28: 2 commits2026-07-29: 1 commit2026-07-30: 4 commits2026-07-31: 0 commits2026-08-01: 0 commits2026-08-02: 2 commits2026-08-03: 4 commits2026-08-04: 26 commits2026-08-05: 16 commits2026-08-06: 2 commits2026-08-07: 11 commits2026-08-08: 0 commits2026-08-09: 0 commits2026-08-10: 4 commits2026-08-11: 4 commits2026-08-12: 3 commits2026-08-13: 1 commit2026-08-14: 4 commits2026-08-15: 4 commits2026-08-16: 8 commits2026-08-17: 5 commits2026-08-18: 9 commits2026-08-19: 6 commits2026-08-20: 6 commits2026-08-21: 5 commits2026-08-22: 4 commits2026-08-23: 3 commits2026-08-24: 6 commits2026-08-25: 0 commits2026-08-26: 4 commits2026-08-27: 1 commit2026-08-28: 3 commits2026-08-29: 1 commit2026-08-30: 1 commit2026-08-31: 7 commits2026-09-01: 12 commits2026-09-02: 6 commits2026-09-03: 0 commits2026-09-04: 5 commits2026-09-05: 1 commit2026-09-06: 0 commits2026-09-07: 8 commits2026-09-08: 10 commits2026-09-09: 29 commits2026-09-10: 17 commits2026-09-11: 19 commits2026-09-12: 19 commits2026-09-13: 3 commits2026-09-14: 8 commits2026-09-15: 10 commits2026-09-16: 11 commits2026-09-17: 3 commits2026-09-18: 6 commits2026-09-19: 2 commits2026-09-20: 0 commits2026-09-21: 1 commit2026-09-22: 8 commits2026-09-23: 2 commits2026-09-24: 1 commit2026-09-25: 7 commits2026-09-26: 2 commits
1,430 commits in the last yearLessMore

Signals and awards

derived from tracked data
  • Widely adopted

    24,575 stars

  • Very active

    1,430 commits in 52 weeks

  • Well documented

    High community health score

  • Permissive license

    MIT

  • Continuous integration

    Automated checks passing

  • Repeat trending

    22 trending appearances

What editor does

Pascal Editor is a specialized 3D architectural and spatial building tool designed around modern web technologies like React Three Fiber and WebGPU. It provides a local runtime environment for declaratively editing complex 3D structures and scenes directly within an application via a Turborepo monorepo architecture. The tool includes a standalone Node.js CLI that provisions a persistent local installation, selects collision-free loopback ports, and manages projects via a local database without requiring repository cloning. Additionally, it features an integrated, authenticated Model Context Protocol (MCP) service running in the background to seamlessly facilitate AI agent interactions.

Frontend developers, 3D artists, and spatial computing engineers building applications that require high-performance, editable 3D environments. It assumes familiarity with React, WebGPU, and Node.js tooling.

  • WebGPU Rendering: Leverages modern WebGPU APIs for high-performance, complex 3D rendering within the browser or local client.
  • React Three Fiber Ecosystem: Uses robust React components for building and managing 3D scenes declaratively and interactively.
  • Local CLI Deployment: Provides a seamless Node.js CLI tool to instantiate a persistent local editor without requiring git cloning.
  • Background MCP Service: Includes an authenticated Model Context Protocol service to enable AI agent connectivity and automation.
  • Local Project Database: Maintains user projects and assets in a local SQLite database for persistent spatial editing and state tracking.
  • Modular Architecture: Structured as a Turborepo monorepo with distinct packages for core schemas, viewer rendering, and editor tools.
  • Zustand State Management: Utilizes isolated Zustand stores for scene data, viewer selection states, and editor tool visibility.

Where teams use it

3D Scene Creation

Allows developers and designers to build and edit interactive 3D architectural or spatial environments locally.

AI Agent Integration

Enables AI agents to interact with and modify the 3D editor state via the integrated background MCP service.

Local Environment Prototyping

Provides a fast, locally hosted environment to test and prototype modern WebGPU rendering techniques.

Spatial Application Development

Serves as a robust foundation for building more complex applications that require an editable 3D viewer runtime.

Getting started: npx @pascal-app/cli editor

README

main branch

Pascal Editor

An open-source, local-first 3D building editor built with React Three Fiber and WebGPU. Run it in the browser or from the CLI, and connect AI agents through MCP.

MIT License npm @pascal-app/core npm @pascal-app/viewer npm @pascal-app/cli Discord X (Twitter)

pascal_editor.mp4

A first look at Pascal Next

Explore the live demo — a real home reconstructed in detail, from its rooms and finishes to the structure and systems behind the walls. This hosted preview explores the direction of the next Pascal editor; the experience shown here is not yet part of the open-source editor release.

Exploded view — see how the home fits together Cut view — slice through the building
Roof lifted above the reconstructed home A section cut reveals the roof framing and interior
X-ray — reveal the modeled systems Walkthrough — step inside at eye level
Building systems isolated with the walls hidden Walking through the home toward the pool terrace
Interactions — open doors and explore Environment — change the light and atmosphere
Interacting with doors in the reconstructed home Changing the lighting around the reconstructed home

We are exploring what this could make possible for facility management, home services, architecture, home building, and infrastructure. Join the discussion on X and tell us where you would use it.

Make something with these videos

Making a video, tutorial, article, or social post about Pascal? You are welcome to use and edit this footage, including in monetized content, under CC BY 4.0. Credit Pascal, link the license, and note your edits; no separate permission is needed.

Download the six original videos and see the creator guide.

Run the Editor Locally

Node.js 22.13 or newer can create a persistent local Pascal installation without cloning this repository:

npx @pascal-app/cli editor

The CLI starts the editor and an authenticated MCP service in the background, selects collision-free loopback ports, and keeps projects in ~/.pascal/data/pascal.db. The npm package holds the CLI and that MCP service; the web editor runtime is downloaded once per version on the first command that starts the editor and verified against a digest published inside the package. Configure an agent to launch pascal mcp connect, which needs neither the editor process nor that download. Install the pascal command with npm install --global @pascal-app/cli. See Run Pascal locally for pnpm/Bun commands, project management, MCP setup, updates, storage paths, and troubleshooting.

Use one active agent client per local CLI service. The standalone local HTTP runtime shares active scene state between clients; use separate PASCAL_HOME directories and service processes when independent concurrent work is required.

Agent skills

Install with skills

Install Pascal's public agent workflows from this repository with skills.sh:

npx skills add pascalorg/editor \
  --skill pascal-3d \
  --skill furniture-fit

Claude Code users can install the same canonical skill source as a plugin:

/plugin marketplace add pascalorg/editor
/plugin install pascal-agent-skills@pascal

The Claude plugin also supplies the local pascal mcp connect server. Install and start the Pascal CLI first, and keep pascal on the PATH used to launch Claude Code. This local connector needs no Pascal account or API key and does not upload projects automatically. Its plugin root is this repository's skills/ directory, so an install copies only the skill bundles and their plugin metadata rather than the repository.

The plugin bundles two servers: the local pascal connector above and a hosted pascal-hosted server for https://editor.pascal.app/api/mcp, which prompts for an optional Pascal API key at enable time and stores it in the OS keychain. Leave the key empty to run local-only.

Claude Code 2.1.258 loads both the user-scoped pascal server created by pascal mcp setup claude and the plugin-provided server. Remove the manual entry before reloading or restarting Claude Code so only the plugin owns the connection lifecycle:

claude mcp remove --scope user pascal

Use /mcp to remove or disable any project- or local-scoped Pascal connection too. Leaving both connections active violates the one-active-agent-client-per-local-service requirement. When the intended project is hosted in a Pascal account or organization, disable the plugin-provided local server in /mcp and configure the hosted endpoint from the skill setup guide instead.

Codex users can install the same plugin from the repository marketplace:

codex plugin marketplace add pascalorg/editor
codex plugin add pascal-agent-skills@pascal

OpenClaw installation becomes available after the skills are published under Pascal's ClawHub publisher. See skills/README.md for the owner-qualified install and verification commands.

pascal-3d covers safe local or hosted MCP setup and verified scene work. furniture-fit produces a bounded, evidence-based footprint assessment without claiming unsupported height, swing, or delivery checks. See skills/README.md for package details and validation.

The skills inspect the connected MCP tool schemas before using optional fields. A capability present in this repository may be absent from an older installed or hosted release; the agent should report the narrower supported result instead of assuming source-only inputs are available.

These workflows require a connected Pascal MCP server for their tool-backed actions. An OpenAI directory submission must therefore use With MCP and submit the production hosted MCP endpoint together with the skills. The repository package does not prove that the endpoint, OAuth flow, reviewer credentials, domain verification, or portal scan is ready for review.

MCP Registry

server.json is Pascal's manifest for the official MCP Registry. Its version tracks the hosted MCP implementation independently of the npm package version. Pull requests validate the manifest and production endpoint. A Pascal organization owner publishes an approved version from main with the official registry publisher.

Using Published Packages

The viewer runtime and built-in node definitions are separate packages. Install the full built-in viewer set, then load the built-in plugin once before mounting <Viewer>. Capture sessions are an optional extension shipped inside those packages as the @pascal-app/core/capture and @pascal-app/viewer/capture subpaths:

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)

See the @pascal-app/viewer quick start for a React example.

Repository Architecture

This is a Turborepo monorepo with the reusable editor packages, the standalone app, and the CLI that distributes it:

editor/
├── apps/
│   └── editor/          # Next.js application
├── packages/
│   ├── core/            # Schemas, scene state, registry contracts, capture contracts
│   ├── viewer/          # 3D rendering runtime, shared systems, capture runtime
│   ├── editor/          # Editing tools and UI components
│   ├── nodes/           # Built-in node definitions, renderers, and systems
│   ├── cli/             # Persistent local editor installer and process manager
│   ├── mcp/             # Model Context Protocol server and scene storage
│   └── ui/              # Shared UI components

Separation of Concerns

Package Responsibility
@pascal-app/core Node schemas, scene state (Zustand), registry contracts, spatial queries, and event bus. core/capture adds versioned capture manifests, normalized streams, and transport-neutral static/live sources
@pascal-app/viewer 3D rendering via React Three Fiber, shared render systems, default camera/controls, and post-processing. viewer/capture adds the capture runtime and reference model, device-motion, point-cloud, and surface-mesh layers
@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/cli Installs and manages a versioned standalone editor runtime and persistent local data
@pascal-app/mcp Exposes scene tools, resources, prompts, and local storage to MCP-compatible AI hosts
apps/editor Standalone Next.js host for the editor packages

The viewer renders the scene with sensible defaults. The editor extends it with interactive tools, selection management, and editing capabilities.

Stores

Each package has its own Zustand store for managing state:

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:

// Subscribe to state changes (React component)
const nodes = useScene((state) => state.nodes)
const levelId = useViewer((state) => state.selection.levelId)
const activeTool = useEditor((state) => state.tool)

// Access state outside React (callbacks, systems)
const node = useScene.getState().nodes[id]
useViewer.getState().setSelection({ levelId: 'level_123' })

Core Concepts

Nodes

Nodes are the data primitives that describe the 3D scene. All nodes extend BaseNode:

BaseNode {
  id: string              // Auto-generated with type prefix (e.g., "wall_abc123")
  type: string            // Discriminator for type-safe handling
  parentId: string | null // Parent node reference
  visible: boolean
  camera?: Camera         // Optional saved camera position
  metadata?: JSON         // Arbitrary metadata (e.g., { isTransient: true })
}

Node Hierarchy:

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

Nodes are stored in a flat dictionary (Record<id, Node>), not a nested tree. Parent-child relationships are defined via parentId and children arrays.


Scene State (Zustand Store)

The scene is managed by a Zustand store in @pascal-app/core:

useScene.getState() = {
  nodes: Record<id, AnyNode>,  // All nodes
  rootNodeIds: string[],       // Top-level nodes (sites)
  dirtyNodes: Set<string>,     // Nodes pending system updates

  createNode(node, parentId),
  updateNode(id, updates),
  deleteNode(id),
}

Middleware:

  • Persist - Saves to IndexedDB (excludes transient nodes)
  • Temporal (Zundo) - Undo/redo with 50-step history

Scene Registry

The registry maps node IDs to their Three.js objects for fast lookup:

sceneRegistry = {
  nodes: Map<id, Object3D>,    // ID → 3D object
  byType: {
    wall: Set<id>,
    item: Set<id>,
    zone: Set<id>,
    // ...
  }
}

Renderers register their refs using the useRegistry hook:

const ref = useRef<Mesh>(null!)
useRegistry(node.id, 'wall', ref)

This allows systems to access 3D objects directly without traversing the scene graph.


Node Renderers

Renderers are React components that create Three.js objects for each node type:

SceneRenderer
└── NodeRenderer (dispatches by type)
    ├── BuildingRenderer
    ├── LevelRenderer
    ├── WallRenderer
    ├── SlabRenderer
    ├── ZoneRenderer
    ├── ItemRenderer
    └── ...

Pattern:

  1. Renderer creates a placeholder mesh/group
  2. Registers it with useRegistry
  3. Systems update geometry based on node data

Example (simplified):

const WallRenderer = ({ node }) => {
  const ref = useRef<Mesh>(null!)
  useRegistry(node.id, 'wall', ref)

  return (
    <mesh ref={ref}>
      <boxGeometry args={[0, 0, 0]} />  {/* Replaced by WallSystem */}
      <meshStandardMaterial />
      {node.children.map(id => <NodeRenderer key={id} nodeId={id} />)}
    </mesh>
  )
}

Systems

Systems are React components that run in the render loop (useFrame) to update geometry and transforms. They process dirty nodes marked by the store.

Core Systems (in @pascal-app/core):

System Responsibility
WallSystem Generates wall geometry with mitering and CSG cutouts for doors/windows
SlabSystem Generates floor geometry from polygons
CeilingSystem Generates ceiling geometry
RoofSystem Generates roof geometry
ItemSystem Positions items on walls, ceilings, or floors (slab elevation)

Viewer Systems (in @pascal-app/viewer):

System Responsibility
LevelSystem Handles level visibility and vertical positioning (stacked/exploded/solo modes)
ScanSystem Controls 3D scan visibility
GuideSystem Controls guide image visibility

Processing Pattern:

useFrame(() => {
  for (const id of dirtyNodes) {
    const obj = sceneRegistry.nodes.get(id)
    const node = useScene.getState().nodes[id]

    // Update geometry, transforms, etc.
    updateGeometry(obj, node)

    dirtyNodes.delete(id)
  }
})

Dirty Nodes

When a node changes, it's marked as dirty in useScene.getState().dirtyNodes. Systems check this set each frame and only recompute geometry for dirty nodes.

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

Manual marking:

useScene.getState().dirtyNodes.add(wallId)

Event Bus

Inter-component communication uses a typed event emitter (mitt):

// Node events
emitter.on('wall:click', (event) => { ... })
emitter.on('item:enter', (event) => { ... })
emitter.on('zone:context-menu', (event) => { ... })

// Grid events (background)
emitter.on('grid:click', (event) => { ... })

// Event payload
NodeEvent {
  node: AnyNode
  position: [x, y, z]
  localPosition: [x, y, z]
  normal?: [x, y, z]
  stopPropagation: () => void
}

Spatial Grid Manager

Handles collision detection and placement validation:

spatialGridManager.canPlaceOnFloor(levelId, position, dimensions, rotation)
spatialGridManager.canPlaceOnWall(wallId, t, height, dimensions)
spatialGridManager.getSlabElevationAt(levelId, x, z)

Used by item placement tools to validate positions and calculate slab elevations.


Editor Architecture

The editor extends the viewer with:

Tools

Tools are activated via the toolbar and handle user input for specific operations:

  • SelectTool - Selection and manipulation
  • WallTool - Draw walls
  • ZoneTool - Create zones
  • ItemTool - Place furniture/fixtures
  • SlabTool - Create floor slabs

Selection Manager

The editor uses a custom selection manager with hierarchical navigation:

Site → Building → Level → Zone → Items

Each depth level has its own selection strategy for hover/click behavior.

Editor-Specific Systems

  • ZoneSystem - Controls zone visibility based on level mode
  • Custom camera controls with node focusing

Data Flow

User Action (click, drag)
       ↓
Tool Handler
       ↓
useScene.createNode() / updateNode()
       ↓
Node added/updated in store
Node marked dirty
       ↓
React re-renders NodeRenderer
useRegistry() registers 3D object
       ↓
System detects dirty node (useFrame)
Updates geometry via sceneRegistry
Clears dirty flag

Building a Plugin

The editor is extensible: a plugin ships node kinds (schema, 3D/2D rendering, placement tools, inspector parametrics) and left-rail panels through the same Plugin manifest the built-ins use — there is no separate internal API.

  • Developer guide — Create a plugin: the Plugin shape, panel contributions, discovery, lifecycle, and what's in/out of v1.
  • Worked example — pascalorg/plugin-trees: a standalone plugin with procedural trees, flowers, grass, and a presets panel. Clone it as a starting point.

Technology Stack

  • React 19 + Next.js 16
  • Three.js (WebGPU renderer)
  • React Three Fiber + Drei
  • Zustand (state management)
  • Zod (schema validation)
  • Zundo (undo/redo)
  • three-bvh-csg (Boolean geometry operations)
  • Turborepo (monorepo management)
  • Bun (package manager)

Getting Started

Development

Run the development server from the root directory to enable hot reload for all packages:

# Install dependencies
bun install

# Run development server (builds packages + starts editor with watch mode)
bun dev

# This will:
# 1. Build @pascal-app/core and @pascal-app/viewer
# 2. Start watching both packages for changes
# 3. Start the Next.js editor dev server
# Open http://localhost:3002

Important: Always run bun dev from the root directory to ensure the package watchers are running. This enables hot reload when you edit files in packages/core/src/ or packages/viewer/src/.

Building for Production

# Build all packages
turbo build

# Build specific package
turbo build --filter=@pascal-app/core

Publishing Packages

Releases run from .github/workflows/release.yml (workflow_dispatch, with package, bump, and dry-run inputs). The workflow bumps versions, rewrites the internal @pascal-app/* ranges, builds, publishes in dependency order (core → viewer → editor → nodes → mcp → ifc-converter → cli), then commits the release and pushes one tag per package. A dry run validates the builds without touching the registry.


Key Files

Path Description
packages/core/src/schema/ Node type definitions (Zod schemas)
packages/core/src/store/use-scene.ts Scene state store
packages/core/src/hooks/scene-registry/ 3D object registry
packages/core/src/systems/ Geometry generation systems
packages/viewer/src/components/renderers/ Node renderers
packages/viewer/src/components/viewer/ Main Viewer component
apps/editor/components/tools/ Editor tools
apps/editor/store/ Editor-specific state

Contributing

Bug fixes, features, docs and ideas are all welcome. Start with CONTRIBUTING.md for setup, code style and the PR flow.


Contributors

Aymeric Rabot Wassim Samad Sudhir


pascalorg/editor | Trendshift

View on GitHub

Recent activity

commits and pull requests

Releases and announcements

29 total
  1. 1.0.3 brings all seven `@pascal-app/*` packages to the same version on npm `latest` and carries the export and visibility fixes into one coordinated release. ### 🐛 Fixes - GLB and USDZ exports now finish or return an actionable timeout instead of remaining in progress indefinitely ([#888](https://github.com/pascalorg/editor/pull/888)). - A hidden Site no longer empties GLB exports, PDF exports or the 2D plan; child visibility remains independent ([#907](https://github.com/pascalorg/editor/pull/907)). - Container node visibility now applies consistently in the 3D viewer ([#908](https://github.com/pascalorg/editor/pull/908)). - The CLI starts the runtime belonging to its own published version ([#893](https://github.com/pascalorg/editor/pull/893)). ### 🧰 Release - The release workflow now aligns all seven package versions and internal ranges ([#909](https://github.com/pascalorg/editor/pull/909)). - Package repository URLs and the MCP executable path were corrected ([#911](https://github.com/pascalorg/editor/pull/911)). ### 📦 Packages | Package | Version | |---|---| | `@pascal-app/core` | `1.0.3` | | `@pascal-app/viewer` | `1.0.3` | | `@pascal-app/editor` | `1.0.3` | | `@pasca

  2. @pascal-app/[email protected]@pascal-app/[email protected]Sep 24, 2026109 downloads

    The Pascal web editor runtime for `@pascal-app/[email protected]`. The CLI downloads `pascal-web-runtime-1.0.3.tar.gz` the first time a command starts the editor and verifies it against the digest published inside the npm package. Offline installs can pass the archive directly: `pascal editor --runtime pascal-web-runtime-1.0.3.tar.gz`.

  3. Pascal Next — creator video kitpascal-next-media-2026-09-21Sep 21, 2026103 downloads

    # Pascal Next — videos for creators Use these six original recordings in your own videos, tutorials, articles, presentations, and social posts, including monetized content. Trim, crop, remix, add narration or captions: no separate permission is needed when you follow [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/). Credit **Pascal Group Inc.**, link the license, and note your edits. The attached `LICENSE.md` covers Pascal's rights in the recordings; the editor source code remains MIT licensed. [Try the demo](https://editor.pascal.app/next) · [Join the discussion on X](https://x.com/pascal_app/status/2102097655031558496) | File | Feature | Duration | | --- | --- | --- | | `pascal-editor-intro.mp4` | Arrival, construction, and exploded view | 35 s | | `pascal-editor-cutview.mp4` | Section cuts through the building | 1 min 3 s | | `pascal-editor-xray.mp4` | Structure and building systems, layer by layer | 52 s | | `pascal-editor-walkthrough.mp4` | Exploring the home at eye level | 2 min | | `pascal-editor-interactions.mp4` | Doors and interactive objects | 20 s | | `pascal-editor-environment.mp4` | Lighting and atmosphere | 30 s | All recordings are the full original MP

  4. @pascal-app/[email protected]@pascal-app/[email protected]Sep 18, 2026449 downloads

    The Pascal web editor runtime for `@pascal-app/[email protected]`. The CLI downloads `pascal-web-runtime-1.0.2.tar.gz` the first time a command starts the editor and verifies it against the digest published inside the npm package. Offline installs can pass the archive directly: `pascal editor --runtime pascal-web-runtime-1.0.2.tar.gz`.

  5. @pascal-app/[email protected]@pascal-app/[email protected]Sep 18, 202662 downloads

    The Pascal web editor runtime for `@pascal-app/[email protected]`. The CLI downloads `pascal-web-runtime-1.0.1.tar.gz` the first time a command starts the editor and verifies it against the digest published inside the npm package. Offline installs can pass the archive directly: `pascal editor --runtime pascal-web-runtime-1.0.1.tar.gz`.

Code frequency

additions and deletions
+206.3K-206.3KWeek of 2026-01-11: +9,668 linesWeek of 2026-01-11: -2,651 linesWeek of 2026-01-18: +9,404 linesWeek of 2026-01-18: -3,597 linesWeek of 2026-01-25: +33,255 linesWeek of 2026-01-25: -25,364 linesWeek of 2026-02-01: +4,671 linesWeek of 2026-02-01: -1,111 linesWeek of 2026-02-08: +10,456 linesWeek of 2026-02-08: -4,860 linesWeek of 2026-02-15: +25,373 linesWeek of 2026-02-15: -13,257 linesWeek of 2026-02-22: +16,097 linesWeek of 2026-02-22: -4,847 linesWeek of 2026-03-01: +10,922 linesWeek of 2026-03-01: -3,275 linesWeek of 2026-03-08: +48,321 linesWeek of 2026-03-08: -68,643 linesWeek of 2026-03-15: +1,945 linesWeek of 2026-03-15: -625 linesWeek of 2026-03-22: +15,591 linesWeek of 2026-03-22: -4,133 linesWeek of 2026-03-29: +4,431 linesWeek of 2026-03-29: -2,334 linesWeek of 2026-04-05: +9,542 linesWeek of 2026-04-05: -2,216 linesWeek of 2026-04-12: +42,049 linesWeek of 2026-04-12: -4,885 linesWeek of 2026-04-19: +25,712 linesWeek of 2026-04-19: -27,050 linesWeek of 2026-04-26: +27,750 linesWeek of 2026-04-26: -13,516 linesWeek of 2026-05-03: +28,803 linesWeek of 2026-05-03: -8,294 linesWeek of 2026-05-10: +24,999 linesWeek of 2026-05-10: -5,963 linesWeek of 2026-05-17: +206,326 linesWeek of 2026-05-17: -38,305 linesWeek of 2026-05-24: +12,042 linesWeek of 2026-05-24: -2,740 linesWeek of 2026-05-31: +32,495 linesWeek of 2026-05-31: -7,415 linesWeek of 2026-06-07: +26,512 linesWeek of 2026-06-07: -7,269 linesWeek of 2026-06-14: +31,283 linesWeek of 2026-06-14: -3,812 linesWeek of 2026-06-21: +30,912 linesWeek of 2026-06-21: -8,204 linesWeek of 2026-06-28: +16,240 linesWeek of 2026-06-28: -2,109 linesWeek of 2026-07-05: +6,024 linesWeek of 2026-07-05: -1,242 linesWeek of 2026-07-12: +54,573 linesWeek of 2026-07-12: -5,574 linesWeek of 2026-07-19: +53,706 linesWeek of 2026-07-19: -6,156 linesWeek of 2026-07-26: +18,379 linesWeek of 2026-07-26: -9,118 linesWeek of 2026-08-02: +11,527 linesWeek of 2026-08-02: -1,436 linesWeek of 2026-08-09: +6,205 linesWeek of 2026-08-09: -1,118 linesWeek of 2026-08-16: +48,045 linesWeek of 2026-08-16: -3,503 linesWeek of 2026-08-23: +26,428 linesWeek of 2026-08-23: -4,877 linesWeek of 2026-08-30: +27,668 linesWeek of 2026-08-30: -5,349 linesWeek of 2026-09-06: +72,702 linesWeek of 2026-09-06: -22,728 linesWeek of 2026-09-13: +76,712 linesWeek of 2026-09-13: -3,341 linesWeek of 2026-09-20: +24,145 linesWeek of 2026-09-20: -3,412 linesWeek of 2026-09-27: +0 linesWeek of 2026-09-27: -0 linesJan 11, 2026Sep 27, 2026
+1.1M lines added, -334.3K removed over the last year.

Commits per week

last 52 weeks
1160Week of 2025-09-27: 0 commitsWeek of 2025-10-04: 0 commitsWeek of 2025-10-11: 0 commitsWeek of 2025-10-18: 0 commitsWeek of 2025-10-25: 0 commitsWeek of 2025-11-01: 0 commitsWeek of 2025-11-09: 0 commitsWeek of 2025-11-16: 0 commitsWeek of 2025-11-23: 0 commitsWeek of 2025-11-30: 0 commitsWeek of 2025-12-07: 0 commitsWeek of 2025-12-14: 0 commitsWeek of 2025-12-21: 0 commitsWeek of 2025-12-28: 0 commitsWeek of 2026-01-04: 0 commitsWeek of 2026-01-11: 19 commitsWeek of 2026-01-18: 40 commitsWeek of 2026-01-25: 62 commitsWeek of 2026-02-01: 32 commitsWeek of 2026-02-08: 44 commitsWeek of 2026-02-15: 71 commitsWeek of 2026-02-22: 59 commitsWeek of 2026-03-01: 39 commitsWeek of 2026-03-08: 20 commitsWeek of 2026-03-15: 4 commitsWeek of 2026-03-22: 23 commitsWeek of 2026-03-29: 15 commitsWeek of 2026-04-05: 10 commitsWeek of 2026-04-12: 55 commitsWeek of 2026-04-19: 42 commitsWeek of 2026-04-26: 37 commitsWeek of 2026-05-03: 27 commitsWeek of 2026-05-10: 116 commitsWeek of 2026-05-17: 47 commitsWeek of 2026-05-24: 16 commitsWeek of 2026-05-31: 28 commitsWeek of 2026-06-07: 48 commitsWeek of 2026-06-14: 69 commitsWeek of 2026-06-21: 72 commitsWeek of 2026-06-28: 7 commitsWeek of 2026-07-05: 24 commitsWeek of 2026-07-12: 15 commitsWeek of 2026-07-19: 40 commitsWeek of 2026-07-26: 9 commitsWeek of 2026-08-02: 61 commitsWeek of 2026-08-09: 20 commitsWeek of 2026-08-16: 43 commitsWeek of 2026-08-23: 18 commitsWeek of 2026-08-30: 32 commitsWeek of 2026-09-06: 102 commitsWeek of 2026-09-13: 43 commitsWeek of 2026-09-20: 21 commitsSep 27, 2025Sep 20, 2026
1.4K commits in the last 52 weeks.

When work happens

weekday and hour
SunMonTueWedThuFriSat036912151821Sun 0:00 — 12 commitsSun 1:00 — 3 commitsSun 2:00 — 2 commitsSun 3:00 — 1 commitsSun 4:00 — 1 commitsSun 5:00 — 1 commitsSun 6:00 — 1 commitsSun 7:00 — 0 commitsSun 8:00 — 4 commitsSun 9:00 — 1 commitsSun 10:00 — 4 commitsSun 11:00 — 3 commitsSun 12:00 — 4 commitsSun 13:00 — 1 commitsSun 14:00 — 0 commitsSun 15:00 — 3 commitsSun 16:00 — 1 commitsSun 17:00 — 6 commitsSun 18:00 — 6 commitsSun 19:00 — 2 commitsSun 20:00 — 6 commitsSun 21:00 — 5 commitsSun 22:00 — 1 commitsSun 23:00 — 3 commitsMon 0:00 — 5 commitsMon 1:00 — 8 commitsMon 2:00 — 2 commitsMon 3:00 — 0 commitsMon 4:00 — 2 commitsMon 5:00 — 0 commitsMon 6:00 — 1 commitsMon 7:00 — 7 commitsMon 8:00 — 19 commitsMon 9:00 — 15 commitsMon 10:00 — 27 commitsMon 11:00 — 18 commitsMon 12:00 — 16 commitsMon 13:00 — 12 commitsMon 14:00 — 13 commitsMon 15:00 — 8 commitsMon 16:00 — 8 commitsMon 17:00 — 14 commitsMon 18:00 — 9 commitsMon 19:00 — 5 commitsMon 20:00 — 5 commitsMon 21:00 — 2 commitsMon 22:00 — 3 commitsMon 23:00 — 3 commitsTue 0:00 — 4 commitsTue 1:00 — 3 commitsTue 2:00 — 5 commitsTue 3:00 — 2 commitsTue 4:00 — 1 commitsTue 5:00 — 2 commitsTue 6:00 — 3 commitsTue 7:00 — 11 commitsTue 8:00 — 5 commitsTue 9:00 — 18 commitsTue 10:00 — 13 commitsTue 11:00 — 17 commitsTue 12:00 — 20 commitsTue 13:00 — 23 commitsTue 14:00 — 28 commitsTue 15:00 — 28 commitsTue 16:00 — 20 commitsTue 17:00 — 8 commitsTue 18:00 — 13 commitsTue 19:00 — 22 commitsTue 20:00 — 10 commitsTue 21:00 — 0 commitsTue 22:00 — 0 commitsTue 23:00 — 9 commitsWed 0:00 — 7 commitsWed 1:00 — 8 commitsWed 2:00 — 2 commitsWed 3:00 — 4 commitsWed 4:00 — 1 commitsWed 5:00 — 1 commitsWed 6:00 — 6 commitsWed 7:00 — 11 commitsWed 8:00 — 13 commitsWed 9:00 — 21 commitsWed 10:00 — 23 commitsWed 11:00 — 18 commitsWed 12:00 — 18 commitsWed 13:00 — 24 commitsWed 14:00 — 29 commitsWed 15:00 — 26 commitsWed 16:00 — 22 commitsWed 17:00 — 21 commitsWed 18:00 — 14 commitsWed 19:00 — 3 commitsWed 20:00 — 9 commitsWed 21:00 — 16 commitsWed 22:00 — 8 commitsWed 23:00 — 8 commitsThu 0:00 — 5 commitsThu 1:00 — 14 commitsThu 2:00 — 3 commitsThu 3:00 — 0 commitsThu 4:00 — 2 commitsThu 5:00 — 0 commitsThu 6:00 — 1 commitsThu 7:00 — 7 commitsThu 8:00 — 10 commitsThu 9:00 — 13 commitsThu 10:00 — 26 commitsThu 11:00 — 25 commitsThu 12:00 — 36 commitsThu 13:00 — 25 commitsThu 14:00 — 19 commitsThu 15:00 — 23 commitsThu 16:00 — 18 commitsThu 17:00 — 10 commitsThu 18:00 — 1 commitsThu 19:00 — 8 commitsThu 20:00 — 1 commitsThu 21:00 — 3 commitsThu 22:00 — 3 commitsThu 23:00 — 8 commitsFri 0:00 — 4 commitsFri 1:00 — 10 commitsFri 2:00 — 1 commitsFri 3:00 — 1 commitsFri 4:00 — 2 commitsFri 5:00 — 3 commitsFri 6:00 — 1 commitsFri 7:00 — 3 commitsFri 8:00 — 8 commitsFri 9:00 — 25 commitsFri 10:00 — 23 commitsFri 11:00 — 24 commitsFri 12:00 — 18 commitsFri 13:00 — 18 commitsFri 14:00 — 15 commitsFri 15:00 — 12 commitsFri 16:00 — 10 commitsFri 17:00 — 19 commitsFri 18:00 — 13 commitsFri 19:00 — 5 commitsFri 20:00 — 3 commitsFri 21:00 — 4 commitsFri 22:00 — 5 commitsFri 23:00 — 7 commitsSat 0:00 — 6 commitsSat 1:00 — 5 commitsSat 2:00 — 1 commitsSat 3:00 — 2 commitsSat 4:00 — 0 commitsSat 5:00 — 1 commitsSat 6:00 — 0 commitsSat 7:00 — 2 commitsSat 8:00 — 3 commitsSat 9:00 — 2 commitsSat 10:00 — 4 commitsSat 11:00 — 3 commitsSat 12:00 — 9 commitsSat 13:00 — 2 commitsSat 14:00 — 3 commitsSat 15:00 — 3 commitsSat 16:00 — 6 commitsSat 17:00 — 11 commitsSat 18:00 — 6 commitsSat 19:00 — 3 commitsSat 20:00 — 5 commitsSat 21:00 — 4 commitsSat 22:00 — 2 commitsSat 23:00 — 2 commits
Commit volume by weekday and hour (UTC). Larger dots mean more commits.
DateListRankStars gained
Sep 12, 2026daily#15+83
Sep 11, 2026daily#15+83
Sep 10, 2026daily#3+442
Sep 9, 2026daily#3+442
Sep 8, 2026daily#10+136
Sep 7, 2026daily#10+136
Aug 6, 2026weekly#10+2,696
Aug 5, 2026weekly#10+2,696
Aug 4, 2026weekly#7+2,953
Aug 3, 2026weekly#5+3,163
Aug 2, 2026weekly#6+3,028
Aug 1, 2026daily#6+625
Aug 1, 2026weekly#6+2,863
Jul 31, 2026daily#6+625
Jul 30, 2026daily#11+1,022
  • freeCodeCamp/freeCodeCamp

    freeCodeCamp.org's open-source codebase and curriculum. Learn math, programming, and computer science for free.

    456.7K stars · TypeScript

  • openclaw/openclaw

    The AI that really does things. Any OS. Any Platform. The lobster way. 🦞

    391.3K stars · TypeScript

  • affaan-m/ECC

    The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

    272.8K stars · JavaScript

  • NousResearch/hermes-agent

    The agent that grows with you

    251.2K stars · Python

  • anomalyco/opencode

    The open source coding agent.

    211.7K stars · TypeScript

  • n8n-io/n8n

    Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.

    206.7K stars · TypeScript