From c8d6214322413e013983a58b7c0db340a09afe1e Mon Sep 17 00:00:00 2001 From: Oleg Proskurin Date: Thu, 4 Dec 2025 20:15:35 +0700 Subject: [PATCH] refactor: split by components --- .../_components/AnimatedGradientBorder.tsx | 55 - .../_components/ApiExampleSection.tsx | 64 ++ .../homepage/_components/BackgroundBlobs.tsx | 42 + .../homepage/_components/FinalCtaSection.tsx | 60 ++ .../homepage/_components/GeminiSection.tsx | 143 +++ .../src/app/homepage/_components/HeroGlow.tsx | 13 + .../app/homepage/_components/HeroSection.tsx | 118 +++ .../_components/HowItWorksSection.tsx | 67 ++ .../_components/IntegrationsSection.tsx | 51 + .../_components/KeyFeaturesSection.tsx | 95 ++ .../_components/ProblemSolutionSection.tsx | 66 ++ .../_components/PromptUrlsSection.tsx | 50 + .../_components/ShapeTheFutureSection.tsx | 91 ++ .../src/app/homepage/_components/index.ts | 12 + apps/landing/src/app/homepage/page.tsx | 943 +----------------- 15 files changed, 889 insertions(+), 981 deletions(-) delete mode 100644 apps/landing/src/app/homepage/_components/AnimatedGradientBorder.tsx create mode 100644 apps/landing/src/app/homepage/_components/ApiExampleSection.tsx create mode 100644 apps/landing/src/app/homepage/_components/BackgroundBlobs.tsx create mode 100644 apps/landing/src/app/homepage/_components/FinalCtaSection.tsx create mode 100644 apps/landing/src/app/homepage/_components/GeminiSection.tsx create mode 100644 apps/landing/src/app/homepage/_components/HeroGlow.tsx create mode 100644 apps/landing/src/app/homepage/_components/HeroSection.tsx create mode 100644 apps/landing/src/app/homepage/_components/HowItWorksSection.tsx create mode 100644 apps/landing/src/app/homepage/_components/IntegrationsSection.tsx create mode 100644 apps/landing/src/app/homepage/_components/KeyFeaturesSection.tsx create mode 100644 apps/landing/src/app/homepage/_components/ProblemSolutionSection.tsx create mode 100644 apps/landing/src/app/homepage/_components/PromptUrlsSection.tsx create mode 100644 apps/landing/src/app/homepage/_components/ShapeTheFutureSection.tsx create mode 100644 apps/landing/src/app/homepage/_components/index.ts diff --git a/apps/landing/src/app/homepage/_components/AnimatedGradientBorder.tsx b/apps/landing/src/app/homepage/_components/AnimatedGradientBorder.tsx deleted file mode 100644 index 3a9e12d..0000000 --- a/apps/landing/src/app/homepage/_components/AnimatedGradientBorder.tsx +++ /dev/null @@ -1,55 +0,0 @@ -interface AnimatedGradientBorderProps { - children: React.ReactNode; - className?: string; -} - -const gradientStyle: React.CSSProperties = { - background: `conic-gradient( - from 0deg, - rgba(99, 102, 241, 0.3), - rgba(139, 92, 246, 0.8), - rgba(236, 72, 153, 0.6), - rgba(34, 211, 238, 0.8), - rgba(99, 102, 241, 0.3) - )`, - filter: 'blur(40px)', -}; - -const glowStyle: React.CSSProperties = { - background: `conic-gradient( - from 0deg, - rgba(99, 102, 241, 0.1), - rgba(139, 92, 246, 0.4), - rgba(236, 72, 153, 0.3), - rgba(34, 211, 238, 0.4), - rgba(99, 102, 241, 0.1) - )`, - filter: 'blur(15px)', -}; - -export const AnimatedGradientBorder = ({ - children, - className = '', -}: AnimatedGradientBorderProps) => { - return ( -
-
-
-
-
-
{children}
-
- ); -}; diff --git a/apps/landing/src/app/homepage/_components/ApiExampleSection.tsx b/apps/landing/src/app/homepage/_components/ApiExampleSection.tsx new file mode 100644 index 0000000..5610299 --- /dev/null +++ b/apps/landing/src/app/homepage/_components/ApiExampleSection.tsx @@ -0,0 +1,64 @@ +'use client'; + +import { Terminal } from 'lucide-react'; + +export function ApiExampleSection() { + return ( +
+
+
+
+
+ +
+
+

One request. Production-ready URL.

+

Simple REST API that handles everything

+
+
+ +
+
# Generate an image
+ curl{' '} + -X POST https://api.banatie.app/v1/generate \ +
+ -H{' '} + "Authorization: Bearer $API_KEY"{' '} + \ +
+ -d{' '} + + '{`{"prompt": "modern office interior, natural light"}`}' + +
+ +
+
# Response
+ {'{'} +
+ "url" + :{' '} + + "https://cdn.banatie.app/img/a7x2k9.png" + + , +
+ "enhanced_prompt" + :{' '} + "A photorealistic modern office..." + , +
+ "generation_time" + : 12.4 +
+ {'}'} +
+ +

+ CDN-cached, optimized, ready to use. No download, no upload, no extra steps. +

+
+
+
+ ); +} diff --git a/apps/landing/src/app/homepage/_components/BackgroundBlobs.tsx b/apps/landing/src/app/homepage/_components/BackgroundBlobs.tsx new file mode 100644 index 0000000..0232f00 --- /dev/null +++ b/apps/landing/src/app/homepage/_components/BackgroundBlobs.tsx @@ -0,0 +1,42 @@ +'use client'; + +const blobs = [ + { + className: 'w-[600px] h-[600px] top-[-200px] right-[-100px]', + gradient: 'rgba(139, 92, 246, 0.3)', + }, + { + className: 'w-[500px] h-[500px] top-[800px] left-[-150px]', + gradient: 'rgba(99, 102, 241, 0.25)', + }, + { + className: 'w-[400px] h-[400px] top-[1600px] right-[-100px]', + gradient: 'rgba(236, 72, 153, 0.2)', + }, + { + className: 'w-[550px] h-[550px] top-[2400px] left-[-200px]', + gradient: 'rgba(34, 211, 238, 0.15)', + }, + { + className: 'w-[450px] h-[450px] top-[3200px] right-[-150px]', + gradient: 'rgba(139, 92, 246, 0.25)', + }, + { + className: 'w-[500px] h-[500px] top-[4000px] left-[-100px]', + gradient: 'rgba(99, 102, 241, 0.2)', + }, +]; + +export function BackgroundBlobs() { + return ( + <> + {blobs.map((blob, i) => ( +
+ ))} + + ); +} diff --git a/apps/landing/src/app/homepage/_components/FinalCtaSection.tsx b/apps/landing/src/app/homepage/_components/FinalCtaSection.tsx new file mode 100644 index 0000000..e8fd5b9 --- /dev/null +++ b/apps/landing/src/app/homepage/_components/FinalCtaSection.tsx @@ -0,0 +1,60 @@ +'use client'; + +import { ArrowRight } from 'lucide-react'; + +export function FinalCtaSection() { + const scrollToTop = () => { + window.scrollTo({ top: 0, behavior: 'smooth' }); + setTimeout(() => { + const input = document.querySelector('input[type="email"]') as HTMLInputElement; + input?.focus(); + }, 500); + }; + + return ( +
+
+ +
+ +
+

+ Ready to build? +

+

+ Join developers waiting for early access. We'll notify you when your spot is ready. +

+ + + +

+ No credit card required • Free to start • Cancel anytime +

+
+
+ ); +} diff --git a/apps/landing/src/app/homepage/_components/GeminiSection.tsx b/apps/landing/src/app/homepage/_components/GeminiSection.tsx new file mode 100644 index 0000000..f313c46 --- /dev/null +++ b/apps/landing/src/app/homepage/_components/GeminiSection.tsx @@ -0,0 +1,143 @@ +'use client'; + +import { Zap, Check, Crown, Type, Brain, Target, Image, Award } from 'lucide-react'; + +const flashFeatures = [ + { text: 'Sub-3 second', detail: 'generation time' }, + { text: 'Multi-turn editing', detail: '— refine through conversation' }, + { text: 'Up to 3 reference images', detail: 'for consistency' }, + { text: '1024px', detail: 'resolution output' }, +]; + +const proFeatures = [ + { text: 'Up to 4K', detail: 'resolution output' }, + { text: '14 reference images', detail: 'for brand consistency' }, + { text: 'Studio controls', detail: '— lighting, focus, color grading' }, + { text: 'Thinking mode', detail: '— advanced reasoning for complex prompts' }, +]; + +const capabilities = [ + { + icon: Type, + title: 'Perfect Text Rendering', + description: + 'Legible text in images — logos, diagrams, posters. What other models still struggle with.', + }, + { + icon: Brain, + title: 'Native Multimodal', + description: + 'Understands text AND images in one model. Not a text model + image model bolted together.', + }, + { + icon: Target, + title: 'Precise Prompt Following', + description: + 'What you ask is what you get. No artistic "interpretation" that ignores your instructions.', + }, + { + icon: Image, + title: 'Professional Realism', + description: + 'Photorealistic output that replaces stock photos. Not fantasy art — real, usable images.', + }, +]; + +export function GeminiSection() { + return ( +
+
+
+
+
+ +

Powered by Google Gemini

+
+

+ We chose Gemini because it's the only model family that combines native + multimodal understanding with production-grade image generation. Two models, optimized + for different needs. +

+
+ +
+
+
+
+ +
+
+

Gemini 2.5 Flash Image

+

Nano Banana

+
+
+

+ Optimized for speed and iteration. Perfect for rapid prototyping and high-volume + generation. +

+
    + {flashFeatures.map((feature, i) => ( +
  • + + + {feature.text} {feature.detail} + +
  • + ))} +
+
+ +
+
+
+ +
+
+

Gemini 3 Pro Image

+

Nano Banana Pro

+
+
+

+ Maximum quality and creative control. For production assets and professional + workflows. +

+
    + {proFeatures.map((feature, i) => ( +
  • + + + {feature.text} {feature.detail} + +
  • + ))} +
+
+
+ +
+

+ Why Gemini outperforms competitors +

+
+ {capabilities.map((cap, i) => ( +
+
+ +
+
{cap.title}
+

{cap.description}

+
+ ))} +
+
+ +

+ + Gemini 2.5 Flash Image ranked #1 on LMArena for both text-to-image and image editing + (August 2025) +

+
+
+
+ ); +} diff --git a/apps/landing/src/app/homepage/_components/HeroGlow.tsx b/apps/landing/src/app/homepage/_components/HeroGlow.tsx new file mode 100644 index 0000000..9770b01 --- /dev/null +++ b/apps/landing/src/app/homepage/_components/HeroGlow.tsx @@ -0,0 +1,13 @@ +'use client'; + +export function HeroGlow() { + return ( +
+ ); +} diff --git a/apps/landing/src/app/homepage/_components/HeroSection.tsx b/apps/landing/src/app/homepage/_components/HeroSection.tsx new file mode 100644 index 0000000..e5e6ac3 --- /dev/null +++ b/apps/landing/src/app/homepage/_components/HeroSection.tsx @@ -0,0 +1,118 @@ +'use client'; + +import { useState } from 'react'; +import { Zap, Globe, FlaskConical, AtSign, Link } from 'lucide-react'; +import GlowEffect from './GlowEffect'; + +export const styles = ` + .gradient-text { + background: linear-gradient(90deg, #818cf8 0%, #c084fc 25%, #f472b6 50%, #c084fc 75%, #818cf8 100%); + background-size: 200% 100%; + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + animation: gradient-shift 6s ease-in-out infinite; + } + + @keyframes gradient-shift { + 0% { background-position: 100% 50%; } + 50% { background-position: 0% 50%; } + 100% { background-position: 100% 50%; } + } + + .beta-dot { + animation: beta-dot-delay 20s linear forwards, beta-dot-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) 20s infinite; + } + + @keyframes beta-dot-delay { + 0%, 99% { background-color: rgb(107, 114, 128); } + 100% { background-color: rgb(74, 222, 128); } + } + + @keyframes beta-dot-pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.5; } + } +`; + +const badges = [ + { icon: Zap, text: 'API-First', variant: 'default' }, + { icon: Globe, text: 'Built-in CDN', variant: 'default' }, + { icon: FlaskConical, text: 'Web Lab', variant: 'default' }, + { icon: AtSign, text: 'Style References', variant: 'default' }, + { icon: Link, text: 'Prompt URLs', variant: 'cyan' }, +]; + +export function HeroSection() { + const [email, setEmail] = useState(''); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + console.log('Email submitted:', email); + }; + + return ( +
+
+
+ + In Active Development +
+ +

+ AI Image Generation +
+ Inside Your Workflow +

+ +

+ Generate images via API, SDK, CLI, Lab, or live URLs. +
+ Production-ready CDN delivery in seconds. +

+ + +
+ setEmail(e.target.value)} + placeholder="your@email.com" + className="flex-1 px-4 py-3 bg-transparent border-none rounded-md text-white outline-none placeholder:text-white/40 focus:bg-white/[0.03]" + /> + +
+
+ +

