Skip to content

[research] UX walls + building-elements pain-points investigation#151

Open
rcasto123 wants to merge 1 commit into
mainfrom
docs/ux-walls-research-2026-04-27
Open

[research] UX walls + building-elements pain-points investigation#151
rcasto123 wants to merge 1 commit into
mainfrom
docs/ux-walls-research-2026-04-27

Conversation

@rcasto123
Copy link
Copy Markdown
Owner

Status

Research-only artifact. Not for merge. This PR exists to make the document discoverable alongside the parallel Engineering investigator's report. The synthesis pass after both land turns these into an MVP plan.

TLDR of the document

The user's frustration ("hard to design a proper office floor plan") traces to two stacked conceptual problems:

  1. The data model treats walls as line strokes, not as architectural objects. Doors, windows, and rooms are disconnected primitives.
  2. Walls were given polished drawing affordances but the editing affordances are missing or broken.

Top three things that make the editor feel broken

  • Placed walls cannot be dragged. Konva moves them visually during drag, then the controlled x=0, y=0 on the Group resets them on the next render. Users believe the editor is broken.
  • Walls do not snap to other walls. Grid-only snap during drawing means rooms never close cleanly. No endpoint-snap, no perpendicular-snap.
  • Doors and windows cannot be dragged on the canvas. Repositioning is via a 0..1 properties-panel slider with no length feedback.

P0 recommendations (fix this week)

  1. Make placed walls draggable (translate points on drag end). Effort: S.
  2. Add wall-to-wall endpoint snap during drawing using the existing findNearestStraightWallHit. Effort: M.
  3. Cascade-delete attached doors and windows when the parent wall is removed. Effort: S.

P1 / P2 highlights

  • Ortho-mode (Shift = 0/45/90° lock).
  • On-canvas drag for doors and windows along their parent wall.
  • "Rectangular room" tool that lays down 4 connected walls in one gesture.
  • Replace Conference Room / Common Area filled boxes with wall-bounded rooms.
  • Wall merge / split, length numeric input, scale-unit thickness.

Open questions for product / eng

  • Is connectedWallIds the seed of a future graph model, or dead code to delete?
  • What's the canonical unit for wall thickness?
  • Backwards-compat for existing conference-room filled-box autosaves?
  • Source format the user is recreating from (image trace? Revit? AutoCAD?) — affects which P0/P1 items matter most.

Files

  • docs/ux-research/walls-pain-points-2026-04-27.md (new)

Testing

N/A — documentation only, no code changes.

Research-only artifact (no code changes). Documents wall, door, window,
common-area, and conference-room pain points reported by users, with
prioritized P0/P1/P2 recommendations and open questions for product/eng.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 27, 2026

Deploy Preview for floorcraft-app ready!

Name Link
🔨 Latest commit a9aa77f
🔍 Latest deploy log https://app.netlify.com/projects/floorcraft-app/deploys/69efd397be363f0008807229
😎 Deploy Preview https://deploy-preview-151--floorcraft-app.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

