YoruAkio's picture
fix: Simplify animation variants to reduce flickering and improve performance
ccbc82f
import Head from 'next/head';
import { motion, useScroll, useTransform } from 'framer-motion';
import { useState, useRef, useMemo, useCallback } from 'react';
import {
FiDownload,
FiRefreshCw,
FiZap,
FiStar,
FiArrowRight,
FiPlay,
FiGift,
FiExternalLink,
FiArrowUpRight,
} from 'react-icons/fi';
import {
HiSparkles,
HiLightningBolt,
HiPhotograph,
HiVideoCamera,
HiCode,
HiChip,
} from 'react-icons/hi';
import { SiYoutube, SiInstagram } from 'react-icons/si';
import { FaSquareXTwitter } from 'react-icons/fa6';
import Navbar from '../components/Navbar';
import Footer from '../components/Footer';
export default function Home() {
const [activeConverter, setActiveConverter] = useState('image');
const heroRef = useRef(null);
const { scrollYProgress } = useScroll({
target: heroRef,
offset: ['start start', 'end start'],
});
const yBg = useTransform(scrollYProgress, [0, 1], ['0%', '30%']);
const opacity = useTransform(scrollYProgress, [0, 0.7], [1, 0]);
// Add smooth scroll handler
const handleSmoothScroll = useCallback(href => {
if (href.startsWith('#')) {
const element = document.querySelector(href);
if (element) {
const offset = 80; // Account for fixed navbar
const elementPosition = element.getBoundingClientRect().top;
const offsetPosition = elementPosition + window.pageYOffset - offset;
window.scrollTo({
top: offsetPosition,
behavior: 'smooth',
});
}
}
}, []);
// Memoized data for better performance
const features = useMemo(
() => [
{
icon: FiDownload,
title: 'Social Media Downloader',
description:
'Download content from YouTube, Twitter, and Instagram with ease',
iconColor: 'text-white',
status: 'Available',
},
{
icon: FiRefreshCw,
title: 'File Converter',
description: 'Convert images, videos, and files to any format you need',
iconColor: 'text-white',
status: 'Available',
},
{
icon: HiChip,
title: 'AI Code Transformer',
description:
'Transform code between programming languages using Gemini AI',
iconColor: 'text-white',
status: 'Coming Soon',
},
],
[],
);
const converters = useMemo(
() => [
{
id: 'image',
icon: HiPhotograph,
title: 'Image Converter',
description: 'Convert to WebP, JPG, PNG, ICO and more',
formats: ['WebP', 'JPG', 'PNG', 'ICO', 'SVG', 'BMP'],
},
{
id: 'video',
icon: HiVideoCamera,
title: 'Video Converter',
description: 'Convert videos to GIF or extract MP3 audio',
formats: ['GIF', 'MP3', 'MP4', 'WebM', 'AVI'],
},
{
id: 'code',
icon: HiCode,
title: 'Code Transformer',
description: 'AI-powered language conversion with Gemini',
formats: ['Python', 'JavaScript', 'TypeScript', 'Go', 'Rust'],
},
],
[],
);
const socialPlatforms = useMemo(
() => [
{
name: 'YouTube',
icon: SiYoutube,
color: 'text-[var(--accent)]',
status: 'Available',
description: 'Download videos and audio from YouTube',
},
{
name: 'Twitter',
icon: FaSquareXTwitter,
color: 'text-[var(--accent)]',
status: 'Coming Soon',
description: 'Save tweets, images, and videos',
},
{
name: 'Instagram',
icon: SiInstagram,
color: 'text-[var(--accent)]',
status: 'Coming Soon',
description: 'Download photos, stories, and reels',
},
],
[],
);
const stats = useMemo(
() => [
{ label: 'Downloads', value: '10K+' },
{ label: 'Formats', value: '50+' },
{ label: 'Users', value: '1K+' },
],
[],
);
const aboutFeatures = useMemo(
() => [
'Social media content downloading',
'Multi-format file conversion',
'AI-powered code transformation',
'User-friendly interface',
'Fast and reliable processing',
],
[],
);
// Simplified animation variants to reduce flickering
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.05,
delayChildren: 0.1,
},
},
};
const itemVariants = {
hidden: { opacity: 0, y: 10 },
visible: {
opacity: 1,
y: 0,
transition: {
duration: 0.4,
ease: [0.25, 0.4, 0.55, 1.4]
},
},
};
const handleConverterChange = useCallback(converterId => {
setActiveConverter(converterId);
}, []);
return (
<div className="min-h-screen bg-[var(--background)] text-[var(--foreground)] overflow-x-hidden">
<Head>
<title>LumaKit - Powerful Media Tools & AI Transformations</title>
<meta
name="description"
content="LumaKit offers powerful tools for social media downloading, file conversion, and AI-powered transformations. Transform your digital workflow with our modern platform."
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#D4A574" />
<link rel="icon" href="/favicon.ico" />
</Head>
<Navbar />
{/* Hero Section */}
<section
ref={heroRef}
id="hero"
className="relative min-h-screen flex items-center justify-center overflow-hidden pt-16 sm:pt-0"
>
{/* Background Elements */}
<motion.div
className="absolute inset-0 opacity-20 pointer-events-none will-change-transform"
style={{ y: yBg, opacity }}
>
<div className="absolute top-1/4 left-1/4 w-32 h-32 sm:w-48 sm:h-48 lg:w-64 lg:h-64 bg-[var(--accent)]/20 rounded-full blur-3xl"></div>
<div className="absolute top-3/4 right-1/4 w-40 h-40 sm:w-60 sm:h-60 lg:w-80 lg:h-80 bg-[var(--accent)]/15 rounded-full blur-3xl"></div>
<div className="absolute bottom-1/4 left-1/2 w-48 h-48 sm:w-72 sm:h-72 lg:w-96 lg:h-96 bg-[var(--accent)]/10 rounded-full blur-3xl"></div>
</motion.div>
<div className="relative max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center w-full">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, ease: [0.25, 0.4, 0.55, 1.4] }}
className="space-y-6 sm:space-y-8"
>
{/* Main Title */}
<div className="space-y-4 sm:space-y-6">
<motion.div
className="flex items-center justify-center space-x-2 mb-4 sm:mb-6"
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 0.6, delay: 0.2 }}
>
<div className="relative">
<HiSparkles className="text-3xl sm:text-4xl text-[var(--accent)]" />
<div className="absolute inset-0 bg-[var(--accent)] blur-lg opacity-30"></div>
</div>
</motion.div>
<motion.h1
className="text-4xl sm:text-6xl lg:text-7xl font-bold leading-tight"
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.3 }}
>
<span className="gradient-text">LumaKit</span>
</motion.h1>
<motion.p
className="text-lg sm:text-xl lg:text-2xl text-[var(--foreground-secondary)] max-w-4xl mx-auto leading-relaxed px-4"
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.4 }}
>
A versatile suite of tools for{' '}
<span className="text-[var(--accent)] font-semibold">
social media downloading
</span>
,{' '}
<span className="text-[var(--accent)] font-semibold">
file conversion
</span>
, and{' '}
<span className="text-[var(--accent)] font-semibold">
AI-powered transformations
</span>
</motion.p>
</div>
{/* CTA Button */}
<motion.div
className="flex items-center justify-center"
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.5 }}
>
<motion.a
href="https://huggingface.co/spaces/YoruAkio/LumaKit"
target="_blank"
rel="noopener noreferrer"
className="group relative flex items-center space-x-2 bg-[var(--accent)] hover:bg-[var(--accent-hover)] text-[var(--background)] px-6 sm:px-8 py-3 sm:py-4 rounded-xl font-semibold text-base sm:text-lg transition-all duration-300 shadow-lg hover:shadow-2xl overflow-hidden"
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
>
<div className="absolute inset-0 bg-gradient-to-r from-[var(--accent)] to-[var(--accent-hover)] opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<FiExternalLink className="text-lg sm:text-xl relative z-10" />
<span className="relative z-10">Try LumaKit Now</span>
<FiArrowUpRight className="text-base sm:text-lg group-hover:translate-x-1 group-hover:-translate-y-1 transition-transform duration-200 relative z-10" />
</motion.a>
</motion.div>
{/* Stats */}
<motion.div
className="grid grid-cols-3 gap-4 sm:gap-8 max-w-md sm:max-w-lg mx-auto mt-12 sm:mt-16"
initial={{ opacity: 0, y: 15 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.6 }}
>
{stats.map((stat, index) => (
<motion.div
key={index}
className="text-center"
whileHover={{ scale: 1.05 }}
transition={{ duration: 0.2 }}
>
<div className="text-xl sm:text-2xl lg:text-3xl font-bold text-[var(--accent)]">
{stat.value}
</div>
<div className="text-xs sm:text-sm text-[var(--foreground-muted)]">
{stat.label}
</div>
</motion.div>
))}
</motion.div>
</motion.div>
</div>
</section>
{/* Features Section */}
<section
id="features"
className="py-16 sm:py-20 lg:py-24 bg-[var(--background-secondary)] overflow-hidden"
>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<motion.div
className="text-center mb-12 sm:mb-16"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.6 }}
>
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-bold mb-4 sm:mb-6">
<span className="gradient-text">Powerful Features</span>
</h2>
<p className="text-lg sm:text-xl text-[var(--foreground-secondary)] max-w-3xl mx-auto px-4">
Everything you need to download, convert, and transform your
digital content
</p>
</motion.div>
<motion.div
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8"
variants={containerVariants}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: '-100px' }}
>
{features.map((feature, index) => (
<motion.div
key={index}
className="group relative glass rounded-2xl p-6 sm:p-8 hover:bg-[var(--background-tertiary)]/50 transition-all duration-300 flex flex-col h-full min-h-[320px]"
variants={itemVariants}
whileHover={{ y: -3, scale: 1.01 }}
transition={{ duration: 0.2 }}
>
{/* Icon */}
<div className="inline-flex p-3 sm:p-4 rounded-xl bg-[var(--accent)] mb-4 sm:mb-6 shadow-lg w-fit">
<feature.icon className="text-xl sm:text-2xl text-white" />
</div>
{/* Content */}
<div className="flex-1 flex flex-col">
<h3 className="text-lg sm:text-xl font-semibold text-[var(--foreground)] mb-3 sm:mb-4">
{feature.title}
</h3>
<p className="text-[var(--foreground-secondary)] mb-6 text-sm sm:text-base leading-relaxed flex-1">
{feature.description}
</p>
</div>
{/* Status and Arrow - Fixed at bottom */}
<div className="flex items-center justify-between mt-auto pt-4">
<span
className={`px-3 py-1 rounded-full text-xs font-medium border ${
feature.status === 'Available'
? 'bg-green-500/20 text-green-400 border-green-500/30'
: 'bg-[var(--accent)]/20 text-[var(--accent)] border-[var(--accent)]/30'
}`}
>
{feature.status}
</span>
<FiArrowRight className="text-[var(--accent)] group-hover:translate-x-1 transition-transform duration-200" />
</div>
</motion.div>
))}
</motion.div>
</div>
</section>
{/* Converters Section */}
<section id="converters" className="py-16 sm:py-20 lg:py-24 overflow-hidden">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<motion.div
className="text-center mb-12 sm:mb-16"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.6 }}
>
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-bold mb-4 sm:mb-6">
<span className="gradient-text">File Converters</span>
</h2>
<p className="text-lg sm:text-xl text-[var(--foreground-secondary)] max-w-3xl mx-auto px-4">
Transform your files between different formats with ease
</p>
</motion.div>
{/* Converter Tabs */}
<div className="flex justify-center mb-8 sm:mb-12">
<div className="flex flex-wrap glass rounded-xl p-1 sm:p-2 gap-1 sm:gap-0">
{converters.map(converter => (
<button
key={converter.id}
onClick={() => handleConverterChange(converter.id)}
className={`flex items-center space-x-2 px-4 sm:px-6 py-2 sm:py-3 rounded-lg font-medium transition-all duration-200 text-sm sm:text-base ${
activeConverter === converter.id
? 'bg-[var(--accent)] text-[var(--background)]'
: 'text-[var(--foreground-secondary)] hover:text-[var(--foreground)]'
}`}
>
<converter.icon className="text-base sm:text-lg" />
<span className="hidden sm:inline">{converter.title}</span>
<span className="sm:hidden">
{converter.title.split(' ')[0]}
</span>
</button>
))}
</div>
</div>
{/* Active Converter Details */}
<motion.div
key={activeConverter}
className="glass rounded-2xl p-6 sm:p-8"
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
>
{converters.map(converter => {
if (converter.id !== activeConverter) return null;
return (
<div key={converter.id} className="text-center">
<converter.icon className="text-4xl sm:text-5xl text-[var(--accent)] mx-auto mb-4 sm:mb-6" />
<h3 className="text-xl sm:text-2xl font-bold text-[var(--foreground)] mb-3 sm:mb-4">
{converter.title}
</h3>
<p className="text-[var(--foreground-secondary)] mb-6 sm:mb-8 text-base sm:text-lg max-w-2xl mx-auto">
{converter.description}
</p>
<div className="flex flex-wrap justify-center gap-2 sm:gap-3 max-w-4xl mx-auto">
{converter.formats.map((format, index) => (
<span
key={index}
className="px-3 sm:px-4 py-2 bg-[var(--background-tertiary)] border border-[var(--border)] rounded-lg text-[var(--foreground-secondary)] text-xs sm:text-sm font-medium"
>
{format}
</span>
))}
</div>
</div>
);
})}
</motion.div>
</div>
</section>
{/* Social Media Section */}
<section
id="social-media"
className="py-16 sm:py-20 lg:py-24 bg-[var(--background-secondary)] overflow-hidden"
>
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<motion.div
className="text-center mb-12 sm:mb-16"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.6 }}
>
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-bold mb-4 sm:mb-6">
<span className="gradient-text">Social Media Downloader</span>
</h2>
<p className="text-lg sm:text-xl text-[var(--foreground-secondary)] max-w-3xl mx-auto px-4">
Download content from your favorite social media platforms
</p>
</motion.div>
<motion.div
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8"
variants={containerVariants}
initial="hidden"
whileInView="visible"
viewport={{ once: true, margin: '-100px' }}
>
{socialPlatforms.map((platform, index) => (
<motion.div
key={index}
className="relative group glass rounded-2xl p-6 sm:p-8 hover:bg-[var(--background-tertiary)]/50 transition-all duration-300 flex flex-col h-full min-h-[280px]"
variants={itemVariants}
whileHover={{ y: -3, scale: 1.01 }}
transition={{ duration: 0.2 }}
>
{/* Icon */}
<platform.icon
className={`text-4xl sm:text-5xl ${platform.color} mb-4 sm:mb-6`}
/>
{/* Content */}
<div className="flex-1 flex flex-col">
<h3 className="text-lg sm:text-xl font-semibold text-[var(--foreground)] mb-3">
{platform.name}
</h3>
<p className="text-[var(--foreground-secondary)] text-sm sm:text-base leading-relaxed flex-1 mb-6">
{platform.description}
</p>
</div>
{/* Status Badge - Fixed at bottom */}
<div className="mt-auto pt-4">
<span
className={`inline-block px-3 py-1 rounded-full text-xs font-medium border ${
platform.status === 'Available'
? 'bg-green-500/20 text-green-400 border-green-500/30'
: 'bg-[var(--accent)]/20 text-[var(--accent)] border-[var(--accent)]/30'
}`}
>
{platform.status}
</span>
</div>
</motion.div>
))}
</motion.div>
</div>
</section>
{/* About Section */}
<section id="about" className="py-16 sm:py-20 lg:py-24 overflow-hidden">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<motion.div
className="text-center mb-12 sm:mb-16"
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.6 }}
>
<h2 className="text-3xl sm:text-4xl lg:text-5xl font-bold mb-4 sm:mb-6">
<span className="gradient-text">About LumaKit</span>
</h2>
</motion.div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-8 sm:gap-12 lg:gap-16 items-start">
<motion.div
className="space-y-6"
initial={{ opacity: 0, x: -30 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.6 }}
>
<p className="text-base sm:text-lg text-[var(--foreground-secondary)] leading-relaxed">
LumaKit is a comprehensive toolkit designed for creators,
developers, and digital enthusiasts. Our platform combines the
power of social media downloading, versatile file conversion,
and cutting-edge AI technology to streamline your workflow.
</p>
<p className="text-base sm:text-lg text-[var(--foreground-secondary)] leading-relaxed">
Built with modern web technologies and powered by Gemini AI,
LumaKit offers an intuitive and efficient solution for all your
digital transformation needs.
</p>
<div className="space-y-4">
{aboutFeatures.map((feature, index) => (
<motion.div
key={index}
className="flex items-center space-x-3"
initial={{ opacity: 0, x: -20 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.4, delay: index * 0.05 }}
>
<FiStar className="text-[var(--accent)] flex-shrink-0" />
<span className="text-[var(--foreground-secondary)] text-sm sm:text-base">
{feature}
</span>
</motion.div>
))}
</div>
</motion.div>
<motion.div
className="w-full"
initial={{ opacity: 0, x: 30 }}
whileInView={{ opacity: 1, x: 0 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.6 }}
>
<div className="glass rounded-2xl p-6 sm:p-8 w-full max-w-lg mx-auto lg:mx-0">
<div className="space-y-6">
<div className="flex items-center space-x-4">
<HiLightningBolt className="text-2xl sm:text-3xl text-[var(--accent)] flex-shrink-0" />
<div className="min-w-0 flex-1">
<h4 className="text-base sm:text-lg font-semibold text-[var(--foreground)]">
Powered by AI
</h4>
<p className="text-[var(--foreground-secondary)] text-sm sm:text-base">
Gemini AI integration for smart transformations
</p>
</div>
</div>
<div className="flex items-center space-x-4">
<FiGift className="text-2xl sm:text-3xl text-[var(--accent)] flex-shrink-0" />
<div className="min-w-0 flex-1">
<h4 className="text-base sm:text-lg font-semibold text-[var(--foreground)]">
Free to Use
</h4>
<p className="text-[var(--foreground-secondary)] text-sm sm:text-base">
No subscriptions, no hidden fees
</p>
</div>
</div>
<div className="flex items-center space-x-4">
<FiZap className="text-2xl sm:text-3xl text-[var(--accent)] flex-shrink-0" />
<div className="min-w-0 flex-1">
<h4 className="text-base sm:text-lg font-semibold text-[var(--foreground)]">
Lightning Fast
</h4>
<p className="text-[var(--foreground-secondary)] text-sm sm:text-base">
Optimized for speed and performance
</p>
</div>
</div>
</div>
</div>
</motion.div>
</div>
</div>
</section>
<Footer />
</div>
);
}