Free early access. No credit card required.

+ +
+ {badges.map((badge, i) => ( + + + {badge.text} + + ))} +
+
+
+ ); +} diff --git a/apps/landing/src/app/homepage/_components/HowItWorksSection.tsx b/apps/landing/src/app/homepage/_components/HowItWorksSection.tsx new file mode 100644 index 0000000..6ad0dcc --- /dev/null +++ b/apps/landing/src/app/homepage/_components/HowItWorksSection.tsx @@ -0,0 +1,67 @@ +'use client'; + +import { Settings2, Check, Info } from 'lucide-react'; + +const steps = [ + { number: 1, title: 'Your Prompt', subtitle: '"a cat on windowsill"' }, + { number: 2, title: 'Smart Enhancement', subtitle: 'Style + details added' }, + { number: 3, title: 'AI Generation', subtitle: 'Gemini creates image' }, + { number: 4, title: 'CDN Delivery', subtitle: 'Instant global URL' }, +]; + +const controls = [ + { text: 'Style templates', detail: '— photorealistic, illustration, minimalist, and more' }, + { text: 'Reference images', detail: '— @aliases maintain visual consistency' }, + { text: 'Output specs', detail: '— aspect ratio, dimensions, format' }, +]; + +export function HowItWorksSection() { + return ( +
+
+

+ Your prompt. Your control. Production-ready. +

+

+ We handle the complexity so you can focus on building. +

+ +
+
+ {steps.map((step) => ( +
+
+ {step.number} +
+

{step.title}

+

{step.subtitle}

+
+ ))} +
+ +
+

+ + What you control +

+
+ {controls.map((control, i) => ( +
+ + + {control.text} {control.detail} + +
+ ))} +
+
+ +

+ + Enhanced prompts are visible in API response. You always see what was generated. +

+
+
+
+ ); +} diff --git a/apps/landing/src/app/homepage/_components/IntegrationsSection.tsx b/apps/landing/src/app/homepage/_components/IntegrationsSection.tsx new file mode 100644 index 0000000..27c2d7e --- /dev/null +++ b/apps/landing/src/app/homepage/_components/IntegrationsSection.tsx @@ -0,0 +1,51 @@ +'use client'; + +import { Server, Code, Cpu, Terminal, FlaskConical, Link2 } from 'lucide-react'; + +const tools = [ + { icon: Server, text: 'REST API', color: 'text-cyan-400' }, + { icon: Code, text: 'TypeScript SDK', color: 'text-blue-400' }, + { icon: Cpu, text: 'MCP Server', color: 'text-purple-400' }, + { icon: Terminal, text: 'CLI', color: 'text-green-400' }, + { icon: FlaskConical, text: 'Banatie Lab', color: 'text-orange-400' }, + { icon: Link2, text: 'Prompt URLs', color: 'text-cyan-400', highlight: true }, +]; + +export function IntegrationsSection() { + return ( +
+
+

Works with your tools

+

+ Use what fits your workflow. All methods, same capabilities. +

+ +
+ {tools.map((tool, i) => ( +
+ + {tool.text} +
+ ))} +
+ +
+

+ Banatie Lab — Official web interface for Banatie + API. Generate images, build flows, browse your gallery, and explore all capabilities + with ready-to-use code snippets. +

+
+ +

+ Perfect for Claude Code, Cursor, and any AI-powered workflow. +

+
+
+ ); +} diff --git a/apps/landing/src/app/homepage/_components/KeyFeaturesSection.tsx b/apps/landing/src/app/homepage/_components/KeyFeaturesSection.tsx new file mode 100644 index 0000000..3d01848 --- /dev/null +++ b/apps/landing/src/app/homepage/_components/KeyFeaturesSection.tsx @@ -0,0 +1,95 @@ +'use client'; + +import { AtSign, GitBranch, Palette, Globe, SlidersHorizontal, Link } from 'lucide-react'; + +const features = [ + { + icon: AtSign, + iconColor: 'text-pink-400', + title: 'Reference Images', + description: + 'Use @aliases to maintain style consistency across your project. Reference up to 3 images per generation.', + isUnique: false, + }, + { + icon: GitBranch, + iconColor: 'text-purple-400', + title: 'Flows', + description: + 'Chain generations, iterate on results, build image sequences with @last and @first references.', + isUnique: false, + }, + { + icon: Palette, + iconColor: 'text-yellow-400', + title: '7 Style Templates', + description: + 'Same prompt, different styles. Photorealistic, illustration, minimalist, product, comic, sticker, and more.', + isUnique: false, + }, + { + icon: Globe, + iconColor: 'text-green-400', + title: 'Instant CDN Delivery', + description: + 'Every image gets production-ready URL. No upload, no optimization, no hosting setup needed.', + isUnique: false, + }, + { + icon: SlidersHorizontal, + iconColor: 'text-blue-400', + title: 'Output Control', + description: + 'Control aspect ratio, dimensions, and format. From square thumbnails to ultra-wide banners.', + isUnique: false, + }, + { + icon: Link, + iconColor: 'text-cyan-400', + title: 'Prompt URLs', + description: + 'Generate images via URL parameters. Put prompt in img src, get real image. Built-in caching.', + isUnique: true, + }, +]; + +export function KeyFeaturesSection() { + return ( +
+
+

+ Built for real development workflows +

+

+ Everything you need to integrate AI images into your projects. +

+ +
+ {features.map((feature, i) => ( +
+
+ +
+
+

{feature.title}

+ {feature.isUnique && ( + + Unique + + )} +
+

{feature.description}

+
+ ))} +
+
+
+ ); +} diff --git a/apps/landing/src/app/homepage/_components/ProblemSolutionSection.tsx b/apps/landing/src/app/homepage/_components/ProblemSolutionSection.tsx new file mode 100644 index 0000000..3e22697 --- /dev/null +++ b/apps/landing/src/app/homepage/_components/ProblemSolutionSection.tsx @@ -0,0 +1,66 @@ +'use client'; + +import { RefreshCw, ArrowLeftRight, Package, Layers, Check } from 'lucide-react'; + +const problems = [ + { + icon: RefreshCw, + title: 'Placeholder hell', + problem: '"I\'ll add images later" never happens', + solution: 'Generate real images as you build', + }, + { + icon: ArrowLeftRight, + title: 'Context switching', + problem: 'Leave IDE, generate elsewhere, come back', + solution: 'Stay in your workflow. API, SDK, MCP', + }, + { + icon: Package, + title: 'Asset management', + problem: 'Download, optimize, upload, get URL', + solution: 'Production CDN URLs instantly', + }, + { + icon: Layers, + title: 'Style drift', + problem: 'Every image looks different', + solution: 'Reference images keep style consistent', + }, +]; + +export function ProblemSolutionSection() { + return ( +
+
+

+ Why developers choose Banatie +

+

+ Stop fighting your image workflow. Start building. +

+ +
+ {problems.map((item, i) => ( +
+
+
+ +
+

{item.title}

+

{item.problem}

+
+ + {item.solution} +
+
+
+ ))} +
+
+
+ ); +} diff --git a/apps/landing/src/app/homepage/_components/PromptUrlsSection.tsx b/apps/landing/src/app/homepage/_components/PromptUrlsSection.tsx new file mode 100644 index 0000000..a121498 --- /dev/null +++ b/apps/landing/src/app/homepage/_components/PromptUrlsSection.tsx @@ -0,0 +1,50 @@ +'use client'; + +import { Sparkles } from 'lucide-react'; + +export function PromptUrlsSection() { + return ( +
+
+
+
+
+ +
+
+ + Unique + +

Prompt URLs — Images via HTML

+

+ Put a prompt in your{' '} + img src and get a + real image. No API calls. No JavaScript. Just HTML. +

+
+
+ +
+ <!-- Write this --> +
+ <img{' '} + src= + + "https://cdn.banatie.app/gen?p=modern office interior" + {' '} + /> +
+
+ + <!-- Get this: production-ready image, cached, CDN-delivered --> + +
+ +

+ Perfect for static sites, prototypes, and AI coding agents that generate HTML. +

+
+
+
+ ); +} diff --git a/apps/landing/src/app/homepage/_components/ShapeTheFutureSection.tsx b/apps/landing/src/app/homepage/_components/ShapeTheFutureSection.tsx new file mode 100644 index 0000000..2f6be07 --- /dev/null +++ b/apps/landing/src/app/homepage/_components/ShapeTheFutureSection.tsx @@ -0,0 +1,91 @@ +'use client'; + +import { MessageCircle, Vote, Users } from 'lucide-react'; + +const ZIGZAG_POINTS = [ + 40, 0, 20, 10, 30, 50, 20, 15, 0, 20, 25, 50, 10, 20, 0, 15, 10, 25, 20, 50, 0, 20, 40, 20, 25, + 10, 0, 15, 0, 20, 0, 40, 10, 0, +]; + +function generateZigzagClipPath(yValues: number[]): string { + const lastIndex = yValues.length - 1; + const getX = (i: number) => `${(i / lastIndex) * 100}%`; + + const topEdge = yValues.map((y, i) => `${getX(i)} ${y}px`).join(', '); + const bottomEdge = [...yValues] + .map((y, i) => [getX(i), y] as const) + .reverse() + .map(([x, y]) => `${x} calc(100% - 50px + ${y}px)`) + .join(', '); + + return `polygon(${topEdge}, ${bottomEdge})`; +} + +export const styles = ` + .shape-future { + clip-path: ${generateZigzagClipPath(ZIGZAG_POINTS)}; + } + + .metal-texture { + position: relative; + overflow: hidden; + } + + .metal-texture::before { + content: ''; + position: absolute; + inset: 0; + background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 300 300' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E"); + opacity: 0.5; + mix-blend-mode: multiply; + pointer-events: none; + z-index: 10; + } + + .shape-future-title { + font-family: 'Caveat', cursive; + } +`; + +const features = [ + { icon: MessageCircle, text: 'Direct feedback channel' }, + { icon: Vote, text: 'Feature voting' }, + { icon: Users, text: 'Early adopter community' }, +]; + +export function ShapeTheFutureSection() { + return ( +
+
+
+
+
+
+
+
+
+
+
+

+ Shape the future of Banatie +

+ +

+ We're building this for developers like you. Early adopters get direct influence on + our roadmap — suggest features, vote on priorities, and help us build exactly what you + need. +

+ +
+ {features.map((feature, i) => ( + + + {feature.text} + + ))} +
+
+
+
+ ); +} diff --git a/apps/landing/src/app/homepage/_components/index.ts b/apps/landing/src/app/homepage/_components/index.ts new file mode 100644 index 0000000..8ca95d6 --- /dev/null +++ b/apps/landing/src/app/homepage/_components/index.ts @@ -0,0 +1,12 @@ +export { BackgroundBlobs } from './BackgroundBlobs'; +export { HeroGlow } from './HeroGlow'; +export { HeroSection, styles as heroStyles } from './HeroSection'; +export { ApiExampleSection } from './ApiExampleSection'; +export { ProblemSolutionSection } from './ProblemSolutionSection'; +export { PromptUrlsSection } from './PromptUrlsSection'; +export { HowItWorksSection } from './HowItWorksSection'; +export { KeyFeaturesSection } from './KeyFeaturesSection'; +export { IntegrationsSection } from './IntegrationsSection'; +export { ShapeTheFutureSection, styles as shapeFutureStyles } from './ShapeTheFutureSection'; +export { GeminiSection } from './GeminiSection'; +export { FinalCtaSection } from './FinalCtaSection'; diff --git a/apps/landing/src/app/homepage/page.tsx b/apps/landing/src/app/homepage/page.tsx index 3fe196d..d05e4a8 100644 --- a/apps/landing/src/app/homepage/page.tsx +++ b/apps/landing/src/app/homepage/page.tsx @@ -1,939 +1,30 @@ 'use client'; -import { useState } from 'react'; -import { AnimatedGradientBorder } from './_components/AnimatedGradientBorder'; import { - Zap, - Globe, - FlaskConical, - AtSign, - Link, - Terminal, - RefreshCw, - ArrowLeftRight, - Package, - Layers, - Check, - Sparkles, - Settings2, - Info, - GitBranch, - Palette, - SlidersHorizontal, - Link2, - Server, - Code, - Cpu, - MessageCircle, - Vote, - Users, - Crown, - Type, - Brain, - Target, - Image, - Award, - ArrowRight, -} from 'lucide-react'; -import GlowEffect from './_components/GlowEffect'; - -// ============================================================================ -// UTILS -// ============================================================================ - -const ZIGZAG_POINTS = [ - 40, 0, 20, 10, 30, 50, 20, 15, 0, 20, 25, 50, 10, 20, 0, 15, 10, 25, 20, 50, 0, 20, 40, 20, 25, - 10, 0, 15, 0, 20, 0, 40, 10, 0, -]; - -function generateZigzagClipPath(yValues: number[]): string { - const lastIndex = yValues.length - 1; - const getX = (i: number) => `${(i / lastIndex) * 100}%`; - - const topEdge = yValues.map((y, i) => `${getX(i)} ${y}px`).join(', '); - const bottomEdge = [...yValues] - .map((y, i) => [getX(i), y] as const) - .reverse() - .map(([x, y]) => `${x} calc(100% - 50px + ${y}px)`) - .join(', '); - - return `polygon(${topEdge}, ${bottomEdge})`; -} - -// ============================================================================ -// STYLES (CSS-in-JS for custom styles not available in Tailwind) -// ============================================================================ + BackgroundBlobs, + HeroGlow, + HeroSection, + heroStyles, + ApiExampleSection, + ProblemSolutionSection, + PromptUrlsSection, + HowItWorksSection, + KeyFeaturesSection, + IntegrationsSection, + ShapeTheFutureSection, + shapeFutureStyles, + GeminiSection, + FinalCtaSection, +} from './_components'; const customStyles = ` @import url('https://fonts.googleapis.com/css2?family=Caveat:wght@500;600;700&display=swap'); - .gradient-text { - background: linear-gradient(90deg, #818cf8 0%, #c084fc 25%, #f472b6 50%, #c084fc 75%, #818cf8 100%); - background-size: 200% 100%; - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - animation: gradient-shift 6s ease-in-out infinite; - } + ${heroStyles} - @keyframes gradient-shift { - 0% { background-position: 100% 50%; } - 50% { background-position: 0% 50%; } - 100% { background-position: 100% 50%; } - } - - .beta-dot { - animation: beta-dot-delay 20s linear forwards, beta-dot-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) 20s infinite; - } - - @keyframes beta-dot-delay { - 0%, 99% { background-color: rgb(107, 114, 128); } - 100% { background-color: rgb(74, 222, 128); } - } - - @keyframes beta-dot-pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.5; } - } - - .shape-future { - clip-path: ${generateZigzagClipPath(ZIGZAG_POINTS)}; - } - - .metal-texture { - position: relative; - overflow: hidden; - } - - .metal-texture::before { - content: ''; - position: absolute; - inset: 0; - background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 300 300' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E"); - opacity: 0.3; - mix-blend-mode: overlay; - pointer-events: none; - z-index: 3; - } - - .shape-future-title { - font-family: 'Caveat', cursive; - } + ${shapeFutureStyles} `; -// ============================================================================ -// BACKGROUND COMPONENTS -// ============================================================================ - -function BackgroundBlobs() { - const blobs = [ - { - className: 'w-[600px] h-[600px] top-[-200px] right-[-100px]', - gradient: 'rgba(139, 92, 246, 0.3)', - }, - { - className: 'w-[500px] h-[500px] top-[800px] left-[-150px]', - gradient: 'rgba(99, 102, 241, 0.25)', - }, - { - className: 'w-[400px] h-[400px] top-[1600px] right-[-100px]', - gradient: 'rgba(236, 72, 153, 0.2)', - }, - { - className: 'w-[550px] h-[550px] top-[2400px] left-[-200px]', - gradient: 'rgba(34, 211, 238, 0.15)', - }, - { - className: 'w-[450px] h-[450px] top-[3200px] right-[-150px]', - gradient: 'rgba(139, 92, 246, 0.25)', - }, - { - className: 'w-[500px] h-[500px] top-[4000px] left-[-100px]', - gradient: 'rgba(99, 102, 241, 0.2)', - }, - ]; - - return ( - <> - {blobs.map((blob, i) => ( -
- ))} - - ); -} - -function HeroGlow() { - return ( -
- ); -} - -// ============================================================================ -// HERO SECTION -// ============================================================================ - -function HeroSection() { - const [email, setEmail] = useState(''); - - const handleSubmit = (e: React.FormEvent) => { - e.preventDefault(); - // TODO: Handle form submission - console.log('Email submitted:', email); - }; - - const badges = [ - { icon: Zap, text: 'API-First', variant: 'default' }, - { icon: Globe, text: 'Built-in CDN', variant: 'default' }, - { icon: FlaskConical, text: 'Web Lab', variant: 'default' }, - { icon: AtSign, text: 'Style References', variant: 'default' }, - { icon: Link, text: 'Prompt URLs', variant: 'cyan' }, - ]; - - return ( -
-
- {/* Status Badge */} -
- - In Active Development -
- - {/* Headline */} -

