diff --git a/README.md b/README.md index 81e2d36..0aed9f5 100644 --- a/README.md +++ b/README.md @@ -1411,6 +1411,19 @@ Things I chose while building, with the reasoning: pre-blurred wallpaper — the scene is clearly visible through the glass, and the pixel-contrast scan still passes. +72. **More, shinier bubbles.** Aero's rising bubbles went from ten to eighteen (the extra eight + interleaved between the others, 18px to 96px, 10-23s runs) with a tighter specular hotspot, a + second reflected-light glint low on the sphere, a 1px glass edge and a brighter inner rim on + both the bubbles and the drifting orbs. The bodies stay translucent and their opacities are + capped (0.75-0.9), so text sitting on the wallpaper stays readable, and the bubble-perf + diagnostic shows no added frame cost (18 bubbles, same p95 as ten). + +71. **The chat's top edge fades instead of hard-clipping.** The conversation scrolls right up to + the glass header, and over the busy wallpaper a line of text clipped exactly at that edge read + as a rendering bug ("the chat looks cut off"). The scroller now carries a 14px top mask in + Aero — shorter than the column's 16px top padding, so a fresh conversation at the top shows no + dimming at all. + 70. **Chat answers are bubbles in Aero too.** The assistant answers are deliberately bubble-less (full-width text on the flat themes) and the user bubble's thin tint washed out over the bright parts of the wallpaper, so the longest text in the app ended up sitting straight on the photo. diff --git a/app/globals.css b/app/globals.css index d9730a1..d4056bd 100644 --- a/app/globals.css +++ b/app/globals.css @@ -276,14 +276,21 @@ /* The orbs become extra bubbles over the photo. */ .aero .ice-orb { - background: radial-gradient( - circle at 32% 28%, - rgb(255 255 255 / 0.95) 0%, - rgb(226 248 255 / 0.4) 22%, - rgb(125 211 252 / 0.14) 56%, - rgb(56 189 248 / 0.38) 100% - ); - 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); + background: + radial-gradient(circle at 30% 24%, rgb(255 255 255 / 0.95) 0%, rgb(255 255 255 / 0) 16%), + radial-gradient(circle at 72% 80%, rgb(255 255 255 / 0.4) 0%, rgb(255 255 255 / 0) 20%), + radial-gradient( + circle at 32% 28%, + rgb(255 255 255 / 0.9) 0%, + rgb(226 248 255 / 0.4) 22%, + rgb(125 211 252 / 0.14) 56%, + rgb(56 189 248 / 0.38) 100% + ); + box-shadow: + inset -8px -12px 20px -10px rgb(3 74 124 / 0.5), + inset 8px 10px 16px -10px rgb(255 255 255 / 1), + inset 0 0 0 1px rgb(255 255 255 / 0.35), + 0 12px 26px -16px rgb(3 74 124 / 0.55); } /* The Aero gloss for the floating surfaces (sheets, dropdowns and the sticky @@ -313,14 +320,22 @@ bottom: -14vh; border-radius: 50%; opacity: 0; - background: radial-gradient( - circle at 32% 28%, - rgb(255 255 255 / 0.95) 0%, - rgb(226 248 255 / 0.38) 24%, - rgb(125 211 252 / 0.12) 58%, - rgb(56 189 248 / 0.34) 100% - ); - box-shadow: inset -6px -10px 16px -8px rgb(3 74 124 / 0.45), inset 6px 8px 14px -8px rgb(255 255 255 / 0.9), 0 10px 22px -14px rgb(3 74 124 / 0.5); + background: + radial-gradient(circle at 30% 24%, rgb(255 255 255 / 0.95) 0%, rgb(255 255 255 / 0) 16%), + radial-gradient(circle at 72% 80%, rgb(255 255 255 / 0.4) 0%, rgb(255 255 255 / 0) 20%), + radial-gradient( + circle at 32% 28%, + rgb(255 255 255 / 0.9) 0%, + rgb(226 248 255 / 0.38) 24%, + rgb(125 211 252 / 0.12) 58%, + rgb(56 189 248 / 0.34) 100% + ); + box-shadow: + inset -6px -10px 16px -8px rgb(3 74 124 / 0.5), + inset 6px 8px 14px -8px rgb(255 255 255 / 1), + inset 0 0 0 1px rgb(255 255 255 / 0.35), + 0 10px 22px -14px rgb(3 74 124 / 0.5); + border: 1px solid rgb(255 255 255 / 0.25); animation: aero-bubble-rise var(--bubble-duration, 20s) linear infinite; animation-delay: var(--bubble-delay, 0s); will-change: transform, opacity; @@ -347,6 +362,14 @@ .aero .ice-bubble-8 { width: 46px; height: 46px; left: 78%; --bubble-duration: 16s; --bubble-delay: -13s; --bubble-sway: 4vw; } .aero .ice-bubble-9 { width: 24px; height: 24px; left: 87%; --bubble-duration: 14s; --bubble-delay: -6s; --bubble-sway: -3vw; } .aero .ice-bubble-10 { width: 120px; height: 120px; left: 92%; --bubble-duration: 27s; --bubble-delay: -20s; --bubble-sway: -5vw; --bubble-opacity: 0.75; } +.aero .ice-bubble-11 { width: 18px; height: 18px; left: 4%; --bubble-duration: 12s; --bubble-delay: -3s; --bubble-sway: 3vw; } +.aero .ice-bubble-12 { width: 58px; height: 58px; left: 12%; --bubble-duration: 18s; --bubble-delay: -11s; --bubble-sway: -3vw; } +.aero .ice-bubble-13 { width: 30px; height: 30px; left: 21%; --bubble-duration: 15s; --bubble-delay: -5s; --bubble-sway: -2vw; } +.aero .ice-bubble-14 { width: 96px; height: 96px; left: 34%; --bubble-duration: 23s; --bubble-delay: -19s; --bubble-sway: 4vw; --bubble-opacity: 0.8; } +.aero .ice-bubble-15 { width: 22px; height: 22px; left: 42%; --bubble-duration: 10s; --bubble-delay: -8s; --bubble-sway: -3vw; } +.aero .ice-bubble-16 { width: 44px; height: 44px; left: 54%; --bubble-duration: 16s; --bubble-delay: -2s; --bubble-sway: 2vw; } +.aero .ice-bubble-17 { width: 62px; height: 62px; left: 62%; --bubble-duration: 21s; --bubble-delay: -14s; --bubble-sway: -4vw; } +.aero .ice-bubble-18 { width: 26px; height: 26px; left: 74%; --bubble-duration: 13s; --bubble-delay: -6s; --bubble-sway: 3vw; } /* Helper lines that sit straight on the wallpaper (the keyboard tip, the AI note) need their own surface in Aero: dark text on the grass measured @@ -516,6 +539,16 @@ box-shadow: inset 0 2px 8px rgb(2 62 110 / 0.2), inset 0 1px 0 rgb(255 255 255 / 0.8); } +/* The conversation scrolls right up to the glass header; a hard-clipped line + of text at that edge reads as a rendering bug over the busy wallpaper, so + the top of the scroll area fades out instead (the mask is fixed to the + element, not the content — and stays inside the column's 16px top padding, + so at the very top nothing is dimmed). */ +.aero .chat-scroll { + mask-image: linear-gradient(to bottom, transparent 0, black 14px); + -webkit-mask-image: linear-gradient(to bottom, transparent 0, black 14px); +} + /* Chat: the longest text in the app sits straight on the wallpaper. The assistant answers are deliberately bubble-less in the flat themes, and the user bubble's thin tint washes out over the bright parts of the scene — in diff --git a/components/IceBackdrop.tsx b/components/IceBackdrop.tsx index 290b12e..c87a0c7 100644 --- a/components/IceBackdrop.tsx +++ b/components/IceBackdrop.tsx @@ -43,6 +43,14 @@ export function IceBackdrop() { + + + + + + + + ); diff --git a/components/chat/ChatScreen.tsx b/components/chat/ChatScreen.tsx index f37d5cc..223784e 100644 --- a/components/chat/ChatScreen.tsx +++ b/components/chat/ChatScreen.tsx @@ -569,7 +569,7 @@ export function ChatScreen() {
-
+
{messages.length === 0 ? (
diff --git a/package.json b/package.json index 29e162a..9c90e6b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "freezmo", - "version": "0.3.5", + "version": "0.3.7", "private": true, "license": "GPL-3.0-only", "scripts": { diff --git a/public/sw.js b/public/sw.js index 815ca68..c7dbefd 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-v65"; +const CACHE_VERSION = "freezmo-v66"; const SHELL_CACHE = `${CACHE_VERSION}-shell`; const ASSET_CACHE = `${CACHE_VERSION}-assets`; diff --git a/tests/mobile-test.mjs b/tests/mobile-test.mjs index df1eb3b..1213db4 100644 --- a/tests/mobile-test.mjs +++ b/tests/mobile-test.mjs @@ -245,7 +245,7 @@ const AXE = axeSource(); ); check( "aero: bubbles rise", - (await page.locator(".ice-bubble").count()) === 10 && + (await page.locator(".ice-bubble").count()) === 18 && (await page.locator(".ice-bubble").first().evaluate((el) => getComputedStyle(el).animationName)) === "aero-bubble-rise", );