Files
editor/wiki/architecture/systems.md
T
Wassim SAMADandClaude Opus 4.7 cf07fcaa97 Restructure agent config: unified .agents/skills + wiki/architecture
Replace per-tool rule trees (.cursor/rules, .claude/rules, .codex/rules)
with a single wiki/architecture/ source — 11 pages + README — readable
as plain markdown by any agent. Canonical skills live in .agents/skills/;
.claude/skills, .cursor/skills, .codex/skills are directory symlinks.

AGENTS.md is the entrypoint (rewritten as a lean overview, no per-tool
path lists). CLAUDE.md, GEMINI.md, and .github/copilot-instructions.md
all point to it.

Add open-pr skill (uses .github/pull_request_template.md as the source
of truth for the PR body) and remove the dangling .claude/CLAUDE.md
relative symlink.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 09:51:25 -04:00

3.8 KiB

Systems

Core and viewer systems architecture.

Applies to: packages/core/src/systems/**, packages/viewer/src/systems/**.

Systems own business logic, geometry generation, and constraints. They run in the Three.js frame loop and are never rendered directly.

Two Kinds of Systems

Core Systems — packages/core/src/systems/

Pure logic: no rendering, no Three.js objects. They read nodes from useScene, compute derived values (geometry, constraints), and write results back.

System Responsibility
WallSystem Wall mitering, corner joints
SlabSystem Polygon-based floor/roof generation
CeilingSystem Polygon-based ceiling generation
RoofSystem Pitched roof shape
DoorSystem Placement constraints on walls
WindowSystem Placement constraints on walls
ItemSystem Item transforms, collision

Viewer Systems — packages/viewer/src/systems/

Access Three.js objects (via useRegistry) and manage rendering side-effects.

System Responsibility
LevelSystem Stacked / exploded / solo / manual level positions
WallCutout Cuts door/window holes in wall geometry
ZoneSystem Zone display and label placement
InteractiveSystem Item toggles and sliders in the scene
GuideSystem Temporary helper geometry
ScanSystem Point cloud rendering

Pattern

Systems are React components that render nothing (return null) and use useFrame for per-frame logic.

// packages/core/src/systems/my-system.tsx
import { useFrame } from '@react-three/fiber'
import { useScene } from '../store/use-scene'

export function MySystem() {
  const nodes = useScene(s => s.nodes)

  useFrame(() => {
    // compute and write back derived state
  })

  return null
}

Core and viewer systems are mounted inside <Viewer> alongside renderers. See packages/viewer/src/components/viewer/index.tsx for the mount order.

Systems are a customization point. Any consumer of <Viewer> — the editor app, an embed, a read-only preview — can inject its own systems as children. This is how editor-specific behaviour (space detection, tool feedback) is added without touching the viewer package.

Rules

  • Core systems must not import Three.js — they work with plain data.
  • Viewer systems must not contain business logic — delegate to core if the rule is domain-level.
  • Never duplicate logic between a system and a renderer — if the renderer needs it, the system should compute and store it, and the renderer reads the result.
  • Systems should be idempotent: given the same nodes, they produce the same output.
  • Mark nodes as dirty in the scene store to signal that a system should re-run. Avoid running expensive logic every frame without a dirty check.

Adding a New System

  1. Decide the scope:

    • Domain logicpackages/core/src/systems/
    • Viewer rendering side-effectpackages/viewer/src/systems/ — mount in packages/viewer/src/components/viewer/index.tsx
    • Editor-specific or integration-specific → keep it in the consuming app (e.g. apps/editor/components/systems/) and inject it as a child of <Viewer>
  2. Create <name>-system.tsx in the appropriate directory.

  3. Mount it in the right place:

    • Viewer-internal systems go in packages/viewer/src/components/viewer/index.tsx
    • App-specific systems are injected as children from outside:
      // apps/editor — editor injects its own systems without modifying the viewer
      <Viewer>
        <MyEditorSystem />
        <ToolManager />
      </Viewer>
      
  4. Mount order matters. Most viewer systems run after renderers in the JSX tree — they consume sceneRegistry data that renderers populate on mount. Only place a system before renderers if it explicitly does not read the registry.