- AI Image Generation -
- Inside Your Workflow -

- - {/* Subheadline */} -

- Generate images via API, SDK, CLI, Lab, or live URLs. -
- Production-ready CDN delivery in seconds. -

- - {/* Email Form */} - -
- setEmail(e.target.value)} - placeholder="your@email.com" - className="flex-1 px-4 py-3 bg-transparent border-none rounded-md text-white outline-none placeholder:text-white/40 focus:bg-white/[0.03]" - /> - -
-
- -

Free early access. No credit card required.

- - {/* Badges */} -
- {badges.map((badge, i) => ( - - - {badge.text} - - ))} -
-
-
- ); -} - -// ============================================================================ -// API EXAMPLE SECTION -// ============================================================================ - -function ApiExampleSection() { - return ( -
-
-
-
-
- -
-
-

One request. Production-ready URL.

-

Simple REST API that handles everything

-
-
- -
-
# Generate an image
- curl{' '} - -X POST https://api.banatie.app/v1/generate \ -
- -H{' '} - "Authorization: Bearer $API_KEY"{' '} - \ -
- -d{' '} - - '{`{"prompt": "modern office interior, natural light"}`}' - -
- -
-
# Response
- {'{'} -
- "url" - :{' '} - - "https://cdn.banatie.app/img/a7x2k9.png" - - , -
- "enhanced_prompt" - :{' '} - "A photorealistic modern office..." - , -
- "generation_time" - : 12.4 -
- {'}'} -
- -

