Refactor viewer hover styles and remove preview state

This commit is contained in:
sudhir
2026-04-24 22:49:04 +05:30
parent 7297c76204
commit 325f2e4603
15 changed files with 142 additions and 360 deletions
@@ -8,7 +8,6 @@ import { useMemo, useRef } from 'react'
import { float, mix, positionWorld, smoothstep } from 'three/tsl'
import { BackSide, FrontSide, type Mesh, MeshBasicNodeMaterial } from 'three/webgpu'
import { useNodeEvents } from '../../../hooks/use-node-events'
import useViewer from '../../../store/use-viewer'
import { NodeRenderer } from '../node-renderer'
const gridScale = 5
@@ -55,16 +54,10 @@ export const CeilingRenderer = ({ node }: { node: CeilingNode }) => {
useRegistry(node.id, 'ceiling', ref)
const handlers = useNodeEvents(node, 'ceiling')
const materialPreview = useViewer((state) =>
state.materialPreview?.target === 'ceiling' && state.materialPreview.nodeId === node.id
? state.materialPreview
: null,
)
const materials = useMemo(() => {
const preset = getMaterialPresetByRef(materialPreview?.materialPreset ?? node.materialPreset)
const props =
preset?.mapProperties ?? resolveMaterial(materialPreview?.material ?? node.material)
const preset = getMaterialPresetByRef(node.materialPreset)
const props = preset?.mapProperties ?? resolveMaterial(node.material)
const color = props.color || '#999999'
return getCeilingMaterials(color)
}, [
@@ -73,11 +66,6 @@ export const CeilingRenderer = ({ node }: { node: CeilingNode }) => {
node.material?.preset,
node.material?.properties,
node.material?.texture,
materialPreview?.materialPreset,
materialPreview?.material,
materialPreview?.material?.preset,
materialPreview?.material?.properties,
materialPreview?.material?.texture,
])
return (
@@ -7,22 +7,14 @@ import {
createMaterialFromPresetRef,
DEFAULT_STAIR_MATERIAL,
} from '../../../lib/materials'
import useViewer from '../../../store/use-viewer'
export const FenceRenderer = ({ node }: { node: FenceNode }) => {
const ref = useRef<Mesh>(null!)
const handlers = useNodeEvents(node, 'fence')
const materialPreview = useViewer((state) =>
state.materialPreview?.target === 'fence' && state.materialPreview.nodeId === node.id
? state.materialPreview
: null,
)
const material = useMemo(() => {
const presetMaterial = createMaterialFromPresetRef(
materialPreview?.materialPreset ?? node.materialPreset,
)
const presetMaterial = createMaterialFromPresetRef(node.materialPreset)
if (presetMaterial) return presetMaterial
const mat = materialPreview?.material ?? node.material
const mat = node.material
if (!mat) return DEFAULT_STAIR_MATERIAL
return createMaterial(mat)
}, [
@@ -31,11 +23,6 @@ export const FenceRenderer = ({ node }: { node: FenceNode }) => {
node.material?.preset,
node.material?.properties,
node.material?.texture,
materialPreview?.materialPreset,
materialPreview?.material,
materialPreview?.material?.preset,
materialPreview?.material?.properties,
materialPreview?.material?.texture,
])
useRegistry(node.id, 'fence', ref)
@@ -23,11 +23,6 @@ export const RoofSegmentRenderer = ({ node }: { node: RoofSegmentNode }) => {
const parentNode = node.parentId
? (nodes[node.parentId as AnyNodeId] as RoofNode | undefined)
: undefined
const materialPreview = useViewer((state) =>
state.materialPreview?.target === 'roof' && state.materialPreview.nodeId === parentNode?.id
? state.materialPreview
: null,
)
const placeholderGeometry = useMemo(() => {
const geometry = new THREE.BufferGeometry()
geometry.setAttribute('position', new THREE.Float32BufferAttribute([], 3))
@@ -38,40 +33,13 @@ export const RoofSegmentRenderer = ({ node }: { node: RoofSegmentNode }) => {
return geometry
}, [])
const previewParentNode = !parentNode
? undefined
: materialPreview?.role === 'top'
? {
...parentNode,
topMaterial: materialPreview.material,
topMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: materialPreview?.role === 'edge'
? {
...parentNode,
edgeMaterial: materialPreview.material,
edgeMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: materialPreview?.role === 'wall'
? {
...parentNode,
wallMaterial: materialPreview.material,
wallMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: parentNode
const customMaterial = useMemo(() => {
if (node.material !== undefined || typeof node.materialPreset === 'string') {
return null
}
return previewParentNode ? getRoofMaterialArray(previewParentNode) : null
}, [node, previewParentNode])
return parentNode ? getRoofMaterialArray(parentNode) : null
}, [node, parentNode])
const material = debugColors ? roofDebugMaterials : customMaterial || roofMaterials
@@ -14,11 +14,6 @@ export const RoofRenderer = ({ node }: { node: RoofNode }) => {
const handlers = useNodeEvents(node, 'roof')
const debugColors = useViewer((s) => s.debugColors)
const materialPreview = useViewer((state) =>
state.materialPreview?.target === 'roof' && state.materialPreview.nodeId === node.id
? state.materialPreview
: null,
)
const placeholderGeometry = useMemo(() => {
const geometry = new THREE.BufferGeometry()
geometry.setAttribute('position', new THREE.Float32BufferAttribute([], 3))
@@ -29,33 +24,7 @@ export const RoofRenderer = ({ node }: { node: RoofNode }) => {
return geometry
}, [])
const previewNode =
materialPreview?.role === 'top'
? {
...node,
topMaterial: materialPreview.material,
topMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: materialPreview?.role === 'edge'
? {
...node,
edgeMaterial: materialPreview.material,
edgeMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: materialPreview?.role === 'wall'
? {
...node,
wallMaterial: materialPreview.material,
wallMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: node
const customMaterial = useMemo(() => getRoofMaterialArray(previewNode), [previewNode])
const customMaterial = useMemo(() => getRoofMaterialArray(node), [node])
const material = debugColors ? roofDebugMaterials : customMaterial || roofMaterials
@@ -8,7 +8,6 @@ import {
createMaterial,
DEFAULT_SLAB_MATERIAL,
} from '../../../lib/materials'
import useViewer from '../../../store/use-viewer'
const slabMaterialCache = new Map<string, THREE.MeshStandardMaterial>()
@@ -52,15 +51,10 @@ export const SlabRenderer = ({ node }: { node: SlabNode }) => {
useRegistry(node.id, 'slab', ref)
const handlers = useNodeEvents(node, 'slab')
const materialPreview = useViewer((state) =>
state.materialPreview?.target === 'slab' && state.materialPreview.nodeId === node.id
? state.materialPreview
: null,
)
const material = useMemo(() => {
const resolvedMaterial = materialPreview?.material ?? node.material
const resolvedMaterialPreset = materialPreview?.materialPreset ?? node.materialPreset
const resolvedMaterial = node.material
const resolvedMaterialPreset = node.materialPreset
const cacheKey = JSON.stringify({
material: resolvedMaterial ?? null,
materialPreset: resolvedMaterialPreset ?? null,
@@ -76,11 +70,6 @@ export const SlabRenderer = ({ node }: { node: SlabNode }) => {
node.material?.properties,
node.material?.texture,
node.materialPreset,
materialPreview?.material,
materialPreview?.material?.preset,
materialPreview?.material?.properties,
materialPreview?.material?.texture,
materialPreview?.materialPreset,
])
return (
@@ -8,7 +8,6 @@ import {
import { useEffect, useLayoutEffect, useMemo, useRef } from 'react'
import * as THREE from 'three'
import { useNodeEvents } from '../../../hooks/use-node-events'
import useViewer from '../../../store/use-viewer'
import { getStraightStairSegmentBodyMaterials } from '../../../systems/stair/stair-materials'
export const StairSegmentRenderer = ({ node }: { node: StairSegmentNode }) => {
@@ -25,42 +24,10 @@ export const StairSegmentRenderer = ({ node }: { node: StairSegmentNode }) => {
const parentNode = node.parentId
? (nodes[node.parentId as AnyNodeId] as StairNode | undefined)
: undefined
const materialPreview = useViewer((state) =>
state.materialPreview?.target === 'stair' && state.materialPreview.nodeId === parentNode?.id
? state.materialPreview
: null,
const material = useMemo(
() => getStraightStairSegmentBodyMaterials(node, parentNode),
[node, parentNode],
)
const previewParentNode = !parentNode
? undefined
: materialPreview?.role === 'railing'
? {
...parentNode,
railingMaterial: materialPreview.material,
railingMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: materialPreview?.role === 'tread'
? {
...parentNode,
treadMaterial: materialPreview.material,
treadMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: materialPreview?.role === 'side'
? {
...parentNode,
sideMaterial: materialPreview.material,
sideMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: parentNode
const material = useMemo(() => {
return getStraightStairSegmentBodyMaterials(node, previewParentNode)
}, [node, previewParentNode])
const placeholderGeometry = useMemo(() => {
const geometry = new THREE.BufferGeometry()
@@ -13,7 +13,6 @@ import {
createMaterialFromPresetRef,
DEFAULT_STAIR_MATERIAL,
} from '../../../lib/materials'
import useViewer from '../../../store/use-viewer'
import {
getStairBodyMaterials,
getStairRailingMaterial,
@@ -62,55 +61,24 @@ export const StairRenderer = ({ node }: { node: StairNode }) => {
}, [node.id])
const handlers = useNodeEvents(node, 'stair')
const materialPreview = useViewer((state) =>
state.materialPreview?.target === 'stair' && state.materialPreview.nodeId === node.id
? state.materialPreview
: null,
)
const previewNode =
materialPreview?.role === 'railing'
? {
...node,
railingMaterial: materialPreview.material,
railingMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: materialPreview?.role === 'tread'
? {
...node,
treadMaterial: materialPreview.material,
treadMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: materialPreview?.role === 'side'
? {
...node,
sideMaterial: materialPreview.material,
sideMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: node
const material = useMemo(() => {
const presetMaterial = createMaterialFromPresetRef(previewNode.materialPreset)
const presetMaterial = createMaterialFromPresetRef(node.materialPreset)
if (presetMaterial) return presetMaterial
const mat = previewNode.material
const mat = node.material
if (!mat) return DEFAULT_STAIR_MATERIAL
return createMaterial(mat)
}, [
previewNode.materialPreset,
previewNode.material,
previewNode.material?.preset,
previewNode.material?.properties,
previewNode.material?.texture,
node.materialPreset,
node.material,
node.material?.preset,
node.material?.properties,
node.material?.texture,
])
const straightBodyMaterials = useMemo(() => getStairBodyMaterials(previewNode), [previewNode])
const straightBodyMaterials = useMemo(() => getStairBodyMaterials(node), [node])
const railingMaterial = useMemo(() => getStairRailingMaterial(previewNode), [previewNode])
const railingMaterial = useMemo(() => getStairRailingMaterial(node), [node])
const straightPlaceholderGeometry = useMemo(() => {
const geometry = new THREE.BufferGeometry()
@@ -2,7 +2,6 @@ import { useRegistry, useScene, type WallNode } from '@pascal-app/core'
import { useLayoutEffect, useRef } from 'react'
import type { Mesh } from 'three'
import { useNodeEvents } from '../../../hooks/use-node-events'
import useViewer from '../../../store/use-viewer'
import { getVisibleWallMaterials } from '../../../systems/wall/wall-materials'
import { NodeRenderer } from '../node-renderer'
@@ -16,30 +15,7 @@ export const WallRenderer = ({ node }: { node: WallNode }) => {
}, [node.id])
const handlers = useNodeEvents(node, 'wall')
const materialPreview = useViewer((state) =>
state.materialPreview?.target === 'wall' && state.materialPreview.nodeId === node.id
? state.materialPreview
: null,
)
const previewNode =
materialPreview && materialPreview.role === 'interior'
? {
...node,
interiorMaterial: materialPreview.material,
interiorMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: materialPreview && materialPreview.role === 'exterior'
? {
...node,
exteriorMaterial: materialPreview.material,
exteriorMaterialPreset: materialPreview.materialPreset,
material: undefined,
materialPreset: undefined,
}
: node
const material = getVisibleWallMaterials(previewNode)
const material = getVisibleWallMaterials(node)
return (
<mesh castShadow material={material} receiveShadow ref={ref} visible={node.visible}>