Layout 488
standardText Align CenterImage/Video Center1 ColumnImageBackground ImageFeature Section

Code
relume-layout488.tsx
"use client";
import { motion, useScroll, useTransform } from "motion/react";
import { useMediaQuery } from "@/hooks/use-media-query";
import { useRef } from "react";
type ImageProps = {
src: string;
alt: string;
};
type Props = {
leftHeading: string;
image: ImageProps;
rightHeading: string;
mobileHeading: string;
};
export type Layout488Props = React.ComponentPropsWithoutRef<"section"> & Partial<Props>;
export const Layout488 = (props: Layout488Props) => {
const { leftHeading, image, rightHeading, mobileHeading } = {
...Layout488Defaults,
...props,
};
const isMobile = useMediaQuery("(max-width: 767px)");
const sectionRef = useRef<HTMLDivElement>(null);
const { scrollYProgress } = useScroll({
target: sectionRef,
offset: ["start start", "end end"],
});
const createTransform = (mobileValues: number[], desktopValues: number[]) =>
useTransform(scrollYProgress, [0, 0.6], isMobile ? mobileValues : desktopValues);
const leftHeadingTranslate = { x: useTransform(scrollYProgress, [0, 0.6], ["10rem", "0rem"]) };
const rightHeadingTranslate = { x: useTransform(scrollYProgress, [0, 0.6], ["-10rem", "0rem"]) };
const imageScale = createTransform([0.7, 1], [0.2, 1]);
const overlayMotion = {
width: useTransform(
scrollYProgress,
[0.6, 1],
isMobile ? ["10vw", "250vw"] : ["10vw", "200vw"],
),
height: useTransform(
scrollYProgress,
[0.6, 1],
isMobile ? ["10vw", "250vw"] : ["10vw", "200vw"],
),
};
return (
<section ref={sectionRef} className="relative h-[200vh]">
<div className="sticky top-0 grid h-svh grid-cols-[60%] content-center items-center justify-center justify-items-center gap-4 overflow-hidden px-[5%] md:grid-cols-[40%_max-content_40%] md:gap-8 lg:h-screen">
<motion.h2
className="relative z-10 hidden justify-self-end text-[4rem] font-bold whitespace-nowrap md:flex lg:text-[6rem]"
style={leftHeadingTranslate}
>
{leftHeading}
</motion.h2>
<motion.div
className="relative order-first flex w-full max-w-[24rem] min-w-16 items-center justify-center md:order-none"
style={{ scale: imageScale }}
>
<img
src={image.src}
alt={image.alt}
className="aspect-square size-full rounded-full object-cover"
/>
<motion.div
className="absolute -z-10 rounded-full bg-scheme-foreground"
style={overlayMotion}
/>
</motion.div>
<motion.h2
className="relative z-10 hidden justify-self-start text-[4rem] font-bold whitespace-nowrap md:flex lg:text-[6rem]"
style={rightHeadingTranslate}
>
{rightHeading}
</motion.h2>
<motion.h2 className="relative z-10 mt-10 flex justify-self-center text-h2 font-bold whitespace-nowrap md:hidden">
{mobileHeading}
</motion.h2>
</div>
<div className="absolute inset-0 -z-10 mt-[100vh]" />
</section>
);
};
export const Layout488Defaults: Props = {
leftHeading: "Heading",
image: {
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
alt: "Relume placeholder",
},
rightHeading: "goes here",
mobileHeading: "Heading goes here",
};npm i @radix-ui/react-slot class-variance-authority@0.7.1 clsx@^2.1.1 motion@^12.15.0 relume-icons@1.3.0 tailwind-merge@^2.2.2


