Communitygithub.com

LP Hero Video Skill

Intégrer efficacement des vidéos de démonstration de produit dans les pages d'atterrissage et sites web.

Qu'est-ce que LP Hero Video Skill ?

Cette compétence fournit un guide complet pour intégrer des vidéos de démonstration de produit dans les pages d'atterrissage et sites web, avec des composants React prêts à l'emploi. Elle prend en charge plusieurs motifs d'intégration : vidéo d'arrière-plan pleine page (Hero), vidéo dans des cartes produits avec lecture au survol, vidéo dans un cadre d'appareil (navigateur/ smartphone) pour renforcer la crédibilité, et vidéo en lightbox modale. En complément, elle propose un motif avancé de maquette UI animée en CSS/SVG/Canvas, qui simule l'interface du produit sans fichier vidéo, offrant une expérience réactive, nette et sans artefact de compression. La compétence détaille également la préparation des actifs vidéo (format, résolution, optimisation avec ffmpeg), les stratégies d'hébergement, des checklists de performance, de responsive design et d'accessibilité, et un plan de classement des fichiers. Elle est conçue pour des frameworks modernes comme React et Next.js, et s'intègre parfaitement avec des solutions de déploiement comme Vercel ou Netlify.

Compatible avec~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/yuidvg/skills/tree/HEAD/skills/lp-hero-video

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Compétence Vidéo Hero pour Page d'Atterrissage

Guide pour intégrer efficacement des vidéos de démonstration de produit dans les pages d'atterrissage et sites web.

Motifs pris en charge

  1. Hero Background Video — Vidéo pleine page en arrière-plan dans l'en-tête
  2. Product Demo Section — Vidéo en ligne dans la section de présentation du produit
  3. Floating Device Mockup — Vidéo affichée dans un cadre d'appareil
  4. Lightbox / Modal Video — Lecture agrandie au clic

Étape 0 : Liste de vérification préalable

Avant d'intégrer la vidéo, vérifier les points suivants :

Vérification du matériel vidéo

  • Le fichier vidéo est-il prêt ? (Sinon, créer d'abord une UI avec un espace réservé)
  • Formats : .mp4 (H.264) + .webm (VP9), idéalement les deux
  • Résolution : 1920x1080 recommandé pour le Hero, 1280x720 suffisant pour les cartes
  • Taille du fichier : 5-15 MB pour le Hero, 2-5 MB pour les cartes
  • Durée : 10-30 secondes en boucle pour la lecture automatique

Création du matériel vidéo (avec Screen Studio ou autre)

  1. Enregistrer le flux d'opérations le plus impressionnant du produit en 15-30 secondes
  2. Enregistrer en résolution 1920x1080 ou plus
  3. À l'exportation, configurer :
    • MP4 (H.264) : Qualité Moyenne-Haute, débit 4-8 Mbps
    • WebM (VP9) : Exportation supplémentaire à qualité équivalente (si l'outil le permet)
  4. Commandes de conversion avec ffmpeg :
# Optimisation MP4 (Web, avec faststart)
ffmpeg -i input.mov -c:v libx264 -crf 23 -preset slow \
  -movflags +faststart -an -vf scale=1920:-2 output.mp4

# Conversion WebM
ffmpeg -i input.mov -c:v libvpx-vp9 -crf 30 -b:v 0 \
  -an -vf scale=1920:-2 output.webm

# Pour les cartes (plus petit)
ffmpeg -i input.mov -c:v libx264 -crf 26 -preset slow \
  -movflags +faststart -an -vf scale=1280:-2 output-card.mp4

Hébergement

  • Local (/public/videos/): Pour les petits sites, déploiements Vercel / Netlify
  • CDN / Stockage objet: Pour les grands sites avec plusieurs vidéos (Cloudflare R2, AWS S3 + CloudFront)
  • Intégration YouTube / Vimeo: Pour le SEO, si vous souhaitez partager en externe

Pattern 1 : Vidéo d'Arrière-plan Hero

Affiche une vidéo de démonstration du produit en plein écran en haut de la page. Avec superposition de texte.

Composant React

interface HeroVideoProps {
  /** Chemin de la vidéo MP4 */
  videoSrc: string;
  /** Chemin de la vidéo WebM (optionnel) */
  videoSrcWebm?: string;
  /** Image d'affiche à afficher avant le chargement de la vidéo */
  posterSrc?: string;
  /** Éléments enfants de la superposition (titre, etc.) */
  children?: React.ReactNode;
  /** Opacité de la superposition (0-1, défaut 0.4) */
  overlayOpacity?: number;
}

function HeroVideo({
  videoSrc,
  videoSrcWebm,
  posterSrc,
  children,
  overlayOpacity = 0.4,
}: HeroVideoProps) {
  const videoRef = useRef<HTMLVideoElement>(null);

  return (
    <div className="relative h-screen w-full overflow-hidden bg-black">
      {/* Vidéo d'arrière-plan */}
      <video
        ref={videoRef}
        autoPlay
        muted
        loop
        playsInline
        poster={posterSrc}
        className="absolute inset-0 w-full h-full object-cover"
      >
        {videoSrcWebm && <source src={videoSrcWebm} type="video/webm" />}
        <source src={videoSrc} type="video/mp4" />
      </video>

      {/* Superposition sombre */}
      <div
        className="absolute inset-0"
        style={{ backgroundColor: `rgba(0, 0, 0, ${overlayOpacity})` }}
      />

      {/* Dégradé vers l'arrière-plan de la page */}
      <div className="absolute inset-x-0 bottom-0 h-32 bg-gradient-to-t from-background to-transparent" />

      {/* Contenu */}
      {children && (
        <div className="absolute inset-0 z-10 flex items-end">
          <div className="container pb-16 md:pb-24">{children}</div>
        </div>
      )}
    </div>
  );
}

Exemple d'utilisation

<HeroVideo
  videoSrc="/videos/product-demo.mp4"
  videoSrcWebm="/videos/product-demo.webm"
  posterSrc="/images/hero-poster.jpg"
  overlayOpacity={0.35}
>
  <h1 className="text-4xl md:text-6xl font-normal text-white tracking-tight">
    Réinventer la conversation avec la technologie.
  </h1>
</HeroVideo>

Zone d'application dans la LP Plural Reality

En remplacement du composant LifeGameHero actuel, ou en coexistence :

// Home.tsx motif de remplacement
// Option A : Remplacement complet
<HeroVideo videoSrc="/videos/hero-demo.mp4" posterSrc="/images/IMG_5298.jpeg">
  <h1 ...>{h.heroTitle}</h1>
</HeroVideo>

// Option B : Conserver LifeGameHero et ajouter une section vidéo en dessous
<LifeGameHero>...</LifeGameHero>
<Section className="py-0">
  <HeroVideo videoSrc="/videos/product-overview.mp4" overlayOpacity={0.2}>
    <h2>Présentation du produit</h2>
  </HeroVideo>
</Section>

Pattern 2 : Vidéo de Carte Produit

Dans chaque carte d'une liste de produits, une vidéo de démonstration est lue au survol, remplaçant une image statique.

Composant React

interface ProductCardVideoProps {
  videoSrc: string;
  posterSrc: string;
  alt: string;
  className?: string;
}

function ProductCardVideo({
  videoSrc,
  posterSrc,
  alt,
  className,
}: ProductCardVideoProps) {
  const videoRef = useRef<HTMLVideoElement>(null);

  const handleMouseEnter = () => {
    videoRef.current?.play();
  };

  const handleMouseLeave = () => {
    const video = videoRef.current;
    if (video) {
      video.pause();
      video.currentTime = 0;
    }
  };

  return (
    <div
      className={cn("relative aspect-video bg-muted overflow-hidden", className)}
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
    >
      <video
        ref={videoRef}
        muted
        loop
        playsInline
        poster={posterSrc}
        preload="metadata"
        className="w-full h-full object-cover"
      >
        <source src={videoSrc} type="video/mp4" />
      </video>
    </div>
  );
}

Exemple d'utilisation (remplacer l'image d'une carte existante)

// Avant :
<ParallaxImage src="/images/kouchoai.png" alt={t.products.kouchouAI} />

// Après :
<ProductCardVideo
  videoSrc="/videos/kouchou-ai-demo.mp4"
  posterSrc="/images/kouchoai.png"
  alt={t.products.kouchouAI}
/>

Pattern 3 : Vidéo dans un Maquette d'Appareil

Affiche une vidéo de démonstration dans le cadre d'un navigateur ou d'un smartphone (pour renforcer la crédibilité).

function BrowserMockupVideo({
  videoSrc,
  posterSrc,
  title,
}: {
  videoSrc: string;
  posterSrc?: string;
  title?: string;
}) {
  return (
    <div className="border border-border bg-background overflow-hidden">
      {/* Chrome du navigateur */}
      <div className="flex items-center gap-2 px-4 py-3 bg-secondary/30 border-b border-border">
        <div className="flex gap-1.5">
          <div className="w-3 h-3 rounded-full bg-muted-foreground/20" />
          <div className="w-3 h-3 rounded-full bg-muted-foreground/20" />
          <div className="w-3 h-3 rounded-full bg-muted-foreground/20" />
        </div>
        {title && (
          <div className="flex-1 text-center">
            <span className="text-xs text-muted-foreground font-mono">{title}</span>
          </div>
        )}
      </div>
      {/* Contenu vidéo */}
      <div className="aspect-video">
        <video
          autoPlay
          muted
          loop
          playsInline
          poster={posterSrc}
          className="w-full h-full object-cover"
        >
          <source src={videoSrc} type="video/mp4" />
        </video>
      </div>
    </div>
  );
}

Pattern 4 : Vidéo en Lightbox Modale

Affiche une vidéo dans une modale au clic sur une vignette. Prend également en charge l'intégration YouTube.

function VideoLightbox({
  thumbnailSrc,
  videoSrc,
  youtubeId,
  alt,
}: {
  thumbnailSrc: string;
  videoSrc?: string;
  youtubeId?: string;
  alt: string;
}) {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <button
        onClick={() => setIsOpen(true)}
        className="relative group cursor-pointer aspect-video w-full overflow-hidden"
      >
        <img src={thumbnailSrc} alt={alt} className="w-full h-full object-cover" />
        {/* Superposition du bouton de lecture */}
        <div className="absolute inset-0 flex items-center justify-center bg-black/20 group-hover:bg-black/30 transition-colors">
          <div className="w-16 h-16 flex items-center justify-center bg-white/90 group-hover:bg-white transition-colors">
            <svg className="w-6 h-6 text-foreground ml-1" fill="currentColor" viewBox="0 0 24 24">
              <path d="M8 5v14l11-7z" />
            </svg>
          </div>
        </div>
      </button>

      {/* Modale */}
      {isOpen && (
        <div
          className="fixed inset-0 z-50 flex items-center justify-center bg-black/80"
          onClick={() => setIsOpen(false)}
        >
          <div className="w-full max-w-5xl aspect-video" onClick={(e) => e.stopPropagation()}>
            {youtubeId ? (
              <iframe
                src={`https://www.youtube.com/embed/${youtubeId}?autoplay=1`}
                className="w-full h-full"
                allow="autoplay; encrypted-media"
                allowFullScreen
              />
            ) : (
              <video
                src={videoSrc}
                autoPlay
                controls
                className="w-full h-full object-contain bg-black"
              />
            )}
          </div>
        </div>
      )}
    </>
  );
}

Liste de vérification de mise en œuvre

Lors de l'ajout d'une vidéo, vérifier les points suivants :

Performance

  • Définir les 4 attributs autoPlay muted loop playsInline (obligatoire pour iOS)
  • Spécifier une image poster pour l'image de la première image (améliore l'expérience pendant le chargement)
  • Utiliser preload="metadata" pour alléger le chargement initial des vidéos dans les cartes
  • Appliquer -movflags +faststart au fichier vidéo (lecture progressive)
  • Fournir les deux formats MP4 + WebM via <source> (compatibilité navigateur)

Responsive

  • Utiliser object-cover / object-contain pour un ajustement approprié
  • Envisager d'afficher une image statique à la place de la vidéo sur mobile
    const isMobile = window.innerWidth < 768;
    // Sur mobile, afficher uniquement l'image poster, ne pas charger la vidéo
    

Accessibilité

  • Les vidéos en lecture automatique doivent impérativement être muted (la lecture audio sans interaction utilisateur est bloquée)
  • Prendre en charge prefers-reduced-motion et revenir à une image statique lorsque les animations sont désactivées
    @media (prefers-reduced-motion: reduce) {
      video { display: none; }
      .video-poster-fallback { display: block; }
    }
    

Design (Conformité Plural Reality)

  • Pas de coins arrondis (border-radius: 0px)
  • Bordure : 1px solid var(--border)
  • Superposition en dégradé noir (garder le monochromatique)
  • Icône du bouton de lecture : utiliser Play de Lucide React

Règles de placement des fichiers

client/
  public/
    videos/
      hero-demo.mp4           # Vidéo Hero (MP4)
      hero-demo.webm           # Vidéo Hero (WebM)
      hero-poster.jpg           # Image d'affiche de la vidéo Hero
      kouchou-ai-demo.mp4      # Vidéo de démonstration Kouchou AI
      baisoku-survey-demo.mp4  # Vidéo de démonstration Baisoku Survey
      baisoku-kaigi-demo.mp4   # Vidéo de démonstration Baisoku Kaigi
  src/
    components/
      HeroVideo.tsx             # Composant vidéo pleine page Hero
      ProductCardVideo.tsx      # Composant vidéo avec lecture au survol dans une carte
      BrowserMockupVideo.tsx    # Vidéo avec cadre de navigateur
      VideoLightbox.tsx         # Composant vidéo modale

Exemples de configurations courantes

SaaS / Page d'atterrissage produit (configuration recommandée)

Vidéo pleine page Hero (boucle de 15 à 30 secondes, lecture automatique muette)
  ↓
Section de texte (mission, valeurs)
  ↓
Vidéo maquette de navigateur (démo du produit principal)
  ↓
Cartes produit (lecture de vidéos de démonstration individuelles au survol)
  ↓
Études de cas / Réalisations
  ↓
CTA

Site corporatif (configuration sobre)

Image Hero + bouton de lecture (clic pour ouvrir la vidéo en lightbox)
  ↓
Section de texte
  ↓
Cartes produit (image statique, vidéo sur la page de détail)

Pattern 5 : Maquette UI animée en CSS (recommandé)

Sans fichier vidéo, dessiner directement la sensation d'utilisation du produit avec des animations CSS / SVG / Canvas. C'est l'approche adoptée par Stripe, Linear, Vercel.

Avantages

  • Aucun fichier vidéo nécessaire (zéro octet ajouté)
  • Entièrement responsive (ne se casse à aucune taille d'écran)
  • Rendu natif net (pas d'artefacts de compression)
  • Peut être interactif (changement au survol, au clic)
  • Compatible automatiquement avec les modes sombre et clair

Prérequis : Actifs d'animation existants

La LP Plural Reality a déjà implémenté les animations de haute qualité suivantes dans SolutionAnimations.tsx :

ComposantContenuTechnologie
NetworkOntologyAnimationOntologie à 3 couches (DATA→ONTOLOGY→APPLICATION)SVG + framer-motion
DataFlowAnimationPipeline collecter → organiser → connecterSVG + framer-motion
ClusterAnimationVisualisation du clustering d'opinionsSVG + framer-motion
ConversationBranchAnimationArbre de branches d'entretien approfondiSVG + framer-motion
FeedbackLoopAnimationCycle de conversation continueSVG + framer-motion
IntegrationMeshAnimationDiagramme d'intégration de plateformeSVG + framer-motion
ParticleFieldAnimationRéseau de particulesCanvas
IsometricLayersAnimationStructure de couches en projection isométriqueSVG + framer-motion

De plus, une animation Canvas de la Terre → du Japon se trouve dans LifeGameHero.tsx.

Principes de conception communs

- Fond : noir (#000000), dessin en éléments blancs
- Monochromatique (ne pas utiliser de couleur ou seulement Brand Teal comme accent)
- Police : var(--font-mono) pour les étiquettes techniques, var(--font-sans) pour les éléments UI
- Pas de coins arrondis : rx={0} / border-radius: 0px
- Animation : useInView + motion.* de framer-motion pour un déclenchement au scroll
- Fond de grille : motif de grille à lignes blanches fines (utilitaire GridBg)
- Lueur : feDropShadow pour une émission lumineuse discrète (utilitaire GlowDef)

Pattern 5A : Cadre de navigateur + UI animée

Affiche une UI maquette animée à l'intérieur du chrome d'un navigateur (barre de titre + points).

function ProductDemoMock({
  title,
  children,
  className,
}: {
  title: string;
  children: React.ReactNode;
  className?: string;
}) {
  return (
    <div className={cn("border border-border bg-black overflow-hidden", className)}>
      {/* Chrome du navigateur */}
      <div className="flex items-center gap-2 px-4 py-3 bg-[#1c1c1e] border-b border-border">
        <div className="flex gap-1.5">
          <div className="w-2.5 h-2.5 rounded-full bg-white/10" />
          <div className="w-2.5 h-2.5 rounded-full bg-white/10" />
          <div className="w-2.5 h-2.5 rounded-full bg-white/10" />
        </div>
        <div className="flex-1 text-center">
          <span className="text-[10px] text-white/40 font-mono">{title}</span>
        </div>
      </div>
      {/* Contenu animé */}
      <div className="aspect-video relative overflow-hidden">
        {children}
      </div>
    </div>
  );
}

Pattern 5B : Animation de démonstration KouchouAI

Flux où les données textuelles entrent → L'IA effectue le clustering → Le résultat est affiché.

// Conception conceptuelle (se référer à ClusterAnimation de SolutionAnimations lors de l'implémentation)
function KouchouAIDemoAnimation() {
  const [phase, setPhase] = useState<"input" | "processing" | "result">("input");

  useEffect(() => {
    const timers = [
      setTimeout(() => setPhase("processing"), 2000),
      setTimeout(() => setPhase("result"), 4000),
    ];
    const loop = setInterval(() => {
      setPhase("input");
      timers.push(setTimeout(() => setPhase("processing"), 2000));
      timers.push(setTimeout(() => setPhase("result"), 4000));
    }, 8000);
    return () => { timers.forEach(clearTimeout); clearInterval(loop); };
  }, []);

  return (
    <ProductDemoMock title="kouchou-ai.plural-reality.com">
      <svg viewBox="0 0 800 450" className="w-full h-full">
        {/* Phase 1 : Les lignes de texte glissent depuis la gauche */}
        {phase === "input" && (
          <g>
            {["Je souffre des transports peu pratiques", "J'aimerais plus de soutien à l'éducation des enfants", "Je m'inquiète des mesures anti-catastrophe"].map((text, i) => (
              <motion.g
                key={text}
                initial={{ opacity: 0, x: -40 }}
                animate={{ opacity: 1, x: 0 }}
                transition={{ delay: i * 0.4 }}
              >
                <rect x={40} y={60 + i * 50} width={350} height={36} fill="white" fillOpacity={0.05} stroke="white" strokeWidth={0.5} />
                <text x={56} y={82 + i * 50} fill="white" fontSize={11} fontFamily="var(--font-sans)" opacity={0.8}>
                  {text}
                </text>
              </motion.g>
            ))}
          </g>
        )}

        {/* Phase 2 : Les particules convergent vers le centre */}
        {phase === "processing" && (
          <motion.text x={400} y={225} textAnchor="middle" fill="white" fontSize={12} fontFamily="var(--font-mono)"
            initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ duration: 0.5 }}>
            Traitement en cours...
          </motion.text>
        )}
      </svg>
    </ProductDemoMock>
  );
}

Skills associés