Theme modern: Titel-Slide und Slide 3 neu gedacht, Badges raus

Die Badges ueber den Ueberschriften sind wieder aus. Auf einer Website
ordnet so eine Pille die Sektion ein, auf einer Slide nimmt sie Platz weg,
ohne etwas zu sagen, was die Ueberschrift nicht schon sagt.

Slide 1 war bisher nur entkritzelt: derselbe Aufbau, nur ohne Zeichnungen.
Jetzt ist das Foto selbst chamfert -- die Markenform, und ein dunkles Bild
auf hellem Grund braucht keinen Rahmen. Darauf zwei Auszeichnungen, die
Inhalt tragen statt zu verzieren: ein Chip oben rechts mit "Vierte
Generation" und eine schwebende weisse Infokarte unten links mit Wabe,
Namen und Rolle. Das ist das Muster aus Autarc und Phase0. Der
Helm-Umschalter entfaellt hier.

Slide 3 ist kein Bild fuer Chaos mehr, sondern der Vorgang selbst: eine
Migration, die nicht durchlaeuft. Fortschritt bei 34 Prozent, drei
Statuszeilen (Stammdaten uebertragen, Auftraege 1.284 Konflikte,
Buchhaltung abgebrochen) und als Fusszeile Noahs eigenes Argument, die
geschaetzte Dauer von einem halben Jahr. Das ist die Sprache unserer
eigenen Oberflaeche; im Pitch-Screen 1 stehen fehlgeschlagene Laeufe
genauso. Die Vorfassungen waren Metaphern -- gerissene Leine, Sackkarre,
Knaeuel -- und ein Betrieb, der ueber einen Wechsel nachdenkt, versteht
eine abgebrochene Uebernahme ohne Sinnbild.

