From 0cf9c66b6b5c2aa9c4274223fbd61d149b9be417 Mon Sep 17 00:00:00 2001 From: Marco Sadjadi Date: Wed, 27 May 2026 12:11:42 +0200 Subject: [PATCH] feat(web): restore tall hero + carousel slide + viewport-fixed scroll cue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three coordinated tweaks to the landing-page above-the-fold: 1. **Hero padding restored to py-14/sm:py-20/md:py-28** (was py-12/14/16). Compressing it for the scroll-cue position fight made the hero feel cramped and gave the ParticleHero background less room to breathe. With the cue moved out (see #3), there's no reason to shrink the hero. 2. **Step rotator switches to carousel-style horizontal slide.** The AnimatePresence transition was a fade+y-shift cross-fade — clean but sequential. Now the leaving card slides left out (x:-220) while the entering card slides right in (x:220→0), both coexisting in the same 3D-space and inheriting the same mouse-tilt. The container gets `min-h-[240px]` so the absolutely-positioned cards have layout to anchor to (claude_desktop_config.json is the tallest at 7 lines). Reduced-motion still gets the opacity-only cross-fade — sliding content sideways is exactly the kind of motion that preference is meant to suppress. 3. **`` extracted into its own client component**, fixed- positioned at viewport bottom (bottom-5) with a frosted pill style. Fades to opacity:0 once `window.scrollY > 80`, so it doesn't shadow the rest of the page. Lives next to `
` in page.tsx rather than inside the hero — that way it anchors to the loadscreen's natural bottom edge whether the hero is short or tall. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/web/app/(marketing)/page.tsx | 18 ++++------ apps/web/components/hero-step-rotator.tsx | 31 +++++++++++----- apps/web/components/scroll-cue.tsx | 43 +++++++++++++++++++++++ 3 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 apps/web/components/scroll-cue.tsx diff --git a/apps/web/app/(marketing)/page.tsx b/apps/web/app/(marketing)/page.tsx index c2d2ef8..734a5de 100644 --- a/apps/web/app/(marketing)/page.tsx +++ b/apps/web/app/(marketing)/page.tsx @@ -1,9 +1,9 @@ import { HeroStepRotator } from '@/components/hero-step-rotator'; import { JsonLd } from '@/components/json-ld'; import { ParticleHero } from '@/components/particle-hero'; +import { ScrollCue } from '@/components/scroll-cue'; import { StaticCodeBlock } from '@/components/static-code-block'; import { FAQ, faqJsonLd } from '@/lib/seo'; -import { ChevronDown } from 'lucide-react'; import Link from 'next/link'; const PROMPT_EXAMPLE = `Create an MCP server that searches our Notion workspace. @@ -99,7 +99,7 @@ export default function Landing() { for pointermove on window itself, so the ring still tracks the cursor through the content above. */} -
+
v0.1 — updated 2026-05-20 @@ -149,16 +149,12 @@ export default function Landing() {
- {/* Scroll cue — hints the video section sits directly below. */} - - see it run - -
+ {/* Scroll cue — fixed at the bottom of the loadscreen rather than + inside the hero, so it sits at the natural lower edge of the + first viewport regardless of how tall the hero ends up. Fades + out once the user has scrolled past the loadscreen. */} + {/* Flow video — full-width edge-to-edge under the hero. The clip shows the real flow (prompt → server schematic → live connection diff --git a/apps/web/components/hero-step-rotator.tsx b/apps/web/components/hero-step-rotator.tsx index fb8a40d..511ffee 100644 --- a/apps/web/components/hero-step-rotator.tsx +++ b/apps/web/components/hero-step-rotator.tsx @@ -109,23 +109,38 @@ export function HeroStepRotator() { return (
+ {/* Container is relative + has a min-height so the absolutely- + positioned cards inside (during the slide) overlap cleanly + without collapsing the layout. min-h is sized for the tallest + card (claude_desktop_config.json at 7 lines). */}
- + {/* Cursor-following glow — sits behind the content, additive. */} { + function onScroll() { + setVisible(window.scrollY < 80); + } + onScroll(); + window.addEventListener('scroll', onScroll, { passive: true }); + return () => window.removeEventListener('scroll', onScroll); + }, []); + + return ( + + see it run + + + ); +}