Skip to content

Fix/minor bug fixes#267

Merged
wass08 merged 5 commits intopascalorg:mainfrom
sudhir9297:fix/minor-bug-fixes
Apr 21, 2026
Merged

Fix/minor bug fixes#267
wass08 merged 5 commits intopascalorg:mainfrom
sudhir9297:fix/minor-bug-fixes

Conversation

@sudhir9297
Copy link
Copy Markdown
Contributor

What does this PR do?

This PR improves editor stability, undo/redo reliability, snapping consistency, and fence tooling, with a strong focus on smoother drag interactions and better performance during editing.

It introduces:

  • A more robust undo/redo system that avoids noisy history and ensures clean state commits
  • Improved snapping behavior across walls, fences, slabs, roofs, and stairs
  • Full fence editing parity with walls, including curve support and endpoint controls
  • Performance optimizations to prevent heavy recomputation during drag interactions
  • Fixes for editor stability issues and interaction conflicts

Undo & History

  • Paused scene history during wall and fence move/curve tools to prevent drag previews from flooding undo stack.
  • Fixed nested pause/resume conflicts caused by space detection re-enabling history mid-drag.
  • Updated move commit flow:
    • Restore original baseline state
    • Apply final state as a single undoable action
  • Improved undo/redo redraw timing so position updates reflect immediately.
  • Added shared undo/redo helpers to:
    • Clear live transform states
    • Force dirty-node refresh after history jumps

Wall & Fence Move / Snap

  • Fixed wall endpoint dragging so constrained (horizontal/vertical/diagonal) moves respect snap targets.
  • Updated fence endpoint tools to use:
    • Active grid step
    • Angle snapping (same as walls)
  • Added snap-target following for:
    • Roofs
    • Stairs
    • Slabs
      → These now snap to wall/fence targets instead of only grid midpoints.
  • Updated slab/ceiling hole editing to respect current grid snap settings via shared polygon editor.

Fence Tooling

  • Fixed fence move undo behavior to match wall behavior.
  • Added fence endpoint move tools:
    • Linked endpoint movement
    • Alt + drag detach support
  • Fixed endpoint action-button placement so handles appear correctly at fence ends.
  • Added full curved fence support:
    • curveOffset added to schema
    • Curved fence geometry in renderer
    • Curve tool with live preview and single-step undo
    • Curve controls in fence panel and floating action menu
  • Added snapping support for curved fence editing.

Performance & Drag Responsiveness

  • Disabled space detection during paused history to avoid expensive recomputation while dragging.
  • Prevented room/slab/ceiling recalculation on every preview tick.
  • Reduced render thrashing during wall drag operations.
  • Kept move/curve previews smooth and real-time during interaction.

Floorplan & Editor Stability

  • Fixed Maximum update depth exceeded loop in floorplan panel by preventing redundant viewport updates.
  • Prevented floorplan and selection interactions from interfering during fence curve mode.

Slab / Ceiling Panel UX

  • Added missing Actions section header in slab panel.
  • Ensured Move action appears in the correct location for consistency.

@wass08
Copy link
Copy Markdown
Collaborator

wass08 commented Apr 21, 2026

Architectural review — PR #267 (editor)

Scope: 5 commits, 26 files, +1028/−128. Adds curved fence rendering, fence endpoint-move and curve tools, aligns roof/slab dragging to wall/fence snap targets, and introduces a ref-counted scene-history pause primitive in core.

Rules consulted: .claude/rules/systems.md, renderers.md, tools.md, viewer-isolation.md (mandatory four) plus spot-checks of the editor store for hook hygiene.


Findings

Blockers

None.

Suggestions

S1. Space-detection gating is coupled to the history-pause counterpackages/core/src/lib/space-detection.ts:862

