Files
dogfather-universe/pruef-bildgroessen.mjs
DogFatherGitandClaude Opus 5 508009ecc7 Startseite: Hintergrund-Kanten weg, "Event des Jahres" neu aufgebaut
Gemeldet 27.08.2026: "es ueberschneidet den hintergrund sieht irgendwie
scheisse aus."

1. HARTE KANTEN IM HINTERGRUND
   Das scharfe Trio-Artwork lag als CSS-Hintergrund mit "contain" hinter
   der Seite und endete an einer messerscharfen Linie (bei 1366x800 exakt
   bei 570px und 1345px); darueber/darunter lag sichtbar die verwaschene
   Fassung. Das las sich wie ein aufgeklebtes Band quer ueber der Seite.
   Jetzt ein echtes <img>, das an seinen EIGENEN Raendern weich in die
   verwaschene Ebene uebergeht. Entscheidend: Die Maske haengt am Bild,
   nicht am Fenster -- als CSS-Hintergrund war das unmoeglich, weil die
   Kante je nach Fensterformat wandert.

2. "EVENT DES JAHRES" -- 700px tote Flaeche
   Eine 480px schmale Kachel sass zentriert in einer 1180px breiten
   Kiste, die selbst Rahmen und Hintergrund trug: drei Rahmen ineinander
   um einen einzigen Inhalt, links und rechts je 350px Leere. Jetzt volle
   Breite mit Bild links / Text rechts, die umgebende Kiste ist rahmenlos.
   Hoehe von 656px auf 332px, ohne dass Inhalt verloren geht -- das Bild
   ist dabei doppelt so gross wie vorher.

3. Welt-Kacheln mit einer Spur Milchglas und feinem Lichtsaum, damit sie
   zur Szene gehoeren statt als flache Rechtecke daraufzuliegen.

BEIM BAUEN GEFUNDEN UND KORRIGIERT: Der erste Entwurf hat die versteckte
zweite Event-Kachel wieder sichtbar gemacht (leere Kachel mit einsamem
"Mehr erfahren"). Ursache ist die im Code zweimal dokumentierte Falle:
".jahres-event-card[hidden]" ist genau so stark wie eine
Zwei-Klassen-Regel und verliert gegen die spaetere. Deshalb steht in den
neuen Regeln ueberall :not([hidden]).

Versionsnummern von main.css/main.js hochgesetzt -- Assets werden mit
max-age=14400 ausgeliefert, sonst haette Dogi die Aenderung bis zu vier
Stunden nicht gesehen.

Geprueft: pruef-handy (56), pruef-barrierefrei (60), pruef-design (0
Fundstellen), pruef-blickfang (13), pruef-assets (67), pruef-musik (17)
-- alle gruen. Der Musik-Knopf holt seine Farben jetzt aus dem <img>
statt aus dem CSS-Hintergrund (main.js), sonst waere er ausgerechnet auf
der Startseite auf die Ersatzfarbe zurueckgefallen.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-27 15:45:23 +02:00

95 lines
4.1 KiB
JavaScript

