Build your first 3D architectural scene with Pascal Editor in 5 minutes
This guide will help you create a working 3D building editor with Pascal Editor. You’ll learn how to set up the viewer, create nodes, and interact with the scene.
The Viewer component provides a complete 3D rendering environment with WebGPU, camera controls, lighting, and systems. It fills its parent container, so make sure to set width and height.
When you run this, you’ll see an empty 3D scene with a default Site → Building → Level hierarchy. The camera can be controlled with mouse drag (orbit) and scroll (zoom).
2
Create a wall
Let’s add a wall to the scene. We’ll use the useScene store to create nodes and the WallNode schema to validate our data.
App.tsx
'use client'import { useEffect } from 'react'import { useScene, WallNode } from '@pascal-app/core'import { Viewer, useViewer } from '@pascal-app/viewer'function SceneSetup() { useEffect(() => { const scene = useScene.getState() // Find the default level const levelId = Object.values(scene.nodes).find( node => node.type === 'level' )?.id if (!levelId) return // Create a wall const wall = WallNode.parse({ start: [0, 0], end: [5, 0], thickness: 0.15, height: 3.0 }) // Add wall to the level scene.createNode(wall, levelId) // Select the building to view the wall const buildingId = Object.values(scene.nodes).find( node => node.type === 'building' )?.id if (buildingId) { useViewer.getState().setSelection({ buildingId, levelId }) } }, []) return null}export default function App() { return ( <div style={{ width: '100vw', height: '100vh' }}> <Viewer> <SceneSetup /> </Viewer> </div> )}
You should now see a 3D wall rendered in the scene! The wall is 5 meters long, 0.15 meters thick, and 3 meters high.
The WallSystem automatically generates geometry for the wall based on the start/end points, thickness, and height. The geometry is created in the render loop after the node is marked dirty.
3
Add multiple walls to create a room
Let’s create a simple rectangular room by adding four walls:
App.tsx
'use client'import { useEffect } from 'react'import { useScene, WallNode } from '@pascal-app/core'import { Viewer, useViewer } from '@pascal-app/viewer'function SceneSetup() { useEffect(() => { const scene = useScene.getState() const levelId = Object.values(scene.nodes).find( node => node.type === 'level' )?.id if (!levelId) return // Create four walls forming a 5x4 meter room const walls = [ { start: [0, 0], end: [5, 0] }, // South wall { start: [5, 0], end: [5, 4] }, // East wall { start: [5, 4], end: [0, 4] }, // North wall { start: [0, 4], end: [0, 0] }, // West wall ] walls.forEach(({ start, end }) => { const wall = WallNode.parse({ start, end, thickness: 0.15, height: 3.0 }) scene.createNode(wall, levelId) }) // Center camera on the room const buildingId = Object.values(scene.nodes).find( node => node.type === 'building' )?.id if (buildingId) { useViewer.getState().setSelection({ buildingId, levelId }) } }, []) return null}export default function App() { return ( <div style={{ width: '100vw', height: '100vh' }}> <Viewer> <SceneSetup /> </Viewer> </div> )}
You now have a complete room with four walls! Notice how the walls automatically miter at the corners - this is handled by the WallSystem.
Click the button and watch the walls grow! The WallSystem automatically regenerates geometry when nodes are updated.
Changes to nodes are automatically persisted to IndexedDB. Refresh the page and your scene will be restored. Use Cmd+Z / Ctrl+Z to undo changes (50-step history).
import { useViewer } from '@pascal-app/viewer'// Switch to dark themeuseViewer.getState().setTheme('dark')// Change level display modeuseViewer.getState().setLevelMode('exploded')// Switch to orthographic camerauseViewer.getState().setCameraMode('orthographic')