Filipes Kurznotiz vom 28.09.2026, von links nach rechts:
Kachel sichtbar -> geschlossen -> Vorbereitung -> Wartebereich/
Chat -> Countdown -> LIVE -> Reaction + Gaeste + Chat + PayPal
-> Ende
DREI STAENDE, NICHT SIEBEN
„Wartebereich" und „Countdown" sind keine eigenen Zustaende, sondern
das, was „Vorbereitung" auf dem Bildschirm TUT. Drei Staende, die
sich gegenseitig ausschliessen, sind pruefbar; sieben, von denen sich
vier ueberlappen, sind es nicht.
DAS VIDEO LAEUFT NICHT UEBER DIESEN SERVER
Naheliegend waere: Der Host spielt ab, alle sehen seinen Bildschirm.
Das waere aus zwei Gruenden falsch. Rechtlich ist ein
weitergesendetes YouTube-Video eine oeffentliche Wiedergabe -- genau
die Sache, fuer die Kanaele gesperrt werden. Und technisch kostet es
Bandbreite und Qualitaet.
Jeder Zuschauer laedt das Video deshalb SELBST. Uebertragen wird nur
der Spielstand: Kennung, laeuft/pausiert, Sekunde. Das sind ein paar
Byte, jeder sieht es in voller Qualitaet, und alle sind auf derselben
Sekunde. Nachgefuehrt wird erst ab anderthalb Sekunden Abweichung --
ein Player, dem man jede Sekunde eine neue Position gibt, ruckelt
sichtbar.
DIE KAMERAS LAUFEN DIREKT VON MENSCH ZU MENSCH
Ueber denselben Weg wie die Anrufe im Haus (seit 18.09.), nur mit
mehr Empfaengern. Das hat eine Grenze, und sie ist gerechnet, nicht
geraten: Bei 360p und rund 350 kbit/s sind zwoelf Zuschauer etwa
4 Mbit/s Upload beim Host. Darueber schaltet die Sendung von selbst
auf Ton um -- wer keine Kamera mehr bekommt, hoert alles, sieht das
Video und kann schreiben. Ehrlicher als eine Verbindung, die stockt,
und sichtbar im Regiepult.
Heute sind es elf Menschen im ganzen Haus (gemessen: 1 admin, 1 hand,
1 linke, 4 modi, 4 gast). Die Grenze ist weit weg -- sie steht
trotzdem drin, weil sie sonst erst auffaellt, wenn es zu spaet ist.
DIE SEITE IST ANDERS GEBAUT ALS JEDE ANDERE IM HAUS
Ueberall sonst: Kacheln, Karten, Listen -- man liest, entscheidet,
geht wieder. Hier sitzt man. Eine Stunde, mit anderen, auf EINE
Sache schauend. Deshalb kein Raster, sondern ein SAAL: grosse Flaeche
fuer das Video, Kamerabilder als schwebende Fenster darueber, der
Chat als Schiene daneben. Die Seite scrollt nicht -- ein Video, das
beim Tippen im Chat nach oben rutscht, ist der schnellste Weg, dass
jemand aufhoert zu schreiben.
Fuer den Host ein REGIEPULT: vier senkrechte Regler nebeneinander wie
an einem Mischpult, darueber die Sendung, daneben Gaeste und
Anordnung, unten drei grosse Knoepfe. Es SCHIEBT den Saal, es deckt
ihn nicht zu.
Die Kachel traegt ihren Zustand als Farbe: grau geschlossen,
bernstein in Vorbereitung, rot auf Sendung. Keine Ton-Nummer -- der
Farbraum ist bei 46 voll, und sie braucht auch keine.
PAYPAL: EINE QUELLE
Der Knopf nimmt den Weg, der auf der Unterstuetzen-Seite hinterlegt
ist -- derselbe Eintrag, dieselbe Pflege. Ist dort nichts eingetragen
oder steht er auf unsichtbar, erscheint hier kein Knopf. Eine
geratene Adresse ist an dieser Stelle die gefaehrlichste aller
Abkuerzungen.
=======================================================================
ACHT FEHLER, DIE OHNE MESSUNG LIVE GEGANGEN WAEREN
=======================================================================
1. `data-live` WAR SCHON VERGEBEN. Die Draussen-Kachel bekommt es,
sobald Filipe auf Twitch sendet. Meine Regel haette ihr waehrend
jedes Streams die Farbe genommen -- genau dann, wenn sie wichtig
ist. Heisst jetzt `data-sendung`, und pruef-reaktion haelt beides
auseinander.
2. DIE INHALTSRICHTLINIE HAETTE YOUTUBE LAUTLOS GESPERRT. Die Datei
warnt an genau dieser Stelle selbst davor: Am 27.08.2026 hat
`frame-src 'none'` den Musik-Knopf stillgelegt -- der Knopf
reagierte, das Feld ging auf, und wo die Player sein sollten,
blieb es leer. Hier waere das Ergebnis eine schwarze Leinwand vor
Publikum gewesen. youtube-nocookie.com fuer den Rahmen (setzt keine
Werbekennungen), www.youtube.com fuer die Einbett-API,
i.ytimg.com fuer die Vorschaubilder.
3. KAMERA UND MIKROFON WAREN GESPERRT. Dieselbe Falle, vor der
index.js selbst warnt -- und die am 18.09. schon einmal zugeschlagen
hat. Die Ausnahme ist jetzt eine benannte MENGE statt eines zweiten
Sonderfalls, und pruef-kamera-richtlinie.mjs haelt sie GEGEN DEN
QUELLTEXT: Welche Seite laedt ein Skript, das getUserMedia
aufruft? Genau die muss drinstehen -- und keine andere. Eine
Liste, die abgeleitet wird, kann nicht veralten.
4. ZWEI ANRUFE AN DIESELBE PERSON. Zwischen `await kameraHolen()` und
dem Anlegen der Verbindung laeuft alles andere weiter; jeder Takt
sagte wieder „den kenne ich noch nicht". Der Empfaenger antwortete
auf beide Angebote, und die zweite Antwort traf eine Verbindung,
die laengst stand.
5. DAS ANGEBOT GING HINAUS, BEVOR DER EMPFAENGER ZUHOEREN KONNTE.
Gemessen:
[spur] an [3] reaktion_signal | offen: [2,1]
...
[spur] Strom auf fuer 3 Lenny
Die Anmeldung ist ein gewoehnlicher Abruf und sofort durch, der
Ereignisstrom eine stehende Verbindung. Der Host erfaehrt vom
Neuankoemmling also zuverlaessig, BEVOR der zuhoeren kann.
Die Richtung ist jetzt umgedreht: Wer bereit ist, BITTET um den
Anruf -- er ist der Einzige, der das sicher weiss. Dazu ein
eigener, schneller Takt (2,5 s) und eine Ruecknahme, wenn ein
Angebot bei niemandem ankommt.
6. EIN VIDEO MIT TON STARTET NICHT VON ALLEIN. `videoWidth` war 640,
das Bild kam also an -- und das Fenster blieb schwarz. Kein
Fehler, keine Meldung, es passiert einfach nichts. Die Kameras
starten jetzt stumm (stumm darf losgehen), ein Knopf schaltet den
Ton frei, und die erste Beruehrung der Seite tut es ohnehin.
7. DIE LADE AM HANDY GING NICHT AUF. Gemessen: ein 390x775 grosser
Saal mit 219 px Video und 556 px Leere darunter. Statt den Knopf
zu reparieren, ist die Lade weg -- unter Kopfleiste und Video
bleiben auf einem Telefon rund 550 px, das ist mehr Chat, als eine
Lade je zeigen wuerde. Ein Zustand weniger ist besser als ein
Zustand, der funktioniert.
8. `sendBeacon` KANN NUR POST. Beim Schliessen des Fensters wird ein
gewoehnlicher Abruf abgebrochen; mein DELETE waere nie angekommen,
und jeder haette zwei Minuten lang als anwesend gegolten.
Dazu drei Funde der Hauspruefungen, alle von mir verursacht:
17 Schriftgroessen unter der Lesbarkeitsgrenze von 11,5 px, elf
Maschinenworte ohne deutschen Satz, und ein Aufbewahrungseintrag ohne
Rechtsgrundlage.
=======================================================================
GEMESSEN
pruef-reaktion 74 Punkte, 0 Fehler (11 Abschnitte)
pruef-kamera-richtlinie 10 Punkte, 0 Fehler (neu, abgeleitet)
mess-reaktion beide Kameras kommen an, 640 px, laufen --
beim Zuschauer UND beim Host. Diese Messung
hat einen Rueckgabewert: Alles andere kann
gruen sein, und trotzdem sitzt jeder vor
einem schwarzen Rechteck.
pruef-handy 180 (vorher 177), pruef-notizen 79,
pruef-aufbewahrung 45, pruef-meldungen 8, pruef-css-klassen 33,
pruef-struktur 35, pruef-crew-adresse 161,
pruef-haus-trennung 100, pruef-start-ansicht 160 -- alle 0 Fehler.
271 lines
12 KiB
HTML
271 lines
12 KiB
HTML
<!doctype html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||
<title>Reaction · Team Dogi</title>
|
||
<meta name="robots" content="noindex, nofollow" />
|
||
<link rel="manifest" href="/workspace/app.webmanifest" />
|
||
<meta name="theme-color" content="#06090f" />
|
||
<link rel="icon" type="image/png" href="/assets/img/app-symbole/workspace-32.png?v=202609280151" />
|
||
<link rel="apple-touch-icon" href="/assets/img/app-symbole/workspace-180.png?v=202609280151" />
|
||
<link rel="stylesheet" href="assets/css/gate.css?v=202609280151" />
|
||
<link rel="stylesheet" href="assets/css/start.css?v=202609280151" />
|
||
<link rel="stylesheet" href="assets/css/reaktion.css?v=202609280151" />
|
||
<link rel="stylesheet" href="assets/css/module.css?v=202609280151" />
|
||
<link rel="stylesheet" href="assets/css/haus.css?v=202609280151" />
|
||
</head>
|
||
|
||
<body class="start reaktion-seite" data-stand="laedt">
|
||
|
||
<div class="schleier" aria-hidden="true"></div>
|
||
|
||
<header class="kopfleiste">
|
||
<button type="button" class="zurueck-knopf" id="zurueck" hidden>
|
||
<svg class="zurueck-knopf__pfeil" viewBox="0 0 24 24" aria-hidden="true">
|
||
<path d="M14.5 5.5 8 12l6.5 6.5" />
|
||
</svg>
|
||
<span class="zurueck-knopf__text">Zurück</span>
|
||
</button>
|
||
<p class="marke"><span class="marke__text"><a class="zurueck" href="start.html">Team Dogi</a> · Reaction</span></p>
|
||
<div class="kopfleiste__rechts">
|
||
<span class="wer" id="wer">…</span>
|
||
<button type="button" class="abmelden" id="abmelden">Abmelden</button>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- ======================================================================
|
||
DIE REACTION (28.09.2026)
|
||
|
||
Filipes Kurznotiz: Kachel sichtbar -> geschlossen -> Vorbereitung
|
||
-> Wartebereich/Chat -> Countdown -> LIVE -> Reaction + Gäste +
|
||
Chat + PayPal -> Ende.
|
||
|
||
WARUM DIESE SEITE ANDERS GEBAUT IST ALS JEDE ANDERE IM HAUS
|
||
|
||
Alle anderen Seiten sind Listen und Karten: Man liest, man
|
||
entscheidet, man geht wieder. Hier sitzt man. Eine Stunde lang,
|
||
mit anderen zusammen, und schaut auf EINE Sache.
|
||
|
||
Deshalb gibt es hier keine Kacheln und kein Raster, sondern
|
||
einen SAAL: eine große Fläche für das Video, Kamerabilder als
|
||
schwebende Fenster darüber, der Chat als Schiene daneben. Am
|
||
Handy wird daraus ein Stapel, und die Schiene fährt von unten
|
||
ein.
|
||
|
||
DREI HÄUTE ÜBEREINANDER, nicht drei Seiten nebeneinander:
|
||
|
||
.saal[data-stand="zu"] der Vorhang ist zu
|
||
.saal[data-stand="vorbereitung"] Vorschau, Countdown, Chat
|
||
.saal[data-stand="live"] Video, Kameras, Chat
|
||
|
||
Alle drei stehen im Dokument und werden über `data-stand`
|
||
umgeschaltet. Der Grund ist nicht Bequemlichkeit: Beim Wechsel
|
||
von „gleich" auf „live" soll nichts neu geladen werden -- weder
|
||
der Chat, in dem man mitten im Satz ist, noch die Verbindung zur
|
||
Kamera. Ein Seitenwechsel an dieser Stelle wäre ein Abriss.
|
||
====================================================================== -->
|
||
<main class="saal" id="saal" data-stand="zu">
|
||
|
||
<!-- ============ DAS SCHILD ÜBER ALLEM ============================
|
||
Es steht in allen drei Zuständen und sagt in drei Worten, was
|
||
los ist. Unten am Handy ist der Platz knapp; das Schild bleibt
|
||
trotzdem, weil die Antwort auf „läuft schon was?" die einzige
|
||
ist, die jeder beim Öffnen sucht. -->
|
||
<div class="buehne-schild" id="schild">
|
||
<span class="buehne-schild__punkt" aria-hidden="true"></span>
|
||
<span class="buehne-schild__wort" id="schild-wort">…</span>
|
||
<span class="buehne-schild__zahl" id="schild-zahl" hidden></span>
|
||
</div>
|
||
|
||
<p class="fehler" id="fehler" role="alert" aria-live="polite" hidden></p>
|
||
|
||
<!-- ============ ZU ============================================== -->
|
||
<section class="vorhang" id="teil-zu" aria-label="Die Reaction ist geschlossen">
|
||
<div class="vorhang__licht" aria-hidden="true"></div>
|
||
<div class="vorhang__innen">
|
||
<span class="vorhang__marke"><i></i>Team Dogi<i></i></span>
|
||
<h1 class="vorhang__titel">Der Saal ist zu.</h1>
|
||
<p class="vorhang__satz" id="zu-satz">
|
||
Hier schauen wir zusammen. Wenn etwas läuft, steht es hier —
|
||
und du siehst es schon an der Kachel.
|
||
</p>
|
||
<p class="vorhang__naechste" id="zu-naechste" hidden></p>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ VORBEREITUNG ==================================== -->
|
||
<section class="warte" id="teil-warte" aria-label="Wartebereich">
|
||
<div class="warte__buehne">
|
||
<div class="warte__bild" id="warte-bild" aria-hidden="true"></div>
|
||
<div class="warte__text">
|
||
<span class="warte__kicker">Gleich geht es los</span>
|
||
<h1 class="warte__titel" id="warte-titel">Reaction startet bald</h1>
|
||
<!-- Der Countdown ist eine ZAHL und kein Balken. Ein Balken
|
||
sagt „irgendwann"; eine Zahl sagt „in vier Minuten", und
|
||
danach entscheidet jemand, ob er sich noch einen Kaffee
|
||
holt. -->
|
||
<div class="countdown" id="countdown" hidden>
|
||
<span class="countdown__zahl" id="countdown-zahl">–</span>
|
||
<span class="countdown__wort" id="countdown-wort">bis zum Start</span>
|
||
</div>
|
||
<p class="warte__satz">
|
||
Der Chat ist schon offen. Schreib schon mal, wer da ist.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- ============ LIVE ============================================ -->
|
||
<section class="kino" id="teil-live" aria-label="Die Reaction läuft">
|
||
|
||
<!-- Das Video. Der Rahmen bleibt stehen, auch wenn noch nichts
|
||
darin ist -- ein Kasten, der erst entsteht, wenn das Video
|
||
kommt, lässt die halbe Seite springen. -->
|
||
<div class="leinwand" id="leinwand">
|
||
<div class="leinwand__video" id="video-platz">
|
||
<div class="leinwand__warte" id="video-warte">Das Video kommt gleich …</div>
|
||
</div>
|
||
|
||
<!-- Die Kamerafenster liegen ÜBER dem Video, nicht daneben.
|
||
Genau so sieht eine Reaction aus: das Bild groß, das
|
||
Gesicht klein davor. Wer lieber beides gleich groß hat,
|
||
stellt oben die Anordnung um. -->
|
||
<div class="kameras" id="kameras"></div>
|
||
|
||
<!-- DER TON MUSS FREIGEGEBEN WERDEN. Ein Videoelement mit Ton
|
||
darf nicht von allein losgehen -- das verbietet jeder
|
||
Browser. Die Kameras starten deshalb stumm, und dieser
|
||
Knopf (oder die erste Berührung der Seite) schaltet sie
|
||
laut. Ohne ihn säße jemand vor einem stummen Bild und
|
||
suchte den Fehler bei sich. -->
|
||
<button type="button" class="ton-an" id="ton-an" hidden>
|
||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||
<path d="M4 9.4h3.6L12 5.2v13.6L7.6 14.6H4z" />
|
||
<path d="M16.2 9.2a4 4 0 0 1 0 5.6" />
|
||
<path d="M18.6 6.6a7.4 7.4 0 0 1 0 10.8" />
|
||
</svg>
|
||
<span>Ton einschalten</span>
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Der Chat. Auf dem Rechner eine Schiene rechts, am Handy eine
|
||
Lade, die von unten einfährt. -->
|
||
<aside class="schiene" id="schiene" aria-label="Live-Chat">
|
||
<header class="schiene__kopf">
|
||
<h2 class="schiene__titel">Live-Chat</h2>
|
||
<span class="schiene__zahl" id="chat-zahl">0</span>
|
||
|
||
</header>
|
||
<ol class="schiene__liste" id="chat-liste" aria-live="polite"></ol>
|
||
<form class="schiene__form" id="chat-form">
|
||
<input type="text" id="chat-feld" class="schiene__feld" maxlength="400"
|
||
placeholder="Sag was …" autocomplete="off" />
|
||
<button type="submit" class="schiene__senden" aria-label="Senden">
|
||
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 12 20 4l-4 8 4 8z" /></svg>
|
||
</button>
|
||
</form>
|
||
<!-- Der Weg, den Host zu unterstützen. Er steht IM Chat und
|
||
nicht in einer eigenen Ecke: Wer gerade etwas gut findet,
|
||
tippt es in den Chat -- und sieht den Knopf in derselben
|
||
Bewegung. -->
|
||
<a class="danke" id="danke" hidden rel="noopener noreferrer" target="_blank">
|
||
<svg viewBox="0 0 24 24" aria-hidden="true">
|
||
<path d="M12 20.4S3.6 15.2 3.6 9.6A4.2 4.2 0 0 1 12 7.4a4.2 4.2 0 0 1 8.4 2.2c0 5.6-8.4 10.8-8.4 10.8z" />
|
||
</svg>
|
||
<span>Dogi was ausgeben</span>
|
||
</a>
|
||
</aside>
|
||
|
||
|
||
</section>
|
||
|
||
<!-- ============ DAS REGIEPULT ===================================
|
||
Nur für DogFather. Es liegt UNTEN und nicht oben: Beim Senden
|
||
schaut man auf das Bild, nicht auf die Knöpfe -- und was man
|
||
nicht ansieht, greift man mit dem Daumen, und der ist unten.
|
||
|
||
Es ist bewusst als PULT gebaut und nicht als Formular: Regler
|
||
für vier Tonquellen nebeneinander, darüber eine Reihe Schalter,
|
||
daneben der große Knopf, der die Sendung startet und beendet.
|
||
Wer einmal an einem Mischpult gestanden hat, findet sich hier
|
||
ohne Erklärung zurecht. -->
|
||
<section class="pult" id="pult" hidden aria-label="Regie">
|
||
<button type="button" class="pult__griff" id="pult-griff" aria-expanded="false">
|
||
<span class="pult__griff-strich" aria-hidden="true"></span>
|
||
<span class="pult__griff-wort">Regie</span>
|
||
</button>
|
||
|
||
<div class="pult__innen" id="pult-innen">
|
||
|
||
<!-- Reihe 1: was gesendet wird -->
|
||
<div class="pult__block">
|
||
<h3 class="pult__ueber">Die Sendung</h3>
|
||
<div class="pult__zeile">
|
||
<label class="pult__feld">
|
||
<span>Titel</span>
|
||
<input type="text" id="p-titel" maxlength="120" placeholder="Worum geht es?" />
|
||
</label>
|
||
<label class="pult__feld">
|
||
<span>YouTube</span>
|
||
<input type="text" id="p-video" placeholder="Adresse oder Kennung einfügen" />
|
||
</label>
|
||
</div>
|
||
<div class="pult__zeile">
|
||
<label class="pult__feld">
|
||
<span>Vorschaubild</span>
|
||
<input type="text" id="p-vorschau" placeholder="Adresse eines Bildes (freiwillig)" />
|
||
</label>
|
||
<label class="pult__feld pult__feld--kurz">
|
||
<span>Beginn</span>
|
||
<input type="datetime-local" id="p-beginn" />
|
||
</label>
|
||
<button type="button" class="knopf-still" id="p-sichern">Übernehmen</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Reihe 2: die Regler -->
|
||
<div class="pult__block">
|
||
<h3 class="pult__ueber">Ton</h3>
|
||
<div class="regler-reihe" id="regler"></div>
|
||
</div>
|
||
|
||
<!-- Reihe 3: Gäste -->
|
||
<div class="pult__block">
|
||
<h3 class="pult__ueber">Gäste <span class="pult__klein" id="gast-zahl">0 von 2</span></h3>
|
||
<div class="gast-reihe" id="gast-reihe"></div>
|
||
<div class="pult__zeile">
|
||
<select id="p-wen" class="pult__wahl" aria-label="Wen holen?"></select>
|
||
<button type="button" class="knopf-still" id="p-holen">Dazuholen</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Reihe 4: die Anordnung -->
|
||
<div class="pult__block">
|
||
<h3 class="pult__ueber">Anordnung</h3>
|
||
<div class="layout-reihe" id="layout-reihe"></div>
|
||
</div>
|
||
|
||
<!-- Reihe 5: der große Knopf -->
|
||
<div class="pult__block pult__block--tun">
|
||
<button type="button" class="tun tun--vor" id="p-vorbereiten">Vorbereiten</button>
|
||
<button type="button" class="tun tun--live" id="p-starten">Auf Sendung</button>
|
||
<button type="button" class="tun tun--aus" id="p-beenden">Beenden</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</main>
|
||
|
||
<!-- bereiche.js VOR kopf.js: Dort steht `window.Bereiche`, und kopf.js
|
||
liest daraus die Leitungsrollen. -->
|
||
<script src="assets/js/bereiche.js?v=202609280151" defer></script>
|
||
<script src="assets/js/wahl.js?v=202609280151" defer></script>
|
||
<script src="assets/js/nachfrage.js?v=202609280151" defer></script>
|
||
<script src="assets/js/meldung.js?v=202609280151" defer></script>
|
||
<script src="assets/js/installieren.js?v=202609280151" defer></script>
|
||
<script src="assets/js/kopf.js?v=202609280151" defer></script>
|
||
<script src="assets/js/glocke.js?v=202609280151" defer></script>
|
||
<script src="assets/js/reaktion.js?v=202609280151" defer></script>
|
||
</body>
|
||
</html>
|