Kacheln werden ein Raster -- dritter Anlauf, diesmal die FORM

Filipe zweimal davor: "das ist genau das gleiche" und "sorry aber ich
glaub du verstehst nicht was ich meine". Er hatte beide Male recht, und
ich weiss jetzt warum: Ich habe zweimal die OBERFLAECHE geaendert
(Mattglas, dann Leuchtschiene) und beide Male die FORM gelassen -- eine
breite Zeile, Zeichen links, Text daneben. Wer eine Zeile umlackiert,
bekommt eine lackierte Zeile.

AUS DREI BREITEN ZEILEN WIRD EIN RASTER AUS SECHS KARTEN.
Hochformat, Zeichen oben, Name unten, Schiene von links nach OBEN
gewandert (an einer hochkanten Karte wuerde ein Lichtbalken links sie
optisch halbieren). Die Zahl steht als Marke oben rechts statt in der
Namenszeile, der Pfeil unten rechts. `data-gross="ja"` behaelt das
Querformat -- so hebt sich die Kachel WIRKLICH ab, statt nur breiter zu
sein. Bei 1380 px passen jetzt sechs Karten nebeneinander statt drei.

BILDER: Kontrast 1,08 -> 1,14, Saettigung 1,10 -> 1,26, Glanz 0,34 ->
0,46, dazu ein neuer Durchgang "Tiefe" -- eine S-Kurve auf der
Helligkeit. Das ist NICHT mehr Kontrast: Kontrast dehnt alles gleich und
frisst Zeichnung in den Lichtern; die S-Kurve laesst die Mitte in Ruhe
(dort sitzt das Motiv) und arbeitet nur an den Enden. Gerechnet auf dem
Maximum der drei Kanaele, nicht je Kanal -- sonst wandert der Farbton
(ein dunkles Rot wuerde braun).

ANMELDESEITE: "Dogfather Universe" -> "SpicyMedia x DogFather" (das
Kreuz kleiner und leiser, sonst liest man drei Namen statt zwei), und
der Satz darunter nennt jetzt Manager, Scouts und Creator von Spicy
Media -- ohne DogFather.

ZAHLEN nur noch fuer DogFather. Beides zusammen, nicht nur die Kachel:
Eine Kachel ist ein Weg, keine Schranke -- wer die Adresse kennt, waere
weiterhin hineingekommen. Also auch in der Rechteliste auf ["admin"].

AUFGERAEUMT, weil pruef-struktur zu Recht rot wurde: start.css lief mit
202 KB in die 200-KB-Grenze. Der Grund war echter Ballast -- die Datei
trug DREI Generationen Kacheldesign uebereinander. Die ueberholten
Regeln sind weg (nur was der neue Entwurf nicht selbst setzt, bleibt),
der Entwurfstext dazu auf seine Lehre gekuerzt. 198,7 KB, und wichtiger:
nur noch EINE Stelle, an der eine Kachel beschrieben wird.

Gruen: buehne (38), css-klassen (15), leistung (50), start-ansicht (136),
handy (59), breiten (23), struktur (32).

