Editor "Snap to Nodes / Grid / Hoop" toggles do nothing — settings stored but never applied to node coordinates on drag/drop #170
Labels
No labels
blocked:commit-ready-failed
blocked:gate-fetch
blocked:gate-lint
blocked:gate-plan
blocked:gate-research
blocked:needs-attention
blocked:needs-decision
blocked:needs-human
blocked:no-changes
blocked:verify-failed
bug
deferred
feature-request
in-progress
needs-decompose
needs-triage
quickfix
security/medium
triage-approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Mark/Kimi_Agent_Brother_10_Digitizing_App#170
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Finding
src/pages/Editor.tsx:200storessnapSettingsin state, initialized fromDEFAULT_SNAP_SETTINGS(line 30 ofconstants.ts):src/components/editor/EditorRightPanel.tsx:264-272exposes 3 toggles (Snap to Nodes, Snap to Grid, Snap to Hoop) and a grid size slider (5-50mm) that update the snapSettings state viaonSnapSettingsChange.A
grep -rn 'snapSettings\.' src/returns 6 references, all of them in the right panel's toggle/slider rendering. The canvas's drag handler does not consultsnapSettingsto constrain the node's new position.The user toggles "Snap to Grid" on, sets grid size to 10mm, drags a node, drops it. The node lands wherever the user dropped it — the snap was not applied. The toggles are UI-only state.
Where
src/pages/Editor.tsx:200src/components/editor/EditorRightPanel.tsx:264-272grep -rn 'snapSettings' src/shows no consumer outside the panel's own renderSuggested fix shape
Add a
applySnap(point, snapSettings, allNodes, hoopSize)function tosrc/components/editor/canvasRenderer.ts(or a neweditor/geometry.ts):snapToNodes: find the closest node withinsnapSettings.gridSizemm and snap to itsnapToGrid: round the point to the nearestgridSizemm grid intersectionsnapToHoop: clamp the point to the hoop's boundsWire it into the node drag handler in
src/components/editor/EditorCanvas.tsx:applySnap(finalPoint, snapSettings, allNodes, hoopSize)before committing the new positionVisual feedback: while dragging, draw a small indicator at the snap target (the grid intersection, the snap-to-node candidate, the hoop edge) so the user sees the snap behavior in action.
Severity
Medium. The toggles are surfaced in the right panel with proper labels and the user expects them to work. They don't.
Discovered by
Gap analysis (2026-10-02) of editor interaction state.
Related
DEFAULT_SNAP_SETTINGSconstant is atsrc/components/editor/constants.ts:17-22. The intent is documented; the implementation is missing.Fixed in commit
ebd1ce8(fix(#170): Snap to Nodes/Grid/Hoop toggles now constrain node drags).What changed:
src/components/editor/geometry.tswithapplySnap(candidate, snapSettings, allNodes, excludeNodeId). Precedence: snapToNodes → snapToGrid → snapToHoop; a higher-precedence rule that fires blocks lower rules.EditorCanvas.tsxseeds adragLastSnapTargetRefat the node's starting position on mousedown, then on each move builds a candidate by stepping the cursor delta off the last emitted target, applies snap, and emits the incremental delta toonNodeDrag. The parent's accumulated position stays correct.snapIndicatorstate surfaces the snap target to the canvas renderer;drawSnapIndicatorincanvasRenderer.tspaints a small accent at the target while a drag is in flight and clears on mouseup.geometry.test.ts+ 3 wiring tests inEditorCanvas.test.tsx.tsc -bclean,eslintclean,vite buildclean, 743/743 vitest tests pass on the rebased main (was 735 before my commit).Local CI gates:
Forgejo Actions self-hosted runner is currently non-functional (every recent run is
status: cancelled, started: 1970-01-01per the workflows/runs history) — see the comment in.forgejo/workflows/ci.yml. Local-gate results stand as the gate.selectedPathIdisstring | nullnotSet<string>, so the user can only ever edit one path at a time even with 5+ paths in a design #188