mirror of
https://github.com/Such-Software/such.software.git
synced 2026-10-17 05:32:05 +02:00
Nebula: fix mobile jump + pointer parallax, live cursor, lighter mobile field
- Mobile jump fix: compute the monitor anchor from the title's document-absolute top (scroll-independent) and only recompute on a real width change, so the address-bar resize that fires mid-scroll no longer snaps it. Mobile parallax now lifts the field up and away (faster than scroll) instead of drifting down over the text. - Pointer parallax (desktop only): the field nudges toward the cursor, spring-damped so it can never move abruptly. No mousemove on touch, so no mobile cost. - Live monitor: a CSS blinking terminal cursor inside the screen (opacity only = compositor); it shifts color on each streamer hit, reinforcing the impact pulse. - Lighter mobile field: streamer density 8->5 and lines ~15% thinner on phones. Desktop motion unchanged. (CSS/SMIL streamer rewrite deferred to its own commit.)
This commit is contained in:
@@ -232,4 +232,8 @@
|
||||
/* Splash logo zoom on click-to-enter (CSS, so the logo needs no framer-motion
|
||||
wrapper and stays a clean LCP candidate). */
|
||||
@keyframes splash-zoom { 0% { transform: scale(1); } 50% { transform: scale(1.06); } 100% { transform: scale(1.14); } }
|
||||
.splash-zoom { animation: splash-zoom 0.8s ease-in-out forwards; }
|
||||
.splash-zoom { animation: splash-zoom 0.8s ease-in-out forwards; }
|
||||
|
||||
/* Blinking terminal cursor inside the nebula monitor (opacity only = compositor). */
|
||||
@keyframes nebula-cursor-blink { 0%, 49% { opacity: 0.85; } 50%, 100% { opacity: 0; } }
|
||||
.nebula-cursor { animation: nebula-cursor-blink 1.1s steps(1, end) infinite; }
|
||||
@@ -73,21 +73,33 @@ export function HomeShell({ children }: { children: ReactNode }) {
|
||||
// Place the nebula/monitor just to the left of the hero title, at any screen width.
|
||||
// The title lives in the server-rendered children, so read it by id.
|
||||
useEffect(() => {
|
||||
let lastWidth = window.innerWidth;
|
||||
const updatePosition = () => {
|
||||
const title = document.getElementById("hero-title");
|
||||
if (!title) return;
|
||||
const rect = title.getBoundingClientRect();
|
||||
// Use the title's document-absolute top (rect.top + scrollY), not its
|
||||
// viewport-relative top, so the value does not shift as the page scrolls.
|
||||
// Mobile browsers fire `resize` on scroll when the address bar hides, and a
|
||||
// viewport-relative read at that moment is what made the monitor jump.
|
||||
const titleLeftPercent = (rect.left / window.innerWidth) * 100;
|
||||
const titleTopPercent = (rect.top / window.innerHeight) * 100;
|
||||
const titleTopPercent = ((rect.top + window.scrollY) / window.innerHeight) * 100;
|
||||
setNebulaPosition({
|
||||
x: Math.max(5, titleLeftPercent - 8),
|
||||
y: Math.max(10, titleTopPercent - 2),
|
||||
});
|
||||
};
|
||||
updatePosition();
|
||||
window.addEventListener("resize", updatePosition);
|
||||
// Recompute only on a real width change (orientation / window resize). Ignore
|
||||
// height-only changes, which on mobile are just the address bar showing or hiding.
|
||||
const onResize = () => {
|
||||
if (window.innerWidth === lastWidth) return;
|
||||
lastWidth = window.innerWidth;
|
||||
updatePosition();
|
||||
};
|
||||
window.addEventListener("resize", onResize);
|
||||
document.fonts?.ready.then(updatePosition);
|
||||
return () => window.removeEventListener("resize", updatePosition);
|
||||
return () => window.removeEventListener("resize", onResize);
|
||||
}, [entered]);
|
||||
|
||||
const enterFromButton = () => {
|
||||
|
||||
Reference in New Issue
Block a user