diff --git a/server/pruef-chat-neu.mjs b/server/pruef-chat-neu.mjs index d510f2e4..5de480ec 100644 --- a/server/pruef-chat-neu.mjs +++ b/server/pruef-chat-neu.mjs @@ -330,23 +330,72 @@ console.log("\n=== 3. Der Ruf ans Rudel ==="); `die Schriftfarben der Blase sind lesbar, ${schriftFarben.woher}` + ` (${schriftFarben.text || "nichts"} / ${schriftFarben.leise || "nichts"})`); - if (textRgb && leiseRgb) { - let schlimmster = Infinity, schlimmsterWinkel = -1, gemessen = 0; - for (let w = 0; w < KREIS.length; w++) { - const f = zuZahl(KREIS[w]); - if (!f) continue; - gemessen++; - for (const [s3, noetig] of [[textRgb, 7], [leiseRgb, 4.8]]) { - const v = kontrast(f, s3) / noetig; - if (v < schlimmster) { schlimmster = v; schlimmsterWinkel = w; } + /* ==== DIESE MESSUNG WURDE NACHGEZOGEN (25.09.2026) ============== + + Sie rechnete: „Jeder der 360 Ringtoene traegt als FLAECHE die + Schrift der Blase." Das war richtig, solange die Blase in der + gewaehlten Farbe stand. + + Seit dem 25.09.2026 tut sie das nicht mehr -- sie ist dunkles + Glas fuer alle, und der gewaehlte Ton ist Kante und NAME. Die + alte Rechnung haette also eine Beziehung geprueft, die es nicht + mehr gibt; sie wurde beim Umbau sofort rot (Winkel 299), und das + war die richtige Reaktion einer Pruefung auf eine geaenderte + Sache. + + WAS SIE JETZT MISST, und es ist mehr wert als vorher: Jeder der + 360 Toene muss als NAME auf dem Blasengrund lesbar sein. Das ist + die Stelle, an der ein Ton heute durchfallen kann -- ein dunkles + Blau etwa waere als Name auf dunklem Glas nicht zu lesen. Die + Oberflaeche hellt jeden Ton dafuer mit Weiss auf; wie stark, steht + als `--namen-anteil` in chat.css und wird hier GELESEN, nicht + abgeschrieben. + + 4,5 UND NICHT 7: Ein Name ist ein kurzes Wort in fetter Schrift. + Dieselbe Schwelle wie in pruef-chatkachel, aus demselben Grund. + ================================================================= */ + { + const { readFileSync: lies } = await import("node:fs"); + const { fileURLToPath: alsPfad } = await import("node:url"); + const { dirname: ordnerVon, join: fuege } = await import("node:path"); + const cssTxt = lies(fuege(ordnerVon(alsPfad(import.meta.url)), "..", + "workspace", "assets", "css", "chat.css"), "utf8"); + const grundTreffer = /--blasengrund:\s*(#[0-9a-fA-F]{3,6})\s*;/.exec(cssTxt); + const anteilTreffer = /--namen-anteil:\s*([0-9.]+)%\s*;/.exec(cssTxt); + if (!grundTreffer || !anteilTreffer) { + /* DER DRITTE AUSGANG: nicht gruen, nicht rot -- "kann nicht + nachsehen", mit Grund. Ein Rueckfall auf feste Werte waere + genau die zweite Wahrheit, gegen die hier gebaut wird. */ + ok(false, "ABBRUCH: --blasengrund oder --namen-anteil fehlt in chat.css — " + + "ohne sie laesst sich die Namensfarbe nicht nachrechnen"); + } else { + const grund = zuZahl(grundTreffer[1]); + /* Die Blase ist zu 92 % deckend; dahinter liegt ein Foto. Weiss + ist der hellste denkbare Grund -- damit wird gerechnet. */ + const schlimmerGrund = grund.map((v) => Math.round(v * 0.92 + 255 * 0.08)); + const anteil = Number(anteilTreffer[1]) / 100; + const hell = zuZahl("#f2f8ff"); + let schlimmster = Infinity, schlimmsterWinkel = -1, gemessen = 0; + for (let w = 0; w < KREIS.length; w++) { + const f = zuZahl(KREIS[w]); + if (!f) continue; + gemessen++; + const name = f.map((v, i) => Math.round(v * anteil + hell[i] * (1 - anteil))); + const v2 = kontrast(name, schlimmerGrund) / 4.5; + if (v2 < schlimmster) { schlimmster = v2; schlimmsterWinkel = w; } } + /* DIE ANZAHL STEHT IN DER BEDINGUNG. Waere die Tabelle leer, + bliebe schlimmster auf Infinity und die Zeile waere gruen, + ohne eine einzige Farbe angesehen zu haben. */ + ok(gemessen === 360 && schlimmster >= 1, + `alle ${gemessen} Toene des Rings sind als Name auf der Blase lesbar` + + ` (knappster: Winkel ${schlimmsterWinkel}, Faktor ${schlimmster.toFixed(3)})`); } - /* DIE ANZAHL STEHT IN DER BEDINGUNG. Waere die Tabelle leer, - bliebe schlimmster auf Infinity und die Zeile waere gruen, - ohne eine einzige Farbe angesehen zu haben. */ - ok(gemessen === 360 && schlimmster >= 1, - `alle ${gemessen} Toene des Rings tragen die Schrift der Blase` - + ` (knappster: Winkel ${schlimmsterWinkel}, Faktor ${schlimmster.toFixed(3)})`); + } + if (textRgb && leiseRgb) { + /* Und die Schrift der Blase selbst -- sie ist seit dem Umbau fest + und steht auf einem festen Grund. Zwei Zahlen statt 360. */ + void textRgb; void leiseRgb; } /* ---- 4b. Steht der Ring da, und ist er zu treffen? ------------- */ diff --git a/server/pruef-chatkachel.mjs b/server/pruef-chatkachel.mjs index 4fc981a9..c803895d 100644 --- a/server/pruef-chatkachel.mjs +++ b/server/pruef-chatkachel.mjs @@ -118,8 +118,78 @@ const BLASEN_SCHRIFT = [ Schwellen wirklich schafft. Die Funktion darf im Notfall auch das schlechtere Paar zurückgeben (sie MUSS etwas liefern) -- genau dann schlägt diese Zeile an, und das ist ihr Zweck. */ +/* ===================================================================== + DIESE SCHLEIFE MASS AB HEUTE ETWAS, DAS ES NICHT MEHR GIBT + ===================================================================== */ +/* Sie rechnete „Schrift X auf Kachelfarbe Y" -- fuer zwoelf Farben, + zwoelf Ergebnisse. Das war genau richtig, solange der Text AUF der + Kachel stand. + + Seit dem 25.09.2026 steht er das nicht mehr: Die Blase ist dunkles + Glas fuer alle, die persoenliche Farbe ist Kante, Name und Schein. + Die Schleife waere damit gruen geblieben und haette nichts mehr + ueber den Bildschirm gesagt -- die gefaehrlichste Sorte Pruefung, + und in diesem Haus schon dreimal vorgekommen (01.09.2026). + + SIE PRUEFT JETZT DREI DINGE STATT EINES, und jedes kann scheitern: + + 1. Die feste Schrift auf dem festen Grund -- und zwar im + SCHLIMMSTEN Fall. Die Blase ist durchscheinend (92 %), dahinter + liegt ein Foto. Gerechnet wird mit Weiss dahinter; heller geht + es nicht. + 2. JEDE der zwoelf Farben als NAME auf diesem Grund. Das ist die + neue Stelle, an der es kippen kann: Ein dunkler Ton waere als + Name auf dunklem Glas nicht zu lesen. Deshalb mischt die + Oberflaeche ihn mit Weiss auf -- und diese Mischung wird hier + nachgerechnet, nicht geglaubt. + 3. Dass die Farbe ueberhaupt noch als Farbe ankommt (weiter + unten: gleiche Leuchtdichte, bunt genug, keine Dopplung). Das + gilt unveraendert -- die Toene tragen jetzt Kante und Name + statt der Flaeche. + + ALLE WERTE WERDEN AUS chat.css GELESEN, keiner abgeschrieben: + `--blasengrund`, `--blase-text`, `--blase-leise`. Wer dort etwas + aendert, aendert damit diese Pruefung mit. */ + +/** Zwei Farben mischen, wie `color-mix(in srgb, a p%, b)` es tut. */ +const mischen = (a, b, teilA) => { + const z = (h) => { const s = h.replace("#", ""); + return [0, 2, 4].map((i) => parseInt(s.slice(i, i + 2), 16)); }; + const [ar, ag, ab] = z(a), [br, bg, bb] = z(b); + const m = (x, y) => Math.round(x * teilA + y * (1 - teilA)); + return "#" + [m(ar, br), m(ag, bg), m(ab, bb)] + .map((v) => v.toString(16).padStart(2, "0")).join(""); +}; + +/* Auch das Mischverhaeltnis wird GELESEN und nicht abgeschrieben. + Beim ersten Anlauf stand hier 0.58 als Zahl -- und als die + Oberflaeche auf 50 % ging, haette die Pruefung weiter 58 gerechnet + und einen Wert bestaetigt, den niemand sieht. Genau die zweite + Wahrheit, gegen die diese Datei gebaut ist. */ +const anteilAusCss = (() => { + const m = chatCss.match(/--namen-anteil:\s*([0-9.]+)%\s*;/); + return m ? Number(m[1]) / 100 : null; +})(); +if (anteilAusCss === null) { + console.error("ABBRUCH: --namen-anteil steht nicht in chat.css. " + + "Ohne ihn kann diese Pruefung die Namensfarbe nicht nachrechnen."); + process.exit(3); +} +const GRUND = ausCss("blasengrund") || "#0b1019"; +/* 92 % Deckung -- der Rest ist das Foto dahinter. Weiss ist der + schlimmste Fall, den es dort geben kann. */ +const GRUND_SCHLIMM = mischen(GRUND, "#ffffff", 0.92); + for (const [feld, wo, noetig] of [["text", ".chat-nachricht__text", 7], ["leise", ".chat-nachricht__fuss", 4.5]]) { + const schrift = ausCss("blase-" + (feld === "text" ? "text" : "leise")); + const c1 = schrift ? kontrast(schrift, GRUND) : 0; + const c2 = schrift ? kontrast(schrift, GRUND_SCHLIMM) : 0; + ok(!!schrift && c2 >= noetig, + `${wo} traegt auf dem Blasengrund -- auch ueber der hellsten Stelle ` + + `(${c2.toFixed(2)}:1 im schlimmsten Fall, ${c1.toFixed(2)}:1 im besten, ` + + `noetig ${noetig})`); + let schlecht = Infinity, wer = "", gemessen = 0; for (const k of CHAT_KACHELN) { const paar = schriftFuer(k.farbe); @@ -131,11 +201,49 @@ for (const [feld, wo, noetig] of [["text", ".chat-nachricht__text", 7], /* Die ANZAHL gehört in die Bedingung. Wäre CHAT_KACHELN je leer, bliebe `schlecht` auf Infinity und die Zeile wäre grün, ohne einen einzigen Ton angesehen zu haben. */ + /* DIE ALTE MESSUNG BLEIBT DANEBEN STEHEN -- sie misst nicht mehr + die Blase, aber weiterhin den FARBRING: Dort steht die Mitte + wirklich in der Kachelfarbe, mit `schriftFuer` als Schrift + darauf. Sie ist also nicht ueberfluessig geworden, sondern + zustaendig fuer eine andere Stelle -- und deshalb steht das jetzt + auch in ihrem Text. */ ok(gemessen === CHAT_KACHELN.length && gemessen >= 8 && schlecht >= noetig, - `${wo} trägt auf allen ${gemessen} Tönen ` + `die Ringmitte trägt auf allen ${gemessen} Tönen ` + `(schlechtester ${wer}: ${schlecht.toFixed(2)}:1, nötig ${noetig})`); } +/* ==== UND DER NAME? (25.09.2026) ================================== + Er traegt seit heute die persoenliche Farbe -- aufgehellt, damit + auch ein dunkler Ton auf dunklem Glas liest. Die Mischung steht in + chat.css als `color-mix(in srgb, var(--ton) 58%, #f2f8ff)`; hier + wird sie fuer jeden der zwoelf Toene nachgerechnet. + + 4,5:1 UND NICHT 7: Ein Name ist ein kurzes Wort in fetter Schrift, + kein Fliesstext -- dafuer gilt die Schwelle fuer grosse Schrift. + Er steht ausserdem nie allein: Dieselbe Farbe sitzt daneben als + Kante. */ +{ + let schlecht = Infinity, wer = "", gezaehlt = 0; + for (const k of CHAT_KACHELN) { + const name = mischen(k.farbe, "#f2f8ff", anteilAusCss); + const c = kontrast(name, GRUND_SCHLIMM); + gezaehlt++; + if (c < schlecht) { schlecht = c; wer = k.name; } + } + ok(gezaehlt === CHAT_KACHELN.length && gezaehlt >= 8 && schlecht >= 4.5, + `der Name trägt in allen ${gezaehlt} Tönen auf dem Blasengrund ` + + `(schlechtester ${wer}: ${schlecht.toFixed(2)}:1, nötig 4.5)`); + + /* GEGENPROBE: Ohne das Aufhellen MUSS mindestens ein Ton + durchfallen -- sonst waere die Mischung Zierde und die Zeile + darueber ein Haken ohne Gegenstand. */ + const rohSchlecht = Math.min(...CHAT_KACHELN.map( + (k) => kontrast(k.farbe, GRUND_SCHLIMM))); + ok(rohSchlecht < 4.5, + `und ohne das Aufhellen fiele mindestens einer durch ` + + `(${rohSchlecht.toFixed(2)}:1) — die Mischung ist keine Zierde`); +} + /* UND DIE SCHRIFT WECHSELT WIRKLICH. Ohne diese Zeile wäre nicht bewiesen, dass `schriftFuer` mehr tut, als immer dasselbe Paar zurückzugeben -- dann wäre die Schleife oben nur die alte Prüfung diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html index 75b645a3..b365a0fc 100644 --- a/workspace/anruf-probe.html +++ b/workspace/anruf-probe.html @@ -16,15 +16,15 @@ verdeckt. Gefunden hat es pruef-struktur. Richtig sind `gate.css` (die Farbwerte des Hauses) und `haus.css`. --> - - + + - +