Umsetzung des Design-Systems "Baby Blue Optical Luxury" (Edition 2.0), Schritt 1 von mehreren: die zentrale Farbquelle. Nach der Kernregel auf Seite 3 ist das ausdrücklich ein Farb- und Licht-Redesign — Aufbau, Navigation, Texte und Funktionen bleiben unangetastet. FARBEN Grundflächen auf die vier Tiefenebenen des Systems (Void, Midnight, Obsidian, Deep Glass). Palette nach Seite 5: Signature Baby, Ion Blue, Hyper Aqua, Aurora Violet, Prism Indigo, Liquid Gold, Signal Coral, Chrome Silver. Die Variablen behalten ihre alten NAMEN (--wd-blau statt --cryo-baby). Ein Umbenennen hätte über 155 Fundstellen anfassen müssen — viel Bewegung ohne sichtbaren Nutzen, mit der realen Gefahr, eine Stelle zu übersehen und danach zwei fast gleiche Blautöne zu haben. Entscheidend ist die Rolle, nicht der Name; die Systembezeichnungen stehen als Kommentar daneben. EIN FEHLER IM DESIGN-SYSTEM, DER BEWUSST NICHT ÜBERNOMMEN WURDE Die Token-Liste auf Seite 20 ist um eine Zeile verrutscht — Namen und Hex-Werte passen dort nicht zusammen. Am folgenreichsten: --cryo-baby stünde auf #0C2740, einem fast schwarzen Navy, und ist laut Seite 21 zugleich die Standard-Lumenfarbe. Das Mauslicht wäre damit praktisch unsichtbar geworden — ausgerechnet der Effekt, den das System auf fünf Seiten als unantastbar schützt. Maßgeblich ist deshalb die Palette auf Seite 5 und die Lumen-Logik auf Seite 9, die untereinander stimmig sind. MAUSLICHT Der bestehende Effekt bleibt vollständig erhalten (Systemauflage) und bekommt eine Farbvariable pro Kachel: --wd-lumen. Vorher war die Farbe im Verlauf fest verdrahtet, und jede weitere Kachelfarbe hätte zwei neue Blöcke gebraucht (Fläche + leuchtende Kante). Bei sechs Lumen-Rollen wären das zwölf fast gleiche Blöcke gewesen, die beim nächsten Feinschliff zwangsläufig auseinanderlaufen. Jetzt setzt die Kachel nur ihre Farbe, der Verlauf steht einmal da — genau das meint Token-Regel 02 mit "Kachelfarbe steuert Lumenfarbe". 38 lose Hex-Codes durch Token ersetzt (Token-Regel 05). Drei davon (#3d9dbd, #7c5cd6, #a8873a) waren noch die ALTEN Markenfarben und hätten still neben den neuen weitergelebt — genau der Mechanismus, durch den Oberflächen mit der Zeit zwei fast gleiche Töne bekommen. KONTRASTE NACHGERECHNET Die Palette ist auf dunklem Grund durchweg stark (9,7 bis 19,8:1) — mit einer Ausnahme: Prism Indigo erreicht auf keiner Fläche 4,5:1 (nur 3,25 bis 4,29). Es ist deshalb ausschließlich für Kanten, Verläufe und große Premium-Flächen zugelassen, nie für Fließtext. Das System sieht Indigo ohnehin nur für "Premium-Momente" vor — die Rechnung bestätigt die Regel, statt ihr zu widersprechen. NEUER TEST: pruef-cryonova.mjs (24 Prüfungen) Palette, Grundflächen, Mauslicht-Erhalt, echte Zeigerbewegung, keine losen Hex-Codes, Kontraste und die Frage, ob alle 12 Seiten wirklich aus derselben Quelle schöpfen. Dabei drei Fehlalarme im eigenen Test gefunden und behoben — jeder davon hätte dauerhaft rote Zeilen erzeugt und irgendwann dazu geführt, dass man eine echte Meldung übersieht: - Halbtransparente Flächen müssen über ihren Untergrund gerechnet werden. Der aktive Reiter kam sonst auf 1:1 statt echter 8,25–10,23:1. - Text auf Farbverläufen liefert rgba(0,0,0,0) als Hintergrund; der Hauptknopf kam so auf 1:1 statt rund 11:1. - Die Maus muss mit Zwischenschritten bewegt werden, sonst feuert pointermove nicht. Eine Direktmessung bestätigte: Das Licht folgt einwandfrei (30px → 723px, Deckkraft 1). pruef-system.mjs auf den neuen Markenton gesetzt. Dass er dort zunächst "0 von 1804 Elementen" meldete, war kein Fehler, sondern der Beweis, dass der alte Ton nirgends mehr vorkommt. Geprüft: 24 (CRYONOVA) + 0 Fundstellen (Design/WCAG über 12 Seiten × 5 Sprachen) + 40 + 56 + 69 + 54 + 42 + 55 + 5 + 16 — alles grün.
185 lines
8.1 KiB
JavaScript
185 lines
8.1 KiB
JavaScript
/* =====================================================================
|
|
pruef-system.mjs — Beweist, dass das Farbsystem eines IST
|
|
|
|
Ein Designsystem ist erst dann eines, wenn eine Änderung an EINER
|
|
Stelle überall ankommt. Steht die Markenfarbe an 155 Stellen
|
|
ausgeschrieben, hat man kein System, sondern eine Sammlung von
|
|
Zufällen, die sich zufällig ähneln.
|
|
|
|
WIE gemessen wird — und warum nicht anders.
|
|
|
|
Der naheliegende Weg wäre, die Variable im laufenden Browser
|
|
umzustellen und zu schauen, was mitgeht. Er liefert FALSCHE
|
|
Ergebnisse: Chromium erneuert Teilbäume, die per innerHTML eingefügt
|
|
wurden — Kopf- und Fusszeile stammen aus wd-core.js — nicht
|
|
zuverlässig, wenn man eine Variable nachträglich ändert. Auch ein
|
|
erzwungener Neuberechnungsstoss half nicht.
|
|
|
|
Nachgewiesen am 23.08.2026: Bei Laufzeitänderung blieben 110 Elemente
|
|
scheinbar "hängen". Lädt man dieselbe Seite dagegen mit bereits
|
|
geänderter Variable, sind sie orange. Der Fehler lag im
|
|
Messverfahren, nicht im Farbsystem.
|
|
|
|
Deshalb wird die Variable VOR dem Laden überschrieben. Das entspricht
|
|
genau dem, was eine Änderung in der CSS-Datei bewirkt — also dem
|
|
Fall, um den es wirklich geht.
|
|
===================================================================== */
|
|
import { chromium } from "playwright";
|
|
import { createServer } from "node:http";
|
|
import { readFileSync, existsSync, readdirSync } from "node:fs";
|
|
import { join, extname } from "node:path";
|
|
|
|
const W = process.cwd();
|
|
const T = { ".html": "text/html", ".css": "text/css", ".js": "text/javascript",
|
|
".png": "image/png", ".jpg": "image/jpeg", ".svg": "image/svg+xml",
|
|
".webp": "image/webp", ".ico": "image/x-icon", ".json": "application/json" };
|
|
const srv = createServer((q, r) => {
|
|
const p = join(W, decodeURIComponent(q.url.split("?")[0]));
|
|
if (existsSync(p) && !p.endsWith("/")) {
|
|
r.writeHead(200, { "content-type": T[extname(p)] || "text/plain" });
|
|
return r.end(readFileSync(p));
|
|
}
|
|
r.writeHead(404).end("");
|
|
});
|
|
await new Promise((r) => srv.listen(4332, r));
|
|
|
|
/* diagnose.html ist bewusst ausgenommen.
|
|
|
|
Sie ist das Werkzeug fuer den Fall, dass die Seite NICHT laeuft, und
|
|
traegt deshalb alles fest in sich: eigene Farben, eigenes Layout,
|
|
keine externe CSS- oder JS-Datei, keine Uebersetzung. Genau das ist
|
|
ihr Zweck -- eine Diagnoseseite, die an derselben kaputten
|
|
Stilvorlage scheitert wie das Problem, das sie untersuchen soll,
|
|
waere wertlos.
|
|
|
|
Sie deshalb an den Regeln fuer die eigentliche Seite zu messen, wuerde
|
|
zwei Meldungen erzeugen, die man auf Dauer wegsieht -- und irgendwann
|
|
sieht man dann auch eine echte weg. */
|
|
const SEITEN = readdirSync(join(W, "webdesign"))
|
|
.filter((f) => f.endsWith(".html") && f !== "diagnose.html");
|
|
/* Der aktuelle Markenton. Beim Wechsel auf das CRYONOVA-System
|
|
(24.08.2026) stand hier noch der alte Wert 127, 208, 232 -- der Test
|
|
fand daraufhin null Elemente und meldete Alarm. Das war genau
|
|
umgekehrt zu deuten: Dass der alte Ton NIRGENDS mehr vorkam, war der
|
|
Beweis, dass die Umstellung vollstaendig durchgeschlagen ist. Der
|
|
Test misst hier aber, ob eine Aenderung ueberall ankommt -- dafuer
|
|
braucht er den Ton, der gerade gilt. */
|
|
const ALT = "143, 216, 255"; // Signature Baby #8FD8FF
|
|
const NEU = "255 120 40"; // drastisch anders, damit nichts untergeht
|
|
|
|
const ergebnisse = [];
|
|
function pruefe(name, ok, zusatz) {
|
|
ergebnisse.push({ name, ok });
|
|
console.log((ok ? " ok " : " FEHL ") + name + (zusatz ? " -> " + zusatz : ""));
|
|
}
|
|
|
|
const browser = await chromium.launch();
|
|
|
|
async function seiteMitFarbe(datei, umstellen) {
|
|
const s = await browser.newPage({ viewport: { width: 1280, height: 900 } });
|
|
await s.route("**/webdesign/admin/**", (r) => r.fulfill({ json: { ok: true, anfragen: [], kunden: [], projekte: [], verlaeufe: [] } }));
|
|
await s.route("**/webdesign/portal/**", (r) => r.fulfill({ json: { ok: true } }));
|
|
await s.route("**/webdesign/api-ausweis", (r) => r.fulfill({ json: {} }));
|
|
await s.addInitScript(({ um, neu }) => {
|
|
sessionStorage.setItem("wd-sitzung-aktiv", "1");
|
|
if (!um) return;
|
|
const st = document.createElement("style");
|
|
st.textContent = ":root{--wd-blau-rgb: " + neu + " !important;}";
|
|
document.addEventListener("DOMContentLoaded", () => document.head.appendChild(st));
|
|
}, { um: umstellen, neu: NEU });
|
|
await s.goto("http://127.0.0.1:4332/webdesign/" + datei);
|
|
await s.waitForTimeout(420);
|
|
return s;
|
|
}
|
|
|
|
console.log("=== Kommt eine Farbänderung überall an? ===\n");
|
|
|
|
let haengen = 0;
|
|
let betroffen = 0;
|
|
let sichtbarGesamt = 0;
|
|
|
|
for (const datei of SEITEN) {
|
|
/* Erst zählen, wie viele Elemente den Markenton ÜBERHAUPT tragen —
|
|
sonst wäre "0 hängen geblieben" auch dann erfüllt, wenn die Farbe
|
|
auf der Seite gar nicht vorkommt. */
|
|
const vorher = await seiteMitFarbe(datei, false);
|
|
const wieviele = await vorher.evaluate((alt) => {
|
|
let n = 0;
|
|
for (const el of document.querySelectorAll("*")) {
|
|
const r = el.getBoundingClientRect();
|
|
if (r.width < 1 || r.height < 1) continue;
|
|
const st = getComputedStyle(el);
|
|
if ([st.color, st.backgroundColor, st.borderTopColor, st.boxShadow, st.backgroundImage]
|
|
.join("|").includes(alt)) n++;
|
|
}
|
|
return n;
|
|
}, ALT);
|
|
await vorher.close();
|
|
betroffen += wieviele;
|
|
|
|
const nachher = await seiteMitFarbe(datei, true);
|
|
const rest = await nachher.evaluate((alt) => {
|
|
const raus = [];
|
|
let sichtbar = 0;
|
|
for (const el of document.querySelectorAll("*")) {
|
|
const r = el.getBoundingClientRect();
|
|
if (r.width < 1 || r.height < 1) continue;
|
|
sichtbar++;
|
|
const st = getComputedStyle(el);
|
|
if ([st.color, st.backgroundColor, st.borderTopColor, st.boxShadow, st.backgroundImage]
|
|
.join("|").includes(alt)) {
|
|
raus.push(el.tagName.toLowerCase() + "." + (el.className || "").toString().slice(0, 34));
|
|
}
|
|
}
|
|
return { raus, sichtbar };
|
|
}, ALT);
|
|
await nachher.close();
|
|
|
|
sichtbarGesamt += rest.sichtbar;
|
|
haengen += rest.raus.length;
|
|
if (rest.raus.length) {
|
|
console.log(` FEHL ${datei}: ${rest.raus.length} Elemente zeigen weiter den alten Ton`);
|
|
for (const h of [...new Set(rest.raus)].slice(0, 6)) console.log(" " + h);
|
|
}
|
|
}
|
|
|
|
pruefe("die Markenfarbe kommt auf vielen Elementen vor", betroffen > 200,
|
|
betroffen + " von " + sichtbarGesamt + " sichtbaren Elementen");
|
|
pruefe("nach der Umstellung bleibt KEINE Stelle beim alten Ton", haengen === 0,
|
|
haengen + " hängen geblieben");
|
|
|
|
/* ---- Die vier Prozessfarben müssen an den Markenfarben hängen ---- */
|
|
const s3 = await seiteMitFarbe("ablauf.html", false);
|
|
const prozess = await s3.evaluate(() => {
|
|
const w = getComputedStyle(document.documentElement);
|
|
const vor = ["--wd-p1", "--wd-p2", "--wd-p3", "--wd-p4"].map((v) => w.getPropertyValue(v).trim());
|
|
document.documentElement.style.setProperty("--wd-blau-rgb", "255 120 40");
|
|
document.documentElement.style.setProperty("--wd-gold-rgb", "40 255 120");
|
|
const w2 = getComputedStyle(document.documentElement);
|
|
const nach = ["--wd-p1", "--wd-p2", "--wd-p3", "--wd-p4"].map((v) => w2.getPropertyValue(v).trim());
|
|
return { vor, nach };
|
|
});
|
|
pruefe("Prozessfarbe 1 (Start) hängt an der Markenfarbe Blau",
|
|
prozess.vor[0] !== prozess.nach[0], prozess.vor[0] + " -> " + prozess.nach[0]);
|
|
pruefe("Prozessfarbe 4 (Abschluss) hängt an der Markenfarbe Gold",
|
|
prozess.vor[3] !== prozess.nach[3], prozess.vor[3] + " -> " + prozess.nach[3]);
|
|
|
|
/* ---- Radien: eine knappe Skala statt Zufallswerten ---- */
|
|
const radien = await s3.evaluate(() => {
|
|
const werte = new Set();
|
|
for (const el of document.querySelectorAll("*")) {
|
|
if (el.getBoundingClientRect().width < 1) continue;
|
|
const v = getComputedStyle(el).borderTopLeftRadius;
|
|
if (v && v !== "0px" && v.endsWith("px") && parseFloat(v) < 100) werte.add(v);
|
|
}
|
|
return Array.from(werte).sort((a, b) => parseFloat(a) - parseFloat(b));
|
|
});
|
|
pruefe("Eckenradien folgen einer knappen Skala", radien.length <= 5, radien.join(", "));
|
|
await s3.close();
|
|
|
|
await browser.close();
|
|
srv.close();
|
|
const f = ergebnisse.filter((e) => !e.ok).length;
|
|
console.log(`\n===== ${ergebnisse.length - f} bestanden, ${f} fehlgeschlagen =====`);
|
|
process.exitCode = f ? 1 : 0;
|