const unsubscribe = sceneStore.subscribe((state: any) => {
  if (isProcessing) return
  if (getSceneHistoryPauseDepth() > 0) return
  

The skip is piggy-backing on the history-pause depth as a "tool is mid-interaction" signal. That semantics leaks beyond what history-control.ts claims to model. If any future caller pauses history for a non-tool reason (e.g. batching, import), space-detection will silently stop running — surprising and hard to debug.

Rule: .claude/rules/systems.md — systems should be driven by their own dirty signals, not indirectly by an unrelated concern.

Proposed fix: Introduce an explicit flag (e.g. useEditor.isInteracting, or a dedicated counter in the scene store like sceneInteractionDepth) that tool mounts toggle, and gate space-detection on that rather than getSceneHistoryPauseDepth(). Keep history-pause purely about history.

S2. snapFenceDraftPoint is now the shared snap helper, but it still lives under tools/fence/packages/editor/src/components/tools/roof/move-roof-tool.tsx:17 and packages/editor/src/components/tools/slab/move-slab-tool.tsx:18

import { snapFenceDraftPoint } from '../fence/fence-drafting'

Roof and slab move tools now reach into the fence tool's folder for their snap logic. Nothing in .claude/rules/tools.md forbids cross-tool imports, but the name and location imply fence-only ownership while two unrelated tools depend on it.

Proposed fix: Move the grid-point + wall/fence snap target helpers (snapFenceDraftPoint, findFenceSnapTarget, isWallLongEnough, grid-step helpers) into packages/editor/src/components/tools/shared/snap-helpers.ts (or packages/core/src/lib/snap.ts if stateless), and have fence/wall/slab/roof tools all import from there. Keeps the fence folder focused on fence-specific drafting state.

S3. refreshSceneAfterHistoryJump marks every node dirty on every undo/redopackages/editor/src/lib/history.ts:5

function refreshSceneAfterHistoryJump() {
  useLiveTransforms.getState().clearAll()
  const state = useScene.getState()
  for (const node of Object.values(state.nodes)) {
    state.markDirty(node.id)
  }
}

The temporal subscriber in use-scene.ts already diffs prevNodesSnapshotcurrentNodes and marks only the changed nodes. This synchronous pass on every keypress is O(nodes) and renders the diffing logic redundant — it just exists to paper over the fact that the diff runs in a queueMicrotask. On a large scene this will show up in the interaction frame.

Rule: .claude/rules/systems.md — avoid expensive per-interaction logic when a system (the temporal subscriber) already produces the correct derived state.

Proposed fix: Either rely on the microtask diff alone (now that it's no longer behind requestAnimationFrame, timing should be fine), or if there's a specific render that needs a synchronous flush, mark only the nodes that moved via live transforms (useLiveTransforms.getState().keys()) before clearing — not every node.

Nits

N1. Duplicated world-coord branch in FloatingActionMenupackages/editor/src/components/editor/floating-action-menu.tsx:135-163

The wall-vs-fence endpoint world-position computation has the node.type === 'wall' ? … : … ternary twice with nearly identical shape. Extracting a tiny getEndpointWorldPoint(obj, segment, which: 'start' | 'end') helper would be clearer and remove the embedded Math.hypot call. Not a rule issue; optional.


Summary

  • Blockers: 0
  • Suggestions: 3
  • Nits: 1

Verdict: ready to merge (with the three suggestions worth a follow-up thread).

The PR respects the layer boundaries that matter most: packages/viewer/** is untouched, the new history-control primitive sits correctly in core and exposes a pure TS API, new editor-only state (movingFenceEndpoint, curvingFence) lives in useEditor rather than useViewer, and all new tools are in packages/editor/src/components/tools/fence/ and wired through ToolManager. The fence-curve rendering work in FenceSystem reuses the existing wall-curve helpers cleanly and doesn't duplicate geometry math. Selector additions are value subscriptions, not reference-generating slices.

@wass08 wass08 merged commit 5fbab1a into pascalorg:main Apr 21, 2026
@open-pascal open-pascal mentioned this pull request Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants