From 375e9b3e5372044ec387b8b8214a2e8498f727fc Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sun, 30 Aug 2026 11:01:19 +0200 Subject: [PATCH] feat(website): rebuild homepage product mockups Replace static captures with live, responsive scenes that demonstrate building, reviewing, shipping, and extending work across desktop and mobile. --- packages/website/public/blank-page.svg | 11 + .../website/src/components/hero-mockup.tsx | 100 ++- .../website/src/components/landing-page.tsx | 114 +-- .../website/src/components/mockup/atoms.tsx | 201 +++++ .../website/src/components/mockup/chat.tsx | 260 ++++++ .../website/src/components/mockup/diff.tsx | 778 ++++++++++++++++++ .../website/src/components/mockup/geometry.ts | 17 + .../website/src/components/mockup/icons.tsx | 62 ++ .../website/src/components/mockup/index.ts | 7 + .../src/components/mockup/mobile/atoms.tsx | 56 ++ .../src/components/mockup/mobile/chat.tsx | 155 ++++ .../src/components/mockup/mobile/diff.tsx | 166 ++++ .../src/components/mockup/mobile/frame.tsx | 91 ++ .../src/components/mockup/mobile/sidebar.tsx | 314 +++++++ .../website/src/components/mockup/motion.ts | 15 + .../website/src/components/mockup/panes.tsx | 13 + .../src/components/mockup/right-panel.tsx | 298 +++++++ .../website/src/components/mockup/sidebar.tsx | 338 ++++++++ .../website/src/components/mockup/states.ts | 19 + .../src/components/mockup/titlebar.tsx | 140 ++++ .../website/src/components/mockup/window.tsx | 118 +++ packages/website/src/routes/index.tsx | 4 +- packages/website/src/styles.css | 71 +- 23 files changed, 3254 insertions(+), 94 deletions(-) create mode 100644 packages/website/public/blank-page.svg create mode 100644 packages/website/src/components/mockup/atoms.tsx create mode 100644 packages/website/src/components/mockup/chat.tsx create mode 100644 packages/website/src/components/mockup/diff.tsx create mode 100644 packages/website/src/components/mockup/geometry.ts create mode 100644 packages/website/src/components/mockup/mobile/atoms.tsx create mode 100644 packages/website/src/components/mockup/mobile/chat.tsx create mode 100644 packages/website/src/components/mockup/mobile/diff.tsx create mode 100644 packages/website/src/components/mockup/mobile/frame.tsx create mode 100644 packages/website/src/components/mockup/mobile/sidebar.tsx create mode 100644 packages/website/src/components/mockup/motion.ts create mode 100644 packages/website/src/components/mockup/panes.tsx create mode 100644 packages/website/src/components/mockup/right-panel.tsx create mode 100644 packages/website/src/components/mockup/sidebar.tsx create mode 100644 packages/website/src/components/mockup/states.ts create mode 100644 packages/website/src/components/mockup/titlebar.tsx create mode 100644 packages/website/src/components/mockup/window.tsx diff --git a/packages/website/public/blank-page.svg b/packages/website/public/blank-page.svg new file mode 100644 index 0000000000..9ee048ce2c --- /dev/null +++ b/packages/website/public/blank-page.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/website/src/components/hero-mockup.tsx b/packages/website/src/components/hero-mockup.tsx index f1a0733d32..4204a8d036 100644 --- a/packages/website/src/components/hero-mockup.tsx +++ b/packages/website/src/components/hero-mockup.tsx @@ -1,15 +1,95 @@ +import { motion } from "framer-motion"; +import { useCallback, useState } from "react"; +import { + DEFAULT_MOCKUP_STATE, + DESIGN_HEIGHT, + DESIGN_WIDTH, + MOCKUP_STATES, + type MockupStateId, + MockupWindow, +} from "~/components/mockup"; + +const ALT = + "Paseo desktop app with coding agents, a conversation, and a code diff open side by side"; + +const ASPECT_STYLE = { aspectRatio: `${DESIGN_WIDTH} / ${DESIGN_HEIGHT}` }; + +// `tan(atan2(a, b))` is the CSS way to divide one length by another, so the scale +// factor tracks the container with no JS, no layout thrash, and a correct +// server-rendered first paint. +const SCALE_STYLE = { + width: DESIGN_WIDTH, + height: DESIGN_HEIGHT, + transform: `scale(tan(atan2(100cqw, ${DESIGN_WIDTH}px)))`, +}; + +const PILL_TRANSITION = { duration: 0.34, ease: [0.22, 0.61, 0.36, 1] as const }; + export function HeroMockup() { + const [state, setState] = useState(DEFAULT_MOCKUP_STATE); + return ( -
- Paseo desktop app with coding agents, a conversation, and a code diff open side by side +
+
+ {MOCKUP_STATES.map((option) => ( + + ))} +
+ +
+ {/* The window is authored at DESIGN_WIDTH and scaled to fit the hero column. */} +
+
+
+ +
+
+
+
); } + +function StatePill({ + id, + label, + selected, + onSelect, +}: { + id: MockupStateId; + label: string; + selected: boolean; + onSelect: (id: MockupStateId) => void; +}) { + const select = useCallback(() => onSelect(id), [onSelect, id]); + return ( + + ); +} diff --git a/packages/website/src/components/landing-page.tsx b/packages/website/src/components/landing-page.tsx index 87f12f69d9..9443c4f6c7 100644 --- a/packages/website/src/components/landing-page.tsx +++ b/packages/website/src/components/landing-page.tsx @@ -27,20 +27,23 @@ const DURATION_05: Transition = { duration: 0.5 }; const VIEWPORT_60 = { once: true, margin: "-60px" }; const SVG_OVERFLOW_VISIBLE_STYLE = { overflow: "visible" as const }; -const PHONE_PERSPECTIVE_STYLE = { minHeight: 480, perspective: 1200 }; +// A ~240px-wide phone rotated 15° only foreshortens a couple percent at +// perspective 1200 — it reads as a flat, skewed card. The side phones already +// sit on a correctly projecting plane (the frame and its scaled interior share +// one flattened texture), so the interior just needs the projection to be +// strong enough to see: a tighter perspective gives the trio a real book-fold. +const PHONE_PERSPECTIVE_STYLE = { minHeight: 480, perspective: 700 }; import { CursorFieldProvider } from "~/components/butterfly"; import { CommandDialog } from "~/components/command-dialog"; import { AGENT_PAGES } from "~/data/agent-pages"; import { appStoreUrl, playStoreUrl, - webAppUrl, getDownloadOptions, useDetectedPlatform, AppleIcon, PlayStoreIcon, TerminalIcon, - GlobeIcon, } from "~/downloads"; import { useRelease } from "~/routes/__root"; import { HeroMockup } from "~/components/hero-mockup"; @@ -52,7 +55,7 @@ import { PiIcon, } from "~/components/agent-icons"; import { DiscordIcon, GitHubIcon, SlackIcon } from "~/components/brand-icons"; -import { ClaudeIcon } from "~/components/mockup"; +import { ClaudeIcon, MobileChat, MobileDiff, MobileSidebar, PhoneFrame } from "~/components/mockup"; import { FAQItem } from "~/components/faq-item"; import { SiteFooter } from "~/components/site-footer"; import { SiteHeader } from "~/components/site-header"; @@ -68,7 +71,7 @@ export function LandingPage({ title, subtitle }: LandingPageProps) { {/* Hero section with background image */}
-
+