Skip to content

Map: unbind the drawing surfaces from the parent's box #278

Description

@QuentinRoy

Destination

A written specification for what bounds the surfaces this library draws — the three stroke canvases and the menu — staged as ready-for-agent tickets in the style of #244/#245/#246. The map is done when someone can unclip the drawing from the parent's box, and keep overflow: hidden working as containment, without another decision being needed.

The concrete defect this starts from: a stroke canvas is sized once to parent.getBoundingClientRect() and pinned at left/top: 0 (stroke.ts:87), so ink outside the parent's box is lost even when the host does not clip. That makes the parent bound display while it does not bound input: pointerdown takes pointer capture (pointer-source.ts:49), so a gesture that leaves the parent keeps driving the machine, and selection is angle-and-distance based with items at pointer-events: none. The menu DOM already overflows freely. Only the canvases clip, and only for implementation reasons.

Notes

Domain. Vocabulary is the code's own: stroke, upper and lower stroke, gesture feedback / trace, canvas, surface, parent, wrapper, containment. Read src/layout/stroke.ts, src/engine/renderer.ts, src/layout/gesture-feedback.ts and src/layout/menu.css before touching a ticket.

Skills every session should consult. grilling and codebase-design. There is no domain-modeling skill installed on this machine — codebase-design is the stand-in for interface work, same as in #263.

The four surfaces.

Surface Built by Paint order Lifetime
Lower stroke createStrokeCanvas behind the menu the gesture
Menu createMenu the open sub-menu
Upper stroke createStrokeCanvas in front of the menu the gesture
Gesture feedback createStrokeCanvas in front of the menu gestureFeedbackDuration after the gesture, several at once

restack() in renderer.ts holds that order by sibling position, deliberately without z-index.

Relationship to #263. The wedge-ring map's "Always a shadow root" decision puts a core-owned wrapper <div> between parent and everything drawn here. That wrapper is the element whose box would decide what can escape, so the two maps touch at exactly one seam. #263's Out-of-scope line — "The wedge ring changes nothing about how strokes are drawn, so the two do not interact" — is true of the wedge geometry and false of the wrapper; it has been corrected there.

Standing decisions, settled while charting

Premises, not open questions.

  • Destination shape. A spec handed off as ready-for-agent tickets. Planning, not execution: no ticket here lands the change. The decisions are cheap to settle in prose and expensive to settle in a diff.
  • Its own map, not tickets on Map: land the wedge-ring menu design and a configurable theming API #263. Map: land the wedge-ring menu design and a configurable theming API #263's destination is a spec for the wedge-ring look and its theming API; what bounds the drawing surfaces is not part of that, and folding it in would widen a map that is already large.
  • Targets the post-wrapper DOM. The specification is written against the world where the core owns a wrapper, and blocks on The wrapper, the shadow root, and the ::part() inventory #269 exactly where the wrapper's box matters — not everywhere.
  • One rule for all four surfaces. The defect is an inconsistency between surfaces, so fixing one canvas without stating the rule leaves the next reader to re-derive it. The menu likely needs documentation rather than code.
  • Three canvases stay three. Two different reasons, both sufficient: the lower stroke sits behind the menu while the other two sit in front of it, and each feedback trace outlives the gesture that drew it, so several can fade concurrently while a new gesture draws. Consolidation is off the table; the restack() complexity is the price of the paint order, not an accident.
  • The never-resizes bug is in scope. A canvas is sized once at creation and never again, so a parent that resizes mid-gesture already draws into a stale surface. It is the same question — what is the surface sized to, and when is that re-evaluated — and any answer has to settle it anyway.
  • The hand-off must ship a way to see it. Nothing in the repo exercises a stroke leaving its parent: the playground clips (live-surface.tsx:354) and the e2e fixture uses overflow: auto. The spec must require a deliberately undersized parent that shows the escape, and a clipped counterpart proving overflow: hidden still contains everything. Both halves of the contract are otherwise untested, and the clipped half already has a consumer.

Decisions so far

Not yet specified

  • Mid-gesture scrolling of an ancestor. The parent rect is re-read every frame and points arrive in client coordinates, so a scroll during a gesture may drift the ink against the pointer. Whether that is a defect, and whether the sizing rule makes it better or worse, has not been looked at.
  • Whether the menu needs any code change at all. It already overflows; it may need only a documented contract. The answer depends on which element ends up being sized.
  • Fading traces when the surface grows. If a new gesture regrows the drawing surface while earlier feedback traces are still visible, what happens to those traces is unspecified.

Out of scope

  • Tier 2: position: fixed and client coordinates. Escaping an ancestor's overflow: hidden, which would also retire toLocalPoint entirely. It subsumes this work's mechanism but takes away overflow: hidden as a clean CSS opt-out, and brings its own failure modes (transform/filter/contain ancestors silently reclipping, stacking-context fights). If it ever happens it is a fresh destination, not a continuation of this one.
  • Viewport-edge menu placement. Once the parent stops bounding the drawing, the viewport is the real bound and a menu opened near a screen edge puts labels off-screen. Already true today, so not caused here; it is a menu-placement feature (clamp the centre, or flip labels) and belongs with Map: land the wedge-ring menu design and a configurable theming API #263.
  • Wedge-ring geometry and the theming API. Map: land the wedge-ring menu design and a configurable theming API #263 owns those.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions