Files
ZeasyAlexandClaude Opus 5 bc2c8f6cbe Overlay: fuenf Browser-Sources fuer OBS
Einblendungen, Chat, Statusleiste, Effekte, Pausenbild. Kein Build, kein
Framework - OBS laedt die Dateien direkt, und jede Zwischenstufe waere ein
Ding, das mitten im Stream kaputtgehen kann.

Server-Sent Events statt WebSocket, entgegen der Skizze in chat-control.md:
Node bringt einen WebSocket-*Client* mit, aber keinen Server, `EventSource`
verbindet sich von allein neu, und die Richtung stimmt - das Overlay hoert
nur zu. Gegen die tote Browser-Source nach einem Neustart stehen drei Dinge:
der eingebaute Reconnect, ein Herzschlag als echtes Ereignis (ein
SSE-Kommentar haelt die Verbindung offen, ist im Browser aber unsichtbar),
und ein Zustands-Schnappschuss beim Verbinden.

Abos, Raids, Bits und Loeschungen kommen ueber IRC-USERNOTICE und CLEARCHAT
herein; das wurde bisher weggeworfen. Follows fehlen weiter, die gibt es nur
ueber EventSub.

GIFs im Chat: Twitch schickt dafuer einen Tag `gifs`, den wir nicht kannten.

  gifs=0-22|Pnd7qLFuGCOntZcNKB|https://media0.giphy.com/media/.../giphy.gif
  PRIVMSG #abdulive_ :[Idk GIF by Respective]

Der Nachrichtentext ist nur ein Platzhalter, der Bereich markiert ihn.
Ausgewertet wird er jetzt; ohne das stand woertlich "[Idk GIF by Respective]"
im Bild. Gefunden wurde der Tag durch einen Rohmitschnitt - in 3094
Nachrichten aus acht grossen Kanaelen war kein einziges GIF, weil die Adresse
eben nicht im Text steht.

Zwei Fehler, die beim Durchklicken im Browser aufgefallen sind:

- Die Aufraeumfunktion im Chat zaehlte Zeilen, die erst nach der
  Ausblend-Animation aus dem DOM verschwinden, und lief in eine
  Endlosschleife. In OBS waere die Quelle beim vierzehnten Chatbeitrag
  eingefroren.
- Der Bereichsparser der GIFs war zu nachsichtig: `-1-4` zerfaellt beim
  Trennen in ['', '1', '4'], und `Number('')` ist 0 - der Bereich saehe
  gueltig aus und wuerde den falschen Textteil ersetzen.

Auf der Uebersichtsseite steht fuer jede Einblendung, jede Chat-Variante und
jeden Effekt ein Knopf. Ohne den liesse sich eine Raid-Einblendung nur
pruefen, indem man auf einen echten Raid wartet. Was einen Zustand setzt, ist
waehrend eines Streams gesperrt; "Stand zuruecksetzen" ausdruecklich nicht,
sonst kaeme man aus einem erfundenen Zustand nicht mehr heraus.

build-package.ts nimmt jetzt auch html/css/js mit - sonst liefert das Paket
404 statt Overlay.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 00:13:28 +02:00

123 lines
3.8 KiB
CSS

/* Gemeinsames Aussehen aller Browser-Sources.
*
* Zwei Dinge gelten auf jeder Seite und sind der Grund, warum es diese Datei
* gibt:
*
* 1. Der Hintergrund ist durchsichtig. Eine Browser-Source mit weissem
* Hintergrund ist der haeufigste Anfaengerfehler, und man sieht ihn erst
* in der Aufzeichnung.
* 2. Text liegt ueber bewegtem Bild. Reine Farbe reicht dafuer nicht -
* jeder Text bekommt eine dunkle Kontur, sonst verschwindet er im hellen
* Gameplay. Deshalb `paint-order` und der Schatten unten.
*/
:root {
/* Twitch-Lila wie im Discord-Bauplan, damit Stream und Server zusammengehoeren. */
--lila: #a970ff;
--lila-tief: #6441a5;
--tuerkis: #4fd1c5;
--pink: #ff4fa3;
--gold: #ffc53d;
--gruen: #4ade80;
--rot: #ef4444;
--tinte: #120e1d;
--tinte-klar: rgba(18, 14, 29, .72);
--schrift: #f6f3ff;
--schrift-leise: #c5bde0;
--rund: 14px;
--schatten: 0 12px 40px rgba(0, 0, 0, .55);
--glanz: inset 0 1px 0 rgba(255, 255, 255, .12);
/* Segoe UI Variable gibt es auf Windows 11 - Abdus Rechner. Der Rest der
* Liste ist Rueckfall fuer Entwicklung auf anderen Systemen. */
--font: "Segoe UI Variable Display", "Segoe UI", Inter, system-ui, sans-serif;
--font-zahl: "Segoe UI Variable Text", "Segoe UI", system-ui, sans-serif;
}
* { box-sizing: border-box; }
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background: transparent;
overflow: hidden;
font-family: var(--font);
color: var(--schrift);
/* OBS rendert mit eigener Skalierung; ohne das wirken Kanten weich. */
-webkit-font-smoothing: antialiased;
user-select: none;
cursor: none;
}
.kontur {
paint-order: stroke fill;
-webkit-text-stroke: 4px rgba(0, 0, 0, .55);
text-shadow: 0 2px 10px rgba(0, 0, 0, .7);
}
/* Glasplatte: der Traeger fuer alles, was ueber dem Spiel steht. */
.glas {
background: var(--tinte-klar);
backdrop-filter: blur(14px) saturate(140%);
border: 1px solid rgba(255, 255, 255, .1);
border-radius: var(--rund);
box-shadow: var(--schatten), var(--glanz);
}
/* Der Lichtstreifen, der einmal ueber eine Flaeche wandert. Wird von den
* Einblendungen benutzt und ist der Grund, warum eine Einblendung "teuer"
* aussieht, ohne dass ein Video dahintersteckt. */
@keyframes streifen {
from { transform: translateX(-120%) skewX(-18deg); }
to { transform: translateX(320%) skewX(-18deg); }
}
.streifen::after {
content: "";
position: absolute;
inset: 0 auto 0 0;
width: 28%;
background: linear-gradient(100deg, transparent, rgba(255, 255, 255, .3), transparent);
animation: streifen 1.5s cubic-bezier(.3, 0, .2, 1) .35s both;
pointer-events: none;
}
@keyframes pulsieren {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: .55; transform: scale(.82); }
}
/* Zum Ansehen im normalen Browser: ?probe=1 legt einen dunklen Grund unter
* die Seite. Ohne den steht heller Text auf Weiss, und man sieht nichts -
* in OBS liegt das Overlay ueber dem Spiel, im Browser ueber gar nichts. */
body.probe {
background:
radial-gradient(60% 60% at 30% 25%, #2a1f45, transparent 70%),
radial-gradient(50% 50% at 75% 70%, #123c3a, transparent 70%),
#0b0912;
}
/* Wer im Browser nachsieht, will nicht raten, ob die Verbindung steht.
* In OBS ist der Punkt unsichtbar, weil er nur bei Verlust erscheint. */
.getrennt {
position: fixed;
right: 10px;
bottom: 8px;
font: 500 12px/1 var(--font-zahl);
color: var(--rot);
background: rgba(0, 0, 0, .7);
padding: 6px 10px;
border-radius: 999px;
opacity: 0;
transition: opacity .4s;
}
body.offline .getrennt { opacity: 1; }
/* Wer mit prefers-reduced-motion arbeitet, bekommt in OBS trotzdem die
* Animationen - eine Browser-Source hat keinen Menschen mit Vestibular-
* problemen davor. Die Einstellung wird hier bewusst nicht beachtet. */