Die Einblendung nimmt die Farbe des Bereichs an, in dem sie steht

Filipe, 27.09.2026: „nimm dann doch die seiten vom community bereich
ne?"

Er hatte recht, und es war derselbe Fehler noch einmal. Beim ersten
Mal stand die Buehne in einer Farbe aus einem fremden Bereich
(#9cde90, die Notizen-Kachel aus dem Team). Beim zweiten Mal stand
sie in EINER Farbe fuer alles -- und jeder Bereich des Treffs hat
seine eigene:

    Rudel-Chat     #5499ff        Wunschliste    #abff96
    Highlights     #f60684        Dogi-Media     #918a01
    Anschlagbrett  #ffabff        Mitmachen      #577ecc
    Was ansteht    #2dc9ba        Unterstuetzen  #e76006

Ein Video ueber Dogi-Media mit violetten Einblendungen sind zwei
Sachen nebeneinander. Mit der Farbe des Bereichs ist es eine.

ABGELESEN, NICHT ABGESCHRIEBEN

Die Buehne fragt nach jedem Seitenwechsel
`getComputedStyle(document.body).--ton` -- genau den Wert, den die
Seite selbst benutzt. Eine Liste hier waere eine zweite Wahrheit, die
irgendwann von der ersten abweicht; tools/treff-farben.mjs liest
dieselben zwei Quellen (workspace.js fuer die Nummer, start.css fuer
den Farbwert), wenn man sie nachsehen will.

AUFGEHELLT, BIS ES LESBAR IST

#918a01 ist als Flaeche schoen und als Schrift auf dunklem Grund
unlesbar (1,9:1). Die Buehne mischt Weiss dazu, bis 4,5:1 erreicht
sind -- dieselbe Rechnung wie bei den Namen im Chat. Balken, Schein
und Vorhang bekommen den rohen Ton, die brauchen keinen Kontrast.

DER ABSPANN BLEIBT MARKE

Er ist in allen vier Videos derselbe und faellt deshalb auf
--violett/--akzent zurueck, egal auf welcher Seite er steht. Wer drei
Videos gesehen hat, soll den vierten am Schluss wiedererkennen.

UND EIN EIGENER FEHLER, GEMESSEN STATT UEBERSEHEN

Das Ablesen stand zuerst in `auf()` -- und `auf()` laeuft vor jeder
Karte, jedem Untertitel und jedem Rollen. Ueber hundert zusaetzliche
Wege in den Browser fuer eine Antwort, die sich nur beim
Seitenwechsel aendern kann. Video 1 wuchs dadurch von 32,9 auf
36,1 s. Jetzt wird beim Seitenwechsel gelesen: 32,0 s.

Alle vier neu gedreht: 24 bis 34 s, 1080x1920.
This commit is contained in:
2026-09-27 19:37:06 +02:00
parent a28a8ea2e3
commit 6261d548d0
2 changed files with 113 additions and 10 deletions
+77 -10
View File
@@ -561,7 +561,14 @@ function BUEHNE(blendeZu) {
+ "filter='url(%23n)'/%3E%3C/svg%3E\")";
const css = [
'#tk-buehne{position:fixed;inset:0;z-index:2147483000;pointer-events:none;',
/* Zwei Regler: `--tk-ton` ist die rohe Bereichsfarbe (Balken,
Schein, Vorhang), `--tk-ton-text` dieselbe Farbe so weit
aufgehellt, dass man sie LESEN kann. Vorgabe sind die
Hausfarben -- solange keine Seite geladen ist, gibt es keinen
Bereich, dessen Farbe man nehmen koennte. */
'#tk-buehne{--tk-ton:' + VIOLETT + ';--tk-ton-text:' + VIOLETT + ';',
' --tk-hell:' + AKZENT + ';',
' position:fixed;inset:0;z-index:2147483000;pointer-events:none;',
' font-family:"Segoe UI",system-ui,-apple-system,"Helvetica Neue",Arial,sans-serif;',
' -webkit-font-smoothing:antialiased}',
@@ -594,11 +601,11 @@ function BUEHNE(blendeZu) {
zwei Striche, ein Wort dazwischen, weit gesperrt. */
'#tk-karte .kicker{display:flex;align-items:center;justify-content:center;gap:9px;',
' font-size:9px;font-weight:700;letter-spacing:.38em;text-transform:uppercase;',
' color:' + VIOLETT + ';opacity:0;transform:translateY(10px);',
' color:var(--tk-ton-text);opacity:0;transform:translateY(10px);',
' transition:opacity .42s ease .04s,transform .42s cubic-bezier(.16,.8,.3,1) .04s}',
'#tk-karte .kicker i{display:block;width:22px;height:1px;',
' background:linear-gradient(90deg,rgba(169,139,255,0),' + VIOLETT + ')}',
'#tk-karte .kicker i + i{background:linear-gradient(90deg,' + VIOLETT + ',rgba(169,139,255,0))}',
' background:linear-gradient(90deg,transparent,var(--tk-ton-text))}',
'#tk-karte .kicker i + i{background:linear-gradient(90deg,var(--tk-ton-text),transparent)}',
'#tk-karte.an .kicker{opacity:.92;transform:none}',
/* `text-wrap: balance` verteilt die Woerter selbst auf die Zeilen.
@@ -614,8 +621,8 @@ function BUEHNE(blendeZu) {
/* Wenig Schein, dafuer ein enger dunkler Schatten: Ein breiter
Schein frisst die Kanten der Buchstaben, und im Video wird
daraus Matsch. */
'#tk-karte p b{color:' + AKZENT + ';font-weight:800;',
' text-shadow:0 1px 2px rgba(3,2,8,.85),0 0 16px rgba(142,201,255,.30)}',
'#tk-karte p b{color:var(--tk-ton-text);font-weight:800;',
' text-shadow:0 1px 2px rgba(3,2,8,.85)}',
/* Der Abspann bekommt mehr Gewicht als die Zwischenkarten: Er ist
das Einzige, was der Mensch danach noch tun soll. */
@@ -623,6 +630,11 @@ function BUEHNE(blendeZu) {
' radial-gradient(100% 52% at 50% 6%, rgba(169,139,255,.36), rgba(0,0,0,0) 66%),',
' radial-gradient(130% 62% at 50% 94%, rgba(142,201,255,.22), rgba(0,0,0,0) 64%),',
' linear-gradient(180deg,#120e27 0%,#0a0817 56%,#050409 100%)}',
/* Der Abspann ist in allen vier Videos derselbe und soll auch so
aussehen -- er faellt deshalb auf die Hausfarben zurueck, egal
auf welcher Seite er steht. */
'#tk-karte.ende{--tk-ton-text:' + AKZENT + '}',
'#tk-karte.ende .kicker{color:' + VIOLETT + '}',
'#tk-karte.ende p{font-size:32px}',
/* `display:block` ist nicht Zierde: Ein <span> ist inline, und
dort gelten Hoehe, Breite und margin:auto nicht. Der Strich war
@@ -645,10 +657,11 @@ function BUEHNE(blendeZu) {
'#tk-satz span{display:flex;align-items:stretch;gap:11px;',
' background:rgba(10,8,22,.80);backdrop-filter:blur(14px) saturate(1.25);',
' -webkit-backdrop-filter:blur(14px) saturate(1.25);',
' border:1px solid rgba(169,139,255,.26);border-radius:15px;padding:11px 14px;',
' border:1px solid color-mix(in srgb,var(--tk-ton) 34%,transparent);',
' border-radius:15px;padding:11px 14px;',
' box-shadow:0 20px 44px -20px #000,inset 0 1px 0 rgba(255,255,255,.07)}',
'#tk-satz i{flex:none;width:3px;border-radius:3px;',
' background:linear-gradient(180deg,' + VIOLETT + ',' + AKZENT + ')}',
' background:linear-gradient(180deg,var(--tk-ton),var(--tk-hell))}',
'#tk-satz em{font-style:normal;font-weight:700;font-size:19px;line-height:1.32;',
' letter-spacing:-.006em;color:#ece8fa}',
@@ -658,7 +671,8 @@ function BUEHNE(blendeZu) {
fertigen Video -- das sieht nach Bildschirmaufnahme aus und
nicht nach Film. */
'#tk-blende{position:absolute;inset:0;transform:translateY(102%);',
' background:linear-gradient(180deg,' + VIOLETT + ' 0%,#4b3fa8 34%,#0b0918 78%,' + TINTE + ' 100%)}',
' background:linear-gradient(180deg,var(--tk-ton) 0%,',
' color-mix(in srgb,var(--tk-ton) 45%,#0b0918) 34%,#0b0918 78%,' + TINTE + ' 100%)}',
'#tk-blende.zu{transform:translateY(0);',
' transition:transform .34s cubic-bezier(.66,0,.34,1)}',
'#tk-blende.auf{transform:translateY(-102%);',
@@ -773,15 +787,67 @@ function buehneFuer(seite) {
was sie zudecken sollte. Der Zustand lebt deshalb hier und nicht
im Browser. */
let vorhangZu = false;
/* Die Bereichsfarbe wird ABGELESEN, nicht gefuehrt: Jede Seite des
Treffs setzt `--ton` auf ihrem <body>, und genau dieser Wert geht
an die Buehne. Eine Liste hier waere eine zweite Wahrheit, die
irgendwann von der ersten abweicht. */
const TON_LESEN = () => {
const b = document.getElementById("tk-buehne");
if (!b) return null;
const roh = getComputedStyle(document.body).getPropertyValue("--ton").trim();
if (!/^#[0-9a-f]{6}$/i.test(roh)) return null;
/* Aufhellen, bis man es lesen kann -- dieselbe Rechnung wie bei
den Namen im Chat. #918a01 (Dogi-Media) kommt als Schrift auf
dunklem Grund sonst auf 1,9:1. */
const teile = (h) => [1, 3, 5].map((i) => parseInt(h.substr(i, 2), 16) / 255);
const gerade = (c) => (c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4));
const leucht = (v) => 0.2126 * gerade(v[0]) + 0.7152 * gerade(v[1]) + 0.0722 * gerade(v[2]);
const abstand = (x, y) => {
const a = leucht(x); const b2 = leucht(y);
const hoch = Math.max(a, b2); const tief = Math.min(a, b2);
return (hoch + 0.05) / (tief + 0.05);
};
const grund = [0.043, 0.035, 0.094]; /* #0b0918 */
const f = teile(roh);
let text = "#f1edff";
for (let t = 0; t <= 0.92; t += 0.04) {
const m = f.map((c) => c + (1 - c) * t);
if (abstand(m, grund) >= 4.5) {
text = "rgb(" + m.map((c) => Math.round(c * 255)).join(",") + ")";
break;
}
}
b.style.setProperty("--tk-ton", roh);
b.style.setProperty("--tk-ton-text", text);
b.style.setProperty("--tk-hell", text);
return roh;
};
/* DIE FARBE WIRD BEIM SEITENWECHSEL GELESEN, NICHT BEI JEDEM
HANDGRIFF (27.09.2026).
Erst stand das Ablesen in `auf()` -- und `auf()` laeuft vor jeder
Karte, jedem Untertitel und jedem Rollen. Das waren ueber
hundert zusaetzliche Wege in den Browser und drei Sekunden mehr
je Video, fuer eine Antwort, die sich nur beim Seitenwechsel
aendern kann. Gemessen: Video 1 wuchs von 32,9 auf 36,1 s. */
const auf = () => seite.evaluate(BUEHNE, vorhangZu);
const tonLesen = () => seite.evaluate(TON_LESEN).catch(() => null);
/* Der Wiederaufbau haengt hier und nicht beim Aufrufer: Er braucht
`vorhangZu`, und ein Zustand, den zwei Stellen fuehren, laeuft
auseinander. */
seite.on("load", () => { seite.evaluate(BUEHNE, vorhangZu).catch(() => {}); });
seite.on("load", () => {
seite.evaluate(BUEHNE, vorhangZu)
.then(() => seite.evaluate(TON_LESEN))
.catch(() => {});
});
return {
auf,
tonLesen,
/** Vorhang zu. Danach darf navigiert werden. */
async zu(ms = 380) {
@@ -1100,6 +1166,7 @@ for (const nr of liste) {
es kurz still -- 450 ms reichten nicht, der Vorhang ging in
dieser Stille auf. Kommt der Hinweis
doch noch, faengt die Uhr von vorn an. */
await b.tonLesen();
const still = await ruhig(seite);
if (!still) {
console.warn(` Hinweis: ${String(a[0]).replace(/^https?:\/\/[^/]+/, "")} `
+36
View File
@@ -0,0 +1,36 @@
/* Welche Farbe traegt jede Kachel des Community-Bereichs?
*
* Gelesen wird aus den zwei Stellen, die es wirklich entscheiden:
* workspace.js sagt, welche TON-NUMMER eine Kachel hat, start.css
* sagt, welcher Farbwert hinter der Nummer steht. Abgeschrieben wird
* nichts -- eine Liste, die niemand pflegt, kann nicht veralten.
*
* node tools/treff-farben.mjs
*/
import { readFileSync } from "node:fs";
import { fileURLToPath } from "node:url";
import { dirname, join } from "node:path";
const HIER = dirname(fileURLToPath(import.meta.url));
const js = readFileSync(join(HIER, "..", "server", "workspace.js"), "utf8");
const css = readFileSync(join(HIER, "..", "workspace", "assets", "css", "start.css"), "utf8");
const hex = new Map();
for (const m of css.matchAll(/\[data-ton="(\d+)"\]\s*\{\s*--ton:\s*(#[0-9a-fA-F]{6})/g)) {
hex.set(m[1], m[2]);
}
/* Die Kacheln des Treffs stehen alle mit `...TREFF_GRUPPE` davor --
daran sind sie erkennbar, ohne sie einzeln aufzuzaehlen. */
const treffer = [...js.matchAll(
/\.\.\.TREFF_GRUPPE,\s*name:\s*"([^"]+)"[\s\S]{0,400}?ton:\s*(\d+)/g)];
console.log("KACHEL TON FARBE");
for (const [, name, ton] of treffer) {
console.log(name.padEnd(20) + String(ton).padEnd(6) + (hex.get(ton) || "?"));
}
console.log("\n" + treffer.length + " Kacheln im Community-Bereich gefunden.");
if (!treffer.length) {
console.error("KEINE gefunden -- die Erkennung passt nicht mehr zum Quelltext.");
process.exit(1);
}