Hero Two
It is a refined, minimal UI component built using Next.js and Framer Motion.
Live Preview
FORK.
BUILD.LAUNCH.
BUILD.LAUNCH.
The Unapologetic UI Framework
Dependencies
npm install
framer-motionCode
"use client";
import React from "react";
import { motion } from "framer-motion";
export default function HeroTwo() {
const words = "BUILD. LAUNCH.".split(" ");
const CHARS = "FORK.".split("");
return (
<section className="relative w-full min-h-screen bg-black text-white flex flex-col items-center justify-center overflow-hidden">
<div
className="absolute top-0 inset-0 transition-transform duration-300 ease-out"
style={{ transform: 'translateX(0%)' }}
>
<div className="absolute top-0 left-1/2 h-2 w-32 -translate-x-1/2 rounded-b-full bg-zinc-400 z-[60] shadow-md">
<div className="absolute inset-0 bg-white blur-md opacity-50"></div>
</div>
<div
className="absolute top-0 left-1/2 h-[100vh] w-[40vw] -translate-x-1/2 z-40"
style={{
background:
"linear-gradient(to bottom, rgba(255,255,255,0.4) 0%, rgba(255,255,255,0.05) 60%, transparent 100%)",
clipPath: "polygon(45% 0%, 55% 0%, 100% 100%, 0% 100%)",
maskImage: "linear-gradient(to bottom, black 20%, transparent 90%)",
WebkitMaskImage:
"linear-gradient(to bottom, black 20%, transparent 90%)",
}}
></div>
<div
className="absolute top-0 left-1/2 h-[40vh] w-[40vw] -translate-x-1/2 z-30 opacity-40 blur-[20px]"
style={{
background:
"conic-gradient(from 165deg at 50% 0%, transparent 0deg, white 10deg, white 20deg, transparent 30deg)",
}}
></div>
<div className="absolute bottom-[10%] left-1/2 -translate-x-1/2 h-[400px] w-[400px] rounded-full bg-white/10 rotate-x-80 z-20"></div>
<div className="absolute bottom-[35%] left-1/2 -translate-x-1/2 h-[100px] w-[300px] rounded-full bg-white/20 rotate-x-70 blur-[40px] z-21"></div>
</div>
<div className="relative z-10 text-center px-4">
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 1 }}
className=" mt-30 mb-10"
>
{CHARS.map((word, i) => (
<motion.span
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
delay: 0.1 * i,
duration: 0.8,
ease: [0.22, 1, 0.36, 1],
}}
key={i}
className="text-4xl md:text-9xl font-black tracking-tighter opacity-100 selection:bg-white selection:text-black"
>
{word}
</motion.span>
))}
<br />
{words.map((word, i) => (
<motion.span
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
delay: 0.1 * i,
duration: 0.8,
ease: [0.22, 1, 0.36, 1],
}}
key={i}
className="text-4xl md:text-9xl font-black tracking-tighter opacity-100 selection:bg-white selection:text-black"
>
{word}
</motion.span>
))}
</motion.div>
<motion.h2
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5 }}
className="text-lg md:text-2xl font-light text-zinc-400 tracking-[0.4em] uppercase mb-12"
>
The Unapologetic UI Framework
</motion.h2>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.8 }}
className="flex flex-col md:flex-row gap-6 justify-center items-center"
>
<div className="group relative">
<div className="absolute -inset-0.5 bg-white opacity-20 group-hover:opacity-100 blur transition duration-500"></div>
<button className="relative px-16 py-5 bg-black text-white font-bold uppercase tracking-widest text-xs border border-zinc-800">
Get Started
</button>
</div>
<button className="text-zinc-500 underline hover:text-white transition-colors text-xs font-bold uppercase tracking-widest">
View on GitHub
</button>
</motion.div>
</div>
</section>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| items | AccordionItem[] | data | An array of objects representing each accordion row, including the header title and body content. |