- CDN-cached, optimized, ready to use. No download, no upload, no extra steps. -

-
-
-
- ); -} - -// ============================================================================ -// PROBLEM/SOLUTION SECTION -// ============================================================================ - -function ProblemSolutionSection() { - const problems = [ - { - icon: RefreshCw, - title: 'Placeholder hell', - problem: '"I\'ll add images later" never happens', - solution: 'Generate real images as you build', - }, - { - icon: ArrowLeftRight, - title: 'Context switching', - problem: 'Leave IDE, generate elsewhere, come back', - solution: 'Stay in your workflow. API, SDK, MCP', - }, - { - icon: Package, - title: 'Asset management', - problem: 'Download, optimize, upload, get URL', - solution: 'Production CDN URLs instantly', - }, - { - icon: Layers, - title: 'Style drift', - problem: 'Every image looks different', - solution: 'Reference images keep style consistent', - }, - ]; - - return ( -
-
-

- Why developers choose Banatie -

-

- Stop fighting your image workflow. Start building. -

- -
- {problems.map((item, i) => ( -
-
-
- -
-

{item.title}

-

{item.problem}

-
- - {item.solution} -
-
-
- ))} -
-
-
- ); -} - -// ============================================================================ -// PROMPT URLs SECTION -// ============================================================================ - -function PromptUrlsSection() { - return ( -
-
-
-
-
- -
-
- - Unique - -

Prompt URLs — Images via HTML

-

- Put a prompt in your{' '} - img src and get a - real image. No API calls. No JavaScript. Just HTML. -

-
-
- -
- <!-- Write this --> -
- <img{' '} - src= - - "https://cdn.banatie.app/gen?p=modern office interior" - {' '} - /> -
-
- - <!-- Get this: production-ready image, cached, CDN-delivered --> - -
- -

- Perfect for static sites, prototypes, and AI coding agents that generate HTML. -

-
-
-
- ); -} - -// ============================================================================ -// HOW IT WORKS SECTION -// ============================================================================ - -function HowItWorksSection() { - const steps = [ - { number: 1, title: 'Your Prompt', subtitle: '"a cat on windowsill"' }, - { number: 2, title: 'Smart Enhancement', subtitle: 'Style + details added' }, - { number: 3, title: 'AI Generation', subtitle: 'Gemini creates image' }, - { number: 4, title: 'CDN Delivery', subtitle: 'Instant global URL' }, - ]; - - const controls = [ - { text: 'Style templates', detail: '— photorealistic, illustration, minimalist, and more' }, - { text: 'Reference images', detail: '— @aliases maintain visual consistency' }, - { text: 'Output specs', detail: '— aspect ratio, dimensions, format' }, - ]; - - return ( -
-
-

- Your prompt. Your control. Production-ready. -

-

- We handle the complexity so you can focus on building. -

- -
-
- {steps.map((step) => ( -
-
- {step.number} -
-

{step.title}

-

{step.subtitle}

-
- ))} -
- -
-

- - What you control -

-
- {controls.map((control, i) => ( -
- - - {control.text} {control.detail} - -
- ))} -
-
- -

- - Enhanced prompts are visible in API response. You always see what was generated. -

-
-
-
- ); -} - -// ============================================================================ -// KEY FEATURES SECTION -// ============================================================================ - -function KeyFeaturesSection() { - const features = [ - { - icon: AtSign, - iconColor: 'text-pink-400', - title: 'Reference Images', - description: - 'Use @aliases to maintain style consistency across your project. Reference up to 3 images per generation.', - isUnique: false, - }, - { - icon: GitBranch, - iconColor: 'text-purple-400', - title: 'Flows', - description: - 'Chain generations, iterate on results, build image sequences with @last and @first references.', - isUnique: false, - }, - { - icon: Palette, - iconColor: 'text-yellow-400', - title: '7 Style Templates', - description: - 'Same prompt, different styles. Photorealistic, illustration, minimalist, product, comic, sticker, and more.', - isUnique: false, - }, - { - icon: Globe, - iconColor: 'text-green-400', - title: 'Instant CDN Delivery', - description: - 'Every image gets production-ready URL. No upload, no optimization, no hosting setup needed.', - isUnique: false, - }, - { - icon: SlidersHorizontal, - iconColor: 'text-blue-400', - title: 'Output Control', - description: - 'Control aspect ratio, dimensions, and format. From square thumbnails to ultra-wide banners.', - isUnique: false, - }, - { - icon: Link, - iconColor: 'text-cyan-400', - title: 'Prompt URLs', - description: - 'Generate images via URL parameters. Put prompt in img src, get real image. Built-in caching.', - isUnique: true, - }, - ]; - - return ( -
-
-

- Built for real development workflows -

-

- Everything you need to integrate AI images into your projects. -

- -
- {features.map((feature, i) => ( -
-
- -
-
-

{feature.title}

- {feature.isUnique && ( - - Unique - - )} -
-

{feature.description}

-
- ))} -
-
-
- ); -} - -// ============================================================================ -// INTEGRATIONS SECTION -// ============================================================================ - -function IntegrationsSection() { - const tools = [ - { icon: Server, text: 'REST API', color: 'text-cyan-400' }, - { icon: Code, text: 'TypeScript SDK', color: 'text-blue-400' }, - { icon: Cpu, text: 'MCP Server', color: 'text-purple-400' }, - { icon: Terminal, text: 'CLI', color: 'text-green-400' }, - { icon: FlaskConical, text: 'Banatie Lab', color: 'text-orange-400' }, - { icon: Link2, text: 'Prompt URLs', color: 'text-cyan-400', highlight: true }, - ]; - - return ( -
-
-

Works with your tools

-

- Use what fits your workflow. All methods, same capabilities. -

- -
- {tools.map((tool, i) => ( -
- - {tool.text} -
- ))} -
- -
-

- Banatie Lab — Official web interface for Banatie - API. Generate images, build flows, browse your gallery, and explore all capabilities - with ready-to-use code snippets. -

