Merge remote-tracking branch 'origin/main' into feat/paint-slots
# Conflicts: # packages/core/src/store/use-scene.ts # packages/editor/src/components/editor/index.tsx
This commit is contained in:
@@ -6,6 +6,7 @@ import type {
|
||||
RoofSegmentNode,
|
||||
WallNode,
|
||||
} from '@pascal-app/core'
|
||||
import { publishOpeningResizeGuides } from '../shared/opening-guides-runtime'
|
||||
import { readRoofFaceHeightMax, readRoofFaceWidthMax } from '../shared/roof-opening-host'
|
||||
import { buildRoofWallOpeningCut } from '../shared/roof-wall-opening-cut'
|
||||
import { scaleHandleHeight } from './door-math'
|
||||
@@ -21,6 +22,9 @@ const SIDE_HANDLE_OFFSET = 0.24
|
||||
const HEIGHT_HANDLE_OFFSET = 0.24
|
||||
const MIN_DOOR_HEIGHT = 0.5
|
||||
const MIN_DOOR_WIDTH = 0.3
|
||||
// How far the move cross floats off the wall face (+Z, the door's facing
|
||||
// normal) so it's grabbable instead of buried in the leaf/frame.
|
||||
const MOVE_HANDLE_LIFT = 0.12
|
||||
|
||||
function readWallLength(door: DoorNodeType, scene: { get: (id: AnyNodeId) => unknown }): number {
|
||||
if (!door.wallId) return Number.POSITIVE_INFINITY
|
||||
@@ -55,6 +59,7 @@ function doorWidthHandle(side: 'left' | 'right'): HandleDescriptor<DoorNodeType>
|
||||
return readWallLength(n, scene)
|
||||
},
|
||||
currentValue: (n) => n.width,
|
||||
onDrag: (node) => publishOpeningResizeGuides(node, false),
|
||||
apply: (initial, newWidth) => {
|
||||
// Anchored edge stays fixed in wall-local coords. Door rotation is
|
||||
// applied by the inner ride group (the renderer mounts a nested
|
||||
@@ -97,6 +102,7 @@ function doorHeightHandle(): HandleDescriptor<DoorNodeType> {
|
||||
return Math.max(MIN_DOOR_HEIGHT, readWallHeight(n, scene) - bottom)
|
||||
},
|
||||
currentValue: (n) => n.height,
|
||||
onDrag: (node) => publishOpeningResizeGuides(node, false),
|
||||
apply: (initial, newHeight) => {
|
||||
const bottom = initial.position[1] - initial.height / 2
|
||||
// Scale the handle so it tracks the door instead of staying glued to a
|
||||
@@ -114,7 +120,26 @@ function doorHeightHandle(): HandleDescriptor<DoorNodeType> {
|
||||
}
|
||||
}
|
||||
|
||||
// Press-drag move grip at the door centre, standing in the wall face. Routes
|
||||
// through the same move tool as the floating Move button (3D
|
||||
// `affordanceTools.move`, 2D `floorplanMoveTarget`) — wall slide + re-host onto
|
||||
// another wall — but `engageMoveDrag` commits on release, with no second click.
|
||||
function doorMoveHandle(): HandleDescriptor<DoorNodeType> {
|
||||
return {
|
||||
kind: 'tap-action',
|
||||
shape: 'move-cross',
|
||||
plane: 'node-normal',
|
||||
portal: 'grandparent',
|
||||
cursor: 'move',
|
||||
onActivate: (node, _scene, editor) => editor.engageMoveDrag(node),
|
||||
placement: {
|
||||
position: () => [0, 0, MOVE_HANDLE_LIFT],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const doorHandles: HandleDescriptor<DoorNodeType>[] = [
|
||||
doorMoveHandle(),
|
||||
doorWidthHandle('left'),
|
||||
doorWidthHandle('right'),
|
||||
doorHeightHandle(),
|
||||
@@ -232,7 +257,7 @@ export const doorDefinition: NodeDefinition<typeof DoorNode> = {
|
||||
presentation: {
|
||||
label: 'Door',
|
||||
description: 'A door cut into a wall. Animated open/close state.',
|
||||
icon: { kind: 'url', src: '/icons/door.png' },
|
||||
icon: { kind: 'url', src: '/icons/door.webp' },
|
||||
paletteSection: 'structure',
|
||||
paletteOrder: 50,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user