Ein App-Symbol aus beiden Marken: Husky in der Mitte, Chili als Sockel
Filipe: "ich will dass du da eine geile mischung machst von diesen zwei logo ... mach was ultra krass geiles draus bitte." DIE AUFGABE IST NICHT "zwei Bilder nebeneinander". Ein App-Symbol steht bei 32 px im Browserreiter und bei 192 px auf dem Startbildschirm. Zwei vollstaendige Logos nebeneinander ergeben dort zwei unlesbare Haelften. Gebraucht wird EINE Form, in der beide vorkommen. Der Husky steht im Zentrum -- eine Silhouette traegt bei kleiner Groesse am besten. Die Chili liegt als Bogen darunter, wie ein Sockel. Der Hintergrund traegt beide Farben: Chili-Rot unten links, Dogi-Blau oben rechts, und sie treffen sich in der Mitte -- dieselbe Klammer wie im Schriftzug "Spicy & Dogi" in der Kopfleiste. Der Husky wird als MASKE eingesetzt und mit Silber gefuellt: Das Original ist schwarzweiss und waere auf dunklem Grund ein dunkler Fleck. UNTER 64 px FAELLT DIE CHILI WEG. Sie waere dort ein verwaschener Fleck und wuerde die Husky-Silhouette anfressen. Ein Symbol, das klein noch erkennbar ist, ist mehr wert als eins, das alle Bestandteile zeigt und dabei zu Matsch wird. EINMAL NACHGEBESSERT nach dem Blick aufs Bild: Die Chili sass zuerst hoeher und schnitt dem Husky die Brust ab. Jetzt liegt sie tiefer, er steht vollstaendig. GEPRUEFT WIRD NICHT DIE DATEIGROESSE, sondern die Streuung der Helligkeit. Ein Symbol, das aus einem Fehler heraus einfarbig ist, hat dieselbe Bytezahl wie eines mit Motiv -- die beweist also nichts. Ein leeres Feld hat keine Streuung; gemessen wurden 48 bis 69 bei einer Untergrenze von 12, unter der das Werkzeug abbricht. EINE FALLE MITENTSCHAERFT: `tools/app-symbole.mjs` fuehrte den Workspace noch in seiner Liste und haette die sechs Dateien beim naechsten Lauf stillschweigend ueberschrieben -- gleiche Namen, gleicher Ordner, kein Fehler, nur wieder das alte Symbol. Er steht dort nicht mehr. pruef-workspace-seiten EXIT=0 (32), pruef-assets EXIT=0. Nebenbefund, NICHT von hier: pruef-verwaltung-app scheitert an einem MODULE_NOT_FOUND -- gegen den alten Stand gegengeprueft, dort derselbe Fehler. Vorbestehend, gehoert auf die offene Liste. Co-Authored-By: Claude Opus 5 <[email protected]>
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 208 KiB |
|
Before Width: | Height: | Size: 209 KiB After Width: | Height: | Size: 212 KiB |
@@ -55,7 +55,19 @@ if (!existsSync(LOGO)) {
|
|||||||
------------------------------------------------------------------ */
|
------------------------------------------------------------------ */
|
||||||
export const APPS = [
|
export const APPS = [
|
||||||
{ schluessel: "universe", name: "Dogfather Universe", kurz: "Universe", wo: "dogfather-universe.com" },
|
{ schluessel: "universe", name: "Dogfather Universe", kurz: "Universe", wo: "dogfather-universe.com" },
|
||||||
{ schluessel: "workspace", name: "Creator Workspace", kurz: "Workspace", wo: "/workspace" },
|
/* DER WORKSPACE STEHT HIER NICHT MEHR (08.09.2026).
|
||||||
|
|
||||||
|
Sein Symbol ist seit heute kein eingefaerbtes Logo mehr, sondern
|
||||||
|
eine Mischung aus Husky UND Chili -- gebaut von
|
||||||
|
tools/workspace-symbol.mjs (Wunsch Filipe: "eine geile mischung
|
||||||
|
von diesen zwei logo").
|
||||||
|
|
||||||
|
Bliebe er in dieser Liste, wuerde der naechste Lauf von
|
||||||
|
`app-symbole.mjs bauen` die sechs Dateien stillschweigend
|
||||||
|
ueberschreiben -- gleiche Namen, gleicher Ordner. Nichts wuerde
|
||||||
|
scheitern, das Symbol waere nur wieder das alte, und niemand
|
||||||
|
wuesste warum. Eine Zeile, die man nicht loescht, ist eine Falle,
|
||||||
|
die man spaeter selbst stellt. */
|
||||||
{ schluessel: "webdesign", name: "Dogfather Webdesign", kurz: "Webdesign", wo: "/webdesign" },
|
{ schluessel: "webdesign", name: "Dogfather Webdesign", kurz: "Webdesign", wo: "/webdesign" },
|
||||||
{ schluessel: "portal", name: "Kundenportal", kurz: "Portal", wo: "/webdesign/portal.html" },
|
{ schluessel: "portal", name: "Kundenportal", kurz: "Portal", wo: "/webdesign/portal.html" },
|
||||||
{ schluessel: "wdverwalt", name: "Webdesign-Verwaltung", kurz: "WD-Verw.", wo: "/webdesign/verwaltung.html" },
|
{ schluessel: "wdverwalt", name: "Webdesign-Verwaltung", kurz: "WD-Verw.", wo: "/webdesign/verwaltung.html" },
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
/* ===================================================================
|
||||||
|
Das App-Symbol des Workspace: Husky UND Chili in einem Zeichen.
|
||||||
|
|
||||||
|
Filipe (08.09.2026): "ich will dass du da eine geile mischung machst
|
||||||
|
von diesen zwei logo ... mach was ultra krass geiles draus bitte."
|
||||||
|
|
||||||
|
DIE AUFGABE IST NICHT "zwei Bilder nebeneinander". Ein App-Symbol
|
||||||
|
steht bei 32 px im Browserreiter und bei 192 px auf dem
|
||||||
|
Startbildschirm. Zwei vollstaendige Logos nebeneinander ergeben dort
|
||||||
|
zwei unlesbare Haelften. Gebraucht wird EINE Form, in der beide
|
||||||
|
vorkommen.
|
||||||
|
|
||||||
|
DIE LOESUNG: Der Husky steht im Zentrum, die Chili bildet den BOGEN
|
||||||
|
um ihn -- wie der Ring eines Siegels, nur nicht geschlossen. Das ist
|
||||||
|
dieselbe Anordnung wie beim Spicy-Media-Original (Zeichen im Kreis)
|
||||||
|
und laesst dem Husky die Mitte, wo eine Silhouette bei kleiner
|
||||||
|
Groesse noch traegt.
|
||||||
|
|
||||||
|
DER HINTERGRUND traegt beide Farben: ein diagonaler Verlauf von
|
||||||
|
Chili-Rot (unten links) nach Dogi-Blau (oben rechts), abgedunkelt,
|
||||||
|
damit der silberne Husky darauf steht statt darin zu verschwinden.
|
||||||
|
Wo sich die beiden treffen, liegt die Mitte -- genauso wie im
|
||||||
|
Schriftzug "Spicy & Dogi" in der Kopfleiste.
|
||||||
|
|
||||||
|
MASKABLE: Android schneidet bis zu 20 % ringsum weg. Fuer diese
|
||||||
|
Fassungen sitzt alles enger zusammen und der Bogen wird kuerzer --
|
||||||
|
sonst waere von der Chili nach dem Beschnitt nur ein Reststueck da.
|
||||||
|
|
||||||
|
Aufrufen mit: node tools/workspace-symbol.mjs
|
||||||
|
=================================================================== */
|
||||||
|
|
||||||
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
|
||||||
|
import { join, dirname } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const WURZEL = join(dirname(fileURLToPath(import.meta.url)), "..");
|
||||||
|
const HUSKY = join(WURZEL, "workspace", "assets", "img", "marke-husky.webp");
|
||||||
|
const CHILI = join(WURZEL, "workspace", "assets", "img", "marke-spicy.webp");
|
||||||
|
const ZIEL = join(WURZEL, "assets", "img", "app-symbole");
|
||||||
|
|
||||||
|
for (const q of [HUSKY, CHILI]) {
|
||||||
|
if (!existsSync(q)) { console.error(`Fehlt: ${q}`); process.exit(1); }
|
||||||
|
}
|
||||||
|
const alsDaten = (p) => "data:image/webp;base64," + readFileSync(p).toString("base64");
|
||||||
|
|
||||||
|
/* Die Groessen, die Manifest und HTML tatsaechlich anfordern. */
|
||||||
|
const GROESSEN = [
|
||||||
|
{ n: 512, endung: "512" },
|
||||||
|
{ n: 192, endung: "192" },
|
||||||
|
{ n: 512, endung: "512-maskable", maskable: true },
|
||||||
|
{ n: 192, endung: "192-maskable", maskable: true },
|
||||||
|
{ n: 180, endung: "180" },
|
||||||
|
{ n: 32, endung: "32" },
|
||||||
|
];
|
||||||
|
|
||||||
|
function html(n, maskable, husky, chili) {
|
||||||
|
/* Bei einem maskable-Symbol darf nur der innere Kreis mit 80 %
|
||||||
|
Durchmesser als sicher gelten. Alles Wichtige sitzt deshalb enger. */
|
||||||
|
const platz = maskable ? 0.62 : 0.80;
|
||||||
|
const huskyGr = Math.round(n * platz * 0.72);
|
||||||
|
const ringGr = Math.round(n * platz);
|
||||||
|
/* Unter 64 px faellt der Chili-Bogen weg: Er waere dort ein
|
||||||
|
verwaschener Fleck und wuerde die Husky-Silhouette anfressen.
|
||||||
|
Ein Symbol, das klein noch erkennbar ist, ist mehr wert als eins,
|
||||||
|
das alle Bestandteile zeigt und dabei zu Matsch wird. */
|
||||||
|
const mitChili = n >= 64;
|
||||||
|
return `<!doctype html><html><head><meta charset="utf-8"><style>
|
||||||
|
html,body{margin:0;width:${n}px;height:${n}px;overflow:hidden}
|
||||||
|
.feld{position:relative;width:${n}px;height:${n}px;
|
||||||
|
/* Der Grund: beide Marken als Verlauf, unten links Rot, oben
|
||||||
|
rechts Blau -- sie treffen sich in der Mitte. */
|
||||||
|
background:
|
||||||
|
radial-gradient(120% 120% at 22% 88%, #7d2018 0%, transparent 58%),
|
||||||
|
radial-gradient(120% 120% at 80% 16%, #1d4e73 0%, transparent 60%),
|
||||||
|
linear-gradient(38deg, #14060a 0%, #0b1320 52%, #0d1c2c 100%);
|
||||||
|
${maskable ? "" : `border-radius:${Math.round(n * 0.22)}px;`}
|
||||||
|
display:grid;place-items:center}
|
||||||
|
/* Ein feiner Lichtrand oben -- dieselbe Sprache wie die Kacheln:
|
||||||
|
Licht kommt von oben, die Kante faengt es. */
|
||||||
|
.feld::before{content:"";position:absolute;inset:0;
|
||||||
|
${maskable ? "" : `border-radius:${Math.round(n * 0.22)}px;`}
|
||||||
|
box-shadow:inset 0 ${Math.max(1, n * 0.004)}px 0 rgba(255,255,255,.18),
|
||||||
|
inset 0 0 ${n * 0.16}px rgba(0,0,0,.55)}
|
||||||
|
.ring{position:absolute;width:${ringGr}px;height:${ringGr}px;
|
||||||
|
display:grid;place-items:center}
|
||||||
|
/* DIE CHILI ALS BOGEN. Sie wird gedreht und sitzt unten -- so
|
||||||
|
laeuft sie um den Husky herum, statt ihn zu ueberdecken. */
|
||||||
|
.chili{position:absolute;width:${Math.round(ringGr * 0.92)}px;
|
||||||
|
height:${Math.round(ringGr * 0.92)}px;
|
||||||
|
background:url("${chili}") center/contain no-repeat;
|
||||||
|
transform:rotate(-16deg) translateY(${Math.round(n * 0.225)}px) scale(1.04);
|
||||||
|
filter:drop-shadow(0 ${n * 0.008}px ${n * 0.02}px rgba(0,0,0,.75))
|
||||||
|
drop-shadow(0 0 ${n * 0.03}px rgba(255,90,70,.45))}
|
||||||
|
/* DER HUSKY als Maske, gefuellt mit Silber -- das Original ist
|
||||||
|
schwarzweiss und waere auf dunklem Grund ein dunkler Fleck. */
|
||||||
|
.husky{position:relative;width:${huskyGr}px;height:${huskyGr}px;
|
||||||
|
background:linear-gradient(168deg,#ffffff 4%,#dae4ef 34%,#9fb0c4 66%,#5d7288 100%);
|
||||||
|
-webkit-mask:url("${husky}") center/contain no-repeat;
|
||||||
|
mask:url("${husky}") center/contain no-repeat;
|
||||||
|
filter:drop-shadow(0 ${n * 0.01}px ${n * 0.022}px rgba(0,0,0,.8))
|
||||||
|
drop-shadow(0 0 ${n * 0.028}px rgba(140,200,245,.5))}
|
||||||
|
</style></head><body><div class="feld"><div class="ring">
|
||||||
|
${mitChili ? '<div class="chili"></div>' : ""}
|
||||||
|
<div class="husky"></div>
|
||||||
|
</div></div></body></html>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { chromium } = await import(
|
||||||
|
"file:///C:/Users/qciga/Documents/Obelix/Analyse/node_modules/playwright/index.mjs");
|
||||||
|
const browser = await chromium.launch();
|
||||||
|
const seite = await (await browser.newContext({ deviceScaleFactor: 1 })).newPage();
|
||||||
|
if (!existsSync(ZIEL)) mkdirSync(ZIEL, { recursive: true });
|
||||||
|
|
||||||
|
const husky = alsDaten(HUSKY), chili = alsDaten(CHILI);
|
||||||
|
let gebaut = 0;
|
||||||
|
const schwach = [];
|
||||||
|
|
||||||
|
for (const g of GROESSEN) {
|
||||||
|
await seite.setViewportSize({ width: g.n, height: g.n });
|
||||||
|
await seite.setContent(html(g.n, !!g.maskable, husky, chili), { waitUntil: "networkidle" });
|
||||||
|
const bild = await seite.screenshot({ omitBackground: false });
|
||||||
|
const datei = join(ZIEL, `workspace-${g.endung}.png`);
|
||||||
|
writeFileSync(datei, bild);
|
||||||
|
|
||||||
|
/* NACHSEHEN, OB WIRKLICH ETWAS DRAUFSTEHT. Ein Symbol, das aus einem
|
||||||
|
Fehler heraus einfarbig ist, hat dieselbe Dateigroesse wie eines
|
||||||
|
mit Motiv -- die Bytezahl beweist gar nichts. Gemessen wird die
|
||||||
|
Streuung der Helligkeit: Ein leeres Feld hat keine. */
|
||||||
|
const streuung = await seite.evaluate(async (b64) => {
|
||||||
|
const bild = new Image(); bild.src = "data:image/png;base64," + b64;
|
||||||
|
await bild.decode();
|
||||||
|
const c = document.createElement("canvas");
|
||||||
|
c.width = bild.width; c.height = bild.height;
|
||||||
|
const g2 = c.getContext("2d"); g2.drawImage(bild, 0, 0);
|
||||||
|
const d = g2.getImageData(0, 0, c.width, c.height).data;
|
||||||
|
let s = 0, s2 = 0, n = 0;
|
||||||
|
for (let i = 0; i < d.length; i += 4) {
|
||||||
|
const h = 0.2126 * d[i] + 0.7152 * d[i + 1] + 0.0722 * d[i + 2];
|
||||||
|
s += h; s2 += h * h; n++;
|
||||||
|
}
|
||||||
|
return Math.sqrt(s2 / n - (s / n) ** 2);
|
||||||
|
}, bild.toString("base64"));
|
||||||
|
|
||||||
|
console.log(` workspace-${g.endung}.png`.padEnd(34)
|
||||||
|
+ `${(bild.length / 1024).toFixed(1)} KB · Streuung ${streuung.toFixed(1)}`);
|
||||||
|
if (streuung < 12) schwach.push(`${g.endung} (${streuung.toFixed(1)})`);
|
||||||
|
gebaut++;
|
||||||
|
}
|
||||||
|
await browser.close();
|
||||||
|
|
||||||
|
/* Die Zahlen gehoeren in die Bedingung, nicht nur in den Bericht. */
|
||||||
|
if (gebaut !== GROESSEN.length) {
|
||||||
|
console.error(`\nFEHLER: ${gebaut} von ${GROESSEN.length} erzeugt.`); process.exit(1);
|
||||||
|
}
|
||||||
|
if (schwach.length) {
|
||||||
|
console.error(`\nFEHLER: kaum Zeichnung in ${schwach.join(", ")} -- da steht vermutlich`
|
||||||
|
+ ` nichts drauf.`); process.exit(1);
|
||||||
|
}
|
||||||
|
console.log(`\n${gebaut} Symbole erzeugt, alle mit erkennbarer Zeichnung.`);
|
||||||