feat: add material system for all node types

- Add MaterialSchema with 10 presets (white, brick, concrete, wood, glass, metal, plaster, tile, marble, custom)
- Add material field to Wall, Slab, Door, Window, Ceiling, Roof, RoofSegment nodes
- Create MaterialPicker UI component with preset selection and custom properties
- Update all renderers to support material rendering with caching
- Add Material section to all node panels (WallPanel, SlabPanel, DoorPanel, WindowPanel, CeilingPanel, RoofPanel, RoofSegmentPanel)
- Update AGENTS.md with Material System documentation
This commit is contained in:
Developer
2026-03-30 12:15:16 +08:00
parent 99bb5f3645
commit 12b6292623
29 changed files with 613 additions and 86 deletions
+96
View File
@@ -89,3 +89,99 @@ User input (pointer/keyboard)
| State | Zustand + Zundo |
| UI | Radix UI, Tailwind CSS 4 |
| Tooling | Biome, TypeScript 5.9, Turborepo |
---
## Material System
The editor supports a flexible material system for all node types.
### Schema Definition
Materials are defined in `packages/core/src/schema/material.ts`:
```typescript
// Preset materials
type MaterialPreset = 'white' | 'brick' | 'concrete' | 'wood' | 'glass' | 'metal' | 'plaster' | 'tile' | 'marble' | 'custom'
// Material properties
type MaterialProperties = {
color: string // Hex color
roughness: number // 0-1
metalness: number // 0-1
opacity: number // 0-1
transparent: boolean
side: 'front' | 'back' | 'double'
}
// Full material schema
type MaterialSchema = {
preset?: MaterialPreset
properties?: MaterialProperties
texture?: { url: string, repeat?: [number, number] }
}
```
### Supported Nodes
All major node types support the `material` field:
| Node Type | Schema File | Panel Component |
|-----------|-------------|-----------------|
| Wall | `nodes/wall.ts` | `WallPanel` |
| Slab | `nodes/slab.ts` | `SlabPanel` |
| Door | `nodes/door.ts` | `DoorPanel` |
| Window | `nodes/window.ts` | `WindowPanel` |
| Ceiling | `nodes/ceiling.ts` | `CeilingPanel` |
| Roof | `nodes/roof.ts` | `RoofPanel` |
| RoofSegment | `nodes/roof-segment.ts` | `RoofSegmentPanel` |
### Usage
**In Editor UI:**
1. Select a node (wall, slab, door, etc.)
2. Find the "Material" section in the right panel
3. Click a preset color or select "Custom" to adjust properties
**Programmatically:**
```typescript
import { WallNode } from '@pascal-app/core'
// Using preset
const wall = WallNode.parse({
start: [0, 0],
end: [5, 0],
material: { preset: 'brick' }
})
// Custom material
const slab = SlabNode.parse({
polygon: [[0,0], [5,0], [5,5], [0,5]],
material: {
preset: 'custom',
properties: {
color: '#8b4513',
roughness: 0.7,
metalness: 0.1,
opacity: 1,
transparent: false,
side: 'front'
}
}
})
```
### Renderer Integration
Renderers use `createMaterial()` from `packages/viewer/src/lib/materials.ts`:
```typescript
import { createMaterial, DEFAULT_WALL_MATERIAL } from '@pascal-app/viewer'
const material = useMemo(() => {
return node.material ? createMaterial(node.material) : DEFAULT_WALL_MATERIAL
}, [node.material])
return <mesh material={material} />
```