Releases: gpu-cli/annotkit
Release list
v0.5.0 — frame selection, tree navigation, Escape, inline icon actions
Everything merged in #1 since v0.4.0. Three epics' worth of overlay work: VRT-cne0 (frame selection + X close), VRT-mijf (tree navigation + frame anchoring), VRT-dp47 (Escape, pill visibility, inline icon actions).
Selection
- Frame selection tool. Draw a rectangle around what you mean instead of hunting for the pixel that hit-tests to it; the drawn frame resolves to the most likely element inside it, and degrades to a region note anchored at the frame's centre when nothing there is annotatable. It is an explicit tool, chosen in the pill — a click in frame mode does nothing by design, so a wobbly hand can never silently plant a framed note. The persisted
regionRectlocator ("a 320x48 band 40pt down inside#Settings.Models") travels with the note. - Select Parent / Select Child replace the one-way "Widen". Both directions are always visible and dim to show where you are in the tree, and a Parent→Child round trip returns to the rung you came from rather than to whatever the live UI now considers most likely.
- Frame mode no longer hover-highlights. A highlight there promised a click-selection the mode cannot make.
Keyboard
- Escape backs out one level at a time — card, then in-flight frame drag, then annotate mode — through a local key monitor that works whether or not the overlay panel is key. A handled Escape is consumed so the host app never double-acts on the same keystroke; an unhandled one is passed through untouched.
The pill
- The toolbar now lives in its own window. It was drawn inside the catcher overlay, so its position was a function of a frame that resizes on every open/close, gets clamped to the visible screen, and is dragged around by AppKit when the host moves. It is now permanently mounted, fixed size, pinned to the host's bottom-right: always visible, always in the same place, and the menu is genuinely just open or closed.
- Placement is clamped to the screen's
visibleFrame, so a host window whose bottom hangs below the display no longer puts the pill under the Dock — and the clamp is re-asserted after AppKit's parent-follow repositioning, which used to silently undo it a runloop turn later. - Scrolling the host while annotating works. The overlay drives the host's clip directly rather than handing the event across windows, which used to wedge the panel's rendering and hit-testing — observed as "the toolbar vanishes after I scroll, then hover on and off it".
AXEnhancedUserInterfaceis written once per process, not per hover, ending a relayout storm that made the pill flicker.
Cards and icons
- One inline row of icon actions on both the composer and the pin editor —
arrow-up,arrow-down,undo-2,send,trash— each with a tooltip and a matching accessibility label, and the commit action carrying its prominence in accent colour. - Real elliptical arcs in the Lucide path parser (SVG 1.1 F.6.5 endpoint→centre, emitted as cubic beziers). The old parser drew a straight line to each arc endpoint, which collapsed
undo-2's loop into a vertical stroke;pencil's corner rounds have quietly been wrong all along and are now correct too.
Verification
191 tests, 11/11 AnnotKitOverlayProbe phases, swift build -Xswiftc -warnings-as-errors clean, iOS simulator cross-compile clean.
Full changelog: v0.4.0...v0.5.0
v0.3.1 — positional specificity, region annotations, hardened hit-testing
Selection: pure positional specificity
The smallest/deepest meaningful element under the cursor wins — a button on a card at the button, the card's surface at the card padding, the section at the section padding. Cursor position is the level selector; there is no depth-walking UI. Plain SwiftUI Text now counts as meaningful via its AXValue (previously text leaves were skipped and hovers escalated to the page container).
Region annotations
Clicks where no accessibility node exists (decoration, dividers, gaps) are no longer dropped: the session captures a region note anchored to the nearest meaningful element with an offset from its top-left, persisted as an optional regionOffset (old note files decode unchanged). Markdown and JSON exports render the locator.
Hit-testing hardening (since 0.2.x)
- Window chrome (traffic lights, including their inner glyph groups) is never an annotation target.
- Whole-window unidentified hosting groups can't swallow background clicks.
- Descent prefers the most specific containing child; equal-area ties resolve to content over seeded surfaces.
- Host-window APIs: install(on:)/mount(on:) for explicit window targeting; overlay geometry settles after content-driven host resizes.
- Fixed: a region-then-element re-selection no longer leaks the region offset onto the element note.
52 tests + two headless probe harnesses (AnnotKitProbe, AnnotKitOverlayProbe with 7 phase groups) all green.