From 13b3a80e1c4bfbecf9b51b02de4facaf8ad49ed2 Mon Sep 17 00:00:00 2001 From: Martin Dvorak Date: Tue, 13 Oct 2026 07:45:22 +0000 Subject: [PATCH] Aero glass is transparent now, blurred without the per-frame cost MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The white-ish fills are gone: every surface is a thin translucent glass with the gloss and a bright rim, and the wallpaper reads through all of it. The blur is a pre-blurred copy of the wallpaper (public/aero/ background-blur.webp, 3 kB) glued to the viewport with background-attachment: fixed, layered under the tint and the gloss, instead of a live backdrop-filter. Blurring the live scene measured 66ms per frame at 2x CPU throttle (115 frames over 34ms) because the bubbles move behind every surface; with the pre-blurred layer the same scene runs at 33ms and 8 slow frames — the same as the other themes, so the MacBook stays cool. Sticky chrome, sheets and dropdowns keep a real backdrop-filter (they sit over scrolling content, and their area is small). Contrast: 0 below-minimum findings, 0 axe violations, all three themes. Version 0.2.5, SW -> freezmo-v58. --- README.md | 11 +++-- app/globals.css | 73 +++++++++++++++++++++---------- package.json | 2 +- public/aero/background-blur.webp | Bin 0 -> 3248 bytes public/sw.js | 2 +- 5 files changed, 59 insertions(+), 29 deletions(-) create mode 100644 public/aero/background-blur.webp diff --git a/README.md b/README.md index d39581e..641f1ec 100644 --- a/README.md +++ b/README.md @@ -1419,9 +1419,14 @@ Things I chose while building, with the reasoning: (, re-encoded to a 237 kB WebP in `public/aero/` and credited in Settings), with ten drawn bubbles rising over it (`.ice-bubble` — `display: none` outside aero so they cost nothing elsewhere, still under reduced motion). Buttons and segments - are **liquid glass** (translucent, glossed top half, bright rim, backdrop blur), the cards are - pale blue glass, and the helper lines that sit straight on the wallpaper (the keyboard tip, the - AI note) get their own small glass chip — dark text on grass measured 2.5:1. The light/dark + are **liquid glass** — transparent, glossed, with a bright rim — and every surface shows a + **pre-blurred copy of the wallpaper** (`public/aero/background-blur.webp`, 3 kB, glued to the + viewport with `background-attachment: fixed`) instead of blurring the live scene: the bubbles + move behind every surface, so a real `backdrop-filter` re-runs ~60 times a second (measured + 66ms/frame at 2x throttle vs 17ms with nothing blurring). The tint and the gloss ride on top of + that layer, so the look is identical at zero per-frame cost. The helper lines that sit straight + on the wallpaper (the keyboard tip, the AI note) get a small glass chip — dark text on grass + measured 2.5:1. The light/dark toggles (header, rail, chat header) hide while it is on and the picker says why; the PWA status bar follows the wallpaper's sky (#2fa7e6). Covered by the axe and pixel-contrast scans in all three themes. diff --git a/app/globals.css b/app/globals.css index 613d6b6..f46650a 100644 --- a/app/globals.css +++ b/app/globals.css @@ -287,14 +287,12 @@ box-shadow: inset -8px -12px 20px -10px rgb(3 74 124 / 0.5), inset 8px 10px 16px -10px rgb(255 255 255 / 0.95), 0 12px 26px -16px rgb(3 74 124 / 0.55); } -/* The Aero gloss: the classic white top half with a horizon line. */ -.aero .card, +/* The Aero gloss for the floating surfaces (sheets, dropdowns and the sticky + chrome keep a real backdrop-filter — they sit over scrolling content). */ .aero .glass-panel, -.aero .sidebar-surface, .aero .study-chrome, .aero .tabbar, -.aero .glass, -.aero .gate-card { +.aero .glass { background-image: linear-gradient( 180deg, rgb(255 255 255 / 0.75) 0%, @@ -369,28 +367,55 @@ .aero .btn-primary, .aero .segmented > button[aria-pressed="true"], .aero .segmented > a[aria-current="page"] { - background-image: linear-gradient( - 180deg, - rgb(255 255 255 / 0.9) 0%, - rgb(226 245 255 / 0.62) 48%, - rgb(168 224 255 / 0.55) 52%, - rgb(219 242 255 / 0.7) 100% - ); - border: 1px solid rgb(255 255 255 / 0.9); - color: #05243d; - box-shadow: 0 10px 24px -14px rgb(2 62 110 / 0.6), inset 0 1px 0 rgb(255 255 255 / 0.98), inset 0 -8px 14px -10px rgb(255 255 255 / 0.7); - /* @apply, not a hand-written backdrop-filter: the minifier keeps only the - -webkit- prefix of a hand-written one, which paints nothing (see decision - 19). This is what makes the buttons read as liquid glass. */ - @apply backdrop-blur-lg backdrop-saturate-150; + border: 1px solid rgb(255 255 255 / 0.6); + color: #04223c; + box-shadow: 0 12px 26px -16px rgb(2 62 110 / 0.55), inset 0 1px 0 rgb(255 255 255 / 0.9); + /* The glass itself comes from the pre-blurred wallpaper rule above. */ } -/* The glass itself, a touch more transparent so the wallpaper reads through - it like liquid, still opaque enough for the dark text (contrast scanned). */ +/* Liquid glass: far more transparent than the other themes, with a strong + backdrop blur doing the legibility work — the wallpaper stays visible + through every surface. Contrast is pixel-scanned in all three themes, so + the tint cannot drop below what the text needs. */ .aero { - --glass-bg: rgb(222 244 255 / 0.72); - --glass-solid-bg: rgb(228 246 255 / 0.82); - --glass-sheet-bg: rgb(230 246 255 / 0.92); + --glass-bg: rgb(228 246 255 / 0.34); + --glass-solid-bg: rgb(232 248 255 / 0.46); + --glass-sheet-bg: rgb(232 248 255 / 0.8); + --surface-strong: rgb(255 255 255 / 0.34); + --surface-sunken: rgb(255 255 255 / 0.26); + --nav-active-bg: rgb(255 255 255 / 0.4); +} + +/* Liquid glass without the per-frame cost: every surface shows a pre-blurred + copy of the wallpaper, glued to the viewport (`background-attachment: + fixed`), with the tint and the gloss layered on top. Blurring the live + scene instead measured 66ms per frame at 2x CPU throttle — the bubbles move + behind every surface, so a real backdrop-filter re-runs ~60 times a second + (vs 17ms with nothing blurring). The look is the same; the cost is zero. */ +.aero .card, +.aero .glass-solid, +.aero .sidebar-surface, +.aero .gate-card, +.aero .nav-action, +.aero .btn-primary, +.aero .grad-ice, +.aero .segmented > button[aria-pressed="true"], +.aero .segmented > a[aria-current="page"], +.aero .hint-line { + background-image: + linear-gradient( + 180deg, + rgb(255 255 255 / 0.5) 0%, + rgb(255 255 255 / 0.2) 47%, + rgb(255 255 255 / 0.07) 53%, + rgb(255 255 255 / 0.24) 100% + ), + linear-gradient(rgb(230 247 255 / 0.42), rgb(230 247 255 / 0.42)), + url("/aero/background-blur.webp"); + background-size: 100% 100%, 100% 100%, cover; + background-position: 0 0, 0 0, center 42%; + background-attachment: scroll, scroll, fixed; + background-repeat: no-repeat, no-repeat, no-repeat; } html, diff --git a/package.json b/package.json index 2054746..4e17e9f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "freezmo", - "version": "0.2.4", + "version": "0.2.5", "private": true, "license": "GPL-3.0-only", "scripts": { diff --git a/public/aero/background-blur.webp b/public/aero/background-blur.webp new file mode 100644 index 0000000000000000000000000000000000000000..7ccbe04729b387bfa64d7059ec8947a33075817f GIT binary patch literal 3248 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 H`^EhaFABps literal 0 HcmV?d00001 diff --git a/public/sw.js b/public/sw.js index b42bc50..48753e6 100644 --- a/public/sw.js +++ b/public/sw.js @@ -9,7 +9,7 @@ * * Bumping CACHE_VERSION is how a new deploy invalidates old assets. */ -const CACHE_VERSION = "freezmo-v57"; +const CACHE_VERSION = "freezmo-v58"; const SHELL_CACHE = `${CACHE_VERSION}-shell`; const ASSET_CACHE = `${CACHE_VERSION}-assets`;