rule for layers

This commit is contained in:
wass08
2026-03-11 07:47:10 +01:00
parent 32406e5a20
commit 8d02e5191b
3 changed files with 60 additions and 1 deletions
+2 -1
View File
@@ -1,6 +1,6 @@
---
description: How to create and maintain project rules
globs:
globs: .cursor/rules/**
alwaysApply: false
---
@@ -76,3 +76,4 @@ Concrete guidance with examples.
| `events` | Typed event bus — emitting and listening to node and grid events |
| `node-schemas` | Zod schema pattern for node types, createNode, updateNode |
| `spatial-queries` | Placement validation (canPlaceOnFloor/Wall/Ceiling) for tools |
| `layers` | Three.js layer constants, ownership, and rendering separation |
+57
View File
@@ -0,0 +1,57 @@
---
description: Three.js layer conventions — which layer each object type lives on and why
globs: packages/viewer/**,apps/editor/**
alwaysApply: false
---
# Three.js Layers
Three.js `Layers` control which objects each camera and render pass sees. We use them to separate scene geometry, editor helpers, and zone overlays into distinct rendering buckets without duplicating scene structure.
## Layer Map
| Constant | Value | Package | Purpose |
|---|---|---|---|
| `SCENE_LAYER` | `0` | `@pascal-app/viewer` | Default Three.js layer — all regular scene geometry |
| `EDITOR_LAYER` | `1` | `apps/editor` | Editor-only helpers: grid, tool previews, cursor meshes, snap guides |
| `ZONE_LAYER` | `2` | `@pascal-app/viewer` | Zone floor fills and wall borders — composited in a separate post-processing pass |
Import the constants from their owning packages:
```ts
// In viewer code
import { SCENE_LAYER, ZONE_LAYER } from '@pascal-app/viewer'
// In editor code
import { EDITOR_LAYER } from '@/lib/constants'
```
## Why Separate Zones onto Layer 2
Zones use semi-transparent, `depthTest: false` materials that must be composited *on top of* the scene without being fed into SSGI or TRAA. The post-processing pipeline in `post-processing.tsx` renders a dedicated `zonePass` with a `Layers` mask that enables only `ZONE_LAYER` (and disables `SCENE_LAYER`), then blends its output into the final composite manually:
```ts
const zoneLayers = useMemo(() => {
const l = new Layers()
l.enable(ZONE_LAYER)
l.disable(SCENE_LAYER)
return l
}, [])
zonePass.setLayers(zoneLayers)
```
This keeps zones out of the SSGI depth/normal buffers (which would produce incorrect AO on transparent surfaces) while still letting them appear correctly over the scene.
## Why Separate Editor Helpers onto Layer 1
The editor camera enables `EDITOR_LAYER` so tools and helpers are visible during editing. The thumbnail generator disables `EDITOR_LAYER` so exports show clean geometry without snap lines or cursor spheres.
## Rules
- **Never hardcode layer numbers.** Always use the named constants.
- **`SCENE_LAYER` and `ZONE_LAYER` belong in `@pascal-app/viewer`** — they are renderer concerns, not editor concerns.
- **`EDITOR_LAYER` belongs in `apps/editor`** — the viewer must never import it; editor behaviour is injected via props/children.
- **Zone meshes must set `layers={ZONE_LAYER}`** so they are picked up by `zonePass` and excluded from `scenePass` depth buffers.
- **Editor helper meshes must set `layers={EDITOR_LAYER}`** so they are invisible to the thumbnail camera and the viewer's render passes.
- **Do not add new layers without updating this rule** and the post-processing pipeline accordingly.