feat(ui): touch and small-screen support (U-13) - #215
Closed
timurbazhirov wants to merge 2 commits into
Closed
Conversation
The proposal's position was that half-support is the worst of the three options, and the viewer was squarely in it. Verified on a 390x844 touch profile before changing anything: - The canvas had `touch-action: auto`, so the browser claimed every touch drag for page scroll and pinch-zoom and sent `pointercancel` to whatever had begun tracking it. Nothing draggable worked with a finger - not orbiting, not moving an atom, not marquee select - even though every handler in the editor is already pointer-event based. A one-finger swipe left the rendered frame byte-identical. - The quick-toggle row, the primary control surface on a phone, was 32 px. - The only surface documenting how to drive the viewer opened on `?` alone. - `isMobile` was computed from the viewport width and forwarded to exactly one dropdown. That is also the wrong question twice over: a narrow window on a desktop is not touch input, and a touch laptop is touch input at any width. Changes: - `touch-action: none` on the renderer canvas. One declaration, and every existing pointer handler starts working with a finger. - Edit mode reserves the first finger, mirroring what it already does with the left mouse button (D-4): while editing, `touches.ONE` is taken off the camera and orbit moves to two fingers (DOLLY_ROTATE). There is no right button to move it to. Restored on exit, verified across repeated round trips. - `utils/inputCapabilities.ts` replaces the viewport guess with capability queries read at call time - a window can move to another display and a tablet can gain a keyboard mid-session. `hasCoarsePointer` gates sizing; `hasTouchSupport` gates documentation, because a touch laptop needs the gestures listed and should keep its compact chrome. - Quick toggles grow to 44 px under `(pointer: coarse)` only. - The shortcut sheet is reachable from View > Shortcuts & gestures, gains a visible Close (the previous exits were `?`, Escape, or knowing that tapping the backdrop works - none available or discoverable on a phone), lists the touch gestures, and puts them first when the pointer is coarse: the sheet reflows to one column there, so group order is scroll distance, and the gestures were below three groups of keyboard shortcuts. - Nothing names an input the device lacks. The edit pill reads "drag atom = move - 2 fingers = orbit" on touch instead of RMB/Del/Esc; the sheet is titled "Shortcuts & gestures" rather than "Keyboard shortcuts" and drops the "? or Esc to close" hint on a coarse pointer. Two of these came only from looking at the rendered result: the sheet still promised `?` and Escape on a device with neither and had no visible way out, and the touch group was last. Re-verified on the same touch profile: main canvas touch-action none, every button at least 44x44, one-finger drag rotates, the sheet opens from the menu with touch first and lists pinch, pill wording correct, no console errors. Desktop rendering and wording unchanged. 32 new tests (440 passing, was 410).
Records touch support against the plan: that it sizes by pointer capability rather than viewport width, that no bottom sheet was needed because the existing layout was measured at 390 px and fits, and the touch-action bug it surfaced - the canvas let the browser claim every touch drag, so none ever reached the editor's pointer handlers. Also records why this is a stacked PR: every other item adds a surface, so a mistake is contained to what it added. This one changes how input the viewer already receives is handled, which is worth being revertable on its own.
This was referenced Aug 13, 2026
Member
Author
|
Closing — superseded, not dropped. U-13 ships in #214, which carries the same commits plus the rest of the UI/UX work. The plan is #216 first (everything except U-13), then #214 on top of it, so this stacked branch has nothing left to add. Nothing here is lost: Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on
claude/uiux-p2-figure-export— review that one first; this PR's diff is U-13 only.Touch and small-screen support, the last item of the UI/UX proposal (
docs/design/uiux-improvements-2026-08.md, U-13). Kept separate because it is the only item in the set that changes how input the viewer already receives is handled, rather than adding a surface — so it is worth being reviewable, and revertable, on its own.What was actually wrong
Measured on a 390×844 touch profile before changing anything:
touch-action: auto, so the browser claimed every touch drag for page scroll and pinch-zoom and sentpointercancelto whatever had begun tracking it. No touch drag ever reached any handler — not orbiting, not moving an atom, not marquee select — even though every pointer handler in the editor is already pointer-event based. A one-finger swipe left the rendered frame byte-identical.?alone — unreachable without a keyboard.isMobilewas computed from the viewport width and forwarded to exactly one dropdown. That is also the wrong question twice over: a narrow window on a desktop is not touch input, and a touch laptop is touch input at any width.Changes
touch-action: noneon the renderer canvas. One declaration, and every existing pointer handler starts working with a finger.touches.ONEcomes off the camera and orbit moves to two fingers (DOLLY_ROTATE). There is no right button to move it to. Restored on exit, verified across repeated round trips.utils/inputCapabilities.tsreplaces the viewport guess with capability queries read at call time — a window can move to another display and a tablet can gain a keyboard mid-session.hasCoarsePointergates sizing;hasTouchSupportgates documentation, so a touch laptop gets the gestures listed and keeps its compact chrome.(pointer: coarse)only.drag atom = move · 2 fingers = orbiton touch instead of RMB/Del/Esc; the sheet is titled "Shortcuts & gestures" rather than "Keyboard shortcuts" and drops its "? or Esc to close" hint on a coarse pointer.Verification
npm run lintandtsc --noEmitclean.touch-action: none, every button ≥ 44×44, one-finger drag rotates the camera, the sheet opens from the View menu with the touch group first and listspinch, pill wording correct, no console errors.Two of the defects here came only from looking at the rendered result rather than the suite: the sheet still promised
?and Escape on a device with neither and had no visible way out, and the touch group rendered last.🤖 Generated with Claude Code
https://claude.ai/code/session_0185JNEgEJLfZZEx7jKHgwu5
Generated by Claude Code