diff --git a/src/app/globals.css b/src/app/globals.css index a01cb9d..569fb24 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -3,7 +3,7 @@ @tailwind utilities; html, body { - background: #030603; + background: #071108; color: #FFFFFF; font-feature-settings: "cv02", "cv03", "cv04", "cv11", "ss01"; -webkit-font-smoothing: antialiased; @@ -12,28 +12,135 @@ html, body { body { font-family: ui-sans-serif, system-ui, -apple-system, "SF Pro Text", "PingFang SC", "Noto Sans SC", "Helvetica Neue", sans-serif; - background-color: #030603; - background-image: linear-gradient(180deg, rgba(13, 24, 12, 0.9), rgba(2, 4, 2, 1)); + background-color: #071108; + background-image: linear-gradient(180deg, rgba(22, 42, 16, 0.92), rgba(5, 12, 4, 1)); background-attachment: fixed; min-height: 100vh; } ::selection { background: rgba(230, 245, 120, 0.28); color: #fff; } +.login-oasis-loop { + position: fixed; + inset: 0; + z-index: 0; + overflow: hidden; + pointer-events: none; + isolation: isolate; + contain: strict; + background: #0d1d0b; +} + +.oasis-loop__sky, +.oasis-loop__light, +.oasis-loop__haze, +.oasis-loop__grass, +.oasis-loop__grain { + position: absolute; + inset: 0; + pointer-events: none; +} + +.oasis-loop__sky { + background: + radial-gradient(circle at 70% 22%, rgba(255, 238, 152, 0.42), transparent 26%), + radial-gradient(circle at 26% 56%, rgba(230, 245, 120, 0.24), transparent 34%), + linear-gradient(180deg, #2f4a23 0%, #172d12 42%, #0a1708 100%); +} + +.oasis-loop__light { + inset: -18%; + background: + conic-gradient(from 26deg at 72% 30%, transparent 0 18%, rgba(255, 240, 170, 0.18) 22%, transparent 36% 100%), + radial-gradient(ellipse at 68% 36%, rgba(230, 245, 120, 0.16), transparent 42%); + filter: blur(18px); + opacity: 0.9; +} + +.oasis-loop__haze { + inset: -8% -12%; + background: + linear-gradient(104deg, transparent 0 20%, rgba(255, 255, 220, 0.12) 24%, transparent 36% 100%), + linear-gradient(74deg, transparent 0 48%, rgba(214, 179, 106, 0.10) 56%, transparent 70% 100%), + repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.035) 0 1px, transparent 1px 70px); + mix-blend-mode: screen; + opacity: 0.82; + transform: translate3d(-1.5%, 0, 0) scale(1.04); + animation: oasis-haze-loop 18s ease-in-out infinite; +} + +.oasis-loop__grass { + top: auto; + bottom: -9vh; + height: 55vh; + transform-origin: 50% 100%; + mask-image: linear-gradient(180deg, transparent, rgba(0, 0, 0, 0.7) 20%, #000 100%); +} + +.oasis-loop__grass--back { + opacity: 0.46; + background: + linear-gradient(180deg, transparent, rgba(61, 100, 42, 0.38) 34%, rgba(5, 18, 5, 0.94)), + repeating-linear-gradient(102deg, transparent 0 18px, rgba(214, 232, 130, 0.18) 18px 20px, transparent 20px 38px), + repeating-linear-gradient(83deg, transparent 0 24px, rgba(111, 160, 79, 0.22) 24px 26px, transparent 26px 48px); + animation: oasis-grass-loop 9s ease-in-out infinite alternate; +} + +.oasis-loop__grass--front { + bottom: -13vh; + height: 49vh; + opacity: 0.58; + background: + linear-gradient(180deg, transparent, rgba(20, 52, 14, 0.46) 32%, rgba(1, 7, 1, 0.98)), + repeating-linear-gradient(107deg, transparent 0 10px, rgba(232, 246, 132, 0.22) 10px 12px, transparent 12px 26px), + repeating-linear-gradient(76deg, transparent 0 16px, rgba(76, 129, 54, 0.28) 16px 18px, transparent 18px 31px); + animation: oasis-grass-loop 7s ease-in-out infinite alternate-reverse; +} + +.oasis-loop__grain { + background-image: + linear-gradient(90deg, rgba(255, 255, 255, 0.032) 1px, transparent 1px), + linear-gradient(180deg, rgba(255, 255, 255, 0.026) 1px, transparent 1px); + background-size: 64px 64px; + opacity: 0.48; +} + +@keyframes oasis-haze-loop { + 0%, 100% { transform: translate3d(-1.5%, 0, 0) scale(1.04); } + 50% { transform: translate3d(1.5%, -1%, 0) scale(1.06); } +} + +@keyframes oasis-grass-loop { + 0% { transform: skewX(-0.6deg) translate3d(-0.5%, 0, 0); } + 100% { transform: skewX(0.8deg) translate3d(0.5%, -1%, 0); } +} + +@media (prefers-reduced-motion: reduce) { + .oasis-loop__haze, + .oasis-loop__grass { + animation: none; + } +} + .app-oasis .login-oasis-canvas { z-index: 0; opacity: 0.74; filter: saturate(0.92) contrast(1.04); } +.app-oasis .login-oasis-loop { + opacity: 1; + filter: saturate(1.08) brightness(1.2); +} + .app-oasis-shade { position: fixed; inset: 0; z-index: 1; pointer-events: none; background: - linear-gradient(90deg, rgba(0, 0, 0, 0.76), rgba(3, 9, 3, 0.46) 42%, rgba(0, 0, 0, 0.72)), - linear-gradient(180deg, rgba(0, 0, 0, 0.68), rgba(0, 0, 0, 0.12) 36%, rgba(0, 0, 0, 0.82)), + linear-gradient(90deg, rgba(0, 0, 0, 0.42), rgba(9, 22, 7, 0.14) 42%, rgba(0, 0, 0, 0.42)), + linear-gradient(180deg, rgba(0, 0, 0, 0.28), rgba(0, 0, 0, 0.02) 36%, rgba(0, 0, 0, 0.54)), linear-gradient(90deg, rgba(255, 255, 255, 0.026) 1px, transparent 1px), linear-gradient(180deg, rgba(255, 255, 255, 0.022) 1px, transparent 1px); background-size: auto, auto, 64px 64px, 64px 64px; @@ -47,11 +154,11 @@ body { z-index: 2; height: 34vh; pointer-events: none; - opacity: 0.38; + opacity: 0.46; background: - linear-gradient(180deg, transparent, rgba(5, 12, 4, 0.78) 60%, rgba(0, 0, 0, 0.94)), - repeating-linear-gradient(103deg, transparent 0 13px, rgba(188, 218, 112, 0.13) 13px 14px, transparent 14px 28px), - repeating-linear-gradient(78deg, transparent 0 18px, rgba(84, 122, 67, 0.18) 18px 20px, transparent 20px 34px); + linear-gradient(180deg, transparent, rgba(10, 25, 7, 0.62) 60%, rgba(0, 0, 0, 0.82)), + repeating-linear-gradient(103deg, transparent 0 13px, rgba(204, 230, 120, 0.18) 13px 14px, transparent 14px 28px), + repeating-linear-gradient(78deg, transparent 0 18px, rgba(98, 146, 76, 0.22) 18px 20px, transparent 20px 34px); mask-image: linear-gradient(180deg, transparent, rgba(0, 0, 0, 0.8) 38%, #000 100%); } @@ -256,7 +363,7 @@ input, textarea { mix-blend-mode: screen; } .login-page--oasis { - background: #030303; + background: #071108; color: #fff; } .login-page--oasis::before { @@ -270,8 +377,8 @@ input, textarea { .login-page--oasis::after { z-index: 1; background: - radial-gradient(circle at 50% 26%, rgba(214, 179, 106, 0.16), transparent 32%), - linear-gradient(90deg, rgba(0, 0, 0, 0.86), rgba(0, 0, 0, 0.34) 48%, rgba(0, 0, 0, 0.76)); + radial-gradient(circle at 50% 26%, rgba(230, 245, 120, 0.18), transparent 32%), + linear-gradient(90deg, rgba(0, 0, 0, 0.58), rgba(0, 0, 0, 0.18) 48%, rgba(0, 0, 0, 0.48)); background-size: auto; opacity: 1; mix-blend-mode: normal; @@ -283,7 +390,7 @@ input, textarea { width: 100vw; height: 100vh; border: 0; - background: #030303; + background: #071108; } .login-oasis-shade { position: fixed; @@ -291,8 +398,8 @@ input, textarea { z-index: 2; pointer-events: none; background: - linear-gradient(180deg, rgba(0, 0, 0, 0.62), rgba(0, 0, 0, 0.12) 42%, rgba(0, 0, 0, 0.74)), - radial-gradient(circle at 78% 50%, rgba(214, 179, 106, 0.12), transparent 32%); + linear-gradient(180deg, rgba(0, 0, 0, 0.42), rgba(0, 0, 0, 0.04) 42%, rgba(0, 0, 0, 0.58)), + radial-gradient(circle at 78% 50%, rgba(230, 245, 120, 0.14), transparent 32%); } .login-page--oasis .login-oasis-hero { color: #fff; @@ -471,8 +578,8 @@ input, textarea { } .login-page--source .login-oasis-shade { background: - radial-gradient(circle at 34% 52%, rgba(230, 245, 120, 0.08), transparent 28%), - linear-gradient(90deg, rgba(0, 0, 0, 0.22), rgba(0, 0, 0, 0.04) 44%, rgba(0, 0, 0, 0.38)); + radial-gradient(circle at 34% 52%, rgba(230, 245, 120, 0.14), transparent 28%), + linear-gradient(90deg, rgba(0, 0, 0, 0.12), rgba(0, 0, 0, 0.02) 44%, rgba(0, 0, 0, 0.24)); } .login-source-overlay { position: fixed; @@ -1696,12 +1803,12 @@ input, textarea { background: linear-gradient(164deg, #f7f7f4 0 48%, #111214 48% 100%); } .login-page--oasis { - background: #030303; + background: #071108; } .login-page--oasis::after { background: - radial-gradient(circle at 50% 34%, rgba(214, 179, 106, 0.16), transparent 40%), - linear-gradient(180deg, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0.2) 48%, rgba(0, 0, 0, 0.82)); + radial-gradient(circle at 50% 34%, rgba(230, 245, 120, 0.18), transparent 40%), + linear-gradient(180deg, rgba(0, 0, 0, 0.48), rgba(0, 0, 0, 0.08) 48%, rgba(0, 0, 0, 0.62)); } .login-page--oasis .login-oasis-hero { min-height: 740px; diff --git a/src/components/login/OasisCanvas.tsx b/src/components/login/OasisCanvas.tsx index 35b8839..d5c4a92 100644 --- a/src/components/login/OasisCanvas.tsx +++ b/src/components/login/OasisCanvas.tsx @@ -2,10 +2,16 @@ import { useEffect, useRef } from 'react'; -export function OasisCanvas() { +type OasisCanvasProps = { + mode?: 'loop' | 'live'; +}; + +export function OasisCanvas({ mode = 'loop' }: OasisCanvasProps) { const frameRef = useRef(null); useEffect(() => { + if (mode !== 'live') return; + const dispatchNativeMouseEvent = (type: 'mousemove' | 'mouseleave', event?: PointerEvent) => { const frameWindow = frameRef.current?.contentWindow; if (!frameWindow) return false; @@ -52,7 +58,20 @@ export function OasisCanvas() { document.removeEventListener('pointermove', onPointerMove, listenerOptions); window.removeEventListener('pointerleave', onPointerLeave, listenerOptions); }; - }, []); + }, [mode]); + + if (mode === 'loop') { + return ( +