# Phase 7: 3D Perspective View

**Status:** :white_check_mark: Complete
**Parent plan:** [PLAN.md](./PLAN.md)
**Domain:** frontend

## Objective
Build a read-only 3D perspective view of the room using @react-three/fiber and @react-three/drei. Extrude walls from the 2D polygon, place doors/windows as openings, render furniture and electrical items as 3D representations.

## Tasks

- [x] Task 1: Create `Room3DView` component — @react-three/fiber Canvas with orbit controls (rotate, zoom, pan). Ambient + directional lighting.
- [x] Task 2: Implement wall extrusion — convert 2D wall polygon to 3D wall meshes. Walls are extruded rectangles with wallHeight. Interior faces rendered, exterior optional.
- [x] Task 3: Implement floor and ceiling planes — floor mesh matching room polygon shape, ceiling mesh at wallHeight. Floor with subtle material, ceiling lighter.
- [x] Task 4: Implement door openings — cut door-shaped holes in wall meshes using wall geometry splitting. Door frame mesh.
- [x] Task 5: Implement window openings — cut window-shaped holes in walls at correct elevation. Window frame and glass material (transparent, slight blue tint).
- [x] Task 6: Create 3D furniture representations — simple geometric shapes matching furniture types. Bed (box + headboard), desk (tabletop + legs), wardrobe (tall box), sofa (L-shape), table (top + legs), chair (seat + back + legs), shelf (flat box).
- [x] Task 7: Create 3D electrical representations — simple 3D indicators. Outlets/switches as small boxes on walls, ceiling lights as disc/sphere hanging from ceiling, wall lights as half-sphere on wall.
- [x] Task 8: Implement camera presets — buttons for preset camera angles: bird's eye, eye level, each corner.
- [x] Task 9: Integrate 3D view into editor page — add "3D Preview" toggle that switches between 2D and 3D views.
- [x] Task 10: Implement selection sync — clicking a furniture/electrical item in 3D view highlights it in the 2D view (via shared EditorContext selectedIds). Read-only in 3D.
- [x] Task 11: Add room label and dimension text in 3D — room name floating above, wall lengths as HTML overlay via drei's Html component.
- [x] Task 12: Render plinth (baseboard) in 3D — extrude plinth geometry along the base of each wall using room's `plinthHeight` and `plinthThickness`. Plinth is interrupted at door openings. Different material/color than walls.

## Files to Modify/Create
- `apps/client/src/components/editor/three/Room3DView.tsx` — main 3D canvas component
- `apps/client/src/components/editor/three/WallMesh.tsx` — wall extrusion with openings
- `apps/client/src/components/editor/three/FloorCeiling.tsx` — floor and ceiling planes
- `apps/client/src/components/editor/three/DoorOpening.tsx` — door hole in wall + frame
- `apps/client/src/components/editor/three/WindowOpening.tsx` — window hole + glass
- `apps/client/src/components/editor/three/FurnitureMesh.tsx` — 3D furniture factory (renders based on type)
- `apps/client/src/components/editor/three/ElectricalMesh.tsx` — 3D electrical indicators
- `apps/client/src/components/editor/three/CameraControls.tsx` — camera presets + orbit controls
- `apps/client/src/components/editor/three/RoomLabels.tsx` — room name + dimensions in 3D
- `apps/client/src/components/editor/three/PlinthMesh.tsx` — baseboard/plinth along wall bases
- `apps/client/src/components/editor/three/utils/wallGeometry.ts` — wall splitting, coordinate conversion, geometry helpers
- `apps/client/src/components/editor/RoomEditorLayout.tsx` — added 2D/3D toggle (update)
- `apps/client/src/components/editor/room-editor-layout.module.css` — added toggle button styles (update)

## Acceptance Criteria
- [x] 3D view renders room walls extruded to correct height
- [x] Floor and ceiling are visible
- [x] Doors appear as openings in walls with frames
- [x] Windows appear as openings with glass at correct elevation
- [x] All furniture types render as recognizable 3D shapes at correct positions and sizes
- [x] Electrical items visible on walls/ceiling
- [x] Orbit controls allow free rotation, zoom, and pan
- [x] Camera presets switch between useful viewing angles
- [x] Clicking items in 3D highlights them in 2D editor
- [x] 3D view updates when room data changes (reactive)

## Notes
- 3D view is READ-ONLY — no editing in 3D. All changes happen in the 2D editor or projection views.
- Wall openings are implemented by splitting wall geometry into sections around openings (simpler and more performant than CSG).
- Furniture 3D models are intentionally simple — box-based geometry, not detailed meshes. The goal is spatial understanding, not photorealism.
- Uses drei helpers: `OrbitControls`, `PerspectiveCamera`, `Html`, `ContactShadows`.
- Three.js uses Y-up coordinate system — 2D (x, y) -> 3D (x, 0, y) for floor plane; Y axis is height.
- Performance: rooms typically have <100 objects — no LOD or instancing needed.
- Room3DView is lazy-loaded to avoid pulling Three.js into the initial bundle.

## Review Checklist
- [x] All tasks completed
- [x] Code follows project conventions
- [x] No unintended side effects
- [x] Build passes
- [x] Tests pass (new + existing)

## Handoff to Next Phase

### Phase 8 Handoff Notes

**What was built:**
- Complete 3D perspective view system with 11 new files in `apps/client/src/components/editor/three/`
- 2D/3D toggle integrated into `RoomEditorLayout` via lazy-loaded `Room3DView` component
- Wall geometry splitting algorithm in `utils/wallGeometry.ts` that creates solid wall segments around door/window openings
- Coordinate conversion: 2D editor (X-right, Y-down) to Three.js (X-right, Y-up, Z-forward) via `(x, 0, y)` mapping

**Key architecture decisions:**
- Room3DView reads all data from `EditorContext` (same state as 2D editor) — fully reactive
- Selection sync: clicking items in 3D dispatches `SET_SELECTED` to EditorContext, same selection state used by both views
- Lazy loading via `React.lazy()` so Three.js bundle (~500KB) only loads when 3D view is opened
- No CSG — walls are split into rectangular segments (above/below/around openings) using `splitWallAroundOpenings()`

**Dependencies added:**
- `@react-three/fiber` ^9.5.0
- `@react-three/drei` ^10.7.7
- `three` ^0.183.2
- `@types/three` ^0.183.1 (devDependency)

**Integration points:**
- `RoomEditorLayout.tsx` — 2D/3D toggle buttons added above the canvas area
- When 3D is active, the 2D canvas, CableLengthStatus, and ProjectionPanel are hidden (replaced by Room3DView)
- Camera presets UI is rendered as absolute-positioned HTML overlay inside the 3D canvas container

**Concerns / known limitations:**
- Camera preset transitions are instant (not animated) — smooth GSAP/tween animation could be added later
- `OrbitControls` ref is typed as `any` due to drei typing limitations
- The `Environment` preset from drei is not used (ambient + directional lights used instead) to avoid loading HDR assets
- Wall thickness rendering uses `boxGeometry` aligned along wall centerline; for rooms with very thick walls or sharp angles, there may be small gaps at corners
