Stop blurring the animated scene on static glass (2x frame time)
The MacBook ran hot browsing the app: the ice scene animates constantly, so every backdrop-filter surface re-ran its blur on every frame. Measured on desktop (2x CPU throttle, software renderer): p50 frame 66.6ms baseline, 33.3ms with the static surfaces not filtering, 16.7ms with the scene's animation also off; frames over 34ms: 128 -> 14. The glass recipe is split: floating layers (sheets, dropdowns, dialogs, the sticky header/chrome/tab bar) keep the blur (backdrop-blur-lg, what phones already used); static layers (cards, the sidebar rail, the gate, the study prompt card) keep the identical tint, rim, highlight and shadow without the filter. The study prompt card moves from glass-panel to card + glass-solid, which is the same surface recipe. Quality: a deterministic pixel diff (scene motion frozen, both themes, desktop + phone) shows a ~1% colour shift in the card backdrops — invisible. The mobile axe contrast audit and the bubbles suite stay green. tests/bubble-perf.mjs now also reports the glass cost. README: decision 61. SW -> freezmo-v49.
This commit is contained in:
parent
9b9e978ef2
commit
1f2e702b4e
5 changed files with 63 additions and 18 deletions
|
|
@ -14,7 +14,7 @@ import { BASE, DECK, launchBrowser, makePage, seed } from "./lib.mjs";
|
|||
const label = process.argv[2] ?? "run";
|
||||
const browser = await launchBrowser();
|
||||
|
||||
async function measure(name, { width, height, throttle, reducedMotion }) {
|
||||
async function measure(name, { width, height, throttle, reducedMotion, extraCss }) {
|
||||
const { context, page } = await makePage(browser, { width, height, deviceScaleFactor: 2, reducedMotion });
|
||||
const cdp = await context.newCDPSession(page);
|
||||
await cdp.send("Emulation.setCPUThrottlingRate", { rate: throttle });
|
||||
|
|
@ -22,6 +22,10 @@ async function measure(name, { width, height, throttle, reducedMotion }) {
|
|||
await seed(page, { decks: [DECK] });
|
||||
await page.goto(BASE, { waitUntil: "networkidle" });
|
||||
await page.waitForTimeout(1500);
|
||||
if (extraCss) {
|
||||
await page.addStyleTag({ content: extraCss });
|
||||
await page.waitForTimeout(400);
|
||||
}
|
||||
|
||||
const scene = await page.evaluate(() => {
|
||||
const orb = document.querySelector(".ice-orb-1");
|
||||
|
|
@ -79,6 +83,19 @@ const phone = { width: 390, height: 844 };
|
|||
const animated = await measure("phone 390 animated", { ...phone, throttle: 4 });
|
||||
const still = await measure("phone 390 reduced-motion", { ...phone, throttle: 4, reducedMotion: "reduce" });
|
||||
const desktop = await measure("desktop 1280 animated", { width: 1280, height: 900, throttle: 2 });
|
||||
/* The glass cost: how much of the frame time is backdrop-filter re-blurring
|
||||
the (always animating) scene. Static surfaces no longer blur at all — see
|
||||
the "Frosted ice glass" block in app/globals.css — so this number should
|
||||
stay close to the animated run; a jump means a new blurred surface landed
|
||||
on top of the scene. */
|
||||
const noGlass = await measure("desktop 1280 no backdrop-filter", {
|
||||
width: 1280,
|
||||
height: 900,
|
||||
throttle: 2,
|
||||
extraCss: "*{backdrop-filter:none !important;-webkit-backdrop-filter:none !important;}",
|
||||
});
|
||||
|
||||
console.log(`\n[${label}] deltas — animated vs reduced-motion: p95 ${(animated.p95 - still.p95).toFixed(1)}ms, busy ${(animated.busyMs - still.busyMs).toFixed(0)}ms; desktop p95 ${desktop.p95.toFixed(1)}ms`);
|
||||
console.log(
|
||||
`\n[${label}] deltas — animated vs reduced-motion: p95 ${(animated.p95 - still.p95).toFixed(1)}ms, busy ${(animated.busyMs - still.busyMs).toFixed(0)}ms; desktop p95 ${desktop.p95.toFixed(1)}ms; glass cost on desktop: p95 ${(desktop.p95 - noGlass.p95).toFixed(1)}ms, over-34ms frames ${desktop.over34 - noGlass.over34}`,
|
||||
);
|
||||
await browser.close();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue