Dreamcore Landing
Build a single-page immersive parallax landing page in React + TypeScript + Tailwind CSS using Vite. The page has two scroll-driven scenes inside a sticky viewport. Everything lives in a single src/App.tsx file. Use Google Fonts: Viaoda Libre (serif headings) and Imprima (sans-serif body). No external UI libraries. Use lucide-react only as a dependency (it is not used in this page). Use Tailwind for responsive layout breakpoints only; all other styling is inline React CSSProperties.
GLOBAL SETUP
tailwind.config.js -- Override the xl breakpoint to 1100px:
screens: { xl: '1100px' }
index.css -- Include Tailwind directives, global reset, dark background #0a0608, font-family: 'Imprima', sans-serif, scrollbar-gutter: stable, and a @keyframes bobUp animation that translates Y by -6px at 50%.
index.html -- Load Google Fonts via <link>:
https://fonts.googleapis.com/css2?family=Viaoda+Libre&family=Imprima&display=swap
Title: "Step Into Wonder"
IMAGE ASSETS (use these exact URLs)
PORTAL_BG = "https://res.cloudinary.com/dy5er7kv5/image/upload/q_auto/f_auto/v1779707217/image_1_vdzwae.png"
CURTAIN_LEFT = "https://res.cloudinary.com/dy5er7kv5/image/upload/q_auto/f_auto/v1779706559/curtain_left_znkmva.png"
CURTAIN_RIGHT= "https://res.cloudinary.com/dy5er7kv5/image/upload/q_auto/f_auto/v1779706564/curtain_right_paeyym.png"
WORLD_BG = "https://res.cloudinary.com/dy5er7kv5/image/upload/q_auto/f_auto/v1779706392/image_2_gkcdlx.png"
BOTTOM_CLOUDS= "https://res.cloudinary.com/dy5er7kv5/image/upload/q_auto/f_auto/v1779706555/bottom_clouds_xskut6.png"
CARD_IMAGES[0] = "https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260525_160507_2ccbb4eb-1469-484f-af25-59168ad9a233.png&w=1280&q=85"
CARD_IMAGES[1] = "https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260525_160644_072a7f68-a101-4ded-a332-7d37707dbdd1.png&w=1280&q=85"
CARD_IMAGES[2] = "https://images.higgs.ai/?default=1&output=webp&url=https%3A%2F%2Fd8j0ntlcm91z4.cloudfront.net%2Fuser_38xzZboKViGWJOttwIXH07lWA1P%2Fhf_20260525_160706_1c153d04-0dfb-4ac9-a4ef-e74f301c329c.png&w=1280&q=85"
SCENE 2 CARD DATA (9 cards for the arc slider)
{ title: 'Hidden Realms', desc: 'Luminous sanctuaries unseen by wandering eyes', color: '#f3cdd6' }
{ title: 'Wild Solitudes', desc: 'Dissolve into untamed horizons and deep calm', color: '#dcedc2' }
{ title: 'Silent Havens', desc: 'Remote escapes far beyond ordinary reach', color: '#c3e3f4' }
{ title: 'Bespoke Quests', desc: 'Journeys shaped around your vision and soul', color: '#f0e4c0' }
{ title: 'Vivid Drifts', desc: 'Surreal passages through breathtaking terrain', color: '#dcd2f2' }
{ title: 'Mystic Crests', desc: 'Timeless ridgelines wrapped in cloud and myth', color: '#f3cdd6' }
{ title: 'Deep Currents', desc: 'Glowing depths alive with uncharted wonder', color: '#c3e3f4' }
{ title: 'Gilded Dusk', desc: 'Amber horizons that stretch past all reason', color: '#f0e4c0' }
{ title: 'Glassy Tides', desc: 'Calm waters holding skies of pure stillness', color: '#dcedc2' }
ARCHITECTURE
The outer container is height: 480vh; position: relative. Inside it is a position: sticky; top: 0; height: 100vh; overflow: hidden; background: #0a0608 viewport. All layers stack via absolute positioning and z-index.
Scroll progress = window.scrollY / (container.scrollHeight - window.innerHeight), clamped 0-1.
Helper functions:
easeInOut(t): quadratic easet < 0.5 ? 2*t*t : -1 + (4 - 2*t)*tlerp(a, b, t): linear interpolationclamp(val, min, max)
useIsMobile() hook: matchMedia('(max-width: 767px)') -- returns boolean.
LAYER STACK (bottom to top by z-index)
Layer 1: World Background (z-index: auto/0)
ref={worldRef}, absolute inset 0,transformOrigin: '50% 50%'WORLD_BGimage,object-fit: cover- Parallax:
scale(lerp(1, 1.18, ep)), mouse offsetMAG.world = 6
Layer 2: Bottom Clouds (z-index: 10)
ref={cloudsRef}, absolute bottom:0, left:0, right:0,transformOrigin: '50% 100%'BOTTOM_CLOUDSimage,width: 100%, height: auto- Parallax:
scale(lerp(1, 1.4, ep)), mouse offsetMAG.clouds = 9(Y dampened to0.4x) - Opacity: fades from 0.7 to 1 in the first 5% of scroll
Layer 2.5: Arc Card Slider (z-index: 9)
- Absolute,
bottom: 60px (mobile) / 80px (desktop), centered horizontally - Opacity =
scene2Opacity - Contains
<ArcCardSlider>component (details below)
Layer 3: Portal Frame (z-index: 15)
ref={portalRef}, absolute inset 0,transformOrigin: '52% 38%'PORTAL_BGimage,object-fit: cover- Parallax:
scale(lerp(1, 7.5, ep)), mouse offsetMAG.portal = 7 - Opacity: 1 until scroll 0.65, then fades to 0 by scroll 0.85
Layer 3.5: Bottom Fade (z-index: 16)
- Absolute bottom,
height: 40%,linear-gradient(to top, rgba(0,0,0,0.45) 0%, transparent 100%),pointer-events: none
Layer 4L: Curtain Left (z-index: 16)
ref={curtainLRef}, absolute inset 0,transformOrigin: 'left center'CURTAIN_LEFTimage,object-fit: cover,object-position: right center- On mount (after 100ms), shifts left by
translateX(-62%)withtransition: transform 1.8s cubic-bezier(0.16, 1, 0.3, 1) - On scroll: additional
translateXvialerp(0, 150, ep)%, scalelerp(1, 1.3, ep) - Mouse offset:
MAG.curtainL = 14(Y dampened to0.3x) - After entrance animation (2200ms), transition switches to
nonefor responsive parallax
Layer 4R: Curtain Right (z-index: 16)
- Mirror of Layer 4L but
transformOrigin: 'right center',object-position: left center - Shifts right instead of left,
MAG.curtainR = 14
Top Fade Gradient (z-index: 45)
- Absolute top,
height: 42vh,linear-gradient(to bottom, rgba(0,0,0,0.45) 0%, transparent 100%),pointer-events: none
NAVIGATION (z-index: 50)
Absolute top, full width, display: flex, justify-content: space-between, align-items: center.
Nav link style: font-family: 'Imprima', sans-serif, font-size: 12px, letter-spacing: 0.12em, text-transform: uppercase, color: #fff, opacity: 0.9, no text decoration.
Mobile (padding: 18px 20px): Three items -- "Explore" (11px) | StarLogo SVG | "Connect" (11px)
Desktop (padding: 22px 48px): Left group ["Worlds", "Atelier", "Immersions"] with gap: 36px | StarLogo SVG center | Right group ["Craft", "Codex", "Connect"] with gap: 36px
StarLogo -- inline SVG, 28x28, white star path + 3 small circles:
<path d="M14 2l2.09 6.42H23l-5.45 3.96 2.09 6.42L14 14.84l-5.64 4.06 2.09-6.42L4.96 8.42h6.95L14 2z" fill="white" opacity="0.9" />
<circle cx="14" cy="24" r="1.5" fill="white" opacity="0.6" />
<circle cx="6" cy="6" r="1" fill="white" opacity="0.4" />
<circle cx="22" cy="6" r="1" fill="white" opacity="0.4" />
SCENE 1 UI (z-index: 20)
Opacity = clamp(1 - scrollProgress / 0.22, 0, 1). Fades out in first ~22% of scroll.
Uses three separate Tailwind-responsive layout blocks (not JS branching for layout):
Mobile layout (md:hidden)
- Centered column,
padding: 80px 24px 100px - Fade-in:
opacity 0.9s ease, transform 0.9s ease, delay0.3s, triggers onuiVisible - Heading (Viaoda Libre): "FALL > INTO" line (
clamp(26px, 7vw, 42px),tracking-widest, color#3b1a0a) then "REVERIE" (clamp(52px, 16vw, 80px),tracking-tight,leading-none, color#3b1a0a). The ">" is a›character in color#6b2e0eat0.8em. "INTO" is italic. - Subtext (Imprima): "Crafting boundless digital worlds where the edge between AI, vision, and living myth dissolves." --
15px,leading-relaxed, color#5c2d0e,max-width: 280px - Single card: 140x140px,
border-radius: 22px,CARD_IMAGES[0]as background-cover,box-shadow: 0 8px 32px rgba(0,0,0,0.5). Bottom gradient overlay (60% height). Bottom-left overlay: white circle (26px) with play triangle SVG + "View Reel" text (13px, white).
Tablet layout (hidden md:flex xl:hidden)
- Centered column,
gap: 28px,padding: 80px 32px 96px - Same fade-in animation as mobile
- Heading: same structure as mobile but dark brown text (
#3b1a0a), sizesclamp(28px, 5vw, 44px)/clamp(60px, 12vw, 86px) - Subtext: same text,
16px, color#5c2d0e,max-width: 400px - Three cards in a row (
flex gap-3.5): each 140x140px,border-radius: 22px. Each has:- Background gradient overlay (60% height, multi-stop)
- Backdrop blur layer (44% height, masked gradient)
- Card 1: play button + "View Reel"
- Card 2: number "32" (Viaoda Libre, 28px, white) + "World Patrons"
- Card 3: play button + "View Reel"
Desktop layout (hidden xl:block / hidden xl:flex)
-
Heading block: absolute,
top: 46%,left: 60px,maxWidth: 440px,translateY(-50%)centered- White text with heavy
text-shadow: 0 2px 24px rgba(0,0,0,0.7), 0 1px 4px rgba(0,0,0,0.9) - "FALL > INTO":
clamp(32px, 4.5vw, 54px),line-height: 1.1,letter-spacing: 0.04em. The>isrgba(255,220,180,0.7). - "REVERIE":
clamp(50px, 7.5vw, 88px),line-height: 0.9,letter-spacing: -0.02em - Subtext:
18px,line-height: 1.7, colorrgba(255,245,235,0.88),max-width: 300px,text-shadow: 0 1px 12px rgba(0,0,0,0.8) - Fade-in: opacity+transform, delay
0.3s
- White text with heavy
-
Cards block: absolute,
right: 40px,top: 50%,translateY(-50%),flex gap: 12px- Three cards, each 158x158px,
border-radius: 28px,box-shadow: 0 8px 32px rgba(0,0,0,0.45) - Each has: gradient overlay, backdrop blur layer (same as tablet), bottom content area at 12px inset
- Play cards: 30px white circle + 18px "View Reel"
- Number card: "32" at 36px Viaoda Libre + 18px "World Patrons"
- Fade-in delay:
0.55s
- Three cards, each 158x158px,
Slider Dots (bottom of Scene 1)
- Absolute, bottom
28px (mobile, centered)/40px (desktop, left: 60px) - 4 dots: first is
28px wide, rest14px, all4px tall,border-radius: 2px - Active dot:
rgba(255,255,255,0.9), inactive:rgba(255,255,255,0.35) - Fade-in delay:
0.8s
Scroll Cue (desktop only)
- Absolute
bottom: 36px, centered - "DESCEND" text:
10px,letter-spacing: 0.22em, uppercase,rgba(255,255,255,0.6) - Below:
ScrollChevron-- 34px circle with 1.5px borderrgba(255,255,255,0.5), chevron SVG inside,animation: bobUp 1.8s ease-in-out infinite - Fade-in delay:
0.9s
SCENE 2 UI (z-index: 46)
Opacity = clamp((scrollProgress - 0.68) / 0.16, 0, 1). Fades in between scroll 68%-84%.
- Centered column
- Heading (Viaoda Libre): "FORGE BEYOND THE REAL" --
clamp(28px, 8vw, 44px) mobile / clamp(38px, 6.5vw, 78px) desktop, white,letter-spacing: 0.03em,line-height: 1.05,text-shadow: 0 2px 20px rgba(0,0,0,0.4) - Subtext (Imprima): "Singular voyages to astonishing destinations, shaped for those who seek beauty beyond the ordinary and the known." --
14px mobile / 20px desktop,line-height: 1.6,letter-spacing: -0.01em,max-width: 260px mobile / 480px desktop, colorrgba(255,255,255,0.82) - Margin-top:
8vh mobile / 12vh desktop
ARC CARD SLIDER COMPONENT
Props: cards[], rotationOffset: number, isMobile: boolean
Layout math:
cardSpacingDeg: 12 (mobile) / 9 (desktop) degrees between cardscenterIndex:Math.floor(totalCards / 2)arcRadius: 700 (mobile) / 1100 (desktop) pxcardW: 160 (mobile) / 220 (desktop) pxcardH: 175 (mobile) / 230 (desktop) pxsliderH: 260 (mobile) / 360 (desktop) px
rotationOffset is driven by scroll: lerp(0, arcSweepDeg, clamp((scrollProgress - 0.70) / 0.30, 0, 1)) where arcSweepDeg = (totalCards - 1) * 10.
Per card positioning:
baseDeg = (i - centerIndex) * cardSpacingDeg
deg = baseDeg - rotationOffset + (centerIndex * cardSpacingDeg)
rad = deg * PI / 180
x = sin(rad) * arcRadius
y = arcRadius - cos(rad) * arcRadius
Each card is absolutely positioned at bottom: -y + (140 mobile / 200 desktop)px, left: calc(50% + x - halfW), transform: rotate(deg), transformOrigin: halfW arcRadius.
Card appearance:
- Rounded rect (
18px mobile / 26px desktop), background =card.color(pastel) box-shadow: 0 8px 40px rgba(80,40,60,0.18)- Top-right: numbered circle (24px,
1.5px border rgba(80,50,60,0.3), textrgba(80,50,60,0.6), 10px Imprima) showing zero-padded index - Bottom: card title in Viaoda Libre (
22px mobile / 30px, color#3a2530) + description in Imprima (12px mobile / 15px, colorrgba(58,37,48,0.65))
ENTRANCE ANIMATION SEQUENCE
- t=100ms: Curtains open --
curtainsOpenRefflips to true, causing 62% horizontal shift on each curtain with1.8s cubic-bezier(0.16, 1, 0.3, 1)transition - t=600ms:
uiVisible= true -- all Scene 1 UI elements fade/slide in with staggered delays (0.3s heading, 0.55s cards, 0.8s dots, 0.9s scroll cue) - t=2200ms:
entranceDone= true -- curtain CSS transition switches tononeso parallax is instant
MOUSE PARALLAX (desktop)
requestAnimationFrame loop smooths raw mouse position at speed = 0.07 (lerp). Each layer is offset by its MAG value in the reverse direction of the mouse. The transforms combine mouse offset with scroll-driven scale/translate.
MAG values: world=6, clouds=9, portal=7, curtainL=14, curtainR=14