/* =====================================================================
Welche Bilder sind größer, als sie je angezeigt werden?
Sammelt über alle öffentlichen Seiten (Desktop UND Handy) für jedes
<img> die größte Anzeigebreite -- mal Pixeldichte, damit Retina zählt.
Vergleicht das mit der echten Dateibreite. Ein Bild, das mehr als das
2,5-fache seiner größten Anzeige misst, ist ein Kandidat zum
Verkleinern: Es überträgt Pixel, die nie ein Auge erreicht.
NUR <img>. CSS-Hintergründe (bg-*.jpg) füllen den Bildschirm und
werden getrennt betrachtet.
===================================================================== */
import { chromium } from "playwright";
import { statSync, readFileSync, existsSync } from "node:fs";
const BASIS = "https://dogfather-universe.com";
const SEITEN = [
"/", "/dogfather.html", "/hasidog.html", "/manager.html", "/casper.html",
"/vanvan.html", "/tt-muddi.html", "/zeitreise.html", "/streamer.html",
"/community.html", "/stimmen.html", "/streamplan.html", "/team-modis.html",
"/team-scouts.html", "/creator.html", "/werte.html", "/bewerben.html",
"/kontakt.html", "/links.html", "/supporter.html", "/abonnieren.html",
"/medien-dogfather.html", "/medien-hasidog.html", "/medien-casper.html",
];
/* Dateibreite eines lokalen JPG/PNG lesen (ohne Bibliothek). */
function breiteVon(pfad) {
if (!existsSync(pfad)) return 0;
const s = readFileSync(pfad);
if (s[0] === 0xFF && s[1] === 0xD8) { // JPEG
let i = 2;
while (i < s.length) {
if (s[i] !== 0xFF) { i++; continue; }
const m = s[i + 1];
if (m >= 0xC0 && m <= 0xC3) return s.readUInt16BE(i + 7);
i += 2 + s.readUInt16BE(i + 2);
}
} else if (s.slice(0, 8).equals(Buffer.from([0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A]))) { // PNG
return s.readUInt32BE(16);
}
return 0;
}
const browser = await chromium.launch();
const maxAnzeige = new Map(); // dateiname -> maxBreite (CSS-px * DPR)
for (const vp of [{ width: 1280, height: 900 }, { width: 390, height: 844 }]) {
for (const pfad of SEITEN) {
const s = await browser.newPage({ viewport: vp });
try {
await s.goto(BASIS + pfad, { waitUntil: "networkidle", timeout: 30000 });
await s.waitForTimeout(300);
const m = await s.evaluate(() => {
const raus = {};
for (const im of document.querySelectorAll("img")) {
const src = (im.currentSrc || im.src || "");
if (!src.includes("/assets/img/")) continue; // nur eigene Bilder
const name = src.split("/assets/img/")[1].split("?")[0];
const r = im.getBoundingClientRect();
if (r.width < 2) continue;
const px = Math.round(r.width * (window.devicePixelRatio || 1));
raus[name] = Math.max(raus[name] || 0, px);
}
return raus;
});
for (const [k, v] of Object.entries(m)) maxAnzeige.set(k, Math.max(maxAnzeige.get(k) || 0, v));
} catch { /* egal */ }
await s.close();
}
}
await browser.close();
const kandidaten = [];
for (const [name, anzeige] of maxAnzeige) {
const pfad = "assets/img/" + name;
const dateiBreite = breiteVon(pfad);
if (!dateiBreite || !existsSync(pfad)) continue;
const kb = Math.round(statSync(pfad).size / 1024);
const faktor = dateiBreite / Math.max(anzeige, 1);
/* 2,5-fach als Schwelle: 2x deckt Retina, der Rest ist Puffer gegen
Layout-Schwankungen. Nur nennen, was auch spürbar wiegt (>=120 KB). */
if (faktor >= 2.5 && kb >= 120) {
kandidaten.push({ name, dateiBreite, anzeige, faktor: faktor.toFixed(1), kb, ziel: Math.min(dateiBreite, anzeige * 2) });
}
}
kandidaten.sort((a, b) => b.kb - a.kb);
console.log(`\n${maxAnzeige.size} <img>-Bilder gesehen. Überdimensioniert (>= 2,5x Anzeige, >= 120 KB):\n`);
if (!kandidaten.length) console.log(" keine -- alle Bilder passen zu ihrer Anzeigegröße.");
for (const k of kandidaten) {
console.log(` ${k.kb.toString().padStart(4)} KB ${k.name.padEnd(26)} Datei ${k.dateiBreite}px, angezeigt ${k.anzeige}px (${k.faktor}x) -> Ziel ${k.ziel}px`);
}
const summe = kandidaten.reduce((a, k) => a + k.kb, 0);
if (kandidaten.length) console.log(`\n Summe der Kandidaten: ${summe} KB`);