Was macht LP Hero Video Skill?
Ein Leitfaden zur effektiven Integration von Produkt-Demo-Videos in Landingpages und Websites.
Unterstützte Muster
- Hero-Background-Video – Vollflächiges Hintergrundvideo im oberen Seitenbereich
- Produkt-Demo-Bereich – Inline-Video im Produktvorstellungsbereich
- Floating Device Mockup – Video in einem Geräterahmen darstellen
- Lightbox / Modal-Video – Bei Klick vergrößert abspielen
Schritt 0: Vorab-Checkliste
Vor der Videointegration Folgendes prüfen:
Videomaterial prüfen
- Videodatei vorhanden? (Falls nicht, zuerst Platzhalter-UI erstellen)
- Format: Ideal
.mp4(H.264) +.webm(VP9) in beiden Formaten - Auflösung: Für Hero 1920x1080 empfohlen, für Karten 1280x720 ausreichend
- Dateigröße: Hero 5-15 MB, Karte 2-5 MB
- Länge: Autoplay 10-30 Sekunden Loop optimal
Videomaterial erstellen (z. B. mit Screen Studio)
- Den eindrucksvollsten Workflow des Produkts in 15-30 Sekunden aufzeichnen
- Aufnahme mit mindestens 1920x1080
- Beim Export einstellen:
- MP4 (H.264): Qualität Mittel-Hoch, Bitrate 4-8 Mbps
- WebM (VP9): Optional mit gleicher Qualität exportieren (falls Tool unterstützt)
- Konvertierung mit ffmpeg:
# MP4-Optimierung (Web, mit faststart)
ffmpeg -i input.mov -c:v libx264 -crf 23 -preset slow \
-movflags +faststart -an -vf scale=1920:-2 output.mp4
# WebM-Konvertierung
ffmpeg -i input.mov -c:v libvpx-vp9 -crf 30 -b:v 0 \
-an -vf scale=1920:-2 output.webm
# Für Karten (kleiner)
ffmpeg -i input.mov -c:v libx264 -crf 26 -preset slow \
-movflags +faststart -an -vf scale=1280:-2 output-card.mp4
Hosting
- Lokal (
/public/videos/): Für kleine Websites, Vercel / Netlify Deploy - CDN / Object Storage: Für große Mengen, mehrere Videos (Cloudflare R2, AWS S3 + CloudFront)
- YouTube / Vimeo Embed: Bei SEO-Fokus und externer Teilbarkeit
Muster 1: Hero-Background-Video
Vollflächiges Produkt-Demo-Video oben auf der Seite mit Text-Overlay.
React-Komponente
interface HeroVideoProps {
/** Pfad zum MP4-Video */
videoSrc: string;
/** Pfad zum WebM-Video (optional) */
videoSrcWebm?: string;
/** Posterbild, das vor dem Laden des Videos angezeigt wird */
posterSrc?: string;
/** Kindelemente für das Overlay (z. B. Überschrift) */
children?: React.ReactNode;
/** Deckkraft des Overlays (0-1, Standard 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">
{/* Hintergrundvideo */}
<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>
{/* Dunkles Overlay */}
<div
className="absolute inset-0"
style={{ backgroundColor: `rgba(0, 0, 0, ${overlayOpacity})` }}
/>
{/* Gradient zum Seitenhintergrund */}
<div className="absolute inset-x-0 bottom-0 h-32 bg-gradient-to-t from-background to-transparent" />
{/* Inhalt */}
{children && (
<div className="absolute inset-0 z-10 flex items-end">
<div className="container pb-16 md:pb-24">{children}</div>
</div>
)}
</div>
);
}
Verwendungsbeispiel
<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">
Technologie, die Gespräche neu erfindet.
</h1>
</HeroVideo>
Anwendungsbereich in der Plural-Reality-Landingpage
Statt oder zusätzlich zur aktuellen LifeGameHero-Komponente:
// Home.tsx – Ersetzungsmuster
// Option A: Vollständiger Ersatz
<HeroVideo videoSrc="/videos/hero-demo.mp4" posterSrc="/images/IMG_5298.jpeg">
<h1 ...>{h.heroTitle}</h1>
</HeroVideo>
// Option B: LifeGameHero behalten, darunter Video hinzufügen
<LifeGameHero>...</LifeGameHero>
<Section className="py-0">
<HeroVideo videoSrc="/videos/product-overview.mp4" overlayOpacity={0.2}>
<h2>Produktvorstellung</h2>
</HeroVideo>
</Section>
Muster 2: Product Card Video
In jeder Produktkarte wird statt eines Standbilds ein Demo-Video bei Hover abgespielt.
React-Komponente
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>
);
}
Verwendungsbeispiel (Bild in vorhandener Karte ersetzen)
// Vorher:
<ParallaxImage src="/images/kouchoai.png" alt={t.products.kouchouAI} />
// Nachher:
<ProductCardVideo
videoSrc="/videos/kouchou-ai-demo.mp4"
posterSrc="/images/kouchoai.png"
alt={t.products.kouchouAI}
/>
Muster 3: Device Mockup Video
Demo-Video in einem Browser- oder Smartphone-Rahmen darstellen (Vertrauensgewinn).
function BrowserMockupVideo({
videoSrc,
posterSrc,
title,
}: {
videoSrc: string;
posterSrc?: string;
title?: string;
}) {
return (
<div className="border border-border bg-background overflow-hidden">
{/* Browser-Chrome */}
<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>
{/* Video-Inhalt */}
<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>
);
}
Muster 4: Lightbox Modal Video
Video per Klick auf ein Thumbnail in einem Modal anzeigen. Auch für YouTube-Embeds geeignet.
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" />
{/* Play-Button-Overlay */}
<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>
{/* Modal */}
{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>
)}
</>
);
}
Implementierungs-Checkliste
Beim Hinzufügen von Videos folgende Punkte prüfen:
Performance
-
autoPlay,muted,loop,playsInline– alle vier Attribute setzen (iOS-Pflicht) -
poster-Attribut mit Startbild (verbessert Ladeerfahrung) -
preload="metadata"für leichteres Erstladen bei Kartenvideos -
-movflags +faststartauf Videodatei anwenden (progressives Abspielen) - MP4 + WebM beide als
<source>anbieten (Browser-Kompatibilität)
Responsiv
- Mit
object-cover/object-containrichtig einpassen - Alternative: Auf Mobilgeräten statt Video ein Standbild anzeigen
const isMobile = window.innerWidth < 768; // Auf Mobilgeräten nur Posterbild, kein Video laden
Barrierefreiheit
- Autoplay-Videos immer mit
muted(Audio ohne Benutzeraktion wird blockiert) -
prefers-reduced-motionunterstützen – bei deaktivierten Animationen auf Standbild zurückfallen@media (prefers-reduced-motion: reduce) { video { display: none; } .video-poster-fallback { display: block; } }
Design (Plural Reality-konform)
- Keine abgerundeten Ecken (
border-radius: 0px) - Border:
1px solid var(--border) - Overlay ist schwarzer Verlauf (monochrom bleiben)
- Play-Button-Symbol aus Lucide React:
Play
Datei-Ablagekonventionen
client/
public/
videos/
hero-demo.mp4 # Hero-Video (MP4)
hero-demo.webm # Hero-Video (WebM)
hero-poster.jpg # Posterbild für Hero-Video
kouchou-ai-demo.mp4 # Demo-Video Kouchou AI
baisoku-survey-demo.mp4 # Demo-Video Baisoku Survey
baisoku-kaigi-demo.mp4 # Demo-Video Baisoku Kaigi
src/
components/
HeroVideo.tsx # Komponente für vollflächiges Hero-Video
ProductCardVideo.tsx # Komponente für Hover-Play-Video in Karten
BrowserMockupVideo.tsx # Video mit Browserrahmen
VideoLightbox.tsx # Modal-Video-Komponente
Typische Layout-Beispiele
SaaS / Produkt-LP (empfohlenes Layout)
Hero-Vollflächenvideo (15-30 Sekunden Loop, stumm Autoplay)
↓
Textabschnitt (Mission & Werte)
↓
Browser-Mockup-Video (Demo des Hauptprodukts)
↓
Produktkarten (Hover für individuelle Demo-Videos)
↓
Fallstudien / Referenzen
↓
CTA
Corporate-Website (zurückhaltendes Layout)
Hero-Bild + Play-Button (Klick öffnet Lightbox-Video)
↓
Textabschnitt
↓
Produktkarten (Standbild, Video auf Detailseite)
Muster 5: CSS-animierter Produkt-UI-Mock (empfohlen)
Ohne Videodatei die Bedienung des Produkts direkt mit CSS-Animation / SVG / Canvas darstellen. Wird von Stripe, Linear und Vercel verwendet.
Vorteile
- Keine Videodatei nötig (null zusätzliche Bytes)
- Vollständig responsiv (bei jeder Bildschirmgröße sauber)
- Native Darstellung – scharf (keine Kompressionsartefakte)
- Interaktiv möglich (Hover, Klick verändert Darstellung)
- Automatische Unterstützung von Dark-/Light-Modus
Vorhandene Animations-Assets
Die Plural-Reality-LP enthält in SolutionAnimations.tsx folgende hochwertige Animationen:
| Komponente | Inhalt | Technik |
|---|---|---|
NetworkOntologyAnimation | 3‑stufige Ontologie (DATA→ONTOLOGY→APPLICATION) | SVG + framer-motion |
DataFlowAnimation | Pipeline: sammeln → organisieren → verbinden | SVG + framer-motion |
ClusterAnimation | Visualisierung von Meinungs-Clustern | SVG + framer-motion |
ConversationBranchAnimation | Verzweigungsbaum für Tiefeninterviews | SVG + framer-motion |
FeedbackLoopAnimation | Kontinuierlicher Dialogzyklus | SVG + framer-motion |
IntegrationMeshAnimation | Plattform-Integrationsdiagramm | SVG + framer-motion |
ParticleFieldAnimation | Partikelnetzwerk | Canvas |
IsometricLayersAnimation | Isometrische Schichtenstruktur | SVG + framer-motion |
Außerdem gibt es in LifeGameHero.tsx eine Canvas-Animation der Erde → Japan.
Gemeinsame Designprinzipien
- Hintergrund: Schwarz (#000000), weiße Elemente zeichnen
- Monochrom (keine Farben oder nur Brand Teal als Akzent)
- Schriftarten: var(--font-mono) für Tech-Labels, var(--font-sans) für UI-Elemente
- Keine abgerundeten Ecken: rx={0} / border-radius: 0px
- Animation: framer-motion useInView + motion.* für scroll-getriggerte Animationen
- Rasterhintergrund: Hellweißes Linienraster (GridBg-Utility)
- Glühen: feDropShadow für dezentes Leuchten (GlowDef-Utility)
Muster 5A: Browserrahmen + animierte UI
Browser-Chrome (Titelzeile + Punkte) mit animiertem Mock-UI darin.
function ProductDemoMock({
title,
children,
className,
}: {
title: string;
children: React.ReactNode;
className?: string;
}) {
return (
<div className={cn("border border-border bg-black overflow-hidden", className)}>
{/* Browser-Chrome */}
<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>
{/* Animierter Inhalt */}
<div className="aspect-video relative overflow-hidden">
{children}
</div>
</div>
);
}
Muster 5B: Kouchou AI Demo-Animation
Textdaten fließen ein → AI clustert → Ergebnis wird angezeigt.
// Konzeptionelles Design (bei Implementierung ClusterAnimation aus SolutionAnimations als Referenz nehmen)
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: Textzeilen gleiten von links ein */}
{phase === "input" && (
<g>
{["Der Verkehr ist umständlich.", "Ich wünsche mir mehr Kinderbetreuung.", "Die Katastrophenvorsorge macht mir Sorgen."].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: Partikel sammeln sich in der Mitte */}
{phase === "processing" && (
<motion.text x={400} y={225} textAnchor="middle" fill="white" fontSize={12} fontFamily="var(--font-mono)"
className="opacity-60">
Verarbeite...
</motion.text>
)}
{/* Phase 3: Cluster-Ergebnis */}
{phase === "result" && (
<g>
{["Verkehr", "Kinderbetreuung", "Katastrophenschutz"].map((label, i) => (
<motion.g
key={label}
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ delay: i * 0.3, type: "spring" }}
>
<circle cx={200 + i * 200} cy={225} r={60} fill="none" stroke="white" strokeWidth={0.5} opacity={0.3} />
<text x={200 + i * 200} y={225} textAnchor="middle" fill="white" fontSize={11} fontFamily="var(--font-mono)">
{label}
</text>
</motion.g>
))}
</g>
)}
</svg>
</ProductDemoMock>
);
}
Datei-Ablagekonventionen (Animationen)
client/
src/
components/
animations/
SolutionAnimations.tsx # Alle Lösungssimulationen gebündelt
LifeGameHero.tsx # Canvas-Erd-Animation (bestehend)