Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion biome.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@
"!**/dist",
"!**/build",
"!**/public",
"!**/components/ui"
"!**/components/ui",
"!**/next-env.d.ts"
]
},
"overrides": [
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export {
resetSceneHistoryPauseDepth,
resumeSceneHistory,
} from './store/history-control'
export { default as useAlignmentGuides } from './store/use-alignment-guides'
export {
type ControlValue,
type DoorAnimationState,
Expand All @@ -106,7 +107,6 @@ export {
getEffectiveNode,
type LiveNodeOverrides,
} from './store/use-live-node-overrides'
export { default as useAlignmentGuides } from './store/use-alignment-guides'
export { default as useLiveTransforms, type LiveTransform } from './store/use-live-transforms'
export { clearSceneHistory, default as useScene } from './store/use-scene'
export { resolveElevatorDispatchTarget } from './systems/elevator/elevator-dispatch'
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/schema/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ export {
} from './nodes/column'
export { CupolaNode } from './nodes/cupola'
export { DoorNode, DoorSegment } from './nodes/door'
export { EyebrowVentNode } from './nodes/eyebrow-vent'
export {
DormerNode,
type DormerSurfaceMaterialRole,
Expand All @@ -66,6 +65,7 @@ export {
ElevatorNode,
ElevatorShaftStyle,
} from './nodes/elevator'
export { EyebrowVentNode } from './nodes/eyebrow-vent'
export { FenceBaseStyle, FenceNode, FenceStyle } from './nodes/fence'
export { GuideNode, GuideScaleReference } from './nodes/guide'
export { GutterNode, GutterOutlet } from './nodes/gutter'
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ export {
type AlignmentGuideAxis,
type AnchorKind,
bboxAnchors,
resolveAlignment,
type ResolveAlignmentInput,
type ResolveAlignmentResult,
resolveAlignment,
} from './alignment'
export {
createDragSession,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,7 @@ export const FloorplanAlignmentGuideLayer = memo(function FloorplanAlignmentGuid

return (
<g key={i}>
<line
stroke={color}
strokeWidth={stroke}
x1={from.x}
x2={to.x}
y1={from.z}
y2={to.z}
/>
<line stroke={color} strokeWidth={stroke} x1={from.x} x2={to.x} y1={from.z} y2={to.z} />
<XCap color={color} size={xCapSize} stroke={stroke} x={from.x} y={from.z} />
<XCap color={color} size={xCapSize} stroke={stroke} x={to.x} y={to.z} />
{distMeters > 1e-4 && (
Expand Down Expand Up @@ -123,8 +116,22 @@ function XCap({
}) {
return (
<g>
<line stroke={color} strokeWidth={stroke} x1={x - size} x2={x + size} y1={y - size} y2={y + size} />
<line stroke={color} strokeWidth={stroke} x1={x - size} x2={x + size} y1={y + size} y2={y - size} />
<line
stroke={color}
strokeWidth={stroke}
x1={x - size}
x2={x + size}
y1={y - size}
y2={y + size}
/>
<line
stroke={color}
strokeWidth={stroke}
x1={x - size}
x2={x + size}
y1={y + size}
y2={y - size}
/>
</g>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,7 @@ export function FloorplanRegistryMoveOverlay() {
if (!otherId || otherId === movingNode.id) continue
const b = (el as SVGGraphicsElement).getBBox()
if (b.width <= 0 || b.height <= 0) continue
candidateAnchors.push(
...bboxAnchors(otherId, b.x, b.y, b.x + b.width, b.y + b.height),
)
candidateAnchors.push(...bboxAnchors(otherId, b.x, b.y, b.x + b.width, b.y + b.height))
}

let lastSnapped: [number, number] | null = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ function cloneWorldGeometry(mesh: THREE.Mesh) {
? sourceGeometry.toNonIndexed()
: sourceGeometry.clone()
const cleanGeometry = new THREE.BufferGeometry()
cleanGeometry.setAttribute('position', toFloat32Attribute(workingGeometry.getAttribute('position')))
cleanGeometry.setAttribute(
'position',
toFloat32Attribute(workingGeometry.getAttribute('position')),
)

const normal = workingGeometry.getAttribute('normal')
if (normal) {
Expand Down
10 changes: 2 additions & 8 deletions packages/editor/src/components/editor/floorplan-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7277,10 +7277,7 @@ export function FloorplanPanel() {
// should stop further pointer-move processing (we either emitted a
// ceiling event or are between ceilings).
const handleCeilingItemPlacementMove = useCallback(
(
planPoint: WallPlanPoint,
nativeEvent: ReactPointerEvent<SVGSVGElement>,
): boolean => {
(planPoint: WallPlanPoint, nativeEvent: ReactPointerEvent<SVGSVGElement>): boolean => {
if (!isCeilingItemPlacementActive) return false

const ceiling = findCeilingAtPlanPoint(planPoint)
Expand Down Expand Up @@ -7317,10 +7314,7 @@ export function FloorplanPanel() {
// Click counterpart — used by the background placement click handler.
// Returns true if the click was a valid ceiling-item placement.
const handleCeilingItemPlacementClick = useCallback(
(
planPoint: WallPlanPoint,
nativeEvent: ReactMouseEvent<SVGSVGElement>,
): boolean => {
(planPoint: WallPlanPoint, nativeEvent: ReactMouseEvent<SVGSVGElement>): boolean => {
if (!isCeilingItemPlacementActive) return false
const ceiling = findCeilingAtPlanPoint(planPoint)
if (!ceiling) return true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@ import { Html } from '@react-three/drei'
import { useFrame } from '@react-three/fiber'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import {
BufferGeometry,
Euler,
Float32BufferAttribute,
type Group,
type LineSegments,
type Mesh,
Expand All @@ -36,6 +34,12 @@ import { LineBasicNodeMaterial, MeshBasicNodeMaterial } from 'three/webgpu'
import { EDITOR_LAYER } from '../../../lib/constants'
import { sfxEmitter } from '../../../lib/sfx-bus'
import useEditor from '../../../store/use-editor'
import {
createLineGeometry,
getBoxEdgePoints,
type PreviewBounds,
updateLineGeometry,
} from '../shared/placement-box-geometry'
import { getGridAlignedDimensions, snapToGrid, snapUpToGridStep } from './placement-math'
import {
ceilingStrategy,
Expand All @@ -61,13 +65,6 @@ function formatMeasurement(value: number, unit: 'metric' | 'imperial') {
return `${Number.parseFloat(value.toFixed(2))}m`
}

type PreviewBounds = {
min: [number, number, number]
max: [number, number, number]
dimensions: [number, number, number]
center: [number, number, number]
}

/**
* Expand `bounds` outward so each axis is rounded up to the active grid step.
* The wireframe stays centered on the original bounds centre on each axis we
Expand Down Expand Up @@ -130,114 +127,6 @@ function getFallbackPreviewBounds(
}
}

function createLineGeometry(points: number[] = [0, 0, 0, 0, 0, 0]): BufferGeometry {
const geometry = new BufferGeometry()
geometry.setAttribute('position', new Float32BufferAttribute(points, 3))
return geometry
}

function getBoxEdgePoints(bounds: PreviewBounds): number[] {
const [width, height, depth] = bounds.dimensions
const [centerX, centerY, centerZ] = bounds.center
const minX = centerX - width / 2
const maxX = centerX + width / 2
const minY = centerY - height / 2
const maxY = centerY + height / 2
const minZ = centerZ - depth / 2
const maxZ = centerZ + depth / 2

return [
minX,
minY,
minZ,
maxX,
minY,
minZ,
maxX,
minY,
minZ,
maxX,
minY,
maxZ,
maxX,
minY,
maxZ,
minX,
minY,
maxZ,
minX,
minY,
maxZ,
minX,
minY,
minZ,

minX,
maxY,
minZ,
maxX,
maxY,
minZ,
maxX,
maxY,
minZ,
maxX,
maxY,
maxZ,
maxX,
maxY,
maxZ,
minX,
maxY,
maxZ,
minX,
maxY,
maxZ,
minX,
maxY,
minZ,

minX,
minY,
minZ,
minX,
maxY,
minZ,
maxX,
minY,
minZ,
maxX,
maxY,
minZ,
maxX,
minY,
maxZ,
maxX,
maxY,
maxZ,
minX,
minY,
maxZ,
minX,
maxY,
maxZ,
]
}

function updateLineGeometry(ref: React.RefObject<LineSegments>, points: number[]) {
const geometry = ref.current?.geometry
if (!geometry) return

const attribute = geometry.getAttribute('position') as Float32BufferAttribute | undefined
if (!attribute || attribute.array.length !== points.length) {
geometry.setAttribute('position', new Float32BufferAttribute(points, 3))
} else {
attribute.set(points)
attribute.needsUpdate = true
}
geometry.computeBoundingSphere()
}

// Shared materials for placement cursor - we just change colors, not swap materials
// Note: EdgesGeometry doesn't work with dashed lines, so using solid lines
const edgeMaterial = new LineBasicNodeMaterial({
Expand Down
Loading
Loading