fix(walls): bound wall miters, heal corrupt scenes, follow grid snap
Three related editor fixes surfaced while debugging a captured house project that rendered an infinite wall and failed to load. Infinite wall (core/systems/wall/wall-mitering.ts): Junction miters are line-line intersections, so the joint point sits ~halfThickness/sin(theta) from the junction. The only guard was an exact-parallel check (det < 1e-9), so two walls meeting at a shallow angle (a room-preset preview dragged onto an existing wall, or a wall drawn nearly collinear to its neighbour) produced a joint point far away — an infinite spike. Add a miter limit: reject joints farther than 10x half-thickness from the junction and fall back to a square joint, exactly like the parallel case. Scene load failure (core/utils/heal-scene-graph.ts + validate-build-json + use-scene migrateNodes): Capture wall-merge could leave a `children: [null]` entry (see the matching merge-walls.ts fix in private-editor) and zero-length walls. `null` children fail wall schema validation, so the whole scene fails to load. Add a shared heal step — strip non-string child refs, drop childless zero-length walls — run on every load path: import validation now repairs instead of hard-failing (with a warning), and setScene heals on the prod project-load path too. Grid snap (nodes slab/ceiling/spawn tools): These tools hardcoded a 0.5 m snap (Math.round(x*2)/2) and ignored the editor's grid-snap setting, so the cursor jumped by 0.5 while later vertices already followed the configured step. Route them through snapPointToGrid / snapScalar with gridSnapStep. Adds unit tests for the miter limit and the heal step. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
cf24b62c44
commit
6d5f041b48
@@ -1,4 +1,5 @@
|
||||
import { AnyNode, type AnyNodeType } from '../schema/types'
|
||||
import { healSceneNodes } from '../utils/heal-scene-graph'
|
||||
|
||||
export type ValidationSeverity = 'error' | 'warning'
|
||||
|
||||
@@ -127,9 +128,22 @@ export function validateBuildJson(input: unknown): ValidateBuildJsonResult {
|
||||
}
|
||||
}
|
||||
|
||||
const nodes = nodesRaw as Record<string, unknown>
|
||||
// Heal known pre-existing corruption (null children, zero-length walls) up
|
||||
// front, so a scene saved before the source fixes still imports instead of
|
||||
// hard-failing schema validation. `parsed` below carries the repaired nodes.
|
||||
const { nodes, droppedWallIds, strippedChildRefs } = healSceneNodes(
|
||||
nodesRaw as Record<string, unknown>,
|
||||
)
|
||||
const rootNodeIds = rootNodeIdsRaw as string[]
|
||||
|
||||
if (strippedChildRefs > 0 || droppedWallIds.length > 0) {
|
||||
warnings.push({
|
||||
severity: 'warning',
|
||||
code: 'auto_repaired',
|
||||
message: `Repaired on import: removed ${strippedChildRefs} invalid child reference${strippedChildRefs === 1 ? '' : 's'} and ${droppedWallIds.length} zero-length wall${droppedWallIds.length === 1 ? '' : 's'}.`,
|
||||
})
|
||||
}
|
||||
|
||||
if (rootNodeIds.length === 0) {
|
||||
errors.push({
|
||||
severity: 'error',
|
||||
|
||||
Reference in New Issue
Block a user