Innovations
heroes /

Video Background Hero

Full-width cinematic hero with an animated gradient background that mimics a video. White text, centered headline, and a scroll indicator.

Preview

Source

tsx
"use client";

import { motion } from "framer-motion";
import { ArrowRight, Play } from "lucide-react";
import { Button } from "@/components/ui/button";

export default function VideoBgHero() {
  return (
    <section className="relative min-h-screen flex items-center justify-center overflow-hidden">
      {/* Cinematic animated gradient — replace this div with a <video> tag for production */}
      <div className="absolute inset-0 z-0">
        <div
          className="absolute inset-0"
          style={{
            background:
              "linear-gradient(135deg, #0f0c29, #302b63, #24243e)",
            animation: "cinematicShift 12s ease-in-out infinite alternate",
          }}
        />
        <div
          className="absolute inset-0 opacity-50"
          style={{
            background:
              "radial-gradient(ellipse at 20% 50%, rgba(120, 40, 200, 0.5) 0%, transparent 60%), radial-gradient(ellipse at 80% 20%, rgba(20, 100, 220, 0.4) 0%, transparent 50%), radial-gradient(ellipse at 60% 80%, rgba(200, 50, 80, 0.3) 0%, transparent 50%)",
            animation: "cinematicGlow 8s ease-in-out infinite alternate",
          }}
        />
        {/* Vignette overlay */}
        <div className="absolute inset-0 bg-gradient-to-b from-black/40 via-transparent to-black/70" />
      </div>

      {/* Keyframe styles injected via a style tag */}
      <style>{`
        @keyframes cinematicShift {
          0%   { filter: brightness(0.9) saturate(1.2); }
          50%  { filter: brightness(1.1) saturate(1.5); }
          100% { filter: brightness(0.85) saturate(1.3); }
        }
        @keyframes cinematicGlow {
          0%   { opacity: 0.4; transform: scale(1); }
          50%  { opacity: 0.65; transform: scale(1.05); }
          100% { opacity: 0.5; transform: scale(1.02); }
        }
      `}</style>

      {/* Content */}
      <div className="relative z-10 container mx-auto px-6 text-center max-w-3xl">
        <motion.div
          initial={{ opacity: 0, y: 40 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.8, ease: "easeOut" }}
          className="flex flex-col items-center gap-6"
        >
          <span className="inline-flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-white/70 border border-white/20 rounded-full px-4 py-2 backdrop-blur-sm">
            Award-winning design studio
          </span>

          <h1 className="text-5xl sm:text-6xl lg:text-7xl font-extrabold tracking-tight text-white leading-[1.05]">
            We craft experiences
            <br />
            that{" "}
            <span className="italic text-transparent bg-clip-text bg-gradient-to-r from-rose-300 to-violet-300">
              move people
            </span>
          </h1>

          <p className="text-lg sm:text-xl text-white/70 max-w-xl leading-relaxed">
            From concept to launch, we build digital products that captivate
            audiences and drive measurable results for ambitious brands.
          </p>

          <div className="flex flex-col sm:flex-row items-center gap-3 pt-2">
            <Button
              size="lg"
              className="gap-2 text-base bg-white text-black hover:bg-white/90 min-w-[180px]"
            >
              Start your project
              <ArrowRight className="w-4 h-4" />
            </Button>
            <Button
              size="lg"
              variant="outline"
              className="gap-2 text-base border-white/30 text-white hover:bg-white/10 hover:text-white min-w-[180px]"
            >
              <Play className="w-4 h-4 fill-current" />
              Watch reel
            </Button>
          </div>
        </motion.div>
      </div>

      {/* Bottom scroll indicator */}
      <motion.div
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        transition={{ delay: 1.2, duration: 0.8 }}
        className="absolute bottom-8 left-1/2 -translate-x-1/2 flex flex-col items-center gap-2"
      >
        <span className="text-xs text-white/40 uppercase tracking-widest">Scroll</span>
        <motion.div
          animate={{ y: [0, 8, 0] }}
          transition={{ duration: 1.5, repeat: Infinity, ease: "easeInOut" }}
          className="w-0.5 h-8 bg-gradient-to-b from-white/40 to-transparent rounded-full"
        />
      </motion.div>
    </section>
  );
}
Claude Code Instructions

CLI Install

npx innovations add video-bg

Where to use it

Place this as a full-bleed hero at the very top of your page (no navbar padding needed — the hero provides its own space). In Astro (src/pages/index.astro): import VideoBgHero from '../components/innovations/heroes/video-bg'; <VideoBgHero client:load /> In Next.js (app/page.tsx): import VideoBgHero from '@/components/innovations/heroes/video-bg'; To use a real video instead of the animated gradient: 1. Remove the animated gradient divs inside the "absolute inset-0 z-0" container 2. Replace with: <video autoPlay muted loop playsInline className="absolute inset-0 w-full h-full object-cover" src="/your-video.mp4" /> 3. Keep the vignette overlay div for readability Keep the vignette overlay (bg-gradient-to-b from-black/40) — it ensures text is readable over any video content.