Pascal Editor Zones for Visibility Control Based on Level Mode: A Technical Deep Dive

Pascal Editor controls zone visibility through a reactive system that reads global state on every frame, showing zones only when the "zones" structure layer is active and hiding zone labels specifically when solo level mode is enabled for non-selected levels.

Pascal Editor is an open-source building information modeling tool that manages architectural zones through a sophisticated visibility system tied to the current level mode. This article examines how the editor determines when to display zone geometry and labels based on real-time state changes in the viewer and editor stores.

How Zone Visibility Works in Pascal Editor

The core visibility logic resides in packages/editor/src/components/systems/zone/zone-system.tsx, a React Three Fiber system that executes during every render frame via useFrame. Unlike static visibility toggles, this system continuously evaluates three critical state values to determine whether each zone should appear.

Global State Dependencies

Zone visibility depends on state from two separate Zustand stores:

  • structureLayer (from useEditor): Determines which structural layer is active—must be set to "zones" for zone geometry to appear
  • levelMode (from useViewer): Controls how levels are presented as stacked, exploded, solo, or manual
  • selection.levelId (from useViewer): Identifies the currently selected level, relevant only when levelMode === 'solo'

The ZoneSystem Render Loop

During each frame, the system executes a five-step visibility calculation:

  1. Read current state from both stores:

    const structureLayer = useEditor.getState().structureLayer
    const levelMode = useViewer.getState().levelMode
    const selectedLevelId = useViewer.getState().selection.levelId
  2. Determine base layer visibility—zones only appear when the user has explicitly selected the zones layer:

    const visible = structureLayer === 'zones'
  3. Check level ownership and solo mode constraints. For each zone, the system retrieves its Three.js object and node data, then checks if it belongs to the selected level:

    const isOnSelectedLevel = zone?.parentId === selectedLevelId
    const hideInSoloMode = levelMode === 'solo' && selectedLevelId && !isOnSelectedLevel
  4. Update geometry visibility by setting the Three.js object flag:

    if (obj.visible !== visible) { obj.visible = visible }
  5. Control label opacity independently of geometry. Labels fade out when hiding in solo mode, even if the zone layer remains active:

    const showLabel = visible && !hideInSoloMode
    const targetOpacity = showLabel ? '1' : '0'
    const labelEl = document.getElementById(`${zoneId}-label`)
    if (labelEl && labelEl.style.opacity !== targetOpacity) {
        labelEl.style.opacity = targetOpacity
    }

Because this logic runs on every frame, changes to levelMode or structureLayer propagate instantly to all zones without requiring manual refresh or component remounting.

Level Modes and Their Impact on Zones

The level mode dictates how Pascal Editor presents multiple floor levels in the 3D viewport. While stacked and exploded modes display all levels simultaneously with different spatial offsets, solo mode selectively isolates a single level.

When operating in solo mode, the LevelSystem (located in packages/viewer/src/systems/level/level-system.tsx) handles the positioning and base visibility of level geometry. The ZoneSystem complements this by filtering zone labels: zones whose parentId does not match the selectedLevelId have their DOM labels set to zero opacity, effectively hiding them from view while preserving the underlying zone data in the scene graph.

Practical Implementation Examples

The following patterns demonstrate how to programmatically control zone visibility using the Pascal Editor API:

Switching to solo mode for a specific level:

import { useViewer } from '@pascal-app/viewer'

function isolateLevel(levelId: string) {
  const setLevelMode = useViewer.getState().setLevelMode
  useViewer.getState().selection.setLevelId(levelId)
  setLevelMode('solo')
  // ZoneSystem automatically hides labels for zones not belonging to levelId
}

Activating the zones structure layer:

import useEditor from '@pascal-app/editor/store/use-editor'

function enableZoneVisibility() {
  useEditor.getState().setStructureLayer('zones')
  // All zone objects become visible; labels respect current levelMode
}

Summary

Frequently Asked Questions

What determines if a zone is visible in Pascal Editor?

Zone geometry appears only when the structureLayer state equals "zones" in the editor store. This boolean check happens every frame in the ZoneSystem component, ensuring that switching away from the zones layer immediately hides all zone objects regardless of level mode.

How does solo mode affect zone labels differently than zone geometry?

While solo mode hides entire levels through the LevelSystem, the ZoneSystem specifically targets DOM labels. When levelMode === 'solo' and a selectedLevelId exists, zones with a parentId mismatching the selected level have their label opacity set to "0", making them invisible even though the zone geometry is already hidden by the layer-level toggle.

Where is the relationship between zones and levels defined in the source code?

The connection exists in packages/core/src/schema/nodes/zone.ts, where the zone node schema includes a parentId field referencing the level. The ZoneSystem uses this field in packages/editor/src/components/systems/zone/zone-system.tsx at line 23 to determine if a zone belongs to the currently selected level when filtering for solo mode.

Can zones be visible when the editor is in manual level mode?

Yes. In manual mode, the ZoneSystem does not apply the solo-mode filter (hideInSoloMode evaluates to false), so zones remain visible provided the structureLayer is set to zones. Manual mode leaves visibility decisions to the user without automatic level-based filtering.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →