Retour au catalogue

Video Background

Section hero avec background video, titre large, description et double CTA centre. Bouton mute inclus.

videomedium Both Responsive a11y
bolddarkelegantuniversalagencyeventfullscreencentered
Theme
"use client";

import { motion } from "framer-motion";
import { ArrowRight, Volume2, VolumeX } from "lucide-react";
import { useState } from "react";

interface VideoBackgroundProps {
  title?: string;
  titleAccent?: string;
  description?: string;
  ctaLabel?: string;
  ctaUrl?: string;
  ctaSecondaryLabel?: string;
}

const EASE = [0.16, 1, 0.3, 1] as const;

export default function VideoBackground({
  title = "Creez l'impossible",
  titleAccent = "avec nous",
  description = "Un studio creatif qui repousse les limites du design digital.",
  ctaLabel = "Demarrer",
  ctaUrl = "#contact",
  ctaSecondaryLabel = "",
}: VideoBackgroundProps) {
  const [muted, setMuted] = useState(true);

  return (
    <section
      style={{
        position: "relative",
        minHeight: "100vh",
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
        overflow: "hidden",
        background: "var(--color-background)",
      }}
    >
      {/* Video background placeholder */}
      <div
        style={{
          position: "absolute",
          inset: 0,
          background: "linear-gradient(160deg, var(--color-background) 0%, var(--color-background-alt) 50%, var(--color-background) 100%)",
        }}
      >
        {/* Simulated video grain */}
        <div
          aria-hidden
          style={{
            position: "absolute",
            inset: 0,
            backgroundImage: "radial-gradient(circle at 20% 50%, color-mix(in srgb, var(--color-accent) 4%, transparent), transparent 50%), radial-gradient(circle at 80% 20%, color-mix(in srgb, var(--color-accent) 3%, transparent), transparent 40%)",
          }}
        />
      </div>

      {/* Dark overlay */}
      <div
        style={{
          position: "absolute",
          inset: 0,
          background: "color-mix(in srgb, var(--color-background) 60%, transparent)",
          pointerEvents: "none",
        }}
      />

      {/* Content overlay */}
      <div
        style={{
          position: "relative",
          zIndex: 2,
          maxWidth: "800px",
          textAlign: "center",
          padding: "0 var(--container-padding-x, 1.5rem)",
        }}
      >
        <motion.h1
          initial={{ opacity: 0, y: 30 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.7, ease: EASE }}
          style={{
            fontFamily: "var(--font-sans)",
            fontSize: "clamp(2.5rem, 6vw, 5rem)",
            fontWeight: 800,
            lineHeight: 1.05,
            letterSpacing: "-0.03em",
            color: "var(--color-foreground)",
            marginBottom: "1.5rem",
          }}
        >
          {title}{" "}
          <span
            style={{
              color: "var(--color-accent)",
              fontFamily: "var(--font-serif)",
              fontWeight: 400,
              fontStyle: "italic",
            }}
          >
            {titleAccent}
          </span>
        </motion.h1>

        <motion.p
          initial={{ opacity: 0, y: 16 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.6, delay: 0.15, ease: EASE }}
          style={{
            fontSize: "1.1875rem",
            lineHeight: 1.7,
            color: "var(--color-foreground-muted)",
            maxWidth: "560px",
            margin: "0 auto 2.5rem",
          }}
        >
          {description}
        </motion.p>

        <motion.div
          initial={{ opacity: 0, y: 12 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.5, delay: 0.28, ease: EASE }}
          style={{ display: "flex", flexWrap: "wrap", justifyContent: "center", gap: "0.75rem" }}
        >
          <a
            href={ctaUrl}
            style={{
              display: "inline-flex",
              alignItems: "center",
              gap: "8px",
              padding: "0.875rem 2rem",
              borderRadius: "var(--radius-full)",
              background: "var(--color-accent)",
              color: "var(--color-foreground)",
              fontWeight: 600,
              fontSize: "0.9375rem",
              textDecoration: "none",
              transition: "opacity var(--duration-normal) var(--ease-out)",
            }}
          >
            {ctaLabel}
            <ArrowRight style={{ width: 16, height: 16 }} />
          </a>

          {ctaSecondaryLabel && (
            <a
              href={ctaUrl}
              style={{
                display: "inline-flex",
                alignItems: "center",
                gap: "6px",
                padding: "0.875rem 2rem",
                borderRadius: "var(--radius-full)",
                border: "1px solid var(--color-border)",
                color: "var(--color-foreground-muted)",
                fontWeight: 500,
                fontSize: "0.9375rem",
                textDecoration: "none",
                transition: "all var(--duration-normal) var(--ease-out)",
              }}
            >
              {ctaSecondaryLabel}
            </a>
          )}
        </motion.div>
      </div>

      {/* Mute toggle */}
      <motion.button
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        transition={{ delay: 0.6 }}
        onClick={() => setMuted((m) => !m)}
        style={{
          position: "absolute",
          bottom: "2rem",
          right: "2rem",
          zIndex: 3,
          width: "44px",
          height: "44px",
          borderRadius: "var(--radius-full)",
          border: "1px solid var(--color-border)",
          background: "color-mix(in srgb, var(--color-background) 80%, transparent)",
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          cursor: "pointer",
          color: "var(--color-foreground-muted)",
        }}
        aria-label={muted ? "Activer le son" : "Couper le son"}
      >
        {muted ? (
          <VolumeX style={{ width: 18, height: 18 }} />
        ) : (
          <Volume2 style={{ width: 18, height: 18 }} />
        )}
      </motion.button>
    </section>
  );
}

Avis

Video Background — React Video Section — Incubator