From 9ed01e28126c96310b22ba73629ddc4244571060 Mon Sep 17 00:00:00 2001 From: iris <2+iris@noreply.localhost> Date: Mon, 7 Sep 2026 16:04:34 -0400 Subject: [PATCH] docs: phone report 2026-09-07 later -- overscroll, low initial fling velocity, input/timing report; queued Co-Authored-By: Claude Fable 5.1 --- docs/IRIS_TODO.md | 40 ++++++++++++++++++++++++++++++++++++++++ docs/RUST.md | 5 +++++ 2 files changed, 45 insertions(+) diff --git a/docs/IRIS_TODO.md b/docs/IRIS_TODO.md index a5da4d2..80069d0 100644 --- a/docs/IRIS_TODO.md +++ b/docs/IRIS_TODO.md @@ -955,3 +955,43 @@ do not duplicate it there. the header's bottom must be masked. Fix both with one rule: a row is drawn if any part of it intersects the viewport, and the viewport is the list's own region. + +## From the phone, 2026-09-07, later (build from 4274b8b, ai-app-bench b47eb73) + +- [ ] **"You shouldn't be able to scroll below the bottom (or above + top)."** The list's offset is not clamped to its content range while + dragging and/or flinging. Compose's `LazyColumn` never moves content + past its ends -- the overscroll *effect* on Android 12+ is a stretch + drawn over clamped content, not a displacement. Clamp the offset in + one place (`List`'s scroll setter, so drag, fling, page-in and + programmatic scroll all go through it) and end a fling that hits the + clamp. Test at layer 1: a drag past either end leaves the offset at + the end; a fling into the end stops there. +- [ ] **"Flinging now actually works but is slower than Compose's + immediately after releasing the flick (the slow down seems + correct)."** The curve is right, so the *initial velocity* is low. + iris's `VelocityTracker::velocity` is total motion over the window's + span -- an average -- where Compose's `VelocityTracker` (`compose.ui` + `VelocityTracker.kt`, `VelocityTracker1D` with `Strategy.Impulse`, + 100ms horizon, 20 samples, `AssumePointerMoveStoppedMilliseconds = + 40`) weights the last samples, so a flick that accelerates into the + release reads faster. Port the impulse strategy from source with + checked-in reference values from an independent transcription, as + the spline was; also apply Compose's min/max fling velocity + (`ViewConfiguration`'s 50dp/s and 8000dp/s) so a slow release does + not fling and a wild one is capped. Layer-1 test on + `flick-120hz.touch` asserting the number Compose's code gives. +- [ ] **Input-event and timing report from the phone.** Iris: "add + another button to copy input event info so that I can do some stuff + manually and then send the event log to you ... instrument a lot of + the code with timings so I can give you time reports through the + same button." Build on the log ring (queue: logging through Dev + Updater), not beside it: every `MotionEvent` (action, pointer + position, event time, historical sample count) and every gesture + decision (`iris drag release:` and its siblings) at debug level into + the ring; frame timings (input handled -> layout -> draw submitted, + and the fling tick's `now` against the frame clock) at debug level + into the same ring; "Copy report" already appends the ring. Add a + second button only if the report gets too long to paste -- then + "Copy input log" copies the ring alone. Says which build it came + from. diff --git a/docs/RUST.md b/docs/RUST.md index be43531..ef6a394 100644 --- a/docs/RUST.md +++ b/docs/RUST.md @@ -240,6 +240,11 @@ closes it. rest of her phone shows (UI_RULES "show what the reader already sees elsewhere"), at the cost of the app no longer looking identical on every device. Not done without her verdict. +- [ ] Scroll clamped at both ends, and Compose's impulse velocity + estimator with min/max fling velocity (docs/IRIS_TODO.md, 2026-09-07 + later). After the culling fix lands (same file). +- [ ] Input-event and timing instrumentation into the log ring, copied + by the report button. After the logging route lands (same ring). - [ ] Masks with a shape -- docs/LAYOUT.md "Masks with a shape (decided 2026-09-07)". A mask references a primitive already drawn (rect SDF, texture or glyph alpha), chained and multiplied; `.masked()`