diff --git a/external/bugs/composite-transform/README.md b/external/bugs/composite-transform/README.md new file mode 100644 index 0000000..0fbbbd6 --- /dev/null +++ b/external/bugs/composite-transform/README.md @@ -0,0 +1,46 @@ +# WebKit nested composite-transform frame pacing reproduction + +This is a dependency-free reproduction for an iOS WebKit frame-pacing issue involving two nested animation clocks: + +- A route-sized parent surface whose `translate3d()` progress is updated by `requestAnimationFrame`. +- A child with an infinite CSS `rotate()` animation, drawn as a rounded border spinner. + +On the originating device, spinner durations within part of the `0.5s`–`1.1s` range produced regular 33–34 ms rAF gaps, while durations outside that band were smooth. The workload per frame is effectively unchanged, making the duration-dependent behavior unexpected. + +## Run + +Open `index.html` directly. The reproduction is a single, self-contained HTML file and works from a `file://` URL without a server. + +To test it through a local HTTP server instead, run this from the repository root: + +```sh +npx vite external/bugs/composite-transform +``` + +This directory is independent of the Vue demo and has no build step or runtime dependencies. The CSS, test scene, controls, and measurement code are all in `index.html`, so that file can be attached directly to a browser bug report. + +## Protocol + +1. Do not scroll or touch the page while a sample is running. +2. Run **Sweep 0.5–1.1 s** with **rAF-driven** selected and **Spinner enabled** checked. +3. Repeat with **Static translate3d parent**. +4. Repeat with **No parent transform**. +5. Clear **Spinner enabled** and run the sweep as a control. + +Each duration runs for 1.8 seconds. In the rAF-parent case, the incoming route moves for 700 ms and then remains stationary for the rest of the measurement. + +## Expected + +Changing only `animation-duration` should alter angular velocity, not cause a stable 60 Hz page to begin missing display deadlines. The rAF stream should remain close to 16.7 ms throughout the sweep on a 60 Hz device. + +## Actual observation in the source application + +The problematic sample showed: + +- A 16 ms baseline. +- Repeated 33–34 ms gaps during the route transition. +- The same gaps continuing while the parent was stationary and the spinner remained visible. +- Normal pacing after the spinner was removed from the DOM. +- No route-loading delay, JavaScript long task, or layout shift correlated with the gaps. + +The reproduction intentionally contains no Vue, Vue Router, Suspense, application store, network request, or service-worker caching logic in its measured path. diff --git a/external/bugs/composite-transform/index.html b/external/bugs/composite-transform/index.html new file mode 100644 index 0000000..762fcde --- /dev/null +++ b/external/bugs/composite-transform/index.html @@ -0,0 +1,288 @@ + + +
+ + +
+ A CSS border spinner rotates inside a route whose parent transform is driven by
+ requestAnimationFrame. On iOS WebKit, changing only the spinner duration can
+ cause repeatable 33–34 ms frame gaps.
+
| Spinner | p95 | Max | Frames > 30 ms |
|---|---|---|---|
| No runs yet. | |||