diff --git a/packages/core/src/material-library.ts b/packages/core/src/material-library.ts index 4c58dad9..e0974830 100644 --- a/packages/core/src/material-library.ts +++ b/packages/core/src/material-library.ts @@ -123,16 +123,13 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ label: 'Hungarian Parquet 10', category: 'wood', description: 'Parquet wood finish', - previewThumbnailUrl: - '/material/wood/hungarian_parquet_10/Hungarian Parquet_10_baseColor.webp', + previewThumbnailUrl: '/material/wood/hungarian_parquet_10/Hungarian Parquet_10_baseColor.webp', preset: { maps: { albedoMap: '/material/wood/hungarian_parquet_10/Hungarian Parquet_10_baseColor.webp', - metalnessMap: - '/material/wood/hungarian_parquet_10/Hungarian Parquet_10_specularLevel.webp', + metalnessMap: '/material/wood/hungarian_parquet_10/Hungarian Parquet_10_specularLevel.webp', normalMap: '/material/wood/hungarian_parquet_10/Hungarian Parquet_10_normal.webp', - roughnessMap: - '/material/wood/hungarian_parquet_10/Hungarian Parquet_10_roughness.webp', + roughnessMap: '/material/wood/hungarian_parquet_10/Hungarian Parquet_10_roughness.webp', }, mapProperties: { color: '#ffffff', @@ -163,13 +160,11 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ label: 'Hungarian Parquet 2', category: 'wood', description: 'Parquet wood finish', - previewThumbnailUrl: - '/material/wood/hungarian_parquet_2/Hungarian Parquet_2_baseColor.webp', + previewThumbnailUrl: '/material/wood/hungarian_parquet_2/Hungarian Parquet_2_baseColor.webp', preset: { maps: { albedoMap: '/material/wood/hungarian_parquet_2/Hungarian Parquet_2_baseColor.webp', - metalnessMap: - '/material/wood/hungarian_parquet_2/Hungarian Parquet_2_specularLevel.webp', + metalnessMap: '/material/wood/hungarian_parquet_2/Hungarian Parquet_2_specularLevel.webp', normalMap: '/material/wood/hungarian_parquet_2/Hungarian Parquet_2_normal.webp', roughnessMap: '/material/wood/hungarian_parquet_2/Hungarian Parquet_2_roughness.webp', }, @@ -210,8 +205,7 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ metalnessMap: '/material/wood/square_parquet_21/Square Pattern Parquet_21_specularLevel.webp', normalMap: '/material/wood/square_parquet_21/Square Pattern Parquet_21_normal.webp', - roughnessMap: - '/material/wood/square_parquet_21/Square Pattern Parquet_21_roughness.webp', + roughnessMap: '/material/wood/square_parquet_21/Square Pattern Parquet_21_roughness.webp', }, mapProperties: { color: '#ffffff', @@ -246,12 +240,10 @@ export const MATERIAL_CATALOG: MaterialCatalogItem[] = [ '/material/wood/square_wood_parquet_23/Square Pattern Parquet_23_baseColor.webp', preset: { maps: { - albedoMap: - '/material/wood/square_wood_parquet_23/Square Pattern Parquet_23_baseColor.webp', + albedoMap: '/material/wood/square_wood_parquet_23/Square Pattern Parquet_23_baseColor.webp', metalnessMap: '/material/wood/square_wood_parquet_23/Square Pattern Parquet_23_specularLevel.webp', - normalMap: - '/material/wood/square_wood_parquet_23/Square Pattern Parquet_23_normal.webp', + normalMap: '/material/wood/square_wood_parquet_23/Square Pattern Parquet_23_normal.webp', roughnessMap: '/material/wood/square_wood_parquet_23/Square Pattern Parquet_23_roughness.webp', }, diff --git a/packages/core/src/systems/stair/stair-opening-sync.ts b/packages/core/src/systems/stair/stair-opening-sync.ts index 1153d61d..5c9b296f 100644 --- a/packages/core/src/systems/stair/stair-opening-sync.ts +++ b/packages/core/src/systems/stair/stair-opening-sync.ts @@ -404,12 +404,10 @@ function getCurvedOpeningPolygon(stair: StairNode, offset: number = 0): Point2D[ const totalSweep = stair.sweepAngle ?? Math.PI / 2 const baseOpeningSweep = Math.abs(totalSweep) * - Math.max( - CURVED_STAIR_SLAB_OPENING_RATIO, - 1 / Math.max(stair.stepCount ?? 1, 1), - ) + Math.max(CURVED_STAIR_SLAB_OPENING_RATIO, 1 / Math.max(stair.stepCount ?? 1, 1)) const angleOffset = offset / Math.max(innerRadius, 0.1) - const openingSweep = Math.sign(totalSweep || 1) * Math.min(Math.abs(totalSweep), baseOpeningSweep + angleOffset * 2) + const openingSweep = + Math.sign(totalSweep || 1) * Math.min(Math.abs(totalSweep), baseOpeningSweep + angleOffset * 2) const startAngle = totalSweep / 2 - openingSweep const endAngle = totalSweep / 2 @@ -562,7 +560,12 @@ function getStairOpeningPolygons( } if (stair.stairType === 'curved') { - return [getCurvedOpeningPolygon(stair, Math.max((stair.openingOffset ?? 0) - STAIR_SLAB_OPENING_TIGHTENING, 0.15))] + return [ + getCurvedOpeningPolygon( + stair, + Math.max((stair.openingOffset ?? 0) - STAIR_SLAB_OPENING_TIGHTENING, 0.15), + ), + ] } if (stair.stairType === 'spiral') { diff --git a/packages/editor/src/components/editor-2d/floorplan-registry-move-overlay.tsx b/packages/editor/src/components/editor-2d/floorplan-registry-move-overlay.tsx index 2eb5f496..29e71cb6 100644 --- a/packages/editor/src/components/editor-2d/floorplan-registry-move-overlay.tsx +++ b/packages/editor/src/components/editor-2d/floorplan-registry-move-overlay.tsx @@ -358,7 +358,7 @@ export function FloorplanRegistryMoveOverlay() { // plan scene; otherwise we'd react to 3D-canvas moves with garbage // plan coords. const target = event.target as Element | null - if (!target || !target.closest('[data-floorplan-scene]')) return + if (!target?.closest('[data-floorplan-scene]')) return const m = toMeters(event.clientX, event.clientY) if (!m) return const [sx, sz] = snapPointToGrid([m[0], m[1]], GRID_STEP) @@ -371,7 +371,7 @@ export function FloorplanRegistryMoveOverlay() { const onPointerUp = (event: PointerEvent) => { if (event.button !== 0) return const target = event.target as Element | null - if (!target || !target.closest('[data-floorplan-scene]')) return + if (!target?.closest('[data-floorplan-scene]')) return const snapped = lastSnapped if (snapped) { diff --git a/packages/editor/src/components/editor-2d/renderers/floorplan-registry-layer.tsx b/packages/editor/src/components/editor-2d/renderers/floorplan-registry-layer.tsx index 3f1cc341..661ae1ac 100644 --- a/packages/editor/src/components/editor-2d/renderers/floorplan-registry-layer.tsx +++ b/packages/editor/src/components/editor-2d/renderers/floorplan-registry-layer.tsx @@ -269,8 +269,6 @@ export const FloorplanRegistryLayer = memo(function FloorplanRegistryLayer() { levelId, nodes, liveTransforms, - liveOverrides, - interactiveElevators, selectedIdSet, highlightedIdSet, hoveredId, @@ -518,9 +516,7 @@ export const FloorplanRegistryLayer = memo(function FloorplanRegistryLayer() { higher-rank kinds (slabs, then walls / items / shelves) layer on top in the expected document-order z-stack. */} - {entries.map(({ id, base }) => - base ? renderEntry(id, base, `base-${id}`) : null, - )} + {entries.map(({ id, base }) => (base ? renderEntry(id, base, `base-${id}`) : null))} {/* Overlay pass — interactive handles (vertex / midpoint / edge / move) and labels (text / dimensions). Painted after every base diff --git a/packages/editor/src/components/editor/custom-camera-controls.tsx b/packages/editor/src/components/editor/custom-camera-controls.tsx index 7392da7b..5050ee4a 100644 --- a/packages/editor/src/components/editor/custom-camera-controls.tsx +++ b/packages/editor/src/components/editor/custom-camera-controls.tsx @@ -7,7 +7,7 @@ import { sceneRegistry, useScene, } from '@pascal-app/core' -import { useViewer, WalkthroughControls, ZONE_LAYER } from '@pascal-app/viewer' +import { useViewer, ZONE_LAYER } from '@pascal-app/viewer' import { CameraControls, CameraControlsImpl } from '@react-three/drei' import { useThree } from '@react-three/fiber' import { useCallback, useEffect, useMemo, useRef } from 'react' diff --git a/packages/editor/src/components/editor/first-person/bvh-ecctrl.tsx b/packages/editor/src/components/editor/first-person/bvh-ecctrl.tsx index 8525f4a1..3c459659 100644 --- a/packages/editor/src/components/editor/first-person/bvh-ecctrl.tsx +++ b/packages/editor/src/components/editor/first-person/bvh-ecctrl.tsx @@ -673,7 +673,7 @@ const BVHEcctrl = forwardRef( rotationDeltaPos.current.copy(totalPlatformDeltaPos.current) characterGroupRef.current.position.add(rotationDeltaPos.current) yawQuaternion.current.setFromUnitVectors(upAxis.current, floatHitNormal.current) - }, [upAxis]) + }, []) const updateCharacterAnimation = useCallback( (run: boolean, jump: boolean): CharacterAnimationStatus => { @@ -756,7 +756,7 @@ const BVHEcctrl = forwardRef( moveDirRef.current?.position.copy(characterSegment.current.end) moveDirRef.current?.setDirection(currentLinVel.current) moveDirRef.current?.setLength(currentLinVel.current.length() / maxWalkSpeed) - }, [characterSegment, maxWalkSpeed]) + }, [maxWalkSpeed]) useFrame((_, delta) => { elapsedRef.current += delta diff --git a/packages/editor/src/components/editor/floorplan-panel.tsx b/packages/editor/src/components/editor/floorplan-panel.tsx index 96af36dc..fc1cd50c 100644 --- a/packages/editor/src/components/editor/floorplan-panel.tsx +++ b/packages/editor/src/components/editor/floorplan-panel.tsx @@ -3475,7 +3475,7 @@ function FloorplanZoneLabel({ if (textRef.current) { setTextWidth(textRef.current.getComputedTextLength()) } - }, [zone.name]) + }, []) const isDeleteMode = mode === 'delete' @@ -5136,7 +5136,7 @@ export function FloorplanPanel() { useEffect(() => { setHoveredGuideCorner(null) - }, [selectedGuide?.id]) + }, []) useEffect(() => { if (!(selectedGuide && showGuides && canInteractWithGuides)) { @@ -6087,7 +6087,7 @@ export function FloorplanPanel() { } scheduleMovingFloorplanNodeRefresh() - }, [hasPendingItemMeshFootprints, scheduleMovingFloorplanNodeRefresh]) + }, [scheduleMovingFloorplanNodeRefresh]) // Subscribe to the live-transforms store so rotation/position changes that // *don't* go through pointer events still refresh the floorplan — e.g. R/T @@ -6631,7 +6631,7 @@ export function FloorplanPanel() { pendingFenceDragRef.current = null clearWallEndpointDrag() clearWallCurveDrag() - }, [clearWallCurveDrag, clearWallEndpointDrag, levelId]) + }, [clearWallCurveDrag, clearWallEndpointDrag]) useEffect(() => { if (shouldShowSiteBoundaryHandles) { diff --git a/packages/editor/src/components/editor/index.tsx b/packages/editor/src/components/editor/index.tsx index 650bd296..f03cfa96 100644 --- a/packages/editor/src/components/editor/index.tsx +++ b/packages/editor/src/components/editor/index.tsx @@ -840,7 +840,7 @@ const ViewerCanvas = memo(function ViewerCanvas({ window.removeEventListener('pointermove', handlePointerMove) window.removeEventListener('pointerup', handlePointerUp) } - }, []) + }, [setFloorplanPaneRatio]) useEffect(() => { setIsCameraControlsHintVisible(!readCameraControlsHintDismissed()) diff --git a/packages/editor/src/components/systems/stair/stair-edit-system.tsx b/packages/editor/src/components/systems/stair/stair-edit-system.tsx index ef1f9124..1831aaaa 100644 --- a/packages/editor/src/components/systems/stair/stair-edit-system.tsx +++ b/packages/editor/src/components/systems/stair/stair-edit-system.tsx @@ -85,7 +85,7 @@ export const StairEditSystem = () => { } prevActiveStairIds.current = activeStairIds - }, [selectedIds, selectedStairSignature]) + }, [selectedIds]) return null } diff --git a/packages/editor/src/components/tools/item/use-placement-coordinator.tsx b/packages/editor/src/components/tools/item/use-placement-coordinator.tsx index 470a3a75..5b268439 100644 --- a/packages/editor/src/components/tools/item/use-placement-coordinator.tsx +++ b/packages/editor/src/components/tools/item/use-placement-coordinator.tsx @@ -1496,7 +1496,16 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea window.removeEventListener('keyup', onKeyUp) window.removeEventListener('contextmenu', onContextMenu) } - }, [asset, canPlaceOnFloor, canPlaceOnWall, canPlaceOnCeiling, draftNode]) + }, [ + asset, + canPlaceOnFloor, + canPlaceOnWall, + canPlaceOnCeiling, + draftNode, + gridSnapStep, + updateDimensionGuides, + updatePreviewGeometry, + ]) // Refresh wireframe when the grid step changes mid-placement so the green/red // box snaps to the new cell size right away. @@ -1510,7 +1519,7 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea ) updatePreviewGeometry(previewBounds) updateDimensionGuides(previewBounds) - }, [gridSnapStep, asset, draftNode]) + }, [gridSnapStep, asset, draftNode, updateDimensionGuides, updatePreviewGeometry]) // Wall/ceiling items are managed by their own surface entry events (ensureDraft / reparent). const viewerLevelId = useViewer((s) => s.selection.levelId) useEffect(() => { @@ -1588,6 +1597,7 @@ export function usePlacementCoordinator(config: PlacementCoordinatorConfig): Rea initialDimensionBounds.dimensions[0], initialDimensionBounds.dimensions[1], initialDimensionBounds.dimensions[2], + initialDimensionBounds, ], ) const basePlaneGeometry = useMemo(() => { diff --git a/packages/editor/src/components/tools/select/box-select-tool.tsx b/packages/editor/src/components/tools/select/box-select-tool.tsx index 56362ab3..6275874d 100644 --- a/packages/editor/src/components/tools/select/box-select-tool.tsx +++ b/packages/editor/src/components/tools/select/box-select-tool.tsx @@ -546,7 +546,7 @@ const BoxSelectToolInner: React.FC = () => { canvas.removeEventListener('pointerdown', onCanvasPointerDown) canvas.removeEventListener('pointerup', onCanvasPointerUp) } - }, [camera, gl]) + }, [gl, raycastToGround, syncPreviewSelectedIds]) // grid:move for cursor tracking + rectangle update during drag useEffect(() => { @@ -603,7 +603,7 @@ const BoxSelectToolInner: React.FC = () => { return () => { emitter.off('grid:move', onMove) } - }, []) + }, [syncPreviewSelectedIds]) return ( diff --git a/packages/nodes/src/door/panel.tsx b/packages/nodes/src/door/panel.tsx index e6b4ba5d..7636636c 100644 --- a/packages/nodes/src/door/panel.tsx +++ b/packages/nodes/src/door/panel.tsx @@ -393,10 +393,7 @@ export default function DoorPanel() { const isGarageDoor = node.doorCategory === 'garage' || doorType.startsWith('garage-') const isSwingDoor = doorType === 'hinged' || doorType === 'double' || doorType === 'french' const isSlideFoldDoor = - doorType === 'folding' || - doorType === 'pocket' || - doorType === 'barn' || - doorType === 'sliding' + doorType === 'folding' || doorType === 'pocket' || doorType === 'barn' || doorType === 'sliding' const isSlidingDoor = doorType === 'pocket' || doorType === 'barn' || doorType === 'sliding' const isFoldingDoor = doorType === 'folding' const isSectionalGarageDoor = doorType === 'garage-sectional' @@ -1027,26 +1024,26 @@ export default function DoorPanel() { <> {showFrameSection && ( - handleUpdate({ frameThickness: v })} - precision={3} - step={0.01} - unit="m" - value={Math.round(node.frameThickness * 1000) / 1000} - /> - handleUpdate({ frameDepth: v })} - precision={3} - step={0.01} - unit="m" - value={Math.round(node.frameDepth * 1000) / 1000} - /> + handleUpdate({ frameThickness: v })} + precision={3} + step={0.01} + unit="m" + value={Math.round(node.frameThickness * 1000) / 1000} + /> + handleUpdate({ frameDepth: v })} + precision={3} + step={0.01} + unit="m" + value={Math.round(node.frameDepth * 1000) / 1000} + /> )} diff --git a/packages/nodes/src/elevator/panel.tsx b/packages/nodes/src/elevator/panel.tsx index 50fefe00..9eb51e3b 100644 --- a/packages/nodes/src/elevator/panel.tsx +++ b/packages/nodes/src/elevator/panel.tsx @@ -240,6 +240,7 @@ export default function ElevatorPanel() { node?.type, selectedId, updateNode, + node, ]) const previewMetric = useCallback( @@ -314,7 +315,7 @@ export default function ElevatorPanel() { }, [clearLivePreview, node, setMovingNode, setSelection]) const handleDuplicate = useCallback(() => { - if (!(node && node.parentId)) return + if (!node?.parentId) return triggerSFX('sfx:item-pick') const duplicate = ElevatorNodeSchema.parse({ @@ -596,9 +597,7 @@ export default function ElevatorPanel() {