Der Fehlerton kommt aus den Tokens der Website (accent-orange #E07B54),
nicht aus eigener Erfindung.

Slide 3 ist NICHT im Bild geprueft. Die Maschine hat nur noch rund 0,3 GB
freien Speicher, headless Chrome bekommt die Assets nicht mehr als
Data-URIs eingelesen und bleibt bei "Lade Screens ..." stehen -- bei
post2.html genauso, die seit dem letzten Commit unveraendert ist. Das
Skript selbst ist mit node --check geprueft.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
dejanandClaude Opus 5 committed 2026-08-13 19:12:14 +02:00
1 parent 9b405ce931
commit 43a4a394f2
2 files changed
+122 -123

No files matched your search

+118 -122
View File
@@ -407,9 +407,17 @@
left: -24.19%; width: 153.23%;
top: -23.23%; height: 141.29%;
}
/* Kein gezeichneter Rahmen mehr: das Foto ist selbst chamfert, das ist die
Markenform, und ein dunkles Bild auf hellem Grund braucht keine
Umrandung. Die Zeichenebene bleibt im Markup, zeichnet aber nichts. */
.vis svg.karte-skizze { display: none; }
.karte {
position: relative; aspect-ratio: 4/5; overflow: hidden;
border-radius: 8px; background: #0f1a2e; isolation: isolate;
background: #0f1a2e; isolation: isolate;
clip-path: polygon(
16px 0, calc(100% - 16px) 0, 100% 16px, 100% calc(100% - 16px),
calc(100% - 16px) 100%, 16px 100%, 0 calc(100% - 16px), 0 16px
);
}
.karte-grund {
position: absolute; inset: 0; z-index: 1; overflow: hidden;
@@ -426,13 +434,39 @@
width: 100%; height: 100%; object-fit: cover;
filter: saturate(1) contrast(1.01);
}
/* Die Infokarte schwebt ueber dem Foto, statt als flaches Schild darin zu
kleben. Weiss auf dunklem Bild, chamfert und ohne Rand: clip-path wuerde
ihn beschneiden (lib/chamfer.ts der Website). */
.karte-name {
position: absolute; left: 6%; bottom: 5.7%; z-index: 5;
display: flex; align-items: baseline; gap: 13px;
padding: 13px 17px; background: var(--accent-yellow); color: #101010;
position: absolute; left: 5.4%; bottom: 5.4%; z-index: 5;
display: flex; align-items: center; gap: 18px;
padding: 20px 28px 20px 20px; background: #FFFFFF;
clip-path: polygon(
14px 0, calc(100% - 14px) 0, 100% 14px, 100% calc(100% - 14px),
calc(100% - 14px) 100%, 14px 100%, 0 calc(100% - 14px), 0 14px
);
}
.karte-name .marke {
width: 52px; height: 46px; flex: none; background: var(--accent-yellow);
clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
}
.karte-name .zeilen { display: flex; flex-direction: column; gap: 2px; }
.karte-name b { font-size: 30px; font-weight: 800; letter-spacing: -.025em;
line-height: 1.1; color: #1A1A1A; }
.karte-name small { font-size: 20px; font-weight: 600; color: #555555; }
/* Der Chip oben rechts traegt die Einordnung, die sonst im Fliesstext
stuende. Inhalt, keine Verzierung. */
.karte-chip {
position: absolute; right: 5.4%; top: 5.4%; z-index: 5;
padding: 10px 18px; background: var(--accent-yellow);
color: var(--accent-yellow-dark);
font-size: 21px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
clip-path: polygon(
10px 0, calc(100% - 10px) 0, 100% 10px, 100% calc(100% - 10px),
calc(100% - 10px) 100%, 10px 100%, 0 calc(100% - 10px), 0 10px
);
}
.karte-name span { font-size: 27px; font-weight: 700; letter-spacing: -.03em; line-height: 1.15; }
.karte-name small { font-size: 12px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; }
/* ─── Bearbeitung im Canvas ───────────────────────────────────────────────
Verschieben läuft über --ex/--ey, also über transform statt über den
@@ -502,8 +536,11 @@
/* Das Chamfer-Badge der Website: gelb aufgehellte Flaeche, dunkler Text,
Versalien und weite Sperrung. Es steht dort ueber jeder Sektion. Im Theme
notebook ist es ausgeblendet, hier traegt es die Einordnung. */
/* Ausgeblendet. Das Badge stand testweise ueber jeder Slide, wie auf der
Website ueber jeder Sektion. Auf einer Slide nimmt es aber Platz weg,
ohne etwas zu sagen, was die Ueberschrift nicht schon sagt. */
.badge {
display: inline-block; margin-bottom: 28px;
display: none; margin-bottom: 28px;
font-size: 24px; font-weight: 600; letter-spacing: 0.16em;
text-transform: uppercase;
padding: 11px 22px;
@@ -1148,8 +1185,7 @@
const VORLAGEN = [
{
key: "titel", type: "feature",
layouts: [{ id: "ecke", label: "Helm auf der Ecke" },
{ id: "kopf", label: "Helm auf dem Kopf" }],
layouts: [{ id: "standard", label: "Standard" }],
eyebrow: "Die Geschichte",
head: 'Die Geschichte fängt<br><span class="a">auf der Baustelle an.</span>',
body: "Noah Geerkens, SHK-Betrieb in vierter Generation.",
@@ -1169,7 +1205,7 @@
eyebrow: "Der Wechsel",
head: 'Und wechseln?<br><span class="a">Kannst du vergessen.</span>',
body: "Da hängen Jahre an Stammdaten, Aufträgen und Buchhaltung drin. Ein Wechsel führt ins Chaos.",
vis: "ersetzen", visW: 896, visLeft: 92, visBottom: 190,
vis: "ersetzen", visW: 896, visLeft: 92, visBottom: 240,
},
{
key: "mehr", type: "feature",
@@ -1319,6 +1355,7 @@
let TINTE = "#1A1A1A", TEXT2 = "#555555", TEXT3 = "#888888",
GELB = "#F1B729", GELB_DUNKEL = "#3E2C0A", GELB_HELL = "#FFE082",
TEAL = "#0D6E6E", TEAL_HELL = "#E8F4F4",
ROT = "#E07B54", ROT_HELL = "#FBEAE4", // accent-orange der Website
LINIE = "#E5E5E5", KARTE = "#F6F8FA";
function farbenNachziehen() {
const d = variant === "dunkel";
@@ -1327,6 +1364,8 @@
TEXT3 = d ? "#8C97A8" : "#888888";
TEAL = d ? "#4FBEBE" : "#0D6E6E";
TEAL_HELL = d ? "rgba(79,190,190,.16)" : "#E8F4F4";
ROT = "#E07B54";
ROT_HELL = d ? "rgba(224,123,84,.18)" : "#FBEAE4";
LINIE = d ? "rgba(255,255,255,.14)" : "#E5E5E5";
KARTE = d ? "#1A2740" : "#F6F8FA";
}
@@ -1899,127 +1938,82 @@
Was jede von ihnen nicht hatte: eine Richtung. Drei Stationen von links
nach rechts liest man in einer Sekunde, drei Teile nebeneinander nicht. */
/* ─── Slide 3 · Der Wechsel ─────────────────────────────────────────────
Kein Bild fuer Chaos, sondern der Vorgang selbst: eine Migration, die
nicht durchlaeuft. Fortschrittsbalken, drei Statuszeilen, geschaetzte
Dauer -- die Sprache, die unsere eigene Oberflaeche spricht (siehe die
Lauf-Liste im Pitch-Screen 1, wo fehlgeschlagene Laeufe genauso stehen).
Die Vorfassungen waren Metaphern: gerissene Leine, Sackkarre, Knaeuel.
Ein Betrieb, der ueber einen Wechsel nachdenkt, versteht eine
abgebrochene Uebernahme sofort und braucht dafuer kein Sinnbild. */
function visWechseln() {
keim(20260815);
/* Die Flaeche ist niedriger als bei den anderen Slides: drei Formen
nebeneinander duerfen in 896 Breite hoechstens rund 200 Radius haben,
und eine 730 hohe Box waere dann zu drei Vierteln leer. Sie sitzt
stattdessen mittig in der freien Hoehe unter dem Text. */
const W = 896, H = 520, MY = 258;
const ZX = 200, RX = 190, RY = 200;
const zeilen = ["Stammdaten", "Aufträge", "Buchhaltung"];
const W = 896, H = 500, P = 48;
const zeilen = [
{ t: "Stammdaten", s: "übertragen", art: "ok" },
{ t: "Aufträge", s: "1.284 Konflikte", art: "warn" },
{ t: "Buchhaltung", s: "abgebrochen", art: "fehler" },
];
const ton = { ok: [TEAL_HELL, TEAL], warn: [GELB_HELL, GELB_DUNKEL], fehler: [ROT_HELL, ROT] };
/* Das Wechsel-Symbol: zwei Boegen mit Luecken links und rechts. Ein
geschlossener Ring waere kein Symbol mehr, sondern eine Ellipse. */
function bogen(a1, a2) {
const n = 18, p = [];
for (let i = 0; i <= n; i++) {
const a = (a1 + (a2 - a1) * i / n) * Math.PI / 180;
p.push([ZX + Math.cos(a) * RX + zit(1.8), MY + Math.sin(a) * RY + zit(1.8)]);
let raus = chamferFlaeche(0, 0, W, H, KARTE);
raus += '<text x="' + P + '" y="66" font-family="Manrope, sans-serif" font-size="20" ' +
'font-weight="700" letter-spacing="0.16em" fill="' + TEXT3 + '">MIGRATION</text>';
raus += '<text x="' + P + '" y="118" font-family="Manrope, sans-serif" font-size="38" ' +
'font-weight="800" letter-spacing="-0.025em" fill="' + TINTE + '">Alles mitnehmen</text>';
// Fortschritt: er bleibt stehen, das ist die Aussage.
const BY = 176, BW = W - 2 * P;
raus += '<text x="' + P + '" y="' + (BY - 14) + '" font-family="Manrope, sans-serif" ' +
'font-size="24" font-weight="600" fill="' + TEXT2 + '">Fortschritt</text>';
raus += '<text x="' + (W - P) + '" y="' + (BY - 14) + '" text-anchor="end" ' +
'font-family="Manrope, sans-serif" font-size="24" font-weight="800" fill="' + TINTE +
'">34 %</text>';
raus += '<rect x="' + P + '" y="' + BY + '" width="' + BW + '" height="12" rx="6" fill="' +
LINIE + '"/>';
raus += '<rect x="' + P + '" y="' + BY + '" width="' + n1(BW * 0.34) + '" height="12" rx="6" fill="' +
GELB + '"/>';
zeilen.forEach((z, i) => {
const y = 262 + i * 66, f = ton[z.art];
raus += '<circle cx="' + (P + 17) + '" cy="' + (y - 9) + '" r="17" fill="' + f[0] + '"/>';
const cx = P + 17, cy = y - 9;
if (z.art === "ok") {
raus += '<path d="M' + (cx - 7) + ',' + cy + 'l5,5l9,-10" fill="none" stroke="' + f[1] +
'" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>';
} else if (z.art === "warn") {
raus += '<path d="M' + cx + ',' + (cy - 8) + 'v9" stroke="' + f[1] +
'" stroke-width="3.2" stroke-linecap="round"/>' +
'<circle cx="' + cx + '" cy="' + (cy + 7) + '" r="2" fill="' + f[1] + '"/>';
} else {
raus += '<path d="M' + (cx - 6) + ',' + (cy - 6) + 'l12,12M' + (cx + 6) + ',' + (cy - 6) +
'l-12,12" stroke="' + f[1] + '" stroke-width="3.2" stroke-linecap="round"/>';
}
raus += '<text x="' + (P + 52) + '" y="' + y + '" font-family="Manrope, sans-serif" ' +
'font-size="30" font-weight="700" letter-spacing="-0.015em" fill="' + TINTE + '">' +
z.t + '</text>';
raus += '<text x="' + (W - P) + '" y="' + y + '" text-anchor="end" ' +
'font-family="Manrope, sans-serif" font-size="26" font-weight="600" fill="' +
(z.art === "fehler" ? ROT : TEXT2) + '">' + z.s + '</text>';
if (i < zeilen.length - 1) {
raus += '<rect x="' + P + '" y="' + (y + 24) + '" width="' + BW + '" height="1" fill="' +
LINIE + '"/>';
}
return p;
}
function mitSpitze(p, laenge) {
const e = p[p.length - 1], v = p[p.length - 2];
const w = Math.atan2(e[1] - v[1], e[0] - v[0]);
let d = glatt(p, false);
[-0.44, 0.44].forEach(o => {
d += strich(e[0], e[1], e[0] - Math.cos(w + o) * laenge,
e[1] - Math.sin(w + o) * laenge, { j: .9, b: .9 });
});
return d;
}
let raus = zug(mitSpitze(bogen(204, 336), 30) +
mitSpitze(bogen(24, 156), 30), { w: 7 });
zeilen.forEach((t, i) => {
raus += '<text x="' + ZX + '" y="' + (MY - 34 + i * 40) + '" text-anchor="middle" ' +
'font-family="Manrope, sans-serif" font-size="30" font-weight="700" ' +
'letter-spacing="-0.02em" fill="' + TINTE + '">' + t + '</text>';
});
/* Der Pfeil dazwischen, gebaut wie die anderen im Beitrag: Umriss
gezeichnet, innen mit Schraegstrichen ausgemalt. */
const px1 = 420, pkopf = 500, pspitze = 548;
const pHalb = x => x <= pkopf ? 19 : Math.max(2, 36 * (1 - (x - pkopf) / (pspitze - pkopf)));
raus += flaeche([[px1, MY - 19], [pkopf, MY - 19], [pkopf, MY - 36],
[pspitze, MY], [pkopf, MY + 36], [pkopf, MY + 19],
[px1, MY + 19]], TINTE);
/* Das Chaos: eine Bahn durch lauter zufaellige Punkte, weich gezogen. Sie
kreuzt sich dadurch staendig selbst. Zwei Durchgaenge, damit es dicht
wird, dazu ein paar lose Enden nach aussen -- ein Knaeuel ohne Enden
sieht aus wie eine Wolke. */
function knaeuel(cx, cy, rx, ry, n) {
const p = [];
for (let i = 0; i < n; i++) {
const a = rnd() * 6.283, r = 0.18 + rnd() * 0.82;
p.push([cx + Math.cos(a) * rx * r, cy + Math.sin(a) * ry * r]);
}
return glatt(p, false);
}
const CX = 726, CRX = 162, CRY = 196;
raus += zug(knaeuel(CX, MY, CRX, CRY, 26), { w: 3.4 });
raus += zug(knaeuel(CX, MY, CRX * 0.78, CRY * 0.78, 20), { w: 2.8, op: .85 });
let enden = "";
[[-0.7, 1], [0.4, 1], [2.3, 1], [3.6, 1], [4.9, 1]].forEach(v => {
const a = v[0];
enden += glatt([[CX + Math.cos(a) * CRX * 0.9, MY + Math.sin(a) * CRY * 0.9],
[CX + Math.cos(a) * CRX * 1.12 + zit(10),
MY + Math.sin(a) * CRY * 1.12 + zit(10)],
[CX + Math.cos(a) * CRX * 1.3 + zit(14),
MY + Math.sin(a) * CRY * 1.3 + zit(14)]], false);
});
raus += zug(enden, { w: 2.6, op: .8 });
/* Noahs eigenes Argument als Fusszeile: kein Chef faehrt seinen Betrieb
ein halbes Jahr an die Wand. */
raus += '<text x="' + P + '" y="' + (H - 44) + '" font-family="Manrope, sans-serif" ' +
'font-size="24" font-weight="600" fill="' + TEXT3 + '">Geschätzte Dauer</text>';
raus += '<text x="' + (W - P) + '" y="' + (H - 44) + '" text-anchor="end" ' +
'font-family="Manrope, sans-serif" font-size="24" font-weight="800" fill="' + TINTE +
'">ein halbes Jahr</text>';
return '<svg viewBox="0 0 ' + W + ' ' + H + '" width="' + W + '" height="' + H +
'" xmlns="http://www.w3.org/2000/svg">' + raus + '</svg>';
}
/* ─── Formen fuer die zugespitzte Fassung ───────────────────────────────
Rueckmeldung aus dem Team: als Handwerker sieht man zu viele Dinge, die
die eigene Handwerkersoftware schon kann. Projektmanagement, Chat und
Mitarbeiter-Verwaltung sind genau das. Diese Fassung zeigt stattdessen,
was das Branchenprogramm nicht hat: Workflow-Engine, CRM, Vertrieb,
Marketing, Automatisierung, KI.
Jede Form nimmt einen Massstab entgegen, damit dieselbe Zeichnung als
kleines Listenzeichen und als grosser Satellit taugt. */
function formWorkflow(cx, cy, s) {
const r = 7 * s, dx = 20 * s, dy = 14 * s;
return kringel(cx - dx, cy, r) + kringel(cx + dx, cy - dy, r) + kringel(cx + dx, cy + dy, r) +
strich(cx - dx + r, cy - r * 0.3, cx + dx - r, cy - dy + r * 0.5) +
strich(cx - dx + r, cy + r * 0.3, cx + dx - r, cy + dy - r * 0.5);
}
function formTrichter(cx, cy, s) {
const b = 20 * s, h = 15 * s;
return "M" + n1(cx - b) + "," + n1(cy - h) + "H" + n1(cx + b) +
"L" + n1(cx + b * 0.26) + "," + n1(cy + h * 0.2) +
"V" + n1(cy + h) + "L" + n1(cx - b * 0.26) + "," + n1(cy + h * 0.55) +
"V" + n1(cy + h * 0.2) + "Z";
}
function formMegafon(cx, cy, s) {
const b = 18 * s, h = 15 * s;
return "M" + n1(cx - b) + "," + n1(cy - h * 0.34) +
"L" + n1(cx + b * 0.28) + "," + n1(cy - h) +
"V" + n1(cy + h) + "L" + n1(cx - b) + "," + n1(cy + h * 0.34) + "Z" +
strich(cx + b * 0.56, cy - h * 0.46, cx + b * 0.94, cy - h * 0.72) +
strich(cx + b * 0.62, cy, cx + b * 1.02, cy) +
strich(cx + b * 0.56, cy + h * 0.46, cx + b * 0.94, cy + h * 0.72);
}
function ikonWorkflow(cx, cy) { return zug(formWorkflow(cx, cy, 2.0), { w: 3 }); }
ikonWorkflow.rad = 56; ikonWorkflow.unten = 84;
function ikonTrichter(cx, cy) { return zug(formTrichter(cx, cy, 2.4), { w: 3 }); }
ikonTrichter.rad = 56; ikonTrichter.unten = 86;
function ikonMegafon(cx, cy) { return zug(formMegafon(cx, cy, 2.4), { w: 3 }); }
ikonMegafon.rad = 56; ikonMegafon.unten = 86;
const glyWorkflow = (cx, cy) => formWorkflow(cx, cy, 0.95);
const glyTrichter = (cx, cy) => formTrichter(cx, cy, 1.05);
const glyMegafon = (cx, cy) => formMegafon(cx, cy, 1.05);
/* ─── Slide 4: wir wollten mehr ──────────────────────────────────────────
Die alte Fassung zeigte vier Kaesten mit "fehlt". Das ist der Mangel, die
Slide handelt aber vom Wunsch. Also ein Blatt mit einer Liste.
@@ -2314,7 +2308,9 @@
'<span class="karte-wash"></span></div>' +
'<img class="karte-person" alt="Noah Geerkens" src="' +
assets["./assets/team/noah-person.webp"] + '">' +
'<div class="karte-name"><span>Noah</span><small>Gründer</small></div>' +
'<div class="karte-chip">Vierte Generation</div>' +
'<div class="karte-name"><span class="marke"></span><span class="zeilen">' +
'<b>Noah Geerkens</b><small>Gründer</small></span></div>' +
'</div></div>',
schiene: () => visProzesse(),
+4 -1
View File
@@ -108,7 +108,10 @@
"dx": 0,
"dy": 3
},
"vis": {}
"vis": {
"dx": -17,
"dy": 3
}
},
{
"body": {