ai-chatbot/packages/nodes/src/shared/level-offset-group.tsx
Sudhir Yadav 5551500d98
feat: HVAC ductwork + DWV plumbing systems (#402)
Adds two new MEP node families (HVAC ductwork, DWV plumbing) built on a shared port-connectivity model. Co-authored by @sudhir9297.
2026-06-16 15:30:39 -04:00

35 lines
1.4 KiB
TypeScript

'use client'
import { type AnyNodeId, sceneRegistry } from '@pascal-app/core'
import { useViewer } from '@pascal-app/viewer'
import { useFrame } from '@react-three/fiber'
import { type ReactNode, useRef } from 'react'
import type { Group } from 'three'
/**
* Wraps a placement tool's preview/ghost so it rides the active level's
* stacked elevation.
*
* Placement tools are mounted inside the building-local group (see the editor's
* ToolManager), which carries no per-floor elevation. But their points, ports,
* and committed paths are level-local (Y=0 = the floor) and the committed nodes
* parent to the level mesh, which DOES carry the stacked Y offset. Without this
* the ghost renders at world ground on upper floors while the cursor raycast
* rides the floor plane — they drift apart. Tracking the level mesh's Y here
* (the same value the grid plane follows) keeps the preview on the floor being
* drawn, with no change to any tool's level-local math.
*/
export function LevelOffsetGroup({ children }: { children: ReactNode }) {
const activeLevelId = useViewer((s) => s.selection.levelId)
const ref = useRef<Group>(null)
useFrame(() => {
const group = ref.current
if (!group) return
const levelMesh = activeLevelId ? sceneRegistry.nodes.get(activeLevelId as AnyNodeId) : null
group.position.y = levelMesh ? levelMesh.position.y : 0
})
return <group ref={ref}>{children}</group>
}