"use client";
import Image from "next/image";
import { useRef, type ReactNode } from "react";
import {
motion,
useMotionTemplate,
useReducedMotion,
useScroll,
useSpring,
useTransform,
} from "motion/react";
import { Lock, TrendingUp, Users } from "lucide-react";
/* ------------------------------------------------------------------ *
* Browser chrome — glass bar over the screenshot
* ------------------------------------------------------------------ */
export function BrowserFrame({
children,
url = "app.kumasy.de",
className = "",
}: {
children: ReactNode;
url?: string;
className?: string;
}) {
return (
);
}
/* ------------------------------------------------------------------ *
* Floating stat chip
*
* Deliberately opaque, unlike the rest of the glass family. These chips
* sit directly on top of the dashboard screenshot, so a translucent
* surface lets the sidebar labels and the chart line read straight
* through the chip's own text — backdrop-blur cannot fix that, because
* what is behind is small sharp type rather than a soft wash. Same call
* the app makes for dialogs: darken behind, never blur, so the content
* in front stays legible.
* ------------------------------------------------------------------ */
function GlassStat({
Icon,
label,
value,
tone,
}: {
Icon: typeof Users;
label: string;
value: string;
tone: "mint" | "amber";
}) {
return (
);
}
/* ------------------------------------------------------------------ *
* ParallaxLayer
* ------------------------------------------------------------------ */
export function ParallaxLayer({
children,
depth = 60,
className = "",
}: {
children: ReactNode;
depth?: number;
className?: string;
}) {
const ref = useRef(null);
const reduced = useReducedMotion();
const { scrollYProgress } = useScroll({
target: ref,
offset: ["start end", "end start"],
});
const y = useSpring(useTransform(scrollYProgress, [0, 1], [depth, -depth]), {
stiffness: 120,
damping: 28,
mass: 0.4,
});
return (
{children}
);
}
/* ------------------------------------------------------------------ *
* ShowcaseStage — one product shot, presented cleanly
* ------------------------------------------------------------------ */
export function ShowcaseStage() {
const ref = useRef(null);
const reduced = useReducedMotion();
const { scrollYProgress } = useScroll({
target: ref,
offset: ["start 0.95", "end 0.2"],
});
// The window tips up from a shallow angle and settles flat, as if being
// set down on the pedestal. One gesture, not five competing ones.
const rotateX = useSpring(useTransform(scrollYProgress, [0, 0.6], [12, 0]), {
stiffness: 90,
damping: 26,
});
const scale = useSpring(useTransform(scrollYProgress, [0, 0.6], [0.94, 1]), {
stiffness: 90,
damping: 26,
});
const lift = useTransform(scrollYProgress, [0, 0.6], [50, 0]);
const glowY = useTransform(scrollYProgress, [0, 1], [40, -40]);
const chipY = useTransform(scrollYProgress, [0, 1], [-46, 46]);
const transform = useMotionTemplate`perspective(1600px) rotateX(${rotateX}deg) scale(${scale})`;
return (
{/* Pedestal: a warm plinth the window stands on, so it reads as
placed rather than pasted onto the page. */}
{/* The product shot. Full opacity, nothing covering it. */}
{/* Two chips, clear of the window on either side. They annotate the
product; they never sit on top of the UI they point at. */}
);
}