rcasto123 added a commit that referenced this pull request Apr 27, 2026
…cade-delete (#155)

Four targeted fixes for the most-cited frustrations from the walls-pain-points
research (PR #151) and walls-implementation audit (PR #153). Each lands as a
self-contained change inside the existing data model — no schema work, no
geometry refactor, no door/window placement changes.

Fix 1 — Walls actually drag. Walls render their wrapping <Group> at (0, 0)
because their geometry lives in `points: number[]` (the `ownsPosition`
contract in ElementRenderer.tsx). The previous drag-end path wrote `{x, y}`
which the renderer ignored, so dragging a wall snapped it back. New
`translateWall(id, dx, dy)` helper in wallEditing.ts shifts every entry of
`points[]` by the drag delta. Doors and windows attached via `parentWallId`
follow automatically because they resolve their world position from the
parent wall's points each render.

Fix 2 — Endpoint snap during wall drawing AND vertex drag. New
`findNearestWallVertex()` in wallAttachment.ts. Wired into
`useWallDrawing.snapPoint` ahead of grid snap, and into `applyVertexMove`
in wallEditing.ts, so a click or vertex drop within
`ENDPOINT_SNAP_PX (10) / stageScale` canvas units of any existing wall
vertex lands exactly on that vertex. Two walls drawn corner-to-corner now
share an endpoint cleanly with no 1-3px gap.

Fix 3 — Shift cardinal angle lock. New `lockToCardinal(ax, ay, px, py)` in a
new wallSnap.ts module that projects a candidate point onto the nearest
0°/45°/90°/135° ray from the previous committed vertex. Active during the
preview phase (so the user sees what they'll commit) and at the commit
itself. Also flows through `applyVertexMove` so vertex drag with Shift
held constrains to a cardinal direction relative to the adjacent vertex.

Fix 4 — Cascade-delete toast with Undo. The cascade itself already lived
in `deleteElements` (seatAssignment.ts); this adds a single info toast
("Wall and N attached elements deleted") with an Undo action that
re-merges the captured pre-delete element + employee snapshots back into
the live stores. We deliberately keep the cascade behaviour rather than
silently re-anchoring children to the nearest other wall — silent
mutation is the worse failure mode.

Tests: src/__tests__/wallsP0Fixes.test.ts adds 16 integration-level
assertions, covering all four fixes plus regression cases (Shift NOT
held, no-attachment delete doesn't toast). Existing wall test suites
remain green (250 files, 1705 tests).

Source-of-truth research:
- docs/ux-research/walls-pain-points-2026-04-27.md (PR #151)
- docs/engineering-research/walls-implementation-2026-04-27.md (PR #153)

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
rcasto123 added a commit that referenced this pull request Apr 27, 2026
… retire connectedWallIds (#156)

Adds the four P1 wall-drawing wins identified by the parallel UX (#151) and
engineering (#153) audits, building on top of the P0 fixes that just landed
in #155.

Changes:

1. Live dimension readout pill (Fix 1). Each in-flight wall segment —
   committed-but-pre-finalisation segments AND the live rubber-band
   preview — now renders a small rounded-rect pill at its midpoint
   showing the segment's real-world length and angle. The pill uses
   `formatLength` + `toRealLength` from `src/lib/units.ts` so a 12-ft
   wall reads "12.0 ft" everywhere; angles within 5° of a cardinal
   gain a "→ N/S/E/W" indicator. Inverse-zoom-scaled the same way the
   alignment-guide labels are. When Shift is held, the pill reflects
   the LOCKED angle/length (because `currentPoint` already runs through
   the cardinal-lock projection at preview time), so the user sees
   what they will commit, not what they're hovering at.

2. Rectangle / room tool (Fix 2). New `'room'` tool registered in
   `ToolSelector` (lucide `Square` icon, Shift+O hotkey). Click-drag
   from corner A to corner B and on release we commit FOUR connected
   `WallElement`s in a single zundo batch — one undo rolls back the
   whole rectangle. Endpoint snap from #155 applies to both corners
   during the drag; cardinal-lock (Shift) constrains the rectangle to
   a square (shorter side wins, sign preserved). The rectangle preview
   renders width+height dimension pills using the same helper as the
   wall-tool pills.

3. Auto-close on snap-back to start (Fix 3). When drawing a polyline
   wall with 3+ committed vertices, if the next click lands within
   `ENDPOINT_SNAP_PX / stageScale` of the FIRST committed vertex, the
   click commits a closing-back-to-start vertex AND auto-finalises the
   wall — no double-click required. Visual cue: a filled green circle
   at the start vertex when the cursor is in close-snap range, mirroring
   the endpoint-snap hit-marker idiom.

4. Retire `connectedWallIds` (Fix 4). The dead metadata slot on
   `WallElement` — declared but never written or read outside test
   fixtures — is removed from the type, every construction site
   (`useWallDrawing`, demo seeder, three template seeders), and the
   live test fixtures that referenced it. The legacy-payload loader
   defensively strips the field on load so older autosave payloads
   round-trip cleanly through the new shape.

Tests: `src/__tests__/wallsP1Improvements.test.ts` covers all four
features (11 tests). The pill helpers, the rectangle-builder, and the
square-constrain helper are pure functions tested directly; the
auto-close path is tested through the `useWallDrawing` hook.

Verification: tsc clean, vitest 1716 passed (1705 original + 11 new),
build green, eslint clean on touched files.

Refs: #151 (UX research), #153 (engineering audit), #155 (P0
predecessor).

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
rcasto123 added a commit that referenced this pull request Apr 27, 2026
…handle attached elements (#158)

Walls are now fully editable post-placement. Two new affordances close the
"delete-and-redraw" gap that the research docs (PR #151) flagged as the
top remaining wall pain point:

1. **Add vertex** — hovering near a wall edge (in the wall tool, or with a
   single wall selected) shows an open-green-circle "+ vertex" indicator
   at the projected point on the polyline. Clicking commits a new vertex
   in `points[]` between the two boundary vertices. Curved segments split
   into two halves with halved bulges so the visible arc continues. The
   newly-inserted vertex is selected as the active vertex so a follow-up
   drag fine-tunes it (or Backspace removes it).

2. **Remove vertex** — clicking a vertex sets it active (a slightly-larger
   filled circle with a dark outline + a "Backspace to remove" tooltip).
   Backspace/Delete prunes that single vertex instead of nuking the whole
   wall. Doors/windows whose `positionOnWall` falls on the removed
   segment(s) are cascade-deleted with the same Undo-toast pattern as
   PR #155's wall-delete cascade. Removing a vertex from a 2-vertex wall
   falls back to the existing wall-delete path. Double-click on a vertex
   is an equivalent mouse-only affordance.

New helpers:
  - `addVertexAt(wall, segmentIndex, point)` — pure, returns updated wall +
    new vertex index (callers wire the store update + active selection)
  - `removeVertex(wall, vertexIndex)` — pure, returns null when the wall
    would become degenerate
  - `findNearestPointOnWallEdge(segs, px, py)` — chord projection across
    a wall's polyline, distance returned for caller-side tolerance
  - `removeWallVertex(wallId, vertexIndex)` — orchestrates the cascade,
    snapshot, store mutation, and Undo toast in one zundo step

State:
  - `useUIStore.activeVertex: { wallId, vertexIndex } | null` clears on
    any selection change so a stale index can never refer to a different
    wall's points array

No renderer changes — geometry edits are enough.

Refs PRs #155 (P0), #156 (P1), research docs #151 / #153.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.

1 participant