Field notes
A complete SaaS landing page where the app window pins in place and changes screens as you scroll: KPIs count up, a funnel grows, a cohort grid fills in, an alert fires. Every chart is hand-built HTML and SVG. No chart library, no images, no WebGL.
Cairn is a full landing page for a product analytics tool: header, hero with a customer strip, a pinned product tour, three-tier pricing with a monthly and yearly toggle, and a closing call to action. The tour is the centrepiece. While you scroll through it, the app window stays on screen and walks through four views (Overview, Funnels, Cohorts, Alerts), each building itself as it arrives, with the sidebar highlight sliding from row to row and the caption beside it changing.
Everything in the window is plain HTML and SVG, drawn from seeded data so it looks the same on every load. The window is laid out at one fixed design size and scaled to fit, so it keeps its proportions from a phone to a wide monitor; on a phone the sidebar drops away so the screen itself gets the width. Anyone who prefers reduced motion sees each screen already built, with plain cross-fades.
How it's built
- One number runs the whole tour: a Framer Motion value from 0 to 4, where screen i is on between i and i + 1. The section's scroll progress feeds it through a spring, and every caption, chart, counter, and the sidebar highlight is a pure function of it, so scrolling back up plays everything in reverse.
- Screens build in stages, not on timers: each element maps its own slice of its screen's progress (say, 0.12 to 0.55) to a path length, a scaleY, or an opacity, so the line chart draws, the funnel bars grow one after another, and the cohort cells light up along the diagonal as you scroll.
- Hand-offs without clutter: the old screen fades out before the new one fades in, so two sets of text never overlap, while the sidebar highlight uses a symmetric cross-fade and glides straight from one row to the next.
- The app window is a fixed 960 × 600 layout scaled with one CSS transform, measured by a ResizeObserver. Below 560 px it switches to a 560-wide layout without the sidebar and hangs from the top of its box instead of centring.
Inside the prompt
Every file below is written out in full, so your agent creates the project exactly — no guessing, no missing pieces.
cairn-tour/
├─ .gitignore
├─ index.html
├─ package.json
├─ tsconfig.json
├─ vite.config.ts
└─ src/
├─ App.tsx
├─ index.css
├─ main.tsx
├─ vite-env.d.ts
├─ components/
│ ├─ AppFrame.tsx
│ ├─ Hero.tsx
│ ├─ Logo.tsx
│ ├─ Pricing.tsx
│ ├─ Tour.tsx
│ └─ screens/
│ ├─ Alerts.tsx
│ ├─ Cohorts.tsx
│ ├─ Funnel.tsx
│ └─ Overview.tsx
└─ lib/
├─ data.ts
└─ loop.tsRecut it
- Rewrite the four tour captions and sidebar names
src/lib/data.ts → FEATURES - Swap in your own KPIs, funnel steps, or cohort weeks
src/lib/data.ts → KPIS / FUNNEL / COHORT_WEEKS - Change the plans, prices, and features
src/lib/data.ts → PLANS - Replace a screen of the app window with your own UI
src/components/AppFrame.tsx → SCREENS - Make the tour longer or shorter to scroll through
src/components/Tour.tsx → Tour() - Recolour the page (paper, ink, and the signal orange)
src/index.css → @theme - Change the headline and the customer strip (the name Cairn also sits in index.html, AppFrame, Pricing's Footer, and FEATURES)
src/components/Hero.tsx → Hero() / CUSTOMERS
Also in the vault
Monolith
3D InteractiveA floating hexagonal basalt monolith split by glowing cyan fissures, with drifting debris, a light shaft, and pointer parallax. Procedural GLSL stone — no textures, no models, no network.
Kinetics
Scroll HeroA dark SaaS hero where giant type slides with scroll inertia, glass stat cards tick like a live dashboard, and a frosted dock magnifies under the pointer. Pure DOM and Framer Motion — no canvas, no images.
CodePulse
Video GeneratorPaste a snippet and export a glowing, typed-out code clip as MP4 — square for X, vertical for Reels, Shorts, and TikTok. A Remotion composition with VS Code-grade highlighting and a live browser preview.