draft custom door

This commit is contained in:
wass08
2026-02-25 13:28:42 +09:00
parent d9317bfba2
commit 27e4afb757
25 changed files with 1661 additions and 14 deletions
@@ -0,0 +1,27 @@
import { useRegistry, type DoorNode } from '@pascal-app/core'
import { useRef } from 'react'
import type { Mesh } from 'three'
import { useNodeEvents } from '../../../hooks/use-node-events'
export const DoorRenderer = ({ node }: { node: DoorNode }) => {
const ref = useRef<Mesh>(null!)
useRegistry(node.id, 'door', ref)
const handlers = useNodeEvents(node, 'door')
return (
<mesh
ref={ref}
castShadow
receiveShadow
visible={node.visible}
position={node.position}
rotation={node.rotation}
{...handlers}
>
{/* DoorSystem replaces this geometry each time the node is dirty */}
<boxGeometry args={[0, 0, 0]} />
<meshStandardMaterial color="#d1d5db" />
</mesh>
)
}
@@ -3,6 +3,7 @@
import { type AnyNode, useScene } from '@pascal-app/core'
import { BuildingRenderer } from './building/building-renderer'
import { CeilingRenderer } from './ceiling/ceiling-renderer'
import { DoorRenderer } from './door/door-renderer'
import { GuideRenderer } from './guide/guide-renderer'
import { ItemRenderer } from './item/item-renderer'
import { LevelRenderer } from './level/level-renderer'
@@ -28,6 +29,7 @@ export const NodeRenderer = ({ nodeId }: { nodeId: AnyNode['id'] }) => {
{node.type === 'item' && <ItemRenderer node={node} />}
{node.type === 'slab' && <SlabRenderer node={node} />}
{node.type === 'wall' && <WallRenderer node={node} />}
{node.type === 'door' && <DoorRenderer node={node} />}
{node.type === 'window' && <WindowRenderer node={node} />}
{node.type === 'zone' && <ZoneRenderer node={node} />}
{node.type === 'roof' && <RoofRenderer node={node} />}
@@ -1,6 +1,6 @@
'use client'
import { CeilingSystem, ItemSystem, RoofSystem, SlabSystem, WallSystem, WindowSystem } from '@pascal-app/core'
import { CeilingSystem, DoorSystem, ItemSystem, RoofSystem, SlabSystem, WallSystem, WindowSystem } from '@pascal-app/core'
import { Bvh } from '@react-three/drei'
import { Canvas, extend, type ThreeToJSXElements } from '@react-three/fiber'
import * as THREE from 'three/webgpu'
@@ -61,6 +61,7 @@ const Viewer: React.FC<ViewerProps> = ({ children, selectionManager = 'default'
<WallCutout />
{/* Core systems */}
<CeilingSystem />
<DoorSystem />
<ItemSystem />
<RoofSystem />
<SlabSystem />
@@ -29,6 +29,7 @@ type SelectableNodeType =
| 'zone'
| 'wall'
| 'window'
| 'door'
| 'item'
| 'slab'
| 'ceiling'
@@ -86,8 +87,8 @@ const isNodeOnLevel = (node: AnyNode, levelId: string): boolean => {
// Direct child of level
if (node.parentId === levelId) return true
// Wall-attached items (windows/doors): check if parent wall is on the level
if (node.type === 'item' && node.parentId) {
// Wall-attached nodes (window/door/item): check if parent wall is on the level
if ((node.type === 'item' || node.type === 'window' || node.type === 'door') && node.parentId) {
const parentNode = nodes[node.parentId as keyof typeof nodes]
if (parentNode?.type === 'wall' && parentNode.parentId === levelId) {
return true
@@ -200,9 +201,9 @@ const getStrategy = (): SelectionStrategy | null => {
}
}
// Zone selected -> can select/hover contents (walls, items, slabs, ceilings, roofs, windows)
// Zone selected -> can select/hover contents (walls, items, slabs, ceilings, roofs, windows, doors)
return {
types: ['wall', 'item', 'slab', 'ceiling', 'roof', 'window'],
types: ['wall', 'item', 'slab', 'ceiling', 'roof', 'window', 'door'],
handleClick: (node) => {
const { selectedIds } = useViewer.getState().selection
// Toggle selection - if already selected, deselect; otherwise select
@@ -224,7 +225,7 @@ const getStrategy = (): SelectionStrategy | null => {
}
},
isValid: (node) => {
const validTypes = ['wall', 'item', 'slab', 'ceiling', 'roof', 'window']
const validTypes = ['wall', 'item', 'slab', 'ceiling', 'roof', 'window', 'door']
if (!validTypes.includes(node.type)) return false
return isNodeInZone(node, levelId, zoneId)
},
@@ -277,6 +278,7 @@ export const SelectionManager = () => {
'ceiling',
'roof',
'window',
'door',
]
for (const type of allTypes) {
emitter.on(`${type}:enter`, onEnter)
@@ -3,6 +3,8 @@ import {
type BuildingNode,
type CeilingEvent,
type CeilingNode,
type DoorEvent,
type DoorNode,
type EventSuffix,
emitter,
type ItemEvent,
@@ -36,6 +38,7 @@ type NodeConfig = {
ceiling: { node: CeilingNode; event: CeilingEvent }
roof: { node: RoofNode; event: RoofEvent }
window: { node: WindowNode; event: WindowEvent }
door: { node: DoorNode; event: DoorEvent }
}
type NodeType = keyof NodeConfig