diff --git a/tools/kachel-regenbogen.mjs b/tools/kachel-regenbogen.mjs index 0ce3369b..c9fd3ea4 100644 --- a/tools/kachel-regenbogen.mjs +++ b/tools/kachel-regenbogen.mjs @@ -10,10 +10,21 @@ „NICHT GEMISCHT" IST DIE EIGENTLICHE ANSAGE. Ein Verlauf über alle Töne wäre ein Brei: Zwischen zwei Nachbarfarben entstehen Zwischentöne, die es im Haus gar nicht gibt, und die - einzelne Farbe ist nicht mehr zu erkennen. Deshalb harte Kanten — - jede Farbe bekommt ihren eigenen Streifen und bleibt sie selbst. - Man kann die Kachel ablaufen und jede Kachel der Wand darin - wiederfinden. + einzelne Farbe ist nicht mehr zu erkennen. Jede Farbe bleibt deshalb + für sich — man kann die Kachel ablaufen und jede Kachel der Wand + darin wiederfinden. + + ZWEITER ANLAUF AM 22.09.2026: PUNKTE STATT STREIFEN. + Der erste Entwurf gab jeder Farbe einen eigenen Streifen. Filipe: + „Das mit den Farben ist mega. Aber irgendwie passen die + balken/streifen nicht … schöner wirken, wenn die Farben als bunte + Punkte auf der gesamten Kachel wären." + + Er hat recht, und der Grund steht in start.css: Jede Kachel des + Hauses ist ein Sternenfeld. Die Streifen waren die einzige Fläche + weit und breit mit harten Kanten — richtig in der Farbe, falsch in + der Form. Jetzt sind es Punkte in derselben Bauart wie überall, nur + bunt statt weiß. WARUM DAS EIN WERKZEUG IST UND KEINE HANDARBEIT Die Liste der Farben steht nicht hier, sie wird ABGELEITET — aus @@ -132,72 +143,225 @@ for (const e of liste) { + " " + String(Math.round(farbwinkel(e.farbe))).padStart(4) + " Grad " + e.wer); } -/* ---- Den Streifenverlauf bauen -------------------------------------- */ -/* Jede Farbe bekommt genau denselben Anteil. Die Breite ist damit eine - Rechnung aus der Anzahl, keine eingetragene Zahl — kommt eine Kachel - dazu, rücken alle zusammen, und es bleibt lückenlos. */ -const anteil = 100 / liste.length; -const streifen = liste.map((e, i) => { - const von = (i * anteil).toFixed(3); - const bis = ((i + 1) * anteil).toFixed(3); - /* GEGEN EINEN DECKENDEN GRUND, NICHT GEGEN --flaeche. - Erster Lauf nahm `var(--flaeche)` -- dieselbe Mischung wie auf - jeder anderen Kachel. Am Bildschirm sahen die Baender dadurch - milchig aus: --flaeche ist halbdurchsichtig (Alpha 0,89), und - durch jedes Band schien das Buehnenbild. Auf einer einfarbigen - Kachel faellt das nicht auf, bei 31 schmalen Streifen nebeneinander - schon -- sie verlieren genau das, wofuer sie da sind. +/* ---- Das Punktfeld bauen -------------------------------------------- + UMGEBAUT AM 22.09.2026, von Streifen auf Punkte. - Diese eine Kachel deckt deshalb. Das ist auch inhaltlich richtig: - Sie soll die Farben des Hauses ZEIGEN, nicht durch sie hindurch - etwas anderes. */ - const f = `color-mix(in srgb, ${e.farbe} 72%, #070b14)`; - return ` ${f} ${von}%,\n ${f} ${bis}%`; -}).join(",\n"); + Filipe, nach dem ersten Bildschirmfoto: „Ja ist cool mit den ganzen + farben, aber ich finde das passt nicht so gut zum eigentlichen Stil. + Würde glaube ich schöner wirken, wenn die Farben als bunte Punkte auf + der gesamten Kachel wären, vielleicht auch eng an eng und größere und + kleinere Punkte, damit es vom Stil her die Punkte der anderen Kacheln + aufgreift, aber trotzdem extrem heraussticht. Das mit den Farben ist + mega. Aber irgendwie passen die balken/streifen nicht." + + ER HAT DEN STIL DES HAUSES GENAUER GELESEN ALS ICH. Jede Kachel der + Startseite ist ein STERNENFELD: nahe Sterne mit Hof, mittlere Sterne, + ferner Staub, dazu ein schräger Schleier. Nachzulesen weiter oben in + start.css unter „NAHE STERNE". Die Streifen waren ein Fremdkörper -- + sie waren die einzige Fläche im Haus mit harten Kanten. + + Das Punktfeld ist dieselbe Bauart wie überall, nur trägt hier JEDER + Punkt eine der Hausfarben statt Weiß. Damit greift die Kachel den + Stil auf und sticht trotzdem heraus: Sie ist die einzige, deren + Sterne bunt sind. + + DREI GRÖSSEN, DREI EIGENE RASTER. Jede Ebene enthält ALLE Farben -- + sonst wäre „alle Farben" davon abhängig, welche Größe man gerade + ansieht. Die drei Rasterweiten sind teilerfremd zueinander gewählt; + dadurch überlagern sie sich nie regelmäßig und das Feld sieht + gestreut aus statt gerastert. + + NICHTS DAVON IST GERATEN: Zahl der Punkte, Rasterweite und Reihung + folgen aus der Anzahl der Farben. Kommt eine Kachel dazu, rückt alles + von selbst zusammen. + --------------------------------------------------------------------- */ + +/* Ein Sprung durch die Farbliste, der teilerfremd zu ihrer Länge ist. + Damit liegen Nachbarpunkte nie auf benachbarten Farbwinkeln -- sonst + entstünden Flecken aus fast gleichen Tönen, und die Kachel sähe + wieder nach Verlauf aus. Abgeleitet, nicht eingetragen: eine feste + Zahl wie 7 versagt still, sobald die Anzahl ein Vielfaches davon ist. */ +function sprungFuer(n, teiler) { + const ggt = (a, b) => (b ? ggt(b, a % b) : a); + for (let s = Math.max(2, Math.round(n / teiler)); s < n; s++) { + if (ggt(s, n) === 1) return s; + } + return 1; +} + +/* Ein Zufall, der immer derselbe ist. `Math.random` wäre hier falsch: + Zwei Läufe ergäben zwei verschiedene Blöcke, und jeder Vergleich + („hat sich etwas geändert?") wäre wertlos. */ +function streu(i, salz) { + const x = Math.sin((i + 1) * 12.9898 + salz * 78.233) * 43758.5453; + return x - Math.floor(x); +} + +/* Eine Ebene: alle Farben einmal, auf ein verwackeltes Raster verteilt. */ +function ebene({ zelle, radius, hof, deckung, salz, teiler }) { + const n = liste.length; + const sprung = sprungFuer(n, teiler); + const spalten = Math.ceil(Math.sqrt(n)); + const reihen = Math.ceil(n / spalten); + const bx = zelle / spalten; + const by = zelle / reihen; + /* Rand frei halten: Ein Punkt, der über die Kachelkante ragt, wird + beim Wiederholen abgeschnitten -- und die abgeschnittene Hälfte + taucht auf der anderen Seite NICHT auf. Das sieht man sofort. */ + const luft = radius + 1; + + const punkte = []; + for (let i = 0; i < n; i++) { + const e = liste[(i * sprung) % n]; + const sp = i % spalten; + const re = Math.floor(i / spalten); + const mx = sp * bx + bx / 2; + const my = re * by + by / 2; + const jx = (streu(i, salz) - 0.5) * bx * 0.62; + const jy = (streu(i, salz + 5) - 0.5) * by * 0.62; + const x = Math.min(zelle - luft, Math.max(luft, mx + jx)); + const y = Math.min(zelle - luft, Math.max(luft, my + jy)); + /* Etwas Größenstreuung innerhalb der Ebene -- sonst sind es drei + Sorten gleicher Kreise statt eines gewachsenen Feldes. */ + const r = (radius * (0.78 + 0.44 * streu(i, salz + 11))).toFixed(2); + const f = `color-mix(in srgb, ${e.farbe} ${deckung}%, #ffffff)`; + const kern = `${f}, ${f} 34%`; + const aussen = hof + ? `, color-mix(in srgb, ${e.farbe} 55%, transparent) 52%` + : ""; + punkte.push(` radial-gradient(${r}px ${r}px at ${x.toFixed(1)}px ${y.toFixed(1)}px,` + + ` ${kern}${aussen}, transparent 100%)`); + } + return { punkte, zelle }; +} + +/* Drei Rasterweiten, absichtlich ohne gemeinsamen Teiler. Lägen sie + z. B. bei 200/100/50, fielen alle drei Ebenen alle 200 px wieder + aufeinander -- und das Auge sieht ein Muster, wo Streuung sein soll. */ +const EBENEN = [ + { zelle: 197, radius: 5.4, hof: true, deckung: 88, salz: 1, teiler: 3 }, + { zelle: 131, radius: 3.0, hof: false, deckung: 82, salz: 2, teiler: 4 }, + { zelle: 83, radius: 1.7, hof: false, deckung: 74, salz: 3, teiler: 5 }, +]; + +const gebaut = EBENEN.map(ebene); +const punktGroessen = gebaut + .map((g) => g.punkte.map(() => `${g.zelle}px ${g.zelle}px`).join(", ")) + .join(", "); +const anzahlPunkte = gebaut.reduce((s2, g) => s2 + g.punkte.length, 0); const block = `${ANFANG} /* ERZEUGT VON tools/kachel-regenbogen.mjs — NICHT VON HAND ÄNDERN. - ${liste.length} Streifen, einer je benutztem Kachelton, sortiert nach - Farbwinkel. Die Liste ist aus den Kachellisten abgeleitet; wer eine - Kachel hinzufügt, lässt das Werkzeug erneut laufen. Die Prüfung - pruef-willkommen zählt nach, ob beides noch zusammenpasst. */ + ${anzahlPunkte} Punkte in drei Größen, jede Größe einmal alle + ${liste.length} benutzten Kacheltöne. Die Liste ist aus den + Kachellisten abgeleitet; wer eine Kachel hinzufügt, lässt das + Werkzeug erneut laufen. pruef-kachelfarben zählt nach, ob beides + noch zusammenpasst. */ .kachel[data-regenbogen="ja"] { background-image: /* 1. DER LESESAUM — er liegt ZUERST, also obenauf, und ist der Grund, warum diese Kachel bunt sein darf, ohne dass die Schrift leidet. - STAERKER ALS AUF DEN ANDEREN KACHELN, und zwar gemessen: - Mit den Werten der normalen Kachel (.90/.70/.24) kam der - Text hier auf 4,45:1 -- fuenf Hundertstel unter der Grenze. - Kein Wunder: Dort liegt EIN dunkler Ton unter der Schrift, - hier liegen deckende Farbbaender. Ein heller Untergrund - braucht einen dunkleren Saum, sonst ist die Kachel schoen - und der Text weg. Gefunden hat das pruef-kachelfarben, nicht - der Blick -- 4,45 gegen 4,50 sieht man nicht. */ + ZURUECKGENOMMEN AM 22.09.2026, und zwar auf eine Messung hin: + Mit dem Saum der Streifenfassung kam der Text hier auf + 8,27:1 — bei einer Grenze von 4,5. Das war kein sicherer + Saum, das war ein Deckel: Er hat die untere Haelfte der + Kachel verschluckt, und genau dort sollten Punkte sein + („auf der gesamten kachel"). Jetzt kuerzer und schwaecher, + der Rest der Luft bleibt als Sicherheit stehen. + pruef-kachelfarben misst es nach jedem Lauf neu. */ linear-gradient(to top, - rgba(4, 6, 14, .95) 0%, rgba(4, 6, 14, .82) 26%, - rgba(4, 6, 14, .32) 48%, transparent 66%), - /* 2. DIE VIGNETTE — aussen dunkler als innen. Ohne sie wäre die + rgba(4, 6, 14, .80) 0%, rgba(4, 6, 14, .48) 24%, + rgba(4, 6, 14, .14) 44%, transparent 60%), + /* 2. DIE VIGNETTE — außen dunkler als innen. Ohne sie wäre die Kachel eine Fläche, mit ihr ein Ausschnitt. */ - radial-gradient(120% 120% at 50% 45%, transparent 44%, rgba(3, 5, 12, .42) 100%), - /* 3. EIN SCHRÄGER GLANZ quer über die Streifen. Er bindet die - ${liste.length} Bänder zu einer Fläche zusammen — ohne ihn sieht es - aus wie ein Farbmuster, mit ihm wie ein Gegenstand. */ + radial-gradient(120% 120% at 50% 40%, transparent 46%, rgba(3, 5, 12, .34) 100%), + + /* 3. DIE GROSSEN PUNKTE, jeder mit Hof — das ist der Unterschied + zwischen einem Licht und einem gestanzten Kreis. Dieselbe + Bauart wie die „nahen Sterne" auf jeder anderen Kachel. */ +${gebaut[0].punkte.join(",\n")}, + + /* 4. DIE MITTLEREN — die Masse des Feldes. */ +${gebaut[1].punkte.join(",\n")}, + + /* 5. DER FEINE STAUB. Er füllt die Lücken: Ein Feld aus nur + großen Punkten sieht aus wie aufgeklebt. */ +${gebaut[2].punkte.join(",\n")}, + + /* 6. EIN SCHRÄGER SCHLEIER quer über das Feld. Er bindet die + ${anzahlPunkte} Punkte zu einer Fläche zusammen — ohne ihn + schweben sie einzeln. Sehr blass; er soll Richtung geben, + nicht auffallen. */ linear-gradient(104deg, - rgba(255, 255, 255, .10) 0%, - rgba(255, 255, 255, .02) 34%, - rgba(0, 0, 0, .10) 68%, - rgba(0, 0, 0, .26) 100%), - /* 4. DIE FARBEN DES HAUSES, harte Kanten, kein Verlauf dazwischen. - Jede Farbe bleibt sie selbst — genau das war die Ansage. */ - linear-gradient(100deg, -${streifen}); - background-size: 100% 100%, 100% 100%, 100% 100%, 100% 100%; - /* Die Kante links trägt alle Farben mit, in derselben Reihenfolge — - sonst wäre ausgerechnet der farbigste Streifen der Kachel einfarbig. */ + rgba(255, 255, 255, .085) 0%, + rgba(255, 255, 255, .02) 36%, + rgba(0, 0, 0, .10) 70%, + rgba(0, 0, 0, .24) 100%), + /* 7. DER GRUND. Deckend, nicht durchscheinend: Die Kachel soll die + Farben des Hauses ZEIGEN, nicht durch sie hindurch das + Bühnenbild. */ + linear-gradient(180deg, #0b1020 0%, #070b14 100%); + background-size: + 100% 100%, 100% 100%, + ${punktGroessen}, + 100% 100%, 100% 100%; + background-repeat: + no-repeat, no-repeat, + ${gebaut.flatMap((g) => g.punkte.map(() => "repeat")).join(", ")}, + no-repeat, no-repeat; + /* Die Kante trägt den Kachelton mit — sonst wäre ausgerechnet die + farbigste Kachel der Wand einfarbig umrandet. */ border-color: color-mix(in srgb, var(--ton) 38%, transparent); } + +/* EIN RUHIGER GRUND HINTER DER SCHRIFT — und nur dort. + + Beim ersten Blick aufs Handybild sass ein heller Punkt mitten unter + dem Wort „gibt". Die Messung sagte trotzdem 8,2:1 und hatte recht: + Sie mittelt ueber die ganze Textflaeche. Ein einzelner Punkt hinter + einem duennen Buchstaben verschwindet in diesem Mittel — im Auge + nicht. + + ZWEI ANLAEUFE, DIE BEIDE FALSCH WAREN: + * Den Lesesaum wieder dunkler machen — dann ist die halbe Kachel + zu, und gewollt waren Punkte auf der GESAMTEN Kachel. + * Ein dunkler Teich im Kachelhintergrund, 400 px breit. Auf dem + grossen Bildschirm sass er richtig; auf dem Handy ist die + Kachel selbst nur 366 px breit, und der Teich hat fast alle + Farben geschluckt. Eine Zahl in Pixeln, die auf einem Geraet + passt, ist auf dem naechsten falsch. + + RICHTIG IST, DEN GRUND AN DEN TEXT ZU HAENGEN statt an die Kachel: + Dann ist er immer genau so breit wie das, was er lesbar machen + soll — auf jedem Geraet, ohne eine einzige Schwelle. Gemessen wird + nicht, sondern abgeleitet. + + "z-index: -1" legt ihn hinter die Schrift, aber vor die Punkte. + (Ohne Schraegstriche geschrieben: Dieser Kommentar steht INNERHALB + einer Vorlagenzeichenkette, und ein Gegenstrich darin beendet sie.) */ +.kachel[data-regenbogen="ja"] .kachel__text { position: relative; } +.kachel[data-regenbogen="ja"] .kachel__text::before { + content: ""; + position: absolute; + inset: -16px -34px -18px -22px; + z-index: -1; + /* KEIN RAND UND KEIN ECKRADIUS. Der erste Entwurf hatte beides, und + dann stand eine Karte in der Karte -- man sah den Kasten und nicht + den Text. Der Verlauf laeuft jetzt deutlich vor der Kante aus; + dadurch ist er ein Schatten und keine Flaeche. */ + /* MITTIG UND KLEINER ALS DER KASTEN. Der zweite Entwurf sass bei + 28 % und war 112 % breit -- am linken Rand war er damit noch fast + deckend, und das Rechteck schnitt ihn hart ab. Man sah die Kante. + Ein Verlauf, der an keiner Seite die Kante erreicht, hat auch + keine. */ + background: radial-gradient(74% 90% at 50% 50%, + rgba(4, 6, 14, .86) 0%, + rgba(4, 6, 14, .60) 42%, + rgba(4, 6, 14, .18) 68%, + transparent 88%); +} ${ENDE}`; if (!process.argv.includes("--schreiben")) { @@ -217,4 +381,4 @@ if (css.includes(ANFANG) && css.includes(ENDE)) { } writeFileSync(CSS, neu, "utf8"); console.log("\nEingetragen in workspace/assets/css/start.css (" - + liste.length + " Streifen)."); + + anzahlPunkte + " Punkte in drei Groessen, je " + liste.length + " Farben)."); diff --git a/workspace/anruf-probe.html b/workspace/anruf-probe.html index 976d4c6b..1aa65f65 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`. --> - - + + - +