47 lines
2.4 KiB
Markdown
47 lines
2.4 KiB
Markdown
# 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.
|