Skip to content

Studio popover chrome: one SVG merged-outline path replaces bridge-and-fillet CSS#102

Merged
Yona-Appletree merged 3 commits into
mainfrom
claude/contiguous-button-popup-ui-1e4d65
Jul 16, 2026
Merged

Studio popover chrome: one SVG merged-outline path replaces bridge-and-fillet CSS#102
Yona-Appletree merged 3 commits into
mainfrom
claude/contiguous-button-popup-ui-1e4d65

Conversation

@Yona-Appletree

Copy link
Copy Markdown
Member

What

Replaces PopoverButton's contiguous-border implementation — the 1px bridge strip, radial-gradient corner fillets, corner-visibility special cases, and hand-synced seam colors — with computed geometry: the union of the trigger and panel rects becomes one rounded SVG path that draws the shared fill, border, and shadow.

Technique write-up: https://lab.photomancer.art/post/2026-07-15-contiguous-popup/ · Spike: spikes/contiguous-popup/index.html (committed) · ADR: docs/adr/2026-07-15-popover-svg-merged-outline.md

How

  • base/outline.rs (new): pure geometry, no DOM — rect union via a small grid, uniform arc emission (concave corners = flipped sweep flag), per-vertex radius clamping, 1.25px edge welding, device-pixel snapping. Host unit tests.
  • Top layer: while open, the trigger's content re-parents into the popover top layer (which paints above everything); the in-flow button remains as an invisible size-pinned placeholder holding layout and keyboard focus. The layer visual is an aria-hidden div — clicking it closes.
  • Animation: open/close interpolates the panel's input rect and re-unions each frame (no path morphing). 160ms open / 120ms close ease-out-cubic, 3px trigger inflate, content clip+fade. rAF loop runs only while a transition is in flight; prefers-reduced-motion jumps to the settled shape.
  • Tones: ux-popover-chrome-* variables now feed SVG gradient stops and stroke — one gradient flows continuously across trigger + panel (impossible with the old multi-element chrome).
  • API unchanged: PopoverButton / IconPopoverButton / PopoverPlacement props identical; no consumer files touched.

Measurement robustness (found via story-capture debugging)

  • First measurement is synchronous — the old rAF-deferred first measure left popovers unpositioned in rAF-throttled environments.
  • Pre-layout (empty) panel measurements are rejected instead of mispositioning the panel.
  • data-story-wait now waits for a real panel measurement, settled animation, and the final 250ms stabilization re-measure — popover story captures were bimodal before; two consecutive capture runs are now pixel-identical.

Stories & baselines

  • icon_menu_stories.rs open_menu hand-mocked the old bridge chrome; rewritten as a static, measurement-free preview using the real merged_outline_path on hardcoded rects (all six side/align variants).
  • Baselines regenerated wholesale (STUDIO_STORY_PNGS_CONCURRENCY=1 — parallel captures hang Chrome on a loaded machine and produce AA artifacts). studio-story-check is clean except the pre-existing base__code-editor__overview CodeMirror flake (churns across unrelated commits in history).

Validation

  • just check ✓ · just build-rv32-builtins && just test ✓ (153 suites)
  • cargo test -p lpa-studio-web 104/104 (8 new geometry tests)
  • Story captures deterministic across consecutive runs

Review notes for Yona

The visual gate is yours: the regenerated popover/detail-popover/icon-menu baselines show the new chrome. Animation feel is best judged live (just studio-web-dev-build) — constants are OPEN_ANIM_MS/CLOSE_ANIM_MS/TRIGGER_INFLATE_PX in popover.rs if you want to tune.

Plan: ~/.photomancer/planning/lp2025/2026-07-15-contiguous-popup-port/

🤖 Generated with Claude Code

Yona-Appletree and others added 3 commits July 15, 2026 17:20
Replace PopoverButton's bridge-and-fillet CSS (1px seam strip, radial-
gradient concave corner patches, corner-visibility special cases, hand-
synced seam colors) with computed geometry: the union of the trigger and
panel rects becomes one rounded SVG path drawing the shared fill, border,
and shadow. Concave fillets are the same arc code path with a flipped
sweep flag; edges within 1.25px weld so alignment cases need no special-
casing.

- new base/outline.rs: pure rect-union -> rounded-path geometry, host
  unit tests
- while open, the trigger's content re-parents into the popover top layer
  (which paints above everything); the in-flow button stays as an
  invisible size-pinned placeholder holding layout and focus
- open/close animates by interpolating the panel's input rect and re-
  unioning per frame; rAF loop only while in flight; honors
  prefers-reduced-motion
- tone vars now feed SVG gradient stops: one gradient flows continuously
  across trigger + panel
- measurement robustness: first measure is synchronous (rAF-throttled
  environments), empty panel measurements rejected, data-story-wait gates
  on the final stabilization re-measure for deterministic captures
- icon-menu open-menu story rewritten as a static preview using the real
  geometry; dead bridge/fillet CSS removed; story baselines regenerated

ADR: docs/adr/2026-07-15-popover-svg-merged-outline.md
Spike: spikes/contiguous-popup/index.html
Technique: https://lab.photomancer.art/post/2026-07-15-contiguous-popup/

Co-Authored-By: Claude Fable 5 <[email protected]>
…ton-popup-ui-1e4d65

Story-image conflicts taken from main; all baselines regenerate in the
next commit from the merged tree.

Co-Authored-By: Claude Fable 5 <[email protected]>
@Yona-Appletree
Yona-Appletree merged commit 7c14f86 into main Jul 16, 2026
3 checks passed
Yona-Appletree added a commit that referenced this pull request Jul 16, 2026
…gate

Brings in PR #92 (shader auto-apply + split-bar editor chrome), PR #102
(popover chrome as one SVG merged-outline path), PR #101 (auto-apply ADR),
PR #100 (path-gated wgpu CI job), PR #99 (interp.f32 in DEFAULT_TARGETS).

Conflicts were story-baseline PNGs only (both sides re-captured) — taken
from main and re-captured from the merged tree in the follow-up commit.
The auto-merged generated tailwind.css was discarded and regenerated with
pinned [email protected] (braces verified balanced).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
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