{
 "$schema": "../../schema.json",
 "schema": "fundus/1",
 "id": "video-vorschau-hover-viewport",
 "name": "Video-Vorschau bei Hover / im Viewport",
 "name_en": "Hover-to-play / in-view video preview",
 "kurz": "Projektkarten zeigen ein Standbild. Erst unter dem Zeiger oder im Viewport läuft der stumme Clip, das Bild zoomt dabei leicht.",
 "kategorie": "Galerien & Slider",
 "kategorie_slug": "galerien-slider",
 "kategorie_nr": 12,
 "bau_chat": "C6",
 "prioritaet": "A",
 "trendstatus": "etabliert",
 "belegstatus": "belegt",
 "website_belege": 2,
 "stimmung": [
  "luxuriös",
  "filmisch",
  "verspielt"
 ],
 "stimmung_roh": [
  "filmisch",
  "lebendig",
  "hochwertig"
 ],
 "technik": [
  "vanilla-js",
  "intersection-observer",
  "css"
 ],
 "technik_gruppen": [
  "css",
  "js"
 ],
 "leistungskosten": "mittel",
 "steckbrief": {
  "beschreibung": "Projektkarten zeigen zuerst ein Standbild. Am Desktop startet beim Hover an derselben Stelle ein stummes Loop-Video von vorn. Das Standbild blendet aus, das Medium zoomt minimal. Beim Verlassen pausiert das Video. Auf Touch-Geräten und in der Viewport-Variante lädt das Video erst, wenn die Karte sichtbar wird, und spielt nur, solange sie sichtbar bleibt. Die Clips sind kurz (3 bis 8 s), stark komprimiert und werden erst bei Bedarf geladen.",
  "warum_es_wirkt": "Das Raster wird lebendig, ohne dass die ganze Seite flimmert. Bewegung entsteht genau dort, wo der Nutzer hinschaut. Ein paar Sekunden Bewegtbild zeigen Motion-Design, Interaktion und Stimmung eines Projekts schneller als jedes Standbild.",
  "wann_einsetzen": "Portfolio-Raster, Projektindizes, Produkt-Features mit kurzen UI-Clips, Kurs-Kacheln mit Trailer, Template-Galerien mit animierter Vorschau.",
  "wann_nicht": "Wenn Datensparsamkeit zählt und viele große Videos nötig wären. Wenn der Clip Ton braucht. Wenn mehr als etwa drei Videos gleichzeitig laufen würden. Wenn das Standbild schon alles sagt.",
  "varianten": [
   "Hover-to-play: Neustart bei 0, Standbild blendet aus (Cuberto)",
   "Viewport: Quelle erst bei Sichtbarkeit setzen, abspielen solange sichtbar, sonst pausieren (Instrument)",
   "Scrubbing: Die waagerechte Mausposition steuert currentTime",
   "Video im mitlaufenden Vorschaufenster einer Projektliste (siehe listen-hover-bildvorschau)",
   "Nur Poster-Bild, Video erst nach Klick",
   "Video nur in der aktiven Folie eines Scroll-Snap-Karussells: Nachbarn zeigen das Standbild, stumm, Pause-Knopf, Fremdplayer (YouTube, Vimeo) erst nach dem zweiten Klick"
  ],
  "umsetzung": "Markup: <a class=karte href=…><img src=poster.jpg alt=…><video muted loop playsinline preload=none aria-hidden=true data-src=clip.mp4></video></a>. Das Poster ist das erste Bild des Clips, dann springt beim Ausblenden nichts. Hover nur bei matchMedia('(hover: hover) and (pointer: fine)'): bei mouseenter video.currentTime = 0 und video.play().catch(() => {}), bei mouseleave video.pause(). Standbild per opacity ausblenden (400 ms, 200 ms Verzögerung, damit das erste Videobild schon da ist), beide Medien in 1200 ms expo.out auf scale 1.05. Viewport: IntersectionObserver mit threshold 0.25 bis 0.5. Beim ersten Eintritt src aus data-src setzen, dann play(), beim Verlassen pause(). Scrubbing: auf pointermove currentTime setzen, während seeking nur den letzten Wert merken und bei seeked nachziehen; dafür Clips mit kurzen Keyframe-Abständen kodieren, und der Server muss Range-Requests beantworten. Fallstricke: play() liefert ein Promise, Fehler abfangen. Autoplay nur mit muted und playsinline. Clips unter etwa 1 bis 2 MB halten, 720p reicht für Kacheln. Nur wenige Videos gleichzeitig dekodieren.",
  "mobil": "Ohne Hover entweder nur das Standbild zeigen (Cuberto blendet das Video ohne feinen Zeiger aus) oder die sichtbare Karte per Viewport-Autoplay abspielen. Den Datensparmodus beachten (navigator.connection.saveData) und dann nichts automatisch starten.",
  "reduzierte_bewegung": "Kein Autoplay und kein Zoom. Das Standbild bleibt stehen, abgespielt wird nur auf ausdrücklichen Klick.",
  "barrierefreiheit": "Rein dekorative Clips bekommen aria-hidden und keinen Ton. Automatisch startende Videos über 5 s brauchen eine Pause-Möglichkeit (WCAG 2.2.2), also in der Viewport-Variante einen Play/Pause-Knopf je Clip wie bei Instrument. Linkziel und Kartentext funktionieren unabhängig vom Video. Bei Tastaturfokus verhält sich die Karte wie beim Hover."
 },
 "messwerte": {
  "easing": "Medien-Zoom cubic-bezier(.16,1,.3,1); Ausblendung Standard-ease",
  "dauer_ms": "Bild-Ausblendung 400 (Verzögerung 200); Zoom 1200; Video-Einblendung 400",
  "stagger_ms": "",
  "distanz": "scale 1 auf 1.05",
  "sonstiges": "Video nur bei pointer: fine; preload=none; Neustart bei currentTime 0 je Hover. Instrument: Laden und Abspielen per IntersectionObserver.",
  "herkunft": "beobachtet",
  "quelle": "https://cuberto.com/; https://cuberto.com/_astro/index.astro_astro_type_script_index_0_lang.DUafXxYS.js?dpl=dpl_9QJjpNzTFmS7yqLWqVJudUB2bNRP; https://www.instrument.com/_nuxt/VideoClip.979b033d.js"
 },
 "kurve": {
  "bezier": [
   0.16,
   1.0,
   0.3,
   1.0
  ],
  "css": "cubic-bezier(0.16, 1, 0.3, 1)",
  "name": "expo.out",
  "dauer_ms": 400
 },
 "gesehen_bei": [
  {
   "seite": "Cuberto",
   "url": "https://cuberto.com/",
   "auszeichnung": "",
   "beobachtung": "Live geprüft: Projektkarten .Card mit <picture> und .preview__media.-video mit <video src=…/cover.mp4 preload=none playsinline loop muted>. Script (Card): nur wenn nicht Touch (ScrollTrigger.isTouch) – mouseenter setzt currentTime = 0 und ruft play(), mouseleave pause(). CSS nur bei @media (pointer: fine): Video zunächst opacity 0 (transition opacity .4s, transform .6s), beim Hover blendet das Bild mit .2s Verzögerung aus, Bild und Video skalieren auf 1.05 mit transform 1.2s cubic-bezier(.16,1,.3,1). Ohne feinen Zeiger ist das Video display: none.",
   "art": "website",
   "browser_gemessen": true
  },
  {
   "seite": "Instrument",
   "url": "https://www.instrument.com/",
   "auszeichnung": "",
   "beobachtung": "Live geprüft: Nuxt-Komponente VideoClip – IntersectionObserver setzt die Video-Quelle erst bei Sichtbarkeit aus data-src, spielt bei isIntersecting ab und pausiert beim Verlassen; dieselbe Logik für eingebettete Vimeo-Player. Dazu ein Play/Pause-Umschalter.",
   "art": "website"
  }
 ],
 "tutorials": [
  {
   "titel": "MDN – HTMLMediaElement.play() (Promise und Autoplay-Regeln)",
   "url": "https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play"
  }
 ],
 "kombinierbar_mit": [
  "listen-hover-bildvorschau",
  "projektindex-hover-vorschau",
  "kontextueller-cursor",
  "bild-zoom-in-maske",
  "bento-grid-interaktiv"
 ],
 "urls": {
  "detail": "https://cecodesign.de/lab/fundus/galerien-slider/video-vorschau-hover-viewport/",
  "meta": "https://cecodesign.de/lab/fundus/galerien-slider/video-vorschau-hover-viewport/meta.json",
  "demo": "https://cecodesign.de/lab/fundus/galerien-slider/video-vorschau-hover-viewport/demo"
 },
 "herkunft": {
  "quelldateien": [
   "patch-luecken-a.json"
  ]
 },
 "bau": {
  "status": "fertig",
  "kurz": "Projektkarten zeigen ein Standbild. Erst unter dem Zeiger oder im Viewport läuft der stumme Clip, das Bild zoomt dabei leicht.",
  "demo": true,
  "abhaengigkeiten": [],
  "werte": {
   "zoom": "scale 1 auf 1.05 (Standbild und Video)",
   "zoom_dauer_ms": 1200,
   "zoom_easing": "cubic-bezier(0.16, 1, 0.3, 1) (expo.out)",
   "standbild_aus": "opacity 400 ms ease, Verzögerung 200 ms",
   "video_ein": "opacity 400 ms ease",
   "neustart": "currentTime = 0 bei jedem Hover, pause() beim Verlassen",
   "hover_nur_bei": "(hover: hover) and (pointer: fine), Ereignis pointerenter mit pointerType mouse",
   "viewport_threshold": 0.5,
   "viewport_laden": "data-src wird beim ersten Bedarf zu src, preload=none",
   "scrubbing": "currentTime = (clientX - links) / Breite × Dauer; laufende Suche wird gepuffert (seeked)",
   "nachbarn": "nicht aktive Karten filter brightness(.5) saturate(.6), Text opacity .45, 400 ms ease",
   "clips": "H.264 MP4, 1280 × 720 px, per object-fit: cover auf 4:5 beschnitten, 25 fps, 4,9 s, 200 bis 340 KB, ohne Ton; Standbild = erstes Bild (-poster.jpg)",
   "reduziert": "kein Autoplay, kein Zoom, Überblenden 150 ms linear",
   "vorfuehrung": "Zeiger besucht je Karte 3400 ms (Weg 650 ms, Verweilen bis 2750 ms)"
  },
  "ausloeser": "hover",
  "touch": "Ohne feinen Zeiger gilt die Viewport-Variante: Der Clip spielt, solange die Karte zur Hälfte sichtbar ist, und pausiert außerhalb. Jede Karte hat einen Play/Pause-Knopf (40 px). Bei aktivem Datensparmodus startet nichts von selbst. Karussell: Wischen mit Scroll-Snap, das Video der neuen Folie startet erst, wenn das Scrollen ruht; Folien 84 vw im Format 4:5.",
  "reduziert": "Kein Clip startet von selbst, kein Zoom. Der Knopf auf jeder Karte spielt den Clip ab, Standbild und Video blenden in 150 ms über. Der Varianten-Umschalter ist ausgeblendet. Karussell: kein Autostart, Abspielen über den Pause-Knopf, Blättern ohne weiches Scrollen, Überblenden 150 ms.",
  "korrekturen": {
   "beschreibung": "Projektkarten zeigen zuerst ein Standbild. Am Desktop startet beim Hover an derselben Stelle ein stummes Loop-Video von vorn. Das Standbild blendet aus, das Medium zoomt minimal. Beim Verlassen pausiert das Video. Auf Touch-Geräten und in der Viewport-Variante lädt das Video erst, wenn die Karte sichtbar wird, und spielt nur, solange sie sichtbar bleibt. Die Clips sind kurz (3 bis 8 s), stark komprimiert und werden erst bei Bedarf geladen.",
   "warum_es_wirkt": "Das Raster wird lebendig, ohne dass die ganze Seite flimmert. Bewegung entsteht genau dort, wo der Nutzer hinschaut. Ein paar Sekunden Bewegtbild zeigen Motion-Design, Interaktion und Stimmung eines Projekts schneller als jedes Standbild.",
   "wann_einsetzen": "Portfolio-Raster, Projektindizes, Produkt-Features mit kurzen UI-Clips, Kurs-Kacheln mit Trailer, Template-Galerien mit animierter Vorschau.",
   "wann_nicht": "Wenn Datensparsamkeit zählt und viele große Videos nötig wären. Wenn der Clip Ton braucht. Wenn mehr als etwa drei Videos gleichzeitig laufen würden. Wenn das Standbild schon alles sagt.",
   "varianten": [
    "Hover-to-play: Neustart bei 0, Standbild blendet aus (Cuberto)",
    "Viewport: Quelle erst bei Sichtbarkeit setzen, abspielen solange sichtbar, sonst pausieren (Instrument)",
    "Scrubbing: Die waagerechte Mausposition steuert currentTime",
    "Video im mitlaufenden Vorschaufenster einer Projektliste (siehe listen-hover-bildvorschau)",
    "Nur Poster-Bild, Video erst nach Klick",
    "Video nur in der aktiven Folie eines Scroll-Snap-Karussells: Nachbarn zeigen das Standbild, stumm, Pause-Knopf, Fremdplayer (YouTube, Vimeo) erst nach dem zweiten Klick"
   ],
   "umsetzung": "Markup: <a class=karte href=…><img src=poster.jpg alt=…><video muted loop playsinline preload=none aria-hidden=true data-src=clip.mp4></video></a>. Das Poster ist das erste Bild des Clips, dann springt beim Ausblenden nichts. Hover nur bei matchMedia('(hover: hover) and (pointer: fine)'): bei mouseenter video.currentTime = 0 und video.play().catch(() => {}), bei mouseleave video.pause(). Standbild per opacity ausblenden (400 ms, 200 ms Verzögerung, damit das erste Videobild schon da ist), beide Medien in 1200 ms expo.out auf scale 1.05. Viewport: IntersectionObserver mit threshold 0.25 bis 0.5. Beim ersten Eintritt src aus data-src setzen, dann play(), beim Verlassen pause(). Scrubbing: auf pointermove currentTime setzen, während seeking nur den letzten Wert merken und bei seeked nachziehen; dafür Clips mit kurzen Keyframe-Abständen kodieren, und der Server muss Range-Requests beantworten. Fallstricke: play() liefert ein Promise, Fehler abfangen. Autoplay nur mit muted und playsinline. Clips unter etwa 1 bis 2 MB halten, 720p reicht für Kacheln. Nur wenige Videos gleichzeitig dekodieren.",
   "mobil": "Ohne Hover entweder nur das Standbild zeigen (Cuberto blendet das Video ohne feinen Zeiger aus) oder die sichtbare Karte per Viewport-Autoplay abspielen. Den Datensparmodus beachten (navigator.connection.saveData) und dann nichts automatisch starten.",
   "reduzierte_bewegung": "Kein Autoplay und kein Zoom. Das Standbild bleibt stehen, abgespielt wird nur auf ausdrücklichen Klick.",
   "barrierefreiheit": "Rein dekorative Clips bekommen aria-hidden und keinen Ton. Automatisch startende Videos über 5 s brauchen eine Pause-Möglichkeit (WCAG 2.2.2), also in der Viewport-Variante einen Play/Pause-Knopf je Clip wie bei Instrument. Linkziel und Kartentext funktionieren unabhängig vom Video. Bei Tastaturfokus verhält sich die Karte wie beim Hover."
  },
  "geprueft": "03.11.2026",
  "notiz": "Portfolio-Raster eines erfundenen Motion-Studios mit vier Karten und drei Varianten (Hover, Viewport mit Play/Pause, Scrubbing). Die vier Clips sind selbst gerenderte Kamerafahrten aus medien/ (flakon, magazin-doppelseite, zitronen-tisch, keramik-stillleben, je .mp4 im Querformat 1280 × 720, per object-fit: cover auf 4:5 beschnitten). Das Standbild ist das zugehörige -poster.jpg, also exakt das erste Bild des Clips. Zeitcode und Fortschrittslinie zeigen den Neustart bei 0. Nicht aktive Karten treten zurück, damit der Effekt in der Vorschau lesbar ist. Scrubbing braucht einen Server mit Range-Requests (der Prüfserver hat keine, dort bleibt das Bild stehen). Bilder 01.11.2026: eigene Bilder statt Portfolio. Varianten 03.11.2026: Die bestehende Demo ist jetzt die Grundvariante basis (?v=basis), Umschalter Raster/Karussell im Pult unten rechts. Neue Variante karussell-folie (Rezept handwerk-werkstatt-klartext): erfundenes Werkhaus am Ryck in Greifswald mit fünf Werkstattfilmen; Scroll-Snap-Karussell, das Video spielt nur in der aktiven Folie, Nachbarn zeigen das Standbild; Pause-Knopf; „Ganzen Film ansehen“ zeigt nur den Zwei-Klick-Hinweis (Beleg Splide Video-Extension). Geprüft: Die Grundvariante nutzt keine Portfolio-Videos mehr, nur eigene Clips aus medien/. Selbsturteil 4.",
  "varianten": [
   {
    "id": "basis",
    "name": "Projektraster mit Hover, Viewport oder Scrubbing",
    "knopf": "Raster",
    "wann": "Portfolio, Studio, Kurs-Kacheln: mehrere kurze Clips im Raster, am Desktop per Hover, auf Touch im Viewport, Unterumschalter Hover, Viewport, Scrubbing.",
    "werte": {
     "welt": "Studio Halbton, Köln; vier eigene Clips (flakon, magazin-doppelseite, zitronen-tisch, keramik-stillleben)",
     "zoom": "scale 1 → 1.05, 1200 ms cubic-bezier(0.16, 1, 0.3, 1)",
     "standbild_aus": "opacity 400 ms ease, 200 ms verzögert",
     "viewport_threshold": 0.5
    }
   },
   {
    "id": "karussell-folie",
    "name": "Video nur in der aktiven Folie (Werkstattfilme)",
    "knopf": "Karussell",
    "wann": "Handwerk (Imagefilm), Fitness, Hotel, Kultur: mehrere kurze Filme nebeneinander, von denen immer nur einer läuft; die ganzen Filme liegen bei YouTube oder Vimeo.",
    "werte": {
     "rezept": "handwerk-werkstatt-klartext",
     "welt": "Werkhaus am Ryck, Greifswald: Töpferei, Glas, Buchbinderei, Hofküche, der Ort; eigene Clips medien/keramik-stillleben, flakon, magazin-doppelseite, zitronen-tisch (je 4,9 s, 1280 × 720) und eigener-videoplayer-am-sund (16 s, 960 × 540), Standbild jeweils das Poster",
     "spur": "scroll-snap-type x mandatory, scroll-snap-align start, scroll-snap-stop always; Folie min(60vw, 820px) im Format 16:9, Telefon 84 vw im Format 4:5; Nachbar angeschnitten; Abstand clamp(12px, 1.6vw, 24px)",
     "aktiv": "Folie, deren linke Kante am Snap-Punkt liegt; Markierung und Zähler sofort beim Scrollen",
     "video": "erst wenn das Scrollen ruht (scrollend, sonst 150 ms ohne scroll-Ereignis): data-src → src, currentTime 0, play() stumm mit loop und playsinline; Nachbarn pause(), Standbild bleibt; Video ein opacity 400 ms cubic-bezier(0.2, 0, 0.38, 0.9)",
     "nachbarn": "nur das Bild tritt zurück: brightness(.62) saturate(.7), 400 ms; Titel und Text bleiben voll lesbar",
     "bedienung": "Pfeile 44 px (am Ende weiter zum anderen Ende), Pause-Knopf „Bewegung anhalten“ mit aria-pressed, ← → Pos1 Ende auf der Spur, Klick oder Fokus auf eine Nachbarfolie holt sie; scrollTo mit Zielposition, weil scrollBy mit snap-stop an jeder Folie hält",
     "anzeige": "Chip mit Zeitcode und „ohne Ton“, Fortschrittslinie 3 px im Signalton am unteren Rand",
     "fremdplayer": "„Ganzen Film ansehen“ öffnet zuerst den Zwei-Klick-Hinweis (Vimeo, Untertitel Deutsch und Englisch, Datenübertragung erst nach „Film laden“); in der Demo keine echte Einbettung",
     "reduziert": "kein Autostart, auch bei Datensparmodus (navigator.connection.saveData); Abspielen per Pause-Knopf",
     "vorfuehrung": "Takt 4600 ms, nach der letzten Folie wieder zur ersten"
    }
   }
  ]
 }
}
