diff --git a/server/chat-kreis-stufen.js b/server/chat-kreis-stufen.js new file mode 100644 index 00000000..79f88053 --- /dev/null +++ b/server/chat-kreis-stufen.js @@ -0,0 +1,141 @@ +/* ===================================================================== + HELLER UND DUNKLER (25.09.2026) + ===================================================================== + + Filipe: „dieser kreis muss viel perfekter sein. ich will dass die + leute auch heller und dunkler aussuchen koennen. perfektionier das + bitte viel krasser. viel profissioneller. so dass die leute viel + krassere moeglichkeiten haben." + + --------------------------------------------------------------------- + WARUM DAS BIS HEUTE NICHT GING + + Die 360 Toene in chat-kreis.js liegen ALLE auf derselben + Leuchtdichte. Das war kein Zufall und keine Bequemlichkeit: Solange + die Blase in der gewaehlten Farbe stand, musste jede dieser Flaechen + dieselbe Schrift tragen -- „gleiche Leuchtdichte heisst gleicher + Kontrast fuer alle". Eine hellere Farbe zuzulassen hiesse damals: + irgendwo im Haus wird eine Nachricht unlesbar. + + SEIT DEM 25.09.2026 IST DAS ANDERS. Die Blase ist fuer alle dunkles + Glas (`--blasengrund`); der gewaehlte Ton ist KANTE und NAME. Damit + faellt die alte Bedingung weg -- und eine neue tritt an ihre Stelle: + + Der Ton muss als NAME auf dem Blasengrund lesbar bleiben. + + Die Oberflaeche hellt ihn dafuer mit Weiss auf (`--namen-anteil`, + 50 %). Genau diese Rechnung prueft pruef-chat-neu fuer alle Toene. + + --------------------------------------------------------------------- + DIE ZAHLEN SIND GEMESSEN, NICHT GEWAEHLT + + Nachgerechnet ueber alle 360 Winkel, jeweils der schlechteste: + + 40 % schwarz 4,468 -- unter der Schwelle, faellt raus + 34 % schwarz 4,555 -- ginge, aber ohne Reserve + 30 % schwarz 4,619 <- die dunkelste Stufe + 20 % schwarz 4,7 + 10 % schwarz 4,9 + 0 % 5,12 <- die Mitte, der alte Kreis + 18 % weiss 6,4 + 36 % weiss 7,9 + 55 % weiss 9,6 <- die hellste Stufe + + Noetig sind 4,5. Die dunkelste Stufe hat also 0,12 Reserve, die + hellste mehr als das Doppelte. Wer hier eine Stufe hinzufuegt, misst + nach -- pruef-chat-neu rechnet jede Stufe an jedem der 360 Winkel + nach und wird rot, bevor es jemand auf dem Bildschirm sieht. + + --------------------------------------------------------------------- + WARUM SIEBEN UND NICHT DREI + + Drei (dunkel / normal / hell) waere die bequeme Zahl. Sieben sind + der Punkt, an dem zwei benachbarte Stufen noch unterscheidbar sind + und man trotzdem das Gefuehl hat, etwas einstellen zu koennen -- + Filipes „viel krassere moeglichkeiten" heisst nicht „zwei mehr". + Zusammen mit 360 Winkeln sind es 2520 Farben statt 360. + + --------------------------------------------------------------------- + WARUM EINE EIGENE DATEI + + chat-kreis.js wird von tools/chat-kacheln-rechnen.mjs ERZEUGT und + traegt oben „NICHT VON HAND AENDERN". Etwas hineinzuschreiben waere + beim naechsten Lauf des Werkzeugs weg. Die Stufen sind ausserdem + keine Tabelle, sondern eine Rechnung -- sie gehoeren nicht in eine + erzeugte Liste. + ===================================================================== */ +import { KREIS } from "./chat-kreis.js"; + +/** Die sieben Stufen. Minus heisst dunkler, Plus heller. + * + * `wert` ist der Teil, der im Schluessel steht ("ton-214-s2"). + * `misch` ist der Anteil, mit dem der Grundton nach Schwarz (negativ) + * oder nach Weiss (positiv) gezogen wird. + * `name` ist das, was ein Vorleseprogramm sagt -- eine Zahl von 1 bis + * 7 saehe aus wie eine Note. + */ +export const KREIS_STUFEN = [ + { wert: "s1", misch: -0.30, name: "sehr dunkel" }, + { wert: "s2", misch: -0.20, name: "dunkler" }, + { wert: "s3", misch: -0.10, name: "leicht dunkel" }, + { wert: "s4", misch: 0, name: "normal" }, + { wert: "s5", misch: 0.18, name: "leicht hell" }, + { wert: "s6", misch: 0.36, name: "heller" }, + { wert: "s7", misch: 0.55, name: "sehr hell" }, +]; + +/** Welche Stufe ist die Mitte -- und damit das, was "ton-214" ohne + * Zusatz bedeutet. Abgeleitet aus `misch === 0` und nicht als Index + * hingeschrieben: Wer eine Stufe vorn einfuegt, verschiebt sonst + * stillschweigend die Bedeutung aller alten Schluessel. */ +export const KREIS_MITTE = KREIS_STUFEN.find((s) => s.misch === 0)?.wert || "s4"; + +/** Zerlegt einen Schluessel in Winkel und Stufe. + * + * "ton-214" -> { winkel: 214, stufe: "s4" } (die Mitte) + * "ton-214-s6" -> { winkel: 214, stufe: "s6" } + * alles andere -> null + * + * DIE ALTEN SCHLUESSEL BLEIBEN GUELTIG, und zwar ohne Umstellung in + * der Datenbank. Wer seit dem 23.09. "ton-214" traegt, traegt danach + * genau dieselbe Farbe -- eine Umstellung, die stillschweigend die + * Wahl von fuenfzehn Leuten verschiebt, waere kein Fortschritt. + */ +export function tonAus(wert) { + const t = /^ton-(\d{1,3})(?:-(s[1-7]))?$/.exec(String(wert ?? "")); + if (!t) return null; + const winkel = Number(t[1]); + if (!(winkel >= 0 && winkel < KREIS.length)) return null; + const stufe = t[2] || KREIS_MITTE; + if (!KREIS_STUFEN.some((s) => s.wert === stufe)) return null; + return { winkel, stufe }; +} + +/** Zwei Farben mischen, wie `color-mix(in srgb, a p%, b)` es tut. */ +function mischen(a, b, anteilB) { + const z = (h) => { + const s = String(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 * (1 - anteilB) + y * anteilB); + return "#" + [m(ar, br), m(ag, bg), m(ab, bb)] + .map((v) => v.toString(16).padStart(2, "0")).join(""); +} + +/** Die fertige Farbe zu Winkel und Stufe. */ +export function tonFarbe(winkel, stufe) { + const grund = KREIS[winkel]; + if (!grund) return null; + const s = KREIS_STUFEN.find((x) => x.wert === stufe) || { misch: 0 }; + if (!s.misch) return grund; + return s.misch < 0 + ? mischen(grund, "#000000", -s.misch) + : mischen(grund, "#ffffff", s.misch); +} + +/** Die Farbe zu einem ganzen Schluessel, oder null. */ +export function farbeZuSchluessel(wert) { + const t = tonAus(wert); + return t ? tonFarbe(t.winkel, t.stufe) : null; +} diff --git a/server/pruef-chat-anhaenge.mjs b/server/pruef-chat-anhaenge.mjs index ca5beb7f..6e53493a 100644 --- a/server/pruef-chat-anhaenge.mjs +++ b/server/pruef-chat-anhaenge.mjs @@ -418,6 +418,142 @@ let pdfNachrichtId = 0; ok(kaeme === 0, `für ein PDF wird kein Bildkasten gebaut (${kaeme})`); } +/* ======================================================================= + 2c. DIE BILDSCHAU (25.09.2026) + ======================================================================= + + Filipe: „wenn man bilder aufmacht, will ich dass die in der mitte + sind. beim hochformat soll links der husky sein und rechts der hase + und beim querformat soll oben dogfather und unten team dogi stehen + da wo platz ist." + + VORHER OEFFNETE DER KLICK DIE DATEI in einem neuen Tab -- und was man + sah, war die eingebaute Bildanzeige des Browsers: schwarzer Grund, + Bild oben links. Das ist kein Fehler des Browsers; eine Datei hat + keine Gestaltung. + + GEMESSEN WIRD, WAS ER GESAGT HAT, und jedes einzeln: + 1. Der Klick oeffnet die Schau (und nicht mehr den Tab). + 2. Das Bild steht in der MITTE -- gemessen als Abstand seines + Mittelpunkts zur Fenstermitte, nicht als „es ist da". + 3. Bei einem breiten Bild stehen die zwei Schriftzuege da. + 4. Escape bringt einen zurueck. + 5. GEGENPROBE: Mit Strg gedrueckt oeffnet sie NICHT -- der Weg in + den neuen Tab bleibt, wie er war. Ohne diese Zeile haette + „die Schau geht auf" auch dann gestimmt, wenn sie IMMER aufgeht + und der alte Weg verloren ist. + ======================================================================= */ +{ + await oeffne(luna.seite, raumId); + /* Das Foto aus Abschnitt 2 ist 240x150 -- also quer. */ + const bildKasten = ".chat-nachricht .chat-bild"; + await luna.seite.waitForSelector(bildKasten, { timeout: 8000 }); + + /* GEGENPROBE ZUERST: mit Strg bleibt der alte Weg. */ + await luna.seite.click(bildKasten, { modifiers: ["Control"] }); + await luna.seite.waitForTimeout(400); + const mitStrg = await luna.seite.evaluate(() => + !!document.querySelector("dialog.bildschau[open]")); + ok(mitStrg === false, + `Gegenprobe: Strg+Klick öffnet die Schau NICHT (${mitStrg}) — der Weg in den Tab bleibt`); + + await luna.seite.click(bildKasten); + await luna.seite.waitForTimeout(600); + const schau = await luna.seite.evaluate(() => { + const d = document.querySelector("dialog.bildschau[open]"); + if (!d) return { offen: false }; + const b = d.querySelector(".bildschau__bild"); + const r = b.getBoundingClientRect(); + const worte = [...d.querySelectorAll(".bildschau__wort")] + .filter((e) => Number(getComputedStyle(e).opacity) > .5) + .map((e) => e.textContent.trim()); + return { + offen: true, + lage: d.dataset.lage, + /* Wie weit ist die Bildmitte von der Fenstermitte weg? Bei + „mittig" sind das ein paar Pixel, bei „oben links" Hunderte. */ + abX: Math.round(Math.abs((r.left + r.width / 2) - window.innerWidth / 2)), + abY: Math.round(Math.abs((r.top + r.height / 2) - window.innerHeight / 2)), + worte, + figuren: [...d.querySelectorAll(".bildschau__figur")] + .filter((e) => Number(getComputedStyle(e).opacity) > .5).length, + grund: getComputedStyle(d.querySelector(".bildschau__grund")).backgroundImage.length, + }; + }); + ok(schau.offen === true, `ein Klick öffnet die Bildschau (${schau.offen})`); + /* 40 px Spielraum: Die Buehne hat oben mehr Polsterung als unten + (dort steht die Leiste), der Mittelpunkt liegt also nie exakt auf + dem Pixel. Bei „oben links in der Ecke" waeren es Hunderte. */ + ok(schau.abX <= 40 && schau.abY <= 60, + `und das Bild steht in der Mitte (${schau.abX} px seitlich, ${schau.abY} px hoch daneben)`); + ok(schau.lage === "quer", + `ein breites Bild bekommt die Querformat-Fassung ("${schau.lage}")`); + ok(schau.worte.length === 2 + && /DogFather/i.test(schau.worte[0]) && /Team Dogi/i.test(schau.worte[1]), + `mit „DogFather" oben und „Team Dogi" unten (${JSON.stringify(schau.worte)})`); + ok(schau.figuren === 0, + `und OHNE die zwei Figuren — die gehören ins Hochformat (${schau.figuren})`); + ok(schau.grund > 80, + `der Grund ist gestaltet und nicht schwarz (${schau.grund} Zeichen Verlauf)`); + + /* EIN BILD FUER DEN MENSCHEN. Andere Pruefungen in diesem Haus legen + ebenso eines ab (pruef-handy.png, pruef-crew-wand-handy.png) -- + eine Zahl sagt „mittig", ein Bild sagt, ob es gut aussieht. */ + await luna.seite.screenshot({ path: "server/pruef-bildschau.png" }); + + await luna.seite.keyboard.press("Escape"); + await luna.seite.waitForTimeout(400); + const zu = await luna.seite.evaluate(() => + !!document.querySelector("dialog.bildschau[open]")); + ok(zu === false, `Escape bringt einen zurück (${zu})`); + + /* ---- UND DAS HOCHFORMAT ----------------------------------------- + Der andere Fall aus Filipes Satz -- „beim hochformat soll links + der husky sein und rechts der hase". Ohne ein zweites, HOHES Bild + waere dieser halbe Auftrag nie gemessen worden; das quere Bild + oben kann ihn nicht beantworten. */ + const hoch = await hochladen(luna.seite, raumId, { + inhalt: { art: "png", breite: 300, hoehe: 800 }, + typ: "image/png", name: "hochformat.png", text: "Und hochkant", + }); + ok(hoch.status === 201, `ein hohes Foto kommt an (HTTP ${hoch.status})`); + await oeffne(luna.seite, raumId); + await luna.seite.waitForSelector(".chat-nachricht:last-of-type .chat-bild", { timeout: 8000 }); + await luna.seite.click(".chat-nachricht:last-of-type .chat-bild"); + await luna.seite.waitForTimeout(700); + const hochSchau = await luna.seite.evaluate(() => { + const d = document.querySelector("dialog.bildschau[open]"); + if (!d) return { offen: false }; + const b = d.querySelector(".bildschau__bild"); + const r = b.getBoundingClientRect(); + const sicht = (s) => [...d.querySelectorAll(s)] + .filter((e) => Number(getComputedStyle(e).opacity) > .5); + const figuren = sicht(".bildschau__figur"); + return { + offen: true, lage: d.dataset.lage, + abX: Math.round(Math.abs((r.left + r.width / 2) - window.innerWidth / 2)), + figuren: figuren.length, + /* LIEGT EINE DAVON UEBER DEM BILD? Das waere der Schaden, den + man erst sieht, wenn ein Gesicht halb verdeckt ist. */ + drueber: figuren.filter((e) => { + const f = e.getBoundingClientRect(); + return Math.min(f.right, r.right) - Math.max(f.left, r.left) > 4; + }).length, + worte: sicht(".bildschau__wort").length, + }; + }); + ok(hochSchau.lage === "hoch", `ein hohes Bild bekommt die Hochformat-Fassung ("${hochSchau.lage}")`); + ok(hochSchau.figuren === 2, `Husky und Hase stehen daneben (${hochSchau.figuren})`); + ok(hochSchau.drueber === 0, + `und KEINE davon liegt über dem Foto (${hochSchau.drueber})`); + ok(hochSchau.worte === 0, + `die Schriftzüge bleiben weg — die gehören ins Querformat (${hochSchau.worte})`); + ok(hochSchau.abX <= 40, `auch hier steht das Bild mittig (${hochSchau.abX} px daneben)`); + await luna.seite.screenshot({ path: "server/pruef-bildschau-hoch.png" }); + await luna.seite.keyboard.press("Escape"); + await luna.seite.waitForTimeout(300); +} + /* ======================================================================= 3. WAS NICHT HEREINDARF — die eigentliche Prüfung diff --git a/server/pruef-chat-neu.mjs b/server/pruef-chat-neu.mjs index 5de480ec..6760388c 100644 --- a/server/pruef-chat-neu.mjs +++ b/server/pruef-chat-neu.mjs @@ -313,6 +313,23 @@ console.log("\n=== 3. Der Ruf ans Rudel ==="); const zuZahl = (f) => { const t = /^#?([0-9a-f]{6})$/i.exec(String(f).trim()); if (t) return [0, 2, 4].map((i) => parseInt(t[1].slice(i, i + 2), 16)); + /* ==== DIE DRITTE SCHREIBWEISE (25.09.2026) ==================== + + Seit die Probe ihre Farbe aus `color-mix(in srgb, …)` bekommt, + gibt Chromium sie als `color(srgb 0.676 0.645 0.504)` zurueck -- + Anteile von 0 bis 1, keine Ganzzahlen, kein Komma. Die zwei + Muster darueber trafen das nicht, `zuZahl` lieferte `null`, und + die Zeile wurde rot, obwohl die Farbe auf den Bildpunkt genau + stimmte (172,5 / 164,5 / 128,5 gegen erwartete 173/165/129). + + Das ist die Sorte Fehlalarm, die teurer ist als ein echter + Befund: Man sucht am Aussehen, und der Fehler liegt im + Lesegeraet. */ + const s = /color\(srgb\s+([^)]+)\)/i.exec(String(f)); + if (s) { + return s[1].trim().split(/[\s/]+/).slice(0, 3) + .map((x) => Math.round(parseFloat(x) * 255)); + } const r = /rgba?\(([^)]+)\)/i.exec(String(f)); return r ? r[1].split(",").slice(0, 3).map((x) => Math.round(parseFloat(x))) : null; }; @@ -375,21 +392,55 @@ console.log("\n=== 3. Der Ruf ans Rudel ==="); const schlimmerGrund = grund.map((v) => Math.round(v * 0.92 + 255 * 0.08)); const anteil = Number(anteilTreffer[1]) / 100; const hell = zuZahl("#f2f8ff"); + /* ==== JEDE STUFE AN JEDEM WINKEL (25.09.2026) ================= + + Filipe: „ich will dass die leute auch heller und dunkler + aussuchen koennen." + + Seit heute gibt es zu jedem der 360 Winkel sieben + Helligkeiten -- 2520 Farben statt 360. Nur den Grundton zu + pruefen hiesse, sechs Siebtel des Angebots ungeprueft + auszuliefern; und die dunkelste Stufe ist genau die, bei der + es kippen wuerde (gemessen 4,62 gegen noetige 4,5 -- die + naechste Stufe darunter faellt durch). + + DIE MISCHANTEILE WERDEN GELESEN, nicht abgeschrieben: Sie + stehen in chat-kreis-stufen.js, und wer sie dort aendert, + aendert damit diese Pruefung mit. Eine zweite Liste hier waere + die, die beim naechsten Umbau nicht mitzieht. */ + const { KREIS_STUFEN } = await import("./chat-kreis-stufen.js"); + const mischen2 = (rgb, misch) => { + if (!misch) return rgb; + const ziel = misch < 0 ? 0 : 255; + const t2 = Math.abs(misch); + return rgb.map((v) => Math.round(v * (1 - t2) + ziel * t2)); + }; let schlimmster = Infinity, schlimmsterWinkel = -1, gemessen = 0; + let schlimmsteStufe = ""; 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; } + for (const st of KREIS_STUFEN) { + gemessen++; + const ton = mischen2(f, st.misch); + const name = ton.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; schlimmsteStufe = st.wert; + } + } } /* 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 -- und sie ist seit heute + 360 mal die Zahl der Stufen. Waere die Stufenliste leer, + bliebe `gemessen` bei 0 und die Zeile waere gruen, ohne eine + einzige Farbe angesehen zu haben. */ + ok(gemessen === 360 * KREIS_STUFEN.length && schlimmster >= 1, + `alle ${gemessen} Farben des Rings (360 Winkel x ${KREIS_STUFEN.length} ` + + `Helligkeiten) sind als Name auf der Blase lesbar (knappste: Winkel ` + + `${schlimmsterWinkel}, Stufe ${schlimmsteStufe}, Faktor ${schlimmster.toFixed(3)})`); } } if (textRgb && leiseRgb) { @@ -466,21 +517,84 @@ console.log("\n=== 3. Der Ruf ans Rudel ==="); const stand = await frida.seite.evaluate(() => { const r = document.getElementById("kachelrad-ring"); - const m = document.getElementById("kachelrad-mitte"); + const p2 = document.querySelector(".kachelrad__probe"); + const leiter = document.getElementById("kachelhell-leiter"); return { winkel: Number(r?.getAttribute("aria-valuenow")), wort: r?.getAttribute("aria-valuetext") || "", - mitte: m ? getComputedStyle(m).backgroundColor : "" }; + /* NICHT MEHR DER GRUND, SONDERN DIE SCHRIFT. Siehe unten. */ + probe: p2 ? getComputedStyle(p2).color : "", + stufen: leiter ? leiter.children.length : 0, + stufeJetzt: leiter?.getAttribute("aria-valuenow") || "" }; }); ok(Math.abs((stand.winkel || 0) - 90) <= 2, `nach dem Drehen auf drei Uhr steht der Ring bei ${stand.winkel} Grad (erwartet 90)`); - const erwartet = zuZahl(KREIS[stand.winkel] || ""); - const gezeigt = zuZahl(stand.mitte); + /* ==== DIE PROBE MISST SEIT HEUTE ETWAS ANDERES (25.09.2026) ===== + + Hier stand: „die Mitte zeigt genau die Farbe dieses Winkels" -- + gemessen am HINTERGRUND der Mitte. Das war richtig, solange die + Blase in der gewaehlten Farbe stand. + + Seit dem 25.09.2026 ist die Blase fuer alle dunkles Glas, und + der gewaehlte Ton ist der NAME darauf. Die Probe zeigte damit + eine Darstellung, die es im Chat nicht mehr gibt -- und die + Pruefung haette sie festgehalten. + + GEMESSEN WIRD JETZT DIE SCHRIFT der Probe: Sie muss genau die + Farbe tragen, die ein Name in der Blase traegt -- der Ton, mit + `--namen-anteil` nach #f2f8ff aufgehellt. Das ist dieselbe + Rechnung wie in chat.css, und sie wird hier NACHGERECHNET statt + abgeschrieben. */ + const grundTon = zuZahl(KREIS[stand.winkel] || ""); + const hell = zuZahl("#f2f8ff"); + const anteil = 0.5; /* --namen-anteil; weiter unten aus dem CSS geprueft */ + const erwartet = grundTon + ? grundTon.map((v, i) => Math.round(v * anteil + hell[i] * (1 - anteil))) + : null; + const gezeigt = zuZahl(stand.probe); ok(!!erwartet && !!gezeigt - && Math.abs(erwartet[0] - gezeigt[0]) <= 1 - && Math.abs(erwartet[1] - gezeigt[1]) <= 1 - && Math.abs(erwartet[2] - gezeigt[2]) <= 1, - `die Mitte zeigt genau die Farbe dieses Winkels (${stand.mitte} gegen ${KREIS[stand.winkel]})`); + && Math.abs(erwartet[0] - gezeigt[0]) <= 2 + && Math.abs(erwartet[1] - gezeigt[1]) <= 2 + && Math.abs(erwartet[2] - gezeigt[2]) <= 2, + `die Probe zeigt den Namen in genau dieser Farbe (${stand.probe} gegen ` + + `${erwartet ? "rgb(" + erwartet.join(", ") + ")" : "?"})`); + + /* ==== UND DIE SIEBEN HELLIGKEITEN (25.09.2026) ================= + + Filipe: „ich will dass die leute auch heller und dunkler + aussuchen koennen … so dass die leute viel krassere + moeglichkeiten haben." */ + ok(stand.stufen === 7, + `die Helligkeitsleiter hat sieben Stufen (${stand.stufen})`); + ok(stand.stufeJetzt === "4", + `und steht von sich aus in der Mitte (${stand.stufeJetzt})`); + + /* EINE STUFE WAEHLEN UND NACHSEHEN, OB SIE ANKOMMT. Ohne das + waere „es gibt sieben Felder" ein Haken ueber Zierde: Sieben + Kaestchen, die nichts tun, sehen genauso aus. */ + await frida.seite.click(".kachelhell__feld[data-stufe='s7']"); + await frida.seite.waitForTimeout(700); + const hellStand = await frida.seite.evaluate(() => { + const p2 = document.querySelector(".kachelrad__probe"); + const leiter = document.getElementById("kachelhell-leiter"); + const an = leiter?.querySelector('[data-an="ja"]'); + return { probe: p2 ? getComputedStyle(p2).color : "", + stufe: leiter?.getAttribute("aria-valuenow") || "", + markiert: an?.dataset.stufe || "" }; + }); + ok(hellStand.stufe === "7" && hellStand.markiert === "s7", + `eine hellere Stufe laesst sich waehlen (${hellStand.stufe}, ${hellStand.markiert})`); + const vorher2 = zuZahl(stand.probe), nachher2 = zuZahl(hellStand.probe); + ok(!!vorher2 && !!nachher2 && leucht(nachher2) > leucht(vorher2), + `und die Probe wird dabei wirklich heller ` + + `(${leucht(vorher2).toFixed(3)} auf ${leucht(nachher2).toFixed(3)})`); + + await frida.seite.screenshot({ path: "server/pruef-farbkreis.png" }); + + /* Und zurueck in die Mitte, damit die Pruefungen danach mit dem + gewohnten Stand weiterarbeiten. */ + await frida.seite.click(".kachelhell__feld[data-stufe='s4']"); + await frida.seite.waitForTimeout(500); ok(/\d+ Grad/.test(stand.wort) && stand.wort.length > 8, `und sie wird vorgelesen als "${stand.wort}"`); diff --git a/server/workspace-chat.js b/server/workspace-chat.js index dc696de4..77db76a1 100644 --- a/server/workspace-chat.js +++ b/server/workspace-chat.js @@ -51,6 +51,7 @@ import { import { erwaehnteIds, rudelGerufen, RUDEL_WORT } from "./chat-erwaehnung.js"; import { KREIS, winkelAus } from "./chat-kreis.js"; +import { KREIS_STUFEN, KREIS_MITTE, tonAus } from "./chat-kreis-stufen.js"; import { KATALOG, ERLAUBT, VORSCHLAG, FAVORITEN_MAX } from "./workspace-reaktionen.js"; /* Der Treff-Chat: eigener Raum, eigene Nachtruhe, keine Anrufe. @@ -425,7 +426,20 @@ export function kachelPruefen(wert) { Die alten Schluessel bleiben gueltig. Wer "veilchen" gewaehlt hat, behaelt es -- eine Umstellung, die stillschweigend die Wahl von fuenfzehn Leuten zuruecksetzt, waere kein Fortschritt. */ - if (winkelAus(wert) !== null) return String(wert); + /* SEIT DEM 25.09.2026 GIBT ES ZU JEDEM WINKEL SIEBEN HELLIGKEITEN. + + Filipe: „ich will dass die leute auch heller und dunkler + aussuchen koennen." + + Der Schluessel heisst dann "ton-214-s6". Ohne Zusatz gilt die + Mitte -- die alten Schluessel bleiben damit Zeichen fuer Zeichen + gueltig und bedeuten dieselbe Farbe wie vorher. + + `tonAus` ERSETZT `winkelAus` HIER, laesst es aber stehen: Es wird + an anderer Stelle noch gebraucht, und zwei Pruefungen fuer + denselben Schluessel waeren eine Gelegenheit, dass eine davon + mehr durchlaesst. */ + if (tonAus(wert) !== null) return String(wert); return CHAT_KACHELN.some((k) => k.wert === String(wert)) ? String(wert) : null; } @@ -1031,6 +1045,20 @@ chatRouter.get("/workspace/api/chat/kacheln", (req, res) => { Kacheln -- also tragen sie auch dieselbe Schrift. Einmal gerechnet und mitgeschickt, statt 360-mal dasselbe. */ kreis_schrift: schriftFuer(KREIS[0]), + /* DIE SIEBEN HELLIGKEITEN (25.09.2026). + + Nicht 2520 fertige Farben, sondern 360 Grundtoene und sieben + Mischanteile: Der Browser mischt selbst, und zwar mit genau + den Zahlen, die hier stehen. Die ganze Tabelle zu schicken + waere 20 kB fuer etwas, das eine Zeile Rechnung ist. + + DIE ZAHLEN KOMMEN TROTZDEM VOM SERVER und stehen nicht im + Browser: Sie sind aus der Kontrastrechnung hergeleitet (siehe + chat-kreis-stufen.js), und eine zweite Fassung im Browser + waere ab der naechsten Messung falsch -- unbemerkt, denn sie + lieferte ja weiter „irgendeine Farbe". */ + kreis_stufen: KREIS_STUFEN, + kreis_mitte: KREIS_MITTE, /* Die eigene WAHL, nicht der getragene Ton -- sonst stuende im Waehler ein Haken bei einer Farbe, die niemand gewaehlt hat. */ meine: gewaehlteKachelFuer(req.person.id), diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html index 4e603c81..932bf84f 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`. --> - - + + - +