-
- -

- Perfect for Claude Code, Cursor, and any AI-powered workflow. -

-
-
- ); -} - -// ============================================================================ -// SHAPE THE FUTURE SECTION -// ============================================================================ - -function ShapeTheFutureSection() { - const features = [ - { icon: MessageCircle, text: 'Direct feedback channel' }, - { icon: Vote, text: 'Feature voting' }, - { icon: Users, text: 'Early adopter community' }, - ]; - - return ( -
-
-
-
-
-
-
-
-
-
-
-

- Shape the future of Banatie -

- -

- We're building this for developers like you. Early adopters get direct influence on - our roadmap — suggest features, vote on priorities, and help us build exactly what you - need. -

- -
- {features.map((feature, i) => ( - - - {feature.text} - - ))} -
-
-
-
- ); -} - -// ============================================================================ -// GEMINI SECTION -// ============================================================================ - -function GeminiSection() { - const flashFeatures = [ - { text: 'Sub-3 second', detail: 'generation time' }, - { text: 'Multi-turn editing', detail: '— refine through conversation' }, - { text: 'Up to 3 reference images', detail: 'for consistency' }, - { text: '1024px', detail: 'resolution output' }, - ]; - - const proFeatures = [ - { text: 'Up to 4K', detail: 'resolution output' }, - { text: '14 reference images', detail: 'for brand consistency' }, - { text: 'Studio controls', detail: '— lighting, focus, color grading' }, - { text: 'Thinking mode', detail: '— advanced reasoning for complex prompts' }, - ]; - - const capabilities = [ - { - icon: Type, - title: 'Perfect Text Rendering', - description: - 'Legible text in images — logos, diagrams, posters. What other models still struggle with.', - }, - { - icon: Brain, - title: 'Native Multimodal', - description: - 'Understands text AND images in one model. Not a text model + image model bolted together.', - }, - { - icon: Target, - title: 'Precise Prompt Following', - description: - 'What you ask is what you get. No artistic "interpretation" that ignores your instructions.', - }, - { - icon: Image, - title: 'Professional Realism', - description: - 'Photorealistic output that replaces stock photos. Not fantasy art — real, usable images.', - }, - ]; - - return ( -
-
-
- {/* Header */} -
-
- -

Powered by Google Gemini

-
-

- We chose Gemini because it's the only model family that combines native - multimodal understanding with production-grade image generation. Two models, optimized - for different needs. -

-
- - {/* Two Model Cards */} -
- {/* Flash Model */} -
-
-
- -
-
-

Gemini 2.5 Flash Image

-

Nano Banana

-
-
-

- Optimized for speed and iteration. Perfect for rapid prototyping and high-volume - generation. -

-
    - {flashFeatures.map((feature, i) => ( -
  • - - - {feature.text} {feature.detail} - -
  • - ))} -
-
- - {/* Pro Model */} -
-
-
- -
-
-

Gemini 3 Pro Image

-

Nano Banana Pro

-
-
-

- Maximum quality and creative control. For production assets and professional - workflows. -

-
    - {proFeatures.map((feature, i) => ( -
  • - - - {feature.text} {feature.detail} - -
  • - ))} -
-
-
- - {/* Shared Capabilities */} -
-

- Why Gemini outperforms competitors -

-
- {capabilities.map((cap, i) => ( -
-
- -
-
{cap.title}
-

{cap.description}

-
- ))} -
-
- - {/* #1 Ranking Note */} -

- - Gemini 2.5 Flash Image ranked #1 on LMArena for both text-to-image and image editing - (August 2025) -

-
-
-
- ); -} - -// ============================================================================ -// FINAL CTA SECTION -// ============================================================================ - -function FinalCtaSection() { - const scrollToTop = () => { - window.scrollTo({ top: 0, behavior: 'smooth' }); - // Focus on email input after scroll - setTimeout(() => { - const input = document.querySelector('input[type="email"]') as HTMLInputElement; - input?.focus(); - }, 500); - }; - - return ( -
- {/* Top accent line */} -
- - {/* Subtle cyan glow accents */} -
- -
-

- Ready to build? -

-

- Join developers waiting for early access. We'll notify you when your spot is ready. -

- - - -

- No credit card required • Free to start • Cancel anytime -

-
-
- ); -} - -// ============================================================================ -// MAIN HOME COMPONENT -// ============================================================================ - export default function Home() { return ( <>