{
 "$schema": "../../schema.json",
 "schema": "fundus/1",
 "id": "eigener-videoplayer",
 "name": "Eigener Videoplayer",
 "name_en": "Custom video player with captions and media state pseudo-classes",
 "kurz": "Natives video mit eigener, ruhiger Steuerung: Zeitleiste mit Vorschaubild, Lautstärke, selbst gesetzte WebVTT-Untertitel, Vollbild, Tastatur und Zustände per :playing/:paused mit Klassen als Fallback.",
 "kategorie": "Sektionen & Funktionen",
 "kategorie_slug": "sektionen",
 "kategorie_nr": 16,
 "bau_chat": "D",
 "prioritaet": "D",
 "trendstatus": "aufsteigend",
 "belegstatus": "quellenbelegt",
 "website_belege": 0,
 "stimmung": [
  "ruhig",
  "editorial",
  "präzise",
  "filmisch"
 ],
 "stimmung_roh": [
  "filmisch",
  "ruhig",
  "kuratiert",
  "funktional"
 ],
 "technik": [
  "css",
  "vanilla-js",
  "video",
  "webvtt"
 ],
 "technik_gruppen": [
  "css",
  "js",
  "canvas"
 ],
 "leistungskosten": "mittel",
 "steckbrief": {
  "beschreibung": "Ein natives video-Element mit eigener Steuerung: Play und Pause, Zeitleiste mit Vorschaubild beim Überfahren, Lautstärke, Untertitel an und aus, Vollbild. Untertitel kommen als WebVTT und werden selbst gesetzt, damit sie nie unter der Steuerung verschwinden. Zustände wie spielt, pausiert und lädt steuern das Aussehen: per Media-Pseudoklassen (:playing, :paused, :buffering), wo der Browser sie kennt, sonst per Klassen aus JavaScript. Die Tastatur bedient alles.",
  "warum_es_wirkt": "Die Standard-Steuerung sieht in jedem Browser anders aus und bricht die Gestaltung einer Film- oder Kursseite. Eine eigene, ruhige Leiste in der Schrift der Marke lässt das Bild wirken. Untertitel und Tastatur machen den Film für mehr Menschen nutzbar, und das Vorschaubild auf der Zeitleiste macht langes Material schnell durchsuchbar.",
  "wann_einsetzen": "Showreel und Werkfilm bei Film- und Fotografie-Studios. Kursvideos mit Kapiteln und Tempo-Wahl. Produkt- und Imagefilme, die selbst gehostet werden.",
  "wann_nicht": "Wenn Videos bei YouTube oder Vimeo liegen und deren Player eingebunden wird (dort 2-Klick-Lösung statt eigener Steuerung). Für stumme Hintergrund-Loops (dann nur ein Pause-Knopf). Wenn kein Budget für Untertitel da ist: ein Film mit Sprache braucht sie. Raumlicht nicht auf hellem Grund, nicht bei Produkt- oder Kursvideos, in denen der Inhalt zählt, und nicht neben Text, der darauf lesbar bleiben muss.",
  "varianten": [
   "Showreel: dunkle Bühne, Steuerung blendet beim Abspielen nach kurzer Ruhe aus",
   "Kursvideo mit Kapiteln: Kapitelmarken auf der Zeitleiste, Kapitelliste, Tempo 1× bis 1,5×, Transkript",
   "Raumlicht (Ambilight): Die Farben des laufenden Films strahlen weich in die Fläche um den Player (verkleinertes Videobild im Canvas, stark weichgezeichnet), abschaltbar",
   "Nur-Poster mit Play-Knopf, Video lädt erst nach Klick",
   "Mini-Player, der beim Wegscrollen in die Ecke wandert"
  ],
  "umsetzung": "Markup: figure.player > video (playsinline, preload=metadata, poster) mit source WebM und MP4, darüber eine Steuerleiste aus echten button-Elementen und einer Zeitleiste aus input type=range (aria-valuetext „0:05 von 0:16“). Untertitel: track kind=subtitles mit WebVTT (im Einsatz als Datei, in der Demo als Blob-URL), mode = hidden und die Cues bei cuechange selbst über der Leiste setzen. Vorschau: ein Sprite aus 16 Standbildern (160 × 90) wird beim Überfahren der Zeitleiste auf die Sekunde gesetzt; im Einsatz besser eine Thumbnail-VTT-Datei. Zustände: CSS.supports('selector(:playing)') prüfen; wenn ja, Regeln mit .player:has(video:playing), sonst setzt JavaScript bei play, pause, waiting, playing die Klassen .spielt, .pausiert, .laedt. Beide Wege in getrennten Regeln schreiben, sonst verwirft der Browser die ganze Regel. Tastatur auf dem Player: Leertaste oder K spielt und pausiert, Pfeil links und rechts springen 5 s, Pfeil hoch und runter ändern die Lautstärke, M stumm, C Untertitel, F Vollbild. Vollbild auf dem figure-Element (requestFullscreen), auf iPhone video.webkitEnterFullscreen. Kein Autoplay mit Ton. Videos mit kurzem Keyframe-Abstand kodieren (-g 24), damit das Springen schnell ist. Browserstand (02.11.2026): Safari ab 15.4 und Firefox ab 150 kennen alle Media-Pseudoklassen. Chrome und Edge laut Web Features Explorer und MDN noch nicht (Limited availability); web.dev nannte sie für die Beta von Chrome 156, für die stabile Version fand sich kein Beleg. Der web.dev-Digest August 2026 führt :paused zwar als Baseline, das widerspricht diesen Kompatibilitätsdaten. Deshalb bleiben die JS-Klassen der Hauptweg und die Pseudoklassen eine Verbesserung.",
  "mobil": "Steuerung bleibt sichtbar, solange das Video pausiert. Tippen auf das Bild zeigt die Leiste, ein zweites Tippen spielt oder pausiert. Kein Lautstärke-Regler (iOS regelt nur über die Tasten), nur stumm. Die Zeitleiste hat eine große Trefferfläche, die Vorschau erscheint beim Ziehen. Vollbild über webkitEnterFullscreen.",
  "reduzierte_bewegung": "Kein automatisches Abspielen, Steuerung ohne Übergänge und ohne Ausblenden.",
  "barrierefreiheit": "Alle Bedienelemente sind button oder input mit Namen, Play, Untertitel und Stumm melden ihren Zustand mit aria-pressed bzw. wechselndem Namen. Die Zeitleiste nennt die Zeit als aria-valuetext. Untertitel standardmäßig verfügbar und sichtbar (WCAG 1.2.2), Transkript als Alternative. Kein Autoplay mit Ton, Pause jederzeit möglich (WCAG 2.2.2). Fokus sichtbar, die Steuerung blendet bei Fokus nicht aus. Tastenkürzel nur, solange der Player den Fokus hat."
 },
 "messwerte": {
  "easing": "cubic-bezier(0.455, 0.03, 0.515, 0.955)",
  "dauer_ms": "200 UI, 350 Ein- und Ausblenden der Steuerung, 2500 Ruhe bis zum Ausblenden",
  "stagger_ms": "",
  "distanz": "Steuerung 8 px nach unten beim Ausblenden",
  "sonstiges": "Kurve und Dauern aus dem Rezept fotograf-film-bild-zuerst (Nadav Kander easeInOutQuad 350 ms, UI 200 ms). Bewegt wird nur die Oberfläche, nie das Bild.",
  "herkunft": "eigene Festlegung",
  "quelle": "Rezept fotograf-film-bild-zuerst"
 },
 "kurve": {
  "bezier": [
   0.455,
   0.03,
   0.515,
   0.955
  ],
  "css": "cubic-bezier(0.455, 0.03, 0.515, 0.955)",
  "name": "eigene Kurve",
  "dauer_ms": 200
 },
 "gesehen_bei": [
  {
   "seite": "modern-css.com: Video player states without JavaScript events",
   "url": "https://modern-css.com/video-player-states-without-javascript-events/",
   "auszeichnung": "",
   "beobachtung": "Selektoren wie video:paused + .controls .play-icon, video:buffering + .controls .spinner und .player:has(video:playing). Rät ausdrücklich, die Klassen aus JavaScript als Hauptweg zu behalten und die Pseudoklassen als Verbesserung zu nutzen. Unterstützung: Safari 15.4+, Firefox 150+.",
   "art": "tutorial"
  },
  {
   "seite": "Web Features Explorer: Media element pseudo-classes",
   "url": "https://web-platform-dx.github.io/web-features-explorer/features/media-pseudos",
   "auszeichnung": "",
   "beobachtung": ":playing, :paused, :seeking, :buffering, :stalled, :muted, :volume-locked. Safari 15.4, Firefox 150 (21.04.2026), Chrome und Edge dort noch ohne Unterstützung; Teil von Interop 2026.",
   "art": "artikel"
  },
  {
   "seite": "MDN: Adding captions and subtitles to HTML video",
   "url": "https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Audio_and_video_delivery/Adding_captions_and_subtitles_to_HTML5_video",
   "auszeichnung": "",
   "beobachtung": "Anleitung für track-Elemente mit WebVTT, Untertitel-Menü in einer eigenen Steuerung und Gestaltung der Cues.",
   "art": "tutorial"
  },
  {
   "seite": "Mux: Introducing Player.style",
   "url": "https://mux.com/blog/introducing-player-style",
   "auszeichnung": "",
   "beobachtung": "Sammlung gestalteter Player-Oberflächen auf Basis von Media Chrome (Web Components für eigene Steuerungen). Zeigt, dass eigene Player-Themes ein eigenes Gestaltungsfeld sind.",
   "art": "artikel"
  }
 ],
 "tutorials": [
  {
   "titel": "MDN: Adding captions and subtitles to HTML video",
   "url": "https://developer.mozilla.org/en-US/docs/Web/Media/Guides/Audio_and_video_delivery/Adding_captions_and_subtitles_to_HTML5_video"
  },
  {
   "titel": "modern-css.com: Video player states without JavaScript events",
   "url": "https://modern-css.com/video-player-states-without-javascript-events/"
  }
 ],
 "kombinierbar_mit": [
  "cinematic-video-hero",
  "video-vorschau-hover-viewport",
  "galerie-shared-element-vollbild",
  "projektindex-hover-vorschau",
  "akkordeon-hoehe-auto"
 ],
 "urls": {
  "detail": "https://cecodesign.de/lab/fundus/sektionen/eigener-videoplayer/",
  "meta": "https://cecodesign.de/lab/fundus/sektionen/eigener-videoplayer/meta.json",
  "demo": "https://cecodesign.de/lab/fundus/sektionen/eigener-videoplayer/demo"
 },
 "herkunft": {
  "quelldateien": [
   "DEF-Recherche 01.11.2026"
  ],
  "pruefnotizen": [
   "02.11.2026 geprüft: Chrome unterstützt die Media-Pseudoklassen noch nicht. Web Features Explorer: Safari 15.4, Firefox 150, Chrome/Edge ohne (Baseline seit April 2026 durch Chromium blockiert). Die Blog-Angabe „Chrome 152“ (codercops) ist falsch: die Release Notes zu Chrome 152 (developer.chrome.com/release-notes/152) nennen das Feature nicht. „Chrome 156 Beta“ aus der Recherche ist nicht belegt; in den gelesenen Chrome-Quellen kein Eintrag. Teil von Interop 2026 (web.dev/blog/interop-2026). Deshalb immer mit JS-Fallback bauen.",
   "Kein Website-Beleg eines Studios mit eigenem Player gemessen; Belege sind Anleitungen und Player-Bibliotheken.",
   "Korrektur 02.11.2026: Widerspruch geklärt, so weit belegbar. web.dev Baseline-Digest August 2026 listet :paused unter „Baseline Newly available“; Web Features Explorer (Feature media-pseudos, abgerufen 02.11.2026: Chrome/Edge „Not supported“, Baseline durch Chromium blockiert seit April 2026) und MDN (:paused „Limited availability“) widersprechen. web.dev „New to the web, September 2026“ nennt :playing, :paused, :seeking, :buffering, :stalled, :muted, :volume-locked für die Chrome-156-Beta; der Chrome-156-Beta-Blog und die Drittquelle zu Chrome 156 stabil nennen sie nicht. Stand im Steckbrief: in Chrome noch nicht belegt, JS-Klassen bleiben Hauptweg. Demo unverändert (prüft per CSS.supports)."
  ]
 },
 "bau": {
  "status": "fertig",
  "kurz": "Natives video mit eigener, ruhiger Steuerung: Zeitleiste mit Vorschaubild, Lautstärke, selbst gesetzte WebVTT-Untertitel, Vollbild, Tastatur und Zustände per :playing/:paused mit Klassen als Fallback.",
  "demo": true,
  "abhaengigkeiten": [],
  "werte": {
   "easing": "cubic-bezier(0.455, 0.03, 0.515, 0.955) (easeInOutQuad)",
   "dauer_ms": "200 UI (Knöpfe, Zeitleiste, Vorschau), 350 Ein- und Ausblenden der Leiste und Untertitel-Lage, 2500 Ruhe bis zum Ausblenden, 900 Hinweis-Blitz",
   "distanz": "Leiste translate 0 → 8px beim Ausblenden; Spur 3 → 5px bei Hover/Fokus; Kopfpunkt scale 0 → 1",
   "sprung": "Pfeiltasten ±5 s, Lautstärke ±10 %",
   "vorschau": "Sprite 4 × 4 Bilder à 160 × 90 px, ein Bild je Sekunde (Mitte der Sekunde)",
   "video": "960 × 540, 24 fps, 16 s, Keyframe alle 24 Bilder; WebM VP9/Opus 0,5 MB und MP4 H.264/AAC 0,58 MB (-preset veryfast, -crf 26)",
   "untertitel": "Instrument Sans 500 clamp(15px, 2.3cqi, 24px)/1.5 auf rgba(8,8,8,.74), 86 px über der Unterkante, bei ausgeblendeter Leiste 28 px",
   "typo": "Name und Projekttitel Instrument Serif; Zeit, Zähler, Bildunterschrift Fragment Mono 12px tabular-nums",
   "farben": "Showreel: Grund #0e0e0e, Text #f2f2f2, leise #8a8a8a; Kapitel: Grund #f4f4f2, Text #141414"
  },
  "ausloeser": "klick",
  "touch": "Ohne Hover kein Lautstärke-Regler (nur stumm) und keine Tastenhilfe. Zeitleiste 30 px hoch, Kopfpunkt immer sichtbar, Vorschau erscheint beim Ziehen. Ist die Leiste ausgeblendet, zeigt das erste Tippen sie, das zweite spielt oder pausiert. Vollbild über webkitEnterFullscreen auf dem iPhone.",
  "reduziert": "Leiste blendet nie aus, keine Übergänge, Lade-Ring steht still, Hinweis-Blitz erscheint ohne Blende. Kein Autoplay; die Vorführung spielt nur auf ausdrücklichen Wunsch stumm.",
  "korrekturen": {},
  "geprueft": "02.11.2026",
  "notiz": "Welt: Rezept fotograf-film-bild-zuerst, erfundene Produktionsfirma Sundlicht Film aus Stralsund (Regie Tjark Prüter). Der Clip „Am Sund“ (Morgen am Sund, Giebel am Alten Markt, Hafen bei Nacht) ist mit Python/numpy selbst gerendert, Ton (Wellen, Klang, Glocke) selbst erzeugt, mit ffmpeg kodiert: medien/eigener-videoplayer-am-sund.webm/.mp4, -poster.jpg, -vorschau.jpg (Sprite). Untertitel als WebVTT per Blob-URL, Spur im Modus hidden, Cues selbst gesetzt. Die Pult-Zeile zeigt, ob die Zustände nativ (:playing) oder per Klassen laufen; im Prüf-Chromium läuft der JS-Fallback. Vorführung: stumm abspielen, +5 s springen, Vorschau über die Zeitleiste fahren, Untertitel aus und an, Pause. Quellen: modern-css.com, web-platform-dx.github.io, developer.mozilla.org, mux.com. AD-Review 02.11.2026: Note 4. Offen: WebM ohne Dauer im Kopf, ohne Range-Anfragen (Prüfserver) kein Springen; auf echtem Hosting geprüft ok. Zugang 02.11.2026: Knopfrahmen im Kontrastmodus (Symbolknöpfe des Players). Kein Fehler: Klickfläche und Zeitleiste sind per Tastatur über Abspielknopf, Leertaste und den Range-Regler erreichbar. Korrektur 02.11.2026: Browserstand der Media-Pseudoklassen in umsetzung (neu/eigener-videoplayer.json): Safari 15.4, Firefox 150; Chrome/Edge laut Web Features Explorer und MDN ohne, web.dev nannte sie für die Chrome-156-Beta, stabile Auslieferung nicht belegt; die Baseline-Angabe zu :paused im web.dev-Digest August 2026 widerspricht den Kompatibilitätsdaten. Demo unverändert (CSS.supports-Weiche, JS-Klassen als Hauptweg). Korrektur 02.11.2026: Variante ambilight „Raumlicht“ (Prinzip Video-Glow aus BUTTONS-SLIDERREV-RECHERCHE Q33, nichts übernommen): 24 × 14 px Canvas aus dem laufenden Video, 12 Bilder/s, Mischung 35 %, blur 40 px hinter dem Player; Startlicht aus dem Poster; pausiert bei Pause, außerhalb des Viewports und bei verstecktem Tab; Schalter Raumlicht; reduziert Standbild. Varianten und wann_nicht in neu/eigener-videoplayer.json ergänzt. Korrektur 02.11.2026 (Prüfung): knopf für showreel und kapitel in bau.varianten nachgetragen.",
  "varianten": [
   {
    "id": "showreel",
    "name": "Showreel auf dunkler Bühne",
    "wann": "Film- und Fotostudios, Regie, Produktionsfirmen: ein Werk im Mittelpunkt, Steuerung tritt beim Abspielen zurück.",
    "werte": {
     "leiste": "blendet nach 2500 ms Ruhe aus (350 ms, 8 px)",
     "grund": "#0e0e0e",
     "extra": "Titelkarte im Bild bis zum ersten Abspielen, Werkliste darunter"
    },
    "knopf": "Showreel"
   },
   {
    "id": "kapitel",
    "name": "Kursvideo mit Kapiteln",
    "wann": "Kurs, Werkstatt, Erklär- und Produktvideos: Kapitel auf der Zeitleiste und als Liste, Tempo-Wahl, Transkript.",
    "werte": {
     "leiste": "bleibt immer sichtbar",
     "grund": "#f4f4f2",
     "kapitel": "Marken bei 0:05,3 und 0:10,3 (3 px), aktives Kapitel per aria-current",
     "tempo": "1× / 1,25× / 1,5×",
     "vorschau": "Zeit plus Kapitelname"
    },
    "knopf": "Kapitel"
   },
   {
    "id": "ambilight",
    "name": "Raumlicht um den Film",
    "knopf": "Raumlicht",
    "wann": "Filmpremiere, Showreel, Kino- und Festivalseite auf dunklem Grund: Die Farben des Films strahlen in die Fläche und machen die Seite zum Vorführraum. Nicht auf hellem Grund und nicht bei Kurs- oder Produktvideos.",
    "werte": {
     "grund": "#070708",
     "buehne": "min(100% − 2 × clamp(24px, 9vw, 150px), 960px); Telefon 100% − 32 px",
     "canvas": "24 × 14 px (drawImage des Videos), alle 1000/12 ms (12 Bilder/s) per requestAnimationFrame, nur wenn das Video läuft, der Player sichtbar ist (IntersectionObserver) und der Tab offen ist",
     "glaettung": "globalAlpha 0,35 je Bild: neue Farbe mischt sich über das alte Licht, kein Flackern",
     "licht": "Canvas absolut hinter dem Player, oben −18 %, Höhe 136 %, seitlich min(12 %, Seitenrand); filter blur(40px) saturate(1.5), opacity .85, mask radial-gradient(closest-side, #000 62 %, transparent)",
     "start": "Posterbild einmal ins Canvas, damit vor dem Start schon Licht da ist",
     "schalter": "„Raumlicht“ als button mit aria-pressed, Schiene 32 × 18 px, Knopf 12 px, 200 ms easeInOutQuad; Licht aus = opacity 0 in 600 ms",
     "reduziert": "Licht bleibt als Standbild aus dem Poster stehen, keine Aktualisierung beim Abspielen"
    }
   }
  ]
 }
}
