'use client'; import Image from 'next/image'; import Link from 'next/link'; import { useEffect, useRef } from 'react'; import { gsap } from 'gsap'; import { Video, MoveRight, Play, Mic, PenTool, Keyboard, BellRing, FolderOpen, FileDown, History, Smartphone, Link as LinkIcon, CheckSquare, MessageSquare, Github, ArrowRight, XCircle, ArrowDown, CheckCircle, Upload, Share2, Check } from 'lucide-react'; interface LandingPageProps { isLoggedIn: boolean; } const controlButtonClass = 'group relative isolate inline-flex h-8 items-center justify-center overflow-hidden border border-border bg-background px-2.5 text-[11px] font-medium text-foreground transition-colors duration-300 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring sm:h-9 sm:px-4 sm:text-xs'; const coreWorkflowFeatures = [ { title: 'Version Compare', description: 'Compare any two versions side-by-side on a single timeline.', icon: History, }, { title: 'Asset Management', description: 'Keep images and supplementary videos grouped perfectly per cut.', icon: FolderOpen, }, { title: 'Version History', description: 'Infinite versioning. Toggle between V1 and V10 without losing where you are.', icon: History, }, { title: 'Approval Workflow', description: 'Assign specific team members or clients to review and sign off on a cut. Get an exact \"Approved\" status.', icon: CheckCircle, }, ]; const workflowAcceleratorFeatures = [ { title: 'Keyboard Shortcuts', description: 'J, K, L, Space, and M controls for professional editing workflows.', icon: Keyboard, }, { title: 'PDF/CSV Exports', description: 'Turn video comments into a professional feedback report in one click.', icon: FileDown, }, { title: 'Real-time Webhooks', description: 'Get instant Telegram or Slack alerts the second a comment is dropped.', icon: BellRing, }, { title: 'Mobile-Optimized Review', description: 'Touch-optimized player for clients reviewing cuts on the move.', icon: Smartphone, }, ]; export function LandingPage({ isLoggedIn }: LandingPageProps) { const rootRef = useRef(null); const navbarRef = useRef(null); const hostedCtaHref = isLoggedIn ? '/dashboard' : '/register'; useEffect(() => { const cleanupHandlers: Array<() => void> = []; const ctx = gsap.context(() => { // General Reveal Animations gsap.from('[data-hero-copy]', { y: 40, opacity: 0, duration: 1, stagger: 0.15, ease: 'power4.out', }); // Voice Notes Waveform Animation const waveformBars = gsap.utils.toArray('.voice-bar'); waveformBars.forEach((bar, index) => { gsap.set(bar, { transformOrigin: 'center bottom' }); gsap.to(bar, { scaleY: gsap.utils.random(0.3, 1.5), duration: gsap.utils.random(0.4, 0.8), repeat: -1, yoyo: true, delay: index * 0.05, ease: 'power2.inOut', }); }); // Navbar Scroll Effect const nav = navbarRef.current; if (nav) { const updateNavbar = () => { const hasScrolled = window.scrollY > 20; gsap.to(nav, { backgroundColor: hasScrolled ? 'color-mix(in oklab, var(--background) 85%, transparent)' : 'transparent', backdropFilter: hasScrolled ? 'blur(16px)' : 'blur(0px)', borderBottomColor: hasScrolled ? 'var(--border)' : 'transparent', duration: 0.3, overwrite: 'auto', }); }; updateNavbar(); window.addEventListener('scroll', updateNavbar, { passive: true }); cleanupHandlers.push(() => window.removeEventListener('scroll', updateNavbar)); } }, rootRef); return () => { cleanupHandlers.forEach((cleanup) => cleanup()); ctx.revert(); }; }, []); return (
{/* Header */}
{/* 1) HERO */}
Open Source Video Review

Cut Video Approval Time in Half.
Stop Chasing Timecodes.

OpenFrame puts comments, voice notes, and annotations on a single timeline so clients say "yes" faster and your team stops guessing.

Product Interface Preview
{/* Toolbar floating UI */}
{/* 2) PROBLEM BLOCK */}

Feedback chaos looks like this:

  • Comments spread across WhatsApp, email, and random screenshots.
  • "Around 1:12" turns into 10 minutes of guessing.
  • Nobody knows which version is actually the latest.
  • One unclear note becomes a full extra revision round.

OpenFrame replaces all of that with one link, one timeline, one source of truth.

{/* 3) HOW IT WORKS */}

From upload to approval — in one flow.

{[ { label: 'Upload a cut', icon: Upload }, { label: 'Share a review link', icon: Share2 }, { label: 'Get timestamped feedback', icon: MessageSquare }, { label: 'Mark approved and move on', icon: Check } ].map((step, idx, arr) => (

{step.label}

0{idx + 1}
{idx < arr.length - 1 && (
)} {idx < arr.length - 1 && (
)}
))}
{/* 4) FEATURES */}
{/* Feature 1 */}
Comparison Mode

Compare versions side-by-side. End "which cut is this?"

See what actually changed between versions then approve with confidence.

Cuts revision cycles.

{/* Feature 2 */}

Explain it better with Voice.

No more "What did you mean by this?" emails. Every note lands at the exact moment in the video.

Faster feedback. Fewer misunderstandings.

Y

Yusuf İpek

00:03:45

{Array.from({ length: 40 }).map((_, i) => ( ))}
{/* Feature 3 */}
Annotate {/* Circle Editor UI mock */}

Point. Draw. Done.

Precise feedback that leaves zero room for error. Circle, sketch, and point directly on the video frame.

Stops "I thought you meant..."

{/* 5) EVERYTHING YOUR TEAM EXPECTS */}

Everything a real production workflow needs.

The core tools teams expect without the complexity that slows clients down.

Core workflow

{coreWorkflowFeatures.map((feat) => (

{feat.title}

{feat.description}

))}

Workflow Accelerators

{workflowAcceleratorFeatures.map((feat) => (

{feat.title}

{feat.description}

))}
{/* 6) BUILT FOR CLIENTS */}

Clients don't need an account. They just review.

If clients can't adopt the tool, approvals don't happen. OpenFrame keeps it frictionless.

One link. Review in the browser.

Works great on mobile.

Timestamped notes that are impossible to miss.

{/* 7) PRICING */}

Deploy it yourself - or let us run it for you.

{/* Card 1: Open Source */}

Open Source (Self-hosted)

Free

For teams who want full control and can run their own infrastructure.

  • Full codebase access
  • Self-hosted infrastructure control
  • Manual update cadence
View on GitHub
{/* Card 2: Hosted Cloud */}

Best for teams who want zero setup.

Hosted Cloud

$10 / month
  • Unlimited collaborators
  • Timestamped comments + voice notes
  • Annotations + version compare
  • Share links with permissions
  • Exports (PDF/CSV)
  • Unlimited YouTube Video Imports
  • Includes: 200 GB Storage

Need more storage? Add 100 GB for $5/mo.

Start free
{/* Card 3: Studio & Agency */}

Need more than the standard limits?

Let's talk

Custom capacity and setup help for high-volume production teams. Tell us your storage, usage, and workflow - we'll recommend the right approach.

Contact us
{/* 8) SECURITY & PRIVACY */}

Security & privacy, by design.

  • - Permissioned share links (control who can view/comment)
  • - Private-by-default projects
  • - Delete videos and projects anytime
  • - Self-host option for full data control
{/* 9) FAQ */}

FAQ

{[ { q: 'Do clients need an account?', a: 'No. They can review in the browser with a share link.', }, { q: 'What happens if I exceed my storage?', a: 'You can add 100 GB for $5/mo. If you need much more, contact us and we’ll help you choose the best setup.', }, { q: 'How is YouTube unlimited?', a: 'There is no storage limit on YouTube imports. You can import an unlimited amount of unlisted YouTube videos and use all of our review features exactly the same.', }, { q: 'Can I self-host?', a: 'Yes. The core is open-source and self-hostable. Hosted Cloud is for teams who want zero setup.', }, { q: 'How is this different from sending a Google Drive link?', a: 'Drive doesn’t give timestamped discussion, voice notes, annotations, or version compare, which is where approval time is actually saved.', }, { q: 'Is it mobile-friendly?', a: 'Yes. Clients can review and comment from mobile.', }, { q: 'Can I export feedback?', a: 'Yes. Export to PDF/CSV for archiving or client handoff.', }, { q: 'Who can access my videos?', a: 'Only people you invite or share a link with (based on permissions you set).', }, { q: 'Can I cancel anytime?', a: 'Yes. Cancel anytime from your billing settings.', }, ].map((item) => (

{item.q}

{item.a}

))}
{/* 10) FINAL CTA STRIP */}

Stop chasing feedback. Start getting approvals.

Your first review link takes minutes.

Start free
); }