Wanderful
Cinematic travel hero: a full-bleed loop drifting under a GSAP mouse parallax, with a liquid-glass pill navbar and two fade-up copy blocks.
Промпт
# Wanderful — Cinematic Travel Hero with GSAP Mouse Parallax
## Goal
Build a full-viewport cinematic hero section for a travel brand called "Wanderful" with React + TypeScript + Tailwind CSS on Vite, GSAP for animation and `lucide-react` for icons. One viewport: a fixed background loop that drifts with the pointer, a liquid-glass pill navbar, a two-line headline near the top and a copy block pinned to the bottom.
**Dependencies**: `react`, `react-dom`, `gsap`, `lucide-react` (`Lock`), Tailwind CSS configured with content globs `./index.html` and `./src/**/*.{js,ts,jsx,tsx}`.
## Fonts (`src/index.css`)
```css
@import url('https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Barlow:wght@300;400;500;600&family=Inter:wght@300;400;500;600;700&display=swap');
@font-face {
font-family: 'Dirtyline';
src: url('https://fonts.cdnfonts.com/s/15011/Dirtyline36DaysofType.woff') format('woff');
font-weight: normal; font-style: normal; font-display: swap;
}
```
Body font `Barlow`, hero headings `Inter`, body background `#000`.
## Background video (fixed, full screen, `z-0`)
- URL (exact): `https://d8j0ntlcm91z4.cloudfront.net/user_38xzZboKViGWJOttwIXH07lWA1P/hf_20260510_060007_60275ce7-030c-4668-a160-8f364ec537d3.mp4`
- Attributes `autoPlay muted loop playsInline`, `object-cover`; the wrapper carries `scale-[1.08]` with `origin-center`.
- On `onLoadedMetadata`, set `playbackRate = 1.25`.
- GSAP mouse parallax: listen to `mousemove`, compute `targetX/Y = ((clientX - cx) / cx) * 20`, lerp `currentX/Y += (target - current) * 0.06` inside a `requestAnimationFrame` loop, and write it out with `gsap.set(videoBg, { x, y })`.
## Liquid glass (`index.css`)
```css
.liquid-glass {
background: rgba(255,255,255,0.01);
background-blend-mode: luminosity;
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
border: none;
box-shadow: inset 0 1px 1px rgba(255,255,255,0.1);
position: relative;
overflow: hidden;
}
.liquid-glass::before {
content: "";
position: absolute; inset: 0;
border-radius: inherit;
padding: 1.4px;
background: linear-gradient(180deg,
rgba(255,255,255,0.45) 0%,
rgba(255,255,255,0.15) 20%,
rgba(255,255,255,0) 40%,
rgba(255,255,255,0) 60%,
rgba(255,255,255,0.15) 80%,
rgba(255,255,255,0.45) 100%);
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
pointer-events: none;
}
```
## Header (fixed top, `z-50`, `px-10 py-8`, flex `justify-between items-center`)
- **Left**: wordmark `Wanderful` followed by `<sup>TM</sup>`, `text-[17px] font-semibold tracking-tight`.
- **Centre**: a `<nav>` styled `.liquid-glass rounded-full px-2 py-2 flex items-center gap-1` holding JOURNEY, BENEFITS, JOURNAL, GUIDEBOOK. Each link `text-[11px] font-medium tracking-[0.12em] text-white/90 hover:text-white px-4 py-1.5 rounded-full transition-colors duration-200`. Four tracked-out links do not fit a phone — hide the pill below `md` and keep the wordmark plus the CTA.
- **Right**: a "GET ROAMING" anchor on the same glass, `rounded-full px-5 py-2.5 text-[11px] font-medium tracking-[0.12em] text-white/90 hover:text-white`.
## Headline (fixed, `top: 120px`, centred, `z-20`)
Two centred lines, `Inter` 400, `font-size: clamp(40px, 5.4vw, 72px)`, `line-height: 1.1`, `letter-spacing: -0.02em`:
- Line 1, white: "Venture without edges."
- Line 2, `rgba(255,255,255,0.55)`: "Uncover with keen instinct."
Fades in on mount: `opacity 0 → 100` and `translate-y-6 → 0` with `transition-all duration-1000`.
## Bottom block (fixed `bottom-14`, `z-20`, flex column, `items-center gap-6`)
Same fade-up, with `delay-300`.
1. A centred paragraph, `max-w-[620px] text-[15px] leading-relaxed` — white: "Our smart itineraries shape around you — your rhythm, your vibe, your hunger for adventure."; then in `text-white/55`: " Each getaway is tailored, seamless, and wholly yours."
2. A button: white background, black text, `text-[15px] font-medium rounded-full px-8 py-3.5`, hover `scale-[1.03]` plus `shadow-[0_0_32px_4px_rgba(255,255,255,0.2)]`, active `scale-[0.97]`. Label "Plan my escape today".
3. A row: the `Lock` icon (`size={13} strokeWidth={1.5}`) beside `text-[11px] font-medium tracking-[0.14em] text-white/70` reading "SECURE BY DESIGN. ZERO DATA LEAKS."
## Root container
`min-h-screen bg-black text-white overflow-x-hidden` with inline `fontFamily: "'Inter', sans-serif"`.
## Quality Bar
- TypeScript strict, zero `any`. Tailwind only — no CSS beyond `index.css`.
- Autoplay only works while the element is genuinely `muted` and `playsInline` — keep both. Give the video `aria-hidden`; it is decoration and never the only carrier of meaning.
- `gsap.set(el, { x, y })` writes an inline `transform` that replaces Tailwind's composite one. It reads the current matrix first, so the wrapper's `scale-[1.08]` does survive — but it survives as a number GSAP captured once. Put a responsive `md:scale-*` on that same element afterwards and the inline transform keeps winning with the old value. Keep the scale where GSAP can see it and leave it alone, or move the offset onto its own wrapper. Either way that scale is what keeps the shifted edges off screen — the video is offset by up to 20px in both axes.
- Tear the effect down properly: `cancelAnimationFrame` plus `removeEventListener`, or a fast unmount leaves a frame loop writing into a detached node.
- Respect `prefers-reduced-motion`: never start the rAF loop, reset the offset to zero, hold a still video frame, and drop the two fade-ups to their end state. Read the query inside the effect and re-read it on `change` — not in a `useState` initialiser, which is client-only and would disagree with hydration in Next.js.
- Watch the payload: a full-resolution source video will dominate page weight. Downscale to the rendered size, drop the audio track that muted playback never uses, and serve a compressed derivative.
- `playbackRate = 1.25` belongs on `loadedmetadata`, not next to the ref assignment — set it before the element has metadata and it silently reverts to 1.
- White type sits directly on the footage. It holds because this clip is dusk-blue sky at the top and near-black grass at the bottom, which is exactly where the headline and the bottom block sit. Re-check both against the actual video before swapping the source; `text-white/55` is the first thing that fails.
- The `.liquid-glass` fill is `rgba(255,255,255,0.01)` — effectively nothing. All the separation comes from `backdrop-filter`, so where that is unsupported the navbar is white text straight on the video. Verify that fallback rather than assuming it.
- The three other families in the `@import` never paint: the root container's inline `Inter` overrides the `Barlow` on `body`, and nothing uses Instrument Serif or Dirtyline. Either give them a job or drop them — every unused family is a font file every visitor downloads for nothing.
- Dirtyline is served from a third-party font mirror, and a hotlink is not a licence. Do not ship it without checking its terms; if it does get a job on the page, self-host it under a licence you actually hold.
Вам также может понравиться
Vectrus Energy
Scroll-tied cinematic section: a 500vh track scrubs an aerial clip frame by frame through a WebCodecs frame bank, with three sequential copy blocks.
Aurora Weather Dashboard
Liquid-glass weather dashboard on a 1357x871 unit grid: frosted panels over a storm photo and a chart that draws itself, then fills.
Fastshot Landing
Single-screen AI app-builder landing: full-bleed dawn video, glass composer card and a pixel-specified absolute toolbar.
Signal
Pixel-locked single-file login page: a looping peregrine-falcon dive beside a frosted card, with embedded fonts, a JS layout engine that switches between desktop, tablet-portrait and phone compositions, and a once-only WAAPI entrance.