Plops editor: focus mode, place/move/resize, semantic zoom #15

Closed
opened 2026-07-18 18:18:44 +00:00 by steve · 0 comments
Owner

Part of epic #20 · Design: DESIGN.md

Context

This issue delivers pansy's core vision: click into a bed, plop garlic in one corner and basil in another, zoom out, and still see what's planted where. It builds focus mode, plop placement/manipulation, and semantic zoom on top of the field editor (#11), the PlantPicker (#13), and the plantings API (#14).

Scope

  • Focus mode: click/tap a plantable object (that isn't being dragged) → animate zoomToFit(object), set focusedObjectId + ?focus= URL param, dim/desaturate everything else. Escape / tap outside / a breadcrumb button exits (animates back to full-garden view). Same canvas, no separate route.
  • Placing: in focus mode, a "plant" action opens PlantPicker (#13); after choosing, click/tap inside the object drops a plop there — default radius max(1.5 × spacing_cm, 15cm), converted into the object's local frame before POSTing. Repeat-place stays armed until Escape/done.
  • Manipulating: select a plop → drag to move; a radius handle resizes; inspector (reuse #11's panel/sheet) shows plant (changeable via picker), radius, count (shows derived value greyed; typing sets the override; clearing restores derived), label, planted date, "remove" (sets removed_at, distinct from hard delete). Optimistic sync with the same one-PATCH-per-gesture + 409-rollback pattern as #11.
  • PlopMarker semantic zoom (web/src/editor/PlopMarker.tsx), three bands on viewport scale (start at <0.75 / 0.75–3 / >3 px per cm; tune by feel and keep thresholds as constants):
    • far: flat circle in the plant's color, no text — plus, on plantable objects, a name label + dominant-plant tint so beds read at a glance;
    • mid: colored circle + emoji icon;
    • near: circle + emoji + plant name + count (derived or override).
  • Rotation correctness: plops render inside the object's rotated group so they track the object; verify moving/rotating a bed in field view carries its plops (no planting writes occur).

Out of scope

  • Read-only mode (#17). Clear-bed bulk action (#18). Region fills (#19). Plop overlap rules (none by design).

Key files & patterns

  • Local-frame transforms from web/src/lib/geometry.ts (#9); semantic-zoom bands: DESIGN.md § Editor / rendering.

Dependencies

Blocked by #11, #13, #14.

Acceptance criteria

  • The DESIGN.md scenario end-to-end on desktop AND a phone: create a bed, focus into it, place a few garlic plops in one corner, basil in another, beans along a side; exit focus; zoom out — colors/labels identify the plantings; zoom mid — icons appear; zoom in — names + counts. Reload: identical.
  • Rotate the bed 45° in field view — plops stay in their corners.
  • Resizing a plop updates its displayed derived count live; setting an override sticks.
  • "Remove" hides the plop everywhere and survives reload (row kept with removed_at).
Part of epic #20 · Design: [DESIGN.md](https://gitea.stevedudenhoeffer.com/steve/pansy/src/branch/main/DESIGN.md) ## Context **This issue delivers pansy's core vision**: click into a bed, plop garlic in one corner and basil in another, zoom out, and still see what's planted where. It builds focus mode, plop placement/manipulation, and semantic zoom on top of the field editor (#11), the PlantPicker (#13), and the plantings API (#14). ## Scope - [ ] **Focus mode**: click/tap a plantable object (that isn't being dragged) → animate `zoomToFit(object)`, set `focusedObjectId` + `?focus=` URL param, dim/desaturate everything else. Escape / tap outside / a breadcrumb button exits (animates back to full-garden view). Same canvas, no separate route. - [ ] **Placing**: in focus mode, a "plant" action opens `PlantPicker` (#13); after choosing, click/tap inside the object drops a plop there — default radius `max(1.5 × spacing_cm, 15cm)`, converted into the object's **local frame** before POSTing. Repeat-place stays armed until Escape/done. - [ ] **Manipulating**: select a plop → drag to move; a radius handle resizes; inspector (reuse #11's panel/sheet) shows plant (changeable via picker), radius, count (shows derived value greyed; typing sets the override; clearing restores derived), label, planted date, "remove" (sets `removed_at`, distinct from hard delete). Optimistic sync with the same one-PATCH-per-gesture + 409-rollback pattern as #11. - [ ] **`PlopMarker` semantic zoom** (`web/src/editor/PlopMarker.tsx`), three bands on viewport scale (start at <0.75 / 0.75–3 / >3 px per cm; tune by feel and keep thresholds as constants): - far: flat circle in the plant's color, no text — plus, on plantable objects, a name label + dominant-plant tint so beds read at a glance; - mid: colored circle + emoji icon; - near: circle + emoji + plant name + count (derived or override). - [ ] Rotation correctness: plops render inside the object's rotated group so they track the object; verify moving/rotating a bed in field view carries its plops (no planting writes occur). ## Out of scope - Read-only mode (#17). Clear-bed bulk action (#18). Region fills (#19). Plop overlap rules (none by design). ## Key files & patterns - Local-frame transforms from `web/src/lib/geometry.ts` (#9); semantic-zoom bands: `DESIGN.md` § Editor / rendering. ## Dependencies Blocked by #11, #13, #14. ## Acceptance criteria - **The DESIGN.md scenario end-to-end on desktop AND a phone**: create a bed, focus into it, place a few garlic plops in one corner, basil in another, beans along a side; exit focus; zoom out — colors/labels identify the plantings; zoom mid — icons appear; zoom in — names + counts. Reload: identical. - Rotate the bed 45° in field view — plops stay in their corners. - Resizing a plop updates its displayed derived count live; setting an override sticks. - "Remove" hides the plop everywhere and survives reload (row kept with `removed_at`).
steve added the frontenddrawing labels 2026-07-18 18:18:44 +00:00
steve closed this issue 2026-07-19 03:22:51 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: steve/pansy#15