Kamerafenster: Groesse und Ecke lassen sich stellen
Filipe: "und danach perfektionierst du auch die verschiedenen groessen von kamera und so, perfektionier das alles bitte." Sechs Groessen (0,6x bis 2x) und vier Ecken, beide an der SENDUNG und nicht am Browser: Was Filipe einstellt, sehen alle. Waere es eine Einstellung je Geraet, redete er ueber ein Bild, das bei den Zusehenden anders aussieht -- und im Stream stuende ein drittes. Anordnung, Groesse und Ecke gehen jetzt EINEN Weg (/layout), weil sie zusammen eine einzige Frage beantworten: Wie sieht das Bild aus? Drei getrennte Aufrufe waeren drei Rundrufe, und dazwischen saehen die Zusehenden eine Mischung -- neue Anordnung, alte Ecke. Eine falsche Angabe laesst auch das Gute stehen, statt halb umzustellen. Die Ecke gibt es, weil unten rechts bei TikTok die Knopfreihe liegt, bei YouTube die Fortschrittsleiste, und Untertitel fast immer unten stehen. Eine feste Ecke ist eine, die bei jeder zweiten Plattform im Weg ist. Die OBS-Videoquelle kennt jetzt die Anordnung und blendet sich bei "Nur Kamera" aus -- sonst laege im Stream ein stehengebliebenes YouTube-Bild unter den Kameras, und Filipe saehe es nicht, weil er auf seine Szene schaut und nicht auf die Quelle. VIER BEFUNDE, ALLE VON DEN PRUEFUNGEN UND KEINER VOM AUGE: 1. Die Knoepfe fuer Groesse und Ecke gab es gar nicht. HTML und Stilblatt waren da, das Programm nicht. Gemessen: "0 von 0 Eckknoepfen gesperrt", und der Hinweistext stand noch wortgleich wie im HTML -- zwei leere Kaesten, die aussahen, als sei alles in Ordnung. 2. Bei "Nur Kamera" war der Stapel 493 px breit statt 1072. Der neue Deckel max-width: 46% -- richtig gegen ein zu grosses Fenster bei "Video gross" -- galt still auch dort, wo die Kameras die ganze Flaeche fuellen sollen. 3. Am Handy haette die Groesseneinstellung ueberhaupt nichts bewirkt: Dort stand weiterhin width: clamp(88px, 26vw, 140px) am Fenster selbst. Das ist die dritte Wiederholung derselben Sache an einem Tag (die Saalzeilen, die Tafeln, jetzt die Kamerabreite): Zwei Regeln fuer dieselbe Frage sind die Garantie, dass eine davon irgendwo falsch gewinnt. Breite und Rand gehen jetzt ueber --kam-grund/--kam-rand, --kam wird an genau EINER Stelle gerechnet, und eine Pruefung zaehlt das nach. 4. Die Pruefung schlug auf ihren EIGENEN Kommentar an, der die entfernte Zeile zitiert. Ein Werkzeug, das bei jedem Lauf meckert, wird nach dem zweiten Mal weggeklickt -- samt dem echten Befund darin. Gezaehlt werden jetzt Regeln, nicht Prosa. Gemessen beim Zuschauer und nicht in der Datenbank: 1x -> 208 px, 2x -> 416 px, alle Fenster innerhalb der Leinwand, und jede der vier Ecken am Abstand zu den Kanten nachgewiesen statt an ihrem eigenen Namen. Ein Knopf, der gerade nichts bewirken kann, ist grau, und der Satz darunter sagt warum. pruef-reaktion 320/0 - pruef-buehne 36/0 - pruef-css-klassen ok - pruef-tippziele 11/0 - mess-reaktion ohne Beanstandung Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -685,6 +685,173 @@ if (zuschauer.konsole.length) console.log(" KONSOLE:", zuschauer.konsole.slice
|
||||
Abzeichen UND ein zweiter Knopf dazugekommen. Genau so ist am
|
||||
28.09. die Regie 197 px uebergelaufen: Die Rechnung ging auf, die
|
||||
Wirklichkeit nicht. */
|
||||
/* ---- Groesse und Ecke der Kamerafenster -------------------------
|
||||
|
||||
Filipe: „und danach perfektionierst du auch die verschiedenen
|
||||
groessen von kamera und so."
|
||||
|
||||
GEMESSEN WIRD BEIM ZUSCHAUER. Dass in der Datenbank 1,5 steht,
|
||||
sagt nichts darueber, ob das Fenster bei den anderen groesser
|
||||
wird -- dazwischen liegen ein Rundruf, eine Variable im Stilblatt
|
||||
und eine Rechnung mit `clamp`. */
|
||||
console.log("");
|
||||
console.log(" --- Kameragroesse und Ecke ---");
|
||||
{
|
||||
/* Sauberer Anfang: „Video gross", damit die Ecke ueberhaupt gilt. */
|
||||
await roh("/workspace/api/reaktion/layout", {
|
||||
method: "POST", keks: k.admin, rumpf: { layout: "kino" },
|
||||
});
|
||||
await zuschauer.seite.waitForTimeout(900);
|
||||
|
||||
const messen = () => zuschauer.seite.evaluate(() => {
|
||||
const kino = document.getElementById("teil-live");
|
||||
const kk = document.querySelector(".kameras");
|
||||
const ein = document.querySelector(".kamera");
|
||||
const lein = document.querySelector(".leinwand");
|
||||
if (!kk || !ein || !lein) return null;
|
||||
const r = ein.getBoundingClientRect();
|
||||
const lr = lein.getBoundingClientRect();
|
||||
const fenster = [...document.querySelectorAll(".kamera")];
|
||||
return {
|
||||
gross: kino.style.getPropertyValue("--kam-gross") || "(?)",
|
||||
ecke: kino.dataset.ecke || "(?)",
|
||||
breit: Math.round(r.width),
|
||||
/* Wo sitzt der Stapel? Als Abstand zu den vier Kanten der
|
||||
Leinwand -- daran erkennt man die Ecke ohne Vorwissen. */
|
||||
links: Math.round(kk.getBoundingClientRect().left - lr.left),
|
||||
rechts: Math.round(lr.right - kk.getBoundingClientRect().right),
|
||||
oben: Math.round(kk.getBoundingClientRect().top - lr.top),
|
||||
unten: Math.round(lr.bottom - kk.getBoundingClientRect().bottom),
|
||||
/* Und liegt noch alles IN der Leinwand? Sie hat
|
||||
`overflow: hidden` -- was daneben liegt, ist unsichtbar,
|
||||
nicht abgeschnitten sichtbar. */
|
||||
drin: fenster.filter((f) => {
|
||||
const q = f.getBoundingClientRect();
|
||||
return q.left >= lr.left - 1 && q.right <= lr.right + 1
|
||||
&& q.top >= lr.top - 1 && q.bottom <= lr.bottom + 1;
|
||||
}).length,
|
||||
fenster: fenster.length,
|
||||
leinwand: Math.round(lr.width),
|
||||
};
|
||||
});
|
||||
|
||||
const normal = await messen();
|
||||
console.log(` 1×: Fenster ${normal?.breit} px, Ecke ${normal?.ecke}, `
|
||||
+ `Abstände l/r/o/u ${normal?.links}/${normal?.rechts}/${normal?.oben}/${normal?.unten}, `
|
||||
+ `${normal?.drin}/${normal?.fenster} im Bild`);
|
||||
|
||||
/* ---- DIE GROESSE MUSS WIRKEN ---- */
|
||||
const { KAMERA_GROESSEN } = await import("./reaktion-tabellen.js");
|
||||
const gross = KAMERA_GROESSEN[KAMERA_GROESSEN.length - 1];
|
||||
await roh("/workspace/api/reaktion/layout", {
|
||||
method: "POST", keks: k.admin, rumpf: { kamera_gross: gross },
|
||||
});
|
||||
await zuschauer.seite.waitForTimeout(900);
|
||||
const dick = await messen();
|
||||
console.log(` ${gross}×: Fenster ${dick?.breit} px, `
|
||||
+ `${dick?.drin}/${dick?.fenster} im Bild (Leinwand ${dick?.leinwand} px)`);
|
||||
|
||||
if (!normal || !dick) {
|
||||
console.log(" ACHTUNG: Die Kamerafenster liessen sich nicht messen.");
|
||||
ausgang = 1;
|
||||
} else {
|
||||
/* NICHT AUF DEN FAKTOR GENAU. `clamp` deckelt die Grundbreite,
|
||||
und `max-width: 46%` deckelt den Stapel -- beides ist Absicht.
|
||||
Geprueft wird, dass es SPUERBAR waechst und im Bild bleibt. */
|
||||
const wuchs = dick.breit / normal.breit;
|
||||
console.log(` Das Fenster wuchs um das ${wuchs.toFixed(2)}-fache`);
|
||||
if (wuchs < 1.3) {
|
||||
console.log(" ACHTUNG: Die Groesse wirkt nicht.");
|
||||
ausgang = 1;
|
||||
}
|
||||
if (dick.drin !== dick.fenster) {
|
||||
console.log(" ACHTUNG: Ein Fenster liegt ausserhalb der Leinwand.");
|
||||
ausgang = 1;
|
||||
}
|
||||
if (dick.breit > dick.leinwand * 0.5) {
|
||||
console.log(" ACHTUNG: Ein Fenster deckt mehr als die halbe Leinwand zu.");
|
||||
ausgang = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- DIE VIER ECKEN ----
|
||||
Geprueft wird der ABSTAND zu den Kanten, nicht der Name der
|
||||
Ecke. Eine Einstellung, die nur ihren eigenen Namen bestaetigt,
|
||||
bestaetigt nichts. */
|
||||
await roh("/workspace/api/reaktion/layout", {
|
||||
method: "POST", keks: k.admin, rumpf: { kamera_gross: 1 },
|
||||
});
|
||||
const erwartet = {
|
||||
ol: ["links", "oben"], or: ["rechts", "oben"],
|
||||
ul: ["links", "unten"], ur: ["rechts", "unten"],
|
||||
};
|
||||
for (const [ecke, [waag, senk]] of Object.entries(erwartet)) {
|
||||
await roh("/workspace/api/reaktion/layout", {
|
||||
method: "POST", keks: k.admin, rumpf: { kamera_ecke: ecke },
|
||||
});
|
||||
await zuschauer.seite.waitForTimeout(800);
|
||||
const m = await messen();
|
||||
const nahWaag = m[waag] < (waag === "links" ? m.rechts : m.links);
|
||||
const nahSenk = m[senk] < (senk === "oben" ? m.unten : m.oben);
|
||||
console.log(` Ecke ${ecke}: l/r/o/u ${m.links}/${m.rechts}/${m.oben}/${m.unten} `
|
||||
+ `-> ${waag}+${senk} ${nahWaag && nahSenk ? "stimmt" : "STIMMT NICHT"}`);
|
||||
if (!nahWaag || !nahSenk || m.ecke !== ecke) {
|
||||
console.log(` ACHTUNG: Die Ecke „${ecke}" kommt nicht an.`);
|
||||
ausgang = 1;
|
||||
}
|
||||
}
|
||||
await bild(zuschauer.seite, "22-kamera-ecke");
|
||||
|
||||
/* ---- EIN KNOPF, DER NICHTS TUN KANN, IST GRAU ----
|
||||
Die Ecke wirkt nur bei „Video gross"; die Groesse wirkt ueberall,
|
||||
wo es Kamerafenster GIBT -- bei „Nur Video" gibt es keine.
|
||||
|
||||
GEMESSEN WIRD DER ZUSTAND DER KNOEPFE, nicht der Satz darunter.
|
||||
Ein Hinweis, der die Wahrheit sagt, waehrend der Knopf daneben
|
||||
bedienbar bleibt, ist die schlechtere Haelfte: Man liest ihn
|
||||
nicht und drueckt trotzdem. */
|
||||
const knoepfe = () => host.seite.evaluate(() => {
|
||||
const e = [...document.querySelectorAll("#kamecke .kamecke__knopf")];
|
||||
const g = [...document.querySelectorAll("#kamgroesse .kamgroesse__knopf")];
|
||||
return {
|
||||
ecken: e.length, eckenGrau: e.filter((x) => x.disabled).length,
|
||||
groessen: g.length, groessenGrau: g.filter((x) => x.disabled).length,
|
||||
hinweis: document.getElementById("kamecke-hinweis")?.textContent || "",
|
||||
};
|
||||
});
|
||||
|
||||
for (const [anordnung, sollEcken, sollGroessen, wort] of [
|
||||
["kamera", "alle", "keine", "Mitte"],
|
||||
["nur_video", "alle", "alle", "Nur Video"],
|
||||
["kino", "keine", "keine", "Ecke"],
|
||||
]) {
|
||||
await roh("/workspace/api/reaktion/layout", {
|
||||
method: "POST", keks: k.admin, rumpf: { layout: anordnung },
|
||||
});
|
||||
await host.seite.waitForTimeout(800);
|
||||
const m = await knoepfe();
|
||||
console.log(` „${anordnung}": ${m.eckenGrau}/${m.ecken} Ecken grau, `
|
||||
+ `${m.groessenGrau}/${m.groessen} Größen grau`);
|
||||
console.log(` Hinweis: „${m.hinweis.replace(/\s+/g, " ").trim()}"`);
|
||||
const soll = (art, wieviel, da) => (wieviel === "alle" ? art === da : art === 0);
|
||||
if (m.ecken !== 4 || m.groessen < 4) {
|
||||
console.log(" ACHTUNG: Die Knoepfe fuer Groesse oder Ecke fehlen.");
|
||||
ausgang = 1;
|
||||
} else if (!soll(m.eckenGrau, sollEcken, m.ecken)
|
||||
|| !soll(m.groessenGrau, sollGroessen, m.groessen)) {
|
||||
console.log(` ACHTUNG: Bei „${anordnung}" stimmt das Grauwerden nicht.`);
|
||||
ausgang = 1;
|
||||
} else if (!m.hinweis.includes(wort)) {
|
||||
console.log(` ACHTUNG: Der Hinweis sagt nichts von „${wort}".`);
|
||||
ausgang = 1;
|
||||
}
|
||||
}
|
||||
await roh("/workspace/api/reaktion/layout", {
|
||||
method: "POST", keks: k.admin, rumpf: { layout: "kino", kamera_ecke: "ur" },
|
||||
});
|
||||
await host.seite.waitForTimeout(700);
|
||||
}
|
||||
|
||||
/* ---- Die Regieleiste ueber dem Saal -----------------------------
|
||||
|
||||
Filipe, 28.09.2026: „ich haette das gerne oben also nicht in dieser
|
||||
|
||||
Reference in New Issue
Block a user