Eiffel Dive
Fall from the sky through the clouds and fly over Paris to a fully 3D Eiffel Tower as you scroll.
- Zero dependencies
- React + Tailwind
- Accessible
- Reduced-motion aware
Preview
Day · Bright sun, blue sky, crisp shadows and cloud shadows on the ground. mood="day"
The tower is a real 3D signed-distance model (tapering legs, arches, three platforms, see-through lattice) standing over procedural Paris: Haussmann blocks with zinc roofs, the Seine, Champ de Mars and Trocadéro. Copy changes at every step of the descent.
Installation
$ npx shadcn@latest add https://guetix.com/r/eiffel-dive.json
Uses the shadcn CLI. It creates components/guetix/eiffel-dive.tsx and installs nothing else.
Usage
example.tsx
"use client";
import EiffelDive from "@/components/guetix/eiffel-dive";
import type { SkyMood } from "@/components/guetix/sky-dive";
export default function EiffelDiveDemo({ variant = "day" }: { variant?: string }) {
const mood = (["day", "night", "rain"].includes(variant) ? variant : "day") as SkyMood;
return <EiffelDive mood={mood} />;
}
Travel / tourism landing pageCulture & history storytellingBrand film-style heroEvent page
Under the hood
The details that make it feel right, and that a one-line prompt usually misses:
- 01One WebGL2 shader: ray-marched heightfield terrain with soft shadows, plus a 56-step volumetric cloud layer lit by the sun with powder and silver-lining phase.
- 02Clouds cast moving shadows on the ground; distance haze matches the sky color, so scale reads correctly.
- 03The camera path is choreographed: horizon → nose-dive with roll → pull-up → approach, with distance on an exponential curve so it never feels slow or jumpy.
- 04Adaptive resolution watches frame time and scales the render, so it stays smooth on laptops and phones.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| mood | "day" | "night" | "rain" | "day" | Day, Night, or Rain → Sun (the storm clears as you scroll). |
| sections | { eyebrow?: string; title: string; body?: string }[] | — | Story steps, one per screen. |
| mode | "contained" | "page" | "contained" | Scroll inside its own box, or use window scroll with a sticky scene. |
| animated | boolean | true | false = no drifting clouds, rain or easing. |
| className | string | — | Extra classes on the root. |
Accessibility
- The canvas is decorative (`aria-hidden`); all copy is real text.
- The scroll area is focusable for keyboard scrolling; the active step has `aria-current`.
- Reduced motion: no easing, cloud drift, rain or lightning. No WebGL2: a gradient fallback.