NOCH OFFEN aus derselben Nachricht: die neue Rolle "Spicy Media" und die
Aenderung, dass Manager Creator anlegen duerfen. Beides greift in die
Rechte und in die CHECK-Regel der Personentabelle ein -- das kommt als
eigener Schritt mit Sicherung und eigener Pruefung, nicht nebenbei.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-07 03:59:16 +02:00
co-authored by Claude Opus 5
parent 1b2874299e
commit 8f8c283a1a
59 changed files with 578 additions and 281 deletions
+49 -4
View File
@@ -386,11 +386,38 @@ const BILD_WERKZEUG = `
g.globalAlpha = 1;
g.globalCompositeOperation = "source-over";
}
/* S-Kurve auf der Helligkeit. staerke 0 = nichts, 0.15 = deutlich. */
function tiefe(g, c, staerke) {
if (staerke <= 0) return;
const d = g.getImageData(0, 0, c.width, c.height);
const D = d.data;
/* Nachschlagetabelle statt Rechnung je Bildpunkt: 256 Werte einmal,
statt drei Millionen Mal dieselbe Formel. */
const t = new Uint8Array(256);
for (let i = 0; i < 256; i++) {
const x = i / 255;
/* Glatte S-Kurve (smoothstep), gemischt mit dem Original. */
const s = x * x * (3 - 2 * x);
const v = x + (s - x) * staerke * 3;
t[i] = Math.max(0, Math.min(255, Math.round(v * 255)));
}
for (let i = 0; i < D.length; i += 4) {
const max = Math.max(D[i], D[i + 1], D[i + 2]);
if (max === 0) continue;
/* Ein Faktor fuer alle drei Kanaele -- der Farbton bleibt. */
const f = t[max] / max;
D[i] = Math.min(255, D[i] * f);
D[i + 1] = Math.min(255, D[i + 1] * f);
D[i + 2] = Math.min(255, D[i + 2] * f);
}
g.putImageData(d, 0, 0);
}
`;
async function bauen({ quelle, ziel, breite, ausschnitt = null, dunkel = 0, guete = 0.82,
seitenverhaeltnis = null, kontrast = 1.08, saettigung = 1.1, vignette = 0.34,
schaerfe = 0.9, glanzStaerke = 0.34 }) {
seitenverhaeltnis = null, kontrast = 1.14, saettigung = 1.26, vignette = 0.34,
schaerfe = 1.05, glanzStaerke = 0.46, tiefe = 0.10 }) {
const webp = await seite.evaluate(async (a) => {
const i = new Image(); i.src = a.daten; await i.decode();
@@ -438,7 +465,24 @@ async function bauen({ quelle, ziel, breite, ausschnitt = null, dunkel = 0, guet
/* 5: GLANZ. Nach dem Schaerfen, damit das Licht die geschaerften
Kanten umspielt und nicht umgekehrt der Glanz mitgeschaerft wird
(das gaebe harte Lichtsaeume statt weichem Strahlen). */
glanz(g, c, a.glanzStaerke, 176, Math.max(3, zb / 190));
glanz(g, c, a.glanzStaerke, 172, Math.max(3, zb / 190));
/* 6: TIEFE. Die dunkelsten Stellen werden noch etwas dunkler, die
hellsten noch etwas heller -- eine S-Kurve, wie sie jeder
Bildbearbeiter als Erstes zieht.
Das ist NICHT dasselbe wie mehr Kontrast: Kontrast dehnt alles
gleichmaessig und frisst dabei Zeichnung in den Lichtern. Die
S-Kurve laesst die MITTE in Ruhe (dort sitzt das Motiv) und
arbeitet nur an den Enden. Genau daran erkennt man ein poliertes
Bild -- der schwarze Stein ist wirklich schwarz, das Neon wirklich
hell, und dazwischen bleibt alles lesbar.
Gerechnet auf dem Maximum der drei Kanaele, nicht je Kanal
einzeln: Je Kanal wuerde die Kurve die FARBE verschieben (ein
dunkles Rot wird sonst braun). So bleibt der Farbton, nur die
Helligkeit wandert. */
tiefe(g, c, a.tiefe);
/* 3: Die Vignette. Elliptisch ueber die ganze Flaeche, in der Mitte
voellig klar, zu den Ecken hin dunkel. Der weiche Verlauf ist
@@ -462,7 +506,8 @@ async function bauen({ quelle, ziel, breite, ausschnitt = null, dunkel = 0, guet
}
return c.toDataURL("image/webp", a.guete);
}, { daten: alsDatenAdresse(quelle), breite, ausschnitt, dunkel, guete, seitenverhaeltnis,
kontrast, saettigung, vignette, schaerfe, glanzStaerke, werkzeug: BILD_WERKZEUG });
kontrast, saettigung, vignette, schaerfe, glanzStaerke, tiefe,
werkzeug: BILD_WERKZEUG });
const puffer = Buffer.from(webp.split(",")[1], "base64");
writeFileSync(ziel, puffer);