Skip to content

feat: opt-in ui coordinate space for explicit swipe/touch coordinates - #74

Merged
onevcat merged 3 commits into
mainfrom
feat/coordinate-space-ui
Jul 28, 2026
Merged

onevcat merged 3 commits into
mainfrom
feat/coordinate-space-ui

Conversation

@onevcat

@onevcat onevcat commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Closes #66 — PR B of two, stacked on #73 (base is fix/gesture-orientation; GitHub will retarget to main when #73 merges).

What

Explicit swipe/touch coordinates keep their device-native portrait default — the #34 acceptance contract, so no existing script changes behavior — and gain --coordinate-space native|ui:

  • ui: endpoints are given in the visual space describe-ui prints and are orientation-calibrated per command (per batch-run for batch steps, shared with tap selector steps and gesture presets via the new BatchContext.uiSpaceCalibration helper). Coordinates lifted from the outline now stay correct on a rotated device.
  • native (default): bit-for-bit the previous behavior — zero-cost, no tree fetch, no calibration, no advisory noise. The rotated-device advisory is deliberately not added to native mode: detecting rotation would itself cost an AX calibration on every raw swipe/touch.
  • Split touch restriction: touch --coordinate-space ui requires the atomic --down --up form. A split touch could straddle a rotation and its two halves would calibrate independently into different spaces; v1 rejects it in shared validation (standalone, top-level, and batch parse all inherit it).
  • Cross-platform contract: the top-level commands accept the flag everywhere and ignore it on Android, where bridge coordinates are display-space and already rotate with the UI (documented in the flag help).
  • Calibration failures degrade to native dispatch with an orientation_calibration_fallback advisory in the envelope / batch result — never silent.

Testing

  • TDD: CoordinateSpaceTests written against the flag-only stub first — 7 red (split-touch rejection ×2, batch ui calibration for swipe/touch, fetch-failure advisory, batch split rejection) with the native zero-cost cases green from the start, then implemented to a full pass.
  • Advisory exclude-from-data contract registered for the swipe/touch ExecutionResults.
  • Full suite: 1190 tests green (includes the forwarder field-copy guard covering the new flag).

🤖 Generated with Claude Code

https://claude.ai/code/session_01Rir4WwrPShf5DYzziJ8RyC

onevcat added 3 commits July 28, 2026 16:52
Explicit swipe/touch coordinates keep their device-native portrait
default - the issue #34 acceptance contract - and gain
--coordinate-space ui to opt endpoints into the visual space
describe-ui prints. In ui mode the endpoints ride a per-command
orientation calibration (the shared UISpaceCalibrationLoader, reused
by the gesture presets from the previous commit); a failed
calibration degrades to native dispatch with an advisory in the
envelope. Native mode stays zero-cost: no tree fetch, no calibration,
and no advisory noise.

touch accepts ui in the atomic --down --up form only: a split touch
could straddle a rotation and its two halves would calibrate
independently into different spaces. Batch swipe/touch steps share
the batch-wide calibration via the new
BatchContext.uiSpaceCalibration helper (the gesture step converges on
it too), and an unreachable AX tree records a step-prefixed advisory
instead of failing the batch.

The top-level cross-platform commands accept the flag everywhere and
ignore it on Android, where display coordinates already rotate with
the UI.

TDD: CoordinateSpaceTests written first against the flag-only stub -
7 failures (split-touch rejection, batch ui calibration for swipe and
touch, fetch-failure advisory) with the native zero-cost cases green,
then implemented to a full pass. 1190 tests green.

Closes #66 (PR B; PR A made directional gesture presets
orientation-aware)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rir4WwrPShf5DYzziJ8RyC

Signed-off-by: onevcat <onevcat@gmail.com>
Review follow-up: the top-level swipe/touch help promises the flag is
accepted and ignored on Android, and every android direct command
mirrors its top-level/iOS flag surface - but android swipe/touch
rejected it at parse time. Declare the option on both as a documented
no-op (Android coordinates are display space and already rotate with
the UI) and pin the parity with parser tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rir4WwrPShf5DYzziJ8RyC

Signed-off-by: onevcat <onevcat@gmail.com>
Base automatically changed from fix/gesture-orientation to main July 28, 2026 09:54
@onevcat
onevcat merged commit 7ed9e4c into main Jul 28, 2026
1 check passed
@onevcat
onevcat deleted the feat/coordinate-space-ui branch July 28, 2026 09:55
onevcat pushed a commit that referenced this pull request Sep 16, 2026
`swipe` and `touch` gained `--coordinate-space` in #74, but `tap` did
not — so a coordinate read off the `describe-ui` outline and passed to
`tap -x/-y` was always dispatched in device-native portrait space and
landed elsewhere on a rotated device, with no flag to correct it.

Explicit `-x/-y` / `--point` now accept `ui`, which runs the point
through the same orientation calibration selector taps already ride
(#34). `native` stays the default and stays zero-cost: no AX round-trip,
no calibration. Batch `tap` steps take the batch-wide calibration, the
way `swipe` / `touch` steps already do.

Aliases and selectors resolve their own coordinates from the AX tree,
which is already ui space and already calibrated, so the flag has
nothing to act on there. Combining them rejects rather than silently
accepting a no-op, matching how `--frame` already rejects targeting
forms it cannot apply to.

Refs #142

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Xerol Wong <hlchbzz@gmail.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.

iOS directional gestures (gesture scroll-*, swipe/touch) ignore device orientation

1 participant