Files
posts/_rahmen.html
T
dejanandClaude Opus 5 c26efa3f0c Varianten-Blatt fuer die Titel-Slide mit aufgenommen
Lag seit dem 12.08. unversioniert im Arbeitsverzeichnis: eine Seite, die
neun Rahmen-Varianten einer Titel-Slide nebeneinanderstellt. Nichts im
Repo verweist darauf, sie laeuft fuer sich.

Kommt als eigener Commit, damit sie sich ohne den Beitrag zurueckziehen
laesst, falls sie nur ein Zwischenstand war.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 23:00:15 +02:00

976 lines
53 KiB
HTML

<!doctype html>
<meta charset="utf-8"><title>Varianten Titel-Slide</title>
<link rel="stylesheet" href="./assets/fonts/manrope.css">
<style>
*{box-sizing:border-box;margin:0;padding:0}
body{background:#fff;font-family:'Manrope',sans-serif;padding:44px 40px 50px}
h1{font-size:30px;font-weight:800;letter-spacing:-.025em;margin-bottom:6px}
h1+.hin{margin-bottom:32px}
.hin{font-size:14px;color:#666;line-height:1.45;max-width:920px}
hr{border:0;border-top:1px solid #E2E6EA;margin:50px 0 40px}
.gitter{display:grid;grid-template-columns:repeat(3,1fr);gap:36px 26px}
figure{display:flex;flex-direction:column;gap:12px}
.buehne{height:452px;position:relative}
.karte-halter{position:absolute;left:20px;top:70px;width:620px;
transform:scale(.46);transform-origin:top left}
.karte-halter.leer{height:775px}
svg.karte-skizze{position:absolute;z-index:6;left:-7.42%;width:114.84%;top:-19.35%;height:125.29%;
overflow:visible}
.karte{position:relative;aspect-ratio:4/5;overflow:hidden;border-radius:8px;background:#0f1a2e;isolation:isolate}
.karte-grund{position:absolute;inset:0;z-index:1;overflow:hidden;border-radius:8px;background:#2b2d2a;
filter:grayscale(.04) saturate(.74) brightness(.73)}
.karte-grund img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.karte-wash{position:absolute;inset:0;background:linear-gradient(180deg,rgba(15,26,46,.01),rgba(15,26,46,.12))}
.karte-person{position:absolute;inset:0;z-index:4;width:100%;height:100%;object-fit:cover;
filter:saturate(1) contrast(1.01)}
.karte-name{position:absolute;left:6%;bottom:5.7%;z-index:5;display:flex;align-items:baseline;gap:13px;
padding:13px 17px;background:#F1B729;color:#101010}
.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}
/* Halb hell, halb dunkel: der Helm liegt im Post auf beidem. */
.probe{width:300px;height:250px;background:linear-gradient(90deg,#fff 50%,#14161A 50%);
border:1px solid #E2E6EA}
.probe svg{display:block}
figcaption{display:flex;flex-direction:column;gap:3px}
figcaption b{font-size:15px;font-weight:800;letter-spacing:-.01em;line-height:1.25}
figcaption span{font-size:12.5px;color:#666;line-height:1.35}
</style>
<h1>1 &middot; Rahmen</h1>
<p class="hin">Ohne Foto, damit nur die Zeichnung zu sehen ist. In Originalgroesse gezogen und fuer die
Ansicht auf 46 % verkleinert, damit die Strichstaerken zueinander stimmen. Nummer 7 ist die gewaehlte
Mischung und steckt bereits in post2.html.</p>
<div class="gitter"><figure><div class="buehne"><div class="karte-halter leer"><svg viewBox="0 0 712 971" width="712" height="971" class="karte-skizze" id="r0"></svg></div></div><figcaption><b>1 · Fein</b><span>Zwei Zuege, der zweite als leichter Nachzieher.</span></figcaption></figure><figure><div class="buehne"><div class="karte-halter leer"><svg viewBox="0 0 712 971" width="712" height="971" class="karte-skizze" id="r1"></svg></div></div><figcaption><b>2 · Kraeftig</b><span>Ein einziger fetter Zug, enger am Bild.</span></figcaption></figure><figure><div class="buehne"><div class="karte-halter leer"><svg viewBox="0 0 712 971" width="712" height="971" class="karte-skizze" id="r2"></svg></div></div><figcaption><b>3 · Versetzt</b><span>Zweiter Rahmen nach unten rechts.</span></figcaption></figure><figure><div class="buehne"><div class="karte-halter leer"><svg viewBox="0 0 712 971" width="712" height="971" class="karte-skizze" id="r3"></svg></div></div><figcaption><b>4 · Passepartout</b><span>Duenner Aussenrahmen mit Abstand, fetter Innenrahmen.</span></figcaption></figure><figure><div class="buehne"><div class="karte-halter leer"><svg viewBox="0 0 712 971" width="712" height="971" class="karte-skizze" id="r4"></svg></div></div><figcaption><b>5 · Chamfer</b><span>Die Markenform, von Hand gezogen.</span></figcaption></figure><figure><div class="buehne"><div class="karte-halter leer"><svg viewBox="0 0 712 971" width="712" height="971" class="karte-skizze" id="r5"></svg></div></div><figcaption><b>6 · Schattenkante</b><span>Fetter Rahmen, aussen an zwei Seiten schraffiert.</span></figcaption></figure><figure><div class="buehne"><div class="karte-halter leer"><svg viewBox="0 0 712 971" width="712" height="971" class="karte-skizze" id="r6"></svg></div></div><figcaption><b>7 · Gewaehlt: Chamfer + Versetzt + Schattenkante</b><span>Der versetzte Zug ist die Aussenkante des Schattens, die Schraffur fuellt das Band dazwischen.</span></figcaption></figure></div>
<hr>
<h1>2 &middot; Helme</h1>
<p class="hin">Jeder Helm auf halb hellem, halb dunklem Grund: im Post liegt er auf beidem, deshalb ist
er ganz in Gelb gezogen. Alle in derselben Breite, damit die Entwuerfe vergleichbar sind.</p>
<div class="gitter"><figure><div class="probe"><svg viewBox="0 0 300 250" width="300" height="250" id="k0"></svg></div><figcaption><b>H1 · Einfach</b><span>Kuppel, Krempe, drei Grate. Der Helm, der im Post steckt.</span></figcaption></figure><figure><div class="probe"><svg viewBox="0 0 300 250" width="300" height="250" id="k1"></svg></div><figcaption><b>H2 · Fein</b><span>Mehr Stuetzpunkte, First, Nebenrippen, Krempendicke, Schattierung.</span></figcaption></figure><figure><div class="probe"><svg viewBox="0 0 300 250" width="300" height="250" id="k2"></svg></div><figcaption><b>H3 · Schraffiert</b><span>Gefuellt statt schattiert, dafuer ohne Rippen.</span></figcaption></figure><figure><div class="probe"><svg viewBox="0 0 300 250" width="300" height="250" id="k3"></svg></div><figcaption><b>H4 · Dreiviertel</b><span>Krempe als Ellipse, dadurch raeumlich statt flach.</span></figcaption></figure><figure><div class="probe"><svg viewBox="0 0 300 250" width="300" height="250" id="k4"></svg></div><figcaption><b>H5 · Mit Kinnriemen</b><span>Wie Fein, dazu Riemen und Schnalle.</span></figcaption></figure><figure><div class="probe"><svg viewBox="0 0 300 250" width="300" height="250" id="k5"></svg></div><figcaption><b>H6 · Kontur</b><span>Nur die Silhouette, zwei kraeftige Zuege.</span></figcaption></figure></div>
<hr>
<h1>3 &middot; Fertiges Konzept</h1>
<p class="hin">Rahmen, Foto und Helm 2 zusammen. Nur Lage und Groesse des Helms unterscheiden sich.</p>
<div class="gitter"><figure><div class="buehne"><div class="karte-halter"><svg viewBox="0 0 712 971" width="712" height="971" class="karte-skizze" id="f0"></svg><div class="karte"><div class="karte-grund"><img alt="" src="./assets/team/noah-bg.webp"><span class="karte-wash"></span></div><img class="karte-person" alt="" src="./assets/team/noah-person.webp"><div class="karte-name"><span>Noah</span><small>CEO</small></div></div></div></div><figcaption><b>A · Ueber der Ecke</b><span>Helm 2, ueber der oberen rechten Ecke.</span></figcaption></figure><figure><div class="buehne"><div class="karte-halter"><svg viewBox="0 0 712 971" width="712" height="971" class="karte-skizze" id="f1"></svg><div class="karte"><div class="karte-grund"><img alt="" src="./assets/team/noah-bg.webp"><span class="karte-wash"></span></div><img class="karte-person" alt="" src="./assets/team/noah-person.webp"><div class="karte-name"><span>Noah</span><small>CEO</small></div></div></div></div><figcaption><b>B · Auf dem Kopf, einfach</b><span>Helm 2 auf dem Kopf, kleinere Breite (186).</span></figcaption></figure><figure><div class="buehne"><div class="karte-halter"><svg viewBox="0 0 712 971" width="712" height="971" class="karte-skizze" id="f2"></svg><div class="karte"><div class="karte-grund"><img alt="" src="./assets/team/noah-bg.webp"><span class="karte-wash"></span></div><img class="karte-person" alt="" src="./assets/team/noah-person.webp"><div class="karte-name"><span>Noah</span><small>CEO</small></div></div></div></div><figcaption><b>C · Auf der Ecke</b><span>Helm 2, nach rechts gekippt, Oeffnung ueber der Ecke.</span></figcaption></figure><figure><div class="buehne"><div class="karte-halter"><svg viewBox="0 0 712 971" width="712" height="971" class="karte-skizze" id="f3"></svg><div class="karte"><div class="karte-grund"><img alt="" src="./assets/team/noah-bg.webp"><span class="karte-wash"></span></div><img class="karte-person" alt="" src="./assets/team/noah-person.webp"><div class="karte-name"><span>Noah</span><small>CEO</small></div></div></div></div><figcaption><b>D · Auf dem Kopf, fein</b><span>Helm 2 auf dem Kopf, groessere Breite (222).</span></figcaption></figure></div>
<script>
/* ─── Skizzen-Primitive ─────────────────────────────────────────────────────
Handzeichnung aus gesetztem Zufall. Der Keim ist fest: der Export rendert
bei fehlgeschlagener Pruefung bis zu fuenfmal neu, und jeder Durchgang muss
denselben Strich ergeben. Mit ungesetztem Math.random zittert jedes Bild
anders und die Kontrolle vergleicht gegen etwas, das es nie wieder gibt. */
let _s = 0;
function keim(n) { _s = n >>> 0; }
function rnd() {
_s = (_s + 0x6D2B79F5) >>> 0;
let t = Math.imul(_s ^ (_s >>> 15), 1 | _s);
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
}
const zit = m => (rnd() * 2 - 1) * m;
const n1 = v => Math.round(v * 10) / 10;
/* Ein Strich, leicht gebogen und an den Enden verwackelt. Der Bogen waechst
mit der Laenge: eine kurze Kante zittert, eine lange schwingt. */
function strich(x1, y1, x2, y2, o) {
o = o || {};
const j = o.j == null ? 1.5 : o.j;
const ue = o.ue == null ? 0 : o.ue; // Ueberschuss an den Enden
let dx = x2 - x1, dy = y2 - y1;
const len = Math.hypot(dx, dy) || 1, ux = dx / len, uy = dy / len;
const ax = x1 - ux * rnd() * ue + zit(j), ay = y1 - uy * rnd() * ue + zit(j);
const bx = x2 + ux * rnd() * ue + zit(j), by = y2 + uy * rnd() * ue + zit(j);
dx = bx - ax; dy = by - ay;
const nx = -dy / len, ny = dx / len;
const b = o.b == null ? len * 0.008 + 1 : o.b;
const o1 = zit(b), o2 = zit(b);
return "M" + n1(ax) + "," + n1(ay) + "C" +
n1(ax + dx / 3 + nx * o1) + "," + n1(ay + dy / 3 + ny * o1) + " " +
n1(ax + dx * 2 / 3 + nx * o2) + "," + n1(ay + dy * 2 / 3 + ny * o2) + " " +
n1(bx) + "," + n1(by);
}
/* Punktfolge zu einer weichen Kurve (Catmull-Rom als Bezier). */
function glatt(pts, zu) {
const n = pts.length;
const at = i => pts[zu ? (i + n) % n : Math.max(0, Math.min(n - 1, i))];
let d = "M" + n1(pts[0][0]) + "," + n1(pts[0][1]);
const bis = zu ? n : n - 1;
for (let i = 0; i < bis; i++) {
const p0 = at(i - 1), p1 = at(i), p2 = at(i + 1), p3 = at(i + 2);
d += "C" + n1(p1[0] + (p2[0] - p0[0]) / 6) + "," + n1(p1[1] + (p2[1] - p0[1]) / 6) +
" " + n1(p2[0] - (p3[0] - p1[0]) / 6) + "," + n1(p2[1] - (p3[1] - p1[1]) / 6) +
" " + n1(p2[0]) + "," + n1(p2[1]);
}
return d;
}
/* Kringel statt Kreis: der Zug faengt irgendwo an, laeuft einmal herum und
schiesst ein Stueck ueber den Anfang hinaus. Genau das macht die Hand. */
function kringel(cx, cy, rx, ry, o) {
o = o || {};
ry = ry == null ? rx : ry;
const wack = o.wack == null ? Math.min(rx, ry) * 0.02 + 1 : o.wack;
const a0 = o.a0 == null ? rnd() * 6.283 : o.a0;
const ueber = o.ueber == null ? 0.16 + rnd() * 0.2 : o.ueber;
const schritte = 18, pts = [];
const spanne = 6.283 + ueber;
for (let i = 0; i <= schritte; i++) {
const a = a0 + spanne * (i / schritte);
pts.push([cx + Math.cos(a) * (rx + zit(wack)), cy + Math.sin(a) * (ry + zit(wack))]);
}
return glatt(pts, false);
}
/* Vier einzelne Kanten mit Ueberschuss an den Ecken. Der Ueberschuss ist das
eigentliche Erkennungsmerkmal von Handzeichnung, nicht das Zittern. */
function rechteck(x, y, w, h, o) {
o = o || {};
const ue = o.ue == null ? 3.5 : o.ue;
return [
strich(x, y, x + w, y, { ue: ue }),
strich(x + w, y, x + w, y + h, { ue: ue }),
strich(x + w, y + h, x, y + h, { ue: ue }),
strich(x, y + h, x, y, { ue: ue }),
].join("");
}
/* Der Chamfer als gezeichneter Kasten: acht Kanten statt vier. Das ist die
Markenform aus rules.md Paragraf 3, hier von Hand gezogen. */
function chamfer(x, y, w, h, c, o) {
o = o || {};
const ue = o.ue == null ? 2.5 : o.ue;
const p = [[x + c, y], [x + w - c, y], [x + w, y + c], [x + w, y + h - c],
[x + w - c, y + h], [x + c, y + h], [x, y + h - c], [x, y + c]];
let d = "";
for (let i = 0; i < 8; i++) {
const a = p[i], b = p[(i + 1) % 8];
d += strich(a[0], a[1], b[0], b[1], { ue: i % 2 ? 1 : ue });
}
return d;
}
/* Schraffur als Schattierung: parallele Striche, an den Enden kuerzer, damit
das Feld nicht als Block steht. */
function schraff(x, y, w, h, abstand, neig) {
neig = neig == null ? 0.55 : neig;
let d = "";
for (let t = -h * neig; t < w; t += abstand) {
const x1 = x + t, x2 = x + t + h * neig;
const a = Math.max(x, Math.min(x + w, x1)), b = Math.max(x, Math.min(x + w, x2));
if (b - a < 3) continue;
const y1 = y + h - (a - x1) / neig, y2 = y + h - (b - x1) / neig;
d += strich(a, Math.min(y + h, Math.max(y, y1)), b, Math.min(y + h, Math.max(y, y2)), { j: .8, b: .8 });
}
return d;
}
/* Bodenschatten: ein paar kurze Striche unter dem Gegenstand. Sie sitzen eng
am Fuss, sonst schwebt der Gegenstand ueber seinem eigenen Schatten. */
function boden(cx, y, w) {
let d = "";
for (let i = 0; i < 4; i++) {
const f = 1 - Math.abs(i - 1.5) * 0.26;
const b = w * f * (0.62 + rnd() * 0.26);
d += strich(cx - b / 2 + zit(3), y + i * 3.6, cx + b / 2 + zit(3), y + i * 3.6 - 4, { j: .9, b: 1.2 });
}
return d;
}
/* ─── Bausteine ────────────────────────────────────────────────────────── */
const TINTE = "#2A2C33", GELB = "#E9A81C";
const zug = (d, o) => {
o = o || {};
return '<path d="' + d + '" fill="none" stroke="' + (o.f || TINTE) +
'" stroke-width="' + (o.w || 3.1) + '" stroke-linecap="round" stroke-linejoin="round"' +
(o.op ? ' stroke-opacity="' + o.op + '"' : '') +
(o.strichel ? ' stroke-dasharray="' + o.strichel + '"' : '') + '/>';
};
const schatten = d => zug(d, { w: 1.9, op: .34 });
/* ─── Die Satelliten ─────────────────────────────────────────────────────
Jedes Ikon meldet zurueck, wie weit es reicht (rad) und wo seine
Beschriftung hingehoert (unten). Sonst haengt der Knoten am kleinen Ikon
zu weit weg und am grossen klebt er drin. */
function ikonKi(cx, cy) {
const zack = (x, y, r) => {
const k = r * 0.28, p = [];
for (let i = 0; i < 8; i++) {
const a = -Math.PI / 2 + i * Math.PI / 4, rr = i % 2 ? k : r;
p.push([x + Math.cos(a) * rr + zit(1.4), y + Math.sin(a) * rr + zit(1.4)]);
}
return glatt(p, true);
};
return zug(zack(cx - 8, cy - 6, 46), { w: 3.4 }) +
zug(zack(cx + 38, cy + 30, 17), { w: 2.7 }) +
zug(zack(cx + 34, cy - 34, 12), { w: 2.5 }) +
schatten(boden(cx, cy + 54, 88));
}
ikonKi.rad = 52; ikonKi.unten = 92;
function ikonChat(cx, cy) {
const blase = (x, y, rx, ry, sx) =>
zug(kringel(x, y, rx, ry, { ueber: .12 })) +
zug(glatt([[x + sx * rx * .42, y + ry * .82], [x + sx * rx * .86, y + ry * 1.6],
[x + sx * rx * .08, y + ry * .98]], false));
return blase(cx + 20, cy - 4, 38, 30, 1) +
blase(cx - 22, cy - 16, 47, 37, -1) +
[-18, 0, 18].map(o => zug(kringel(cx - 22 + o, cy - 16, 4.6), { w: 2.5 })).join("") +
schatten(boden(cx, cy + 52, 100));
}
ikonChat.rad = 58; ikonChat.unten = 90;
function ikonCrm(cx, cy) {
const kopf = (x, y, r, w) => zug(kringel(x, y, r), { w: w }) +
zug(glatt([[x - r * 1.55, y + r * 2.7], [x - r * 1.5, y + r * 1.05],
[x, y + r * .55], [x + r * 1.5, y + r * 1.05], [x + r * 1.55, y + r * 2.7]], false), { w: w });
return kopf(cx - 42, cy - 16, 17, 2.8) + kopf(cx + 42, cy - 16, 17, 2.8) +
kopf(cx, cy + 2, 22, 3.3) +
schatten(boden(cx, cy + 62, 116));
}
ikonCrm.rad = 72; ikonCrm.unten = 92;
function ikonAuto(cx, cy) {
const r = 39, zaehne = 10;
let d = "";
for (let i = 0; i < zaehne; i++) {
const a = i * 6.283 / zaehne, br = 0.22;
const p = [];
[[-br, r], [-br * .8, r + 14], [br * .8, r + 14], [br, r]].forEach(v => {
const aa = a + v[0];
p.push([cx + Math.cos(aa) * v[1] + zit(.9), cy + Math.sin(aa) * v[1] + zit(.9)]);
});
d += glatt(p, false);
}
return zug(kringel(cx, cy, r)) + zug(d, { w: 2.9 }) + zug(kringel(cx, cy, 15), { w: 2.7 }) +
schatten(boden(cx, cy + 60, 96));
}
ikonAuto.rad = 56; ikonAuto.unten = 88;
function ikonBoard(cx, cy) {
const w = 116, h = 88, x = cx - w / 2, y = cy - h / 2;
let d = rechteck(x, y, w, h);
let k = "";
for (let i = 1; i < 3; i++) k += strich(x + w * i / 3, y + 7, x + w * i / 3, y + h - 7, { j: 1, b: 1 });
const karte = (sx, sy, sh) => rechteck(x + sx, y + sy, w / 3 - 16, sh, { ue: 2 });
k += karte(8, 11, 19) + karte(8, 36, 19) + karte(w / 3 + 8, 11, 19) + karte(2 * w / 3 + 8, 11, 31);
return zug(d) + zug(k, { w: 2.4 }) + schatten(boden(cx, cy + h / 2 + 7, 116));
}
ikonBoard.rad = 64; ikonBoard.unten = 84;
function ikonFormular(cx, cy) {
const w = 90, h = 116, x = cx - w / 2, y = cy - h / 2;
let d = rechteck(x, y, w, h);
d += rechteck(x + w / 2 - 19, y - 12, 38, 22, { ue: 2 });
let k = "";
[32, 50, 68].forEach(o => { k += strich(x + 15, y + o, x + w - 34, y + o, { j: 1, b: 1 }); });
k += rechteck(x + 15, y + 80, 23, 23, { ue: 2 });
const hak = [[x + 19, y + 91], [x + 25, y + 98], [x + 35, y + 81]];
return zug(d) + zug(k, { w: 2.4 }) + zug(glatt(hak, false), { w: 3.6, f: GELB }) +
schatten(boden(cx, cy + h / 2 + 7, 92));
}
ikonFormular.rad = 62; ikonFormular.unten = 96;
/* Ein Strich mit Spitze am Ende. Die Spitze sind zwei kurze Zuege, keine
gefuellte Flaeche: gezeichnet wird sie so, gefuellt sieht sie gesetzt aus. */
function pfeil(x1, y1, x2, y2, gr) {
gr = gr == null ? 16 : gr;
const a = Math.atan2(y2 - y1, x2 - x1), oeff = 0.42;
return strich(x1, y1, x2, y2, { j: 1.1 }) +
strich(x2, y2, x2 - Math.cos(a - oeff) * gr, y2 - Math.sin(a - oeff) * gr, { j: .8, b: .8 }) +
strich(x2, y2, x2 - Math.cos(a + oeff) * gr, y2 - Math.sin(a + oeff) * gr, { j: .8, b: .8 });
}
/* Schraffur innerhalb einer Wabe. Eine gezeichnete Flaeche wird nicht
gefuellt, sie wird schraffiert: so bleibt der Raster-Grund sichtbar und
es sieht trotzdem nach "voll" aus wie auf der Website. */
function wabeSchraff(cx, cy, r, abstand) {
const h = r * 0.866;
let d = "";
for (let y = -h + abstand; y < h - abstand * 0.5; y += abstand) {
const halb = r - (r / 2) * (Math.abs(y) / h) - 8;
if (halb < 7) continue;
d += strich(cx - halb, cy + y - 3, cx + halb, cy + y + 3, { j: .9, b: 1 });
}
return d;
}
function ikonBrief(cx, cy, f) {
const w = 46, h = 31, x = cx - w / 2, y = cy - h / 2;
return zug(rechteck(x, y, w, h, { ue: 2.5 }), { w: 2.9, f: f }) +
zug(glatt([[x + 3, y + 4], [cx, y + h * 0.66], [x + w - 3, y + 4]], false),
{ w: 2.7, f: f });
}
function ikonBlaseKlein(cx, cy, f) {
return zug(kringel(cx, cy - 5, 25, 19, { ueber: .1 }), { w: 2.9, f: f }) +
zug(glatt([[cx - 8, cy + 12], [cx - 13, cy + 23], [cx + 3, cy + 13]], false),
{ w: 2.7, f: f }) +
[-9, 0, 9].map(o => zug(kringel(cx + o, cy - 5, 2.8), { w: 2.2, f: f })).join("");
}
function ikonKonfetti(cx, cy, f) {
// Knallbonbon: Tuete unten links, Funken nach oben rechts.
const tuete = glatt([[cx - 28, cy + 24], [cx - 6, cy - 2],
[cx + 10, cy + 19], [cx - 28, cy + 24]], false) +
strich(cx - 20, cy + 15, cx - 2, cy + 19, { j: .9, b: .8 });
let funken = "";
[-1.42, -1.06, -0.68, -0.28].forEach((a, i) => {
const r0 = 16, r1 = 30 + (i % 2) * 7;
funken += strich(cx + 2 + Math.cos(a) * r0, cy + 3 + Math.sin(a) * r0,
cx + 2 + Math.cos(a) * r1, cy + 3 + Math.sin(a) * r1, { j: 1 });
});
let punkte = "";
[[20, -27], [31, -11], [26, -35], [8, -33]].forEach(v => {
punkte += kringel(cx + v[0], cy + v[1], 3.1);
});
return zug(tuete, { w: 2.9, f: f }) + zug(funken, { w: 2.4, f: f }) +
zug(punkte, { w: 2.2, f: f });
}
/* Die Wabe, flat-top, Seitenverhaeltnis 2/Wurzel3 wie in rules.md Paragraf 3.
Bei dieser Form liegen die sechs Ecken auf einem Kreis vom Radius r. Genau
deshalb ist sie hier richtig: jede Speiche setzt an einer Ecke an, nicht
irgendwo auf einer Kante. Gezogen wird sie aus sechs einzelnen Strichen
mit Ueberschuss, nicht als geschlossenes Polygon. */
function wabeEcken(cx, cy, r) {
const p = [];
for (let i = 0; i < 6; i++) {
const a = i * Math.PI / 3;
p.push([cx + Math.cos(a) * r, cy + Math.sin(a) * r]);
}
return p;
}
function wabe(cx, cy, r) {
const p = wabeEcken(cx, cy, r);
let d = "";
for (let i = 0; i < 6; i++) {
const q = p[i], w = p[(i + 1) % 6];
d += strich(q[0], q[1], w[0], w[1], { ue: 5, j: 1.8 });
}
return d;
}
/* ─── Die Mitte: das bestehende System ───────────────────────────────────
Bewusst als Liste gezeichnet, nicht als Kachel-Dashboard: so sieht eine
Warenwirtschaft aus. Und bewusst der schwerste Strich auf der Slide, denn
sie ist das, was bleibt. Das Fenster passt ganz in den Ring, sonst kreuzen
sich Ringbogen und Fensterecke, und weil der Grund durchscheinen soll gibt
es keine Fuellung, die das verdecken koennte. */
function nabe(cx, cy) {
const w = 216, h = 150, x = cx - w / 2, y = cy - h / 2, kopf = 40;
let d = rechteck(x, y, w, h, { ue: 4 });
d += strich(x, y + kopf, x + w, y + kopf, { ue: 3 });
let k = "";
[0, 1, 2].forEach(i => { k += kringel(x + 18 + i * 15, y + kopf / 2, 4.4, 4.4, { ueber: .1 }); });
let z = "";
for (let i = 0; i < 4; i++) {
const yy = y + kopf + 22 + i * 23;
z += strich(x + 17, yy, x + 59, yy, { j: 1, b: 1 });
z += strich(x + 72, yy, x + w - 48, yy, { j: 1, b: 1 });
z += strich(x + w - 38, yy, x + w - 17, yy, { j: 1, b: 1 });
}
return zug(d, { w: 3.6 }) + zug(k, { w: 2.4 }) + zug(z, { w: 2.2, op: .8 }) +
'<text x="' + cx + '" y="' + (y + kopf / 2 + 8) + '" text-anchor="middle" ' +
'font-family="Manrope, sans-serif" font-size="24" font-weight="800" ' +
'letter-spacing="-0.01em" fill="' + TINTE + '">HiveGrid</text>';
}
/* ─── Aufbau ───────────────────────────────────────────────────────────── */
/* ─── Slide 2: nur so gewachsen ──────────────────────────────────────────
Ein Knaeuel aus Kanaelen, durch das sich eine gestrichelte Leitung windet.
Bewusst ohne Aufloesung: das Gegenbild dazu ist Slide 5, und die Pointe
soll nicht zweimal vorkommen.
Die Namen sind allgemein gehalten, keine fremden Produkte. */
function glyBrief(cx, cy) {
const w = 30, h = 21, x = cx - w / 2, y = cy - h / 2;
return rechteck(x, y, w, h, { ue: 1.6 }) +
glatt([[x + 2, y + 3], [cx, y + h * 0.68], [x + w - 2, y + 3]], false);
}
function glyZettel(cx, cy) {
const w = 26, h = 32, x = cx - w / 2, y = cy - h / 2, e = 11;
return glatt([[x, y], [x + w - e, y], [x + w, y + e], [x + w, y + h],
[x, y + h], [x, y]], false) +
glatt([[x + w - e, y], [x + w - e, y + e], [x + w, y + e]], false);
}
function glyTabelle(cx, cy) {
const w = 30, h = 24, x = cx - w / 2, y = cy - h / 2;
let d = rechteck(x, y, w, h, { ue: 1.6 });
d += strich(x, y + h / 3, x + w, y + h / 3, { j: .7, b: .6 });
d += strich(x, y + h * 2 / 3, x + w, y + h * 2 / 3, { j: .7, b: .6 });
d += strich(x + w / 3, y, x + w / 3, y + h, { j: .7, b: .6 });
return d;
}
function glyHandy(cx, cy) {
const w = 20, h = 32, x = cx - w / 2, y = cy - h / 2;
return rechteck(x, y, w, h, { ue: 1.4 }) +
strich(x + 6, y + 4, x + w - 6, y + 4, { j: .6, b: .5 }) +
kringel(cx, y + h - 5, 1.9);
}
function glyOrdner(cx, cy) {
const w = 30, h = 26, x = cx - w / 2, y = cy - h / 2;
return rechteck(x, y + 6, w, h - 6, { ue: 1.4 }) +
glatt([[x + 1, y + 6], [x + 3, y], [x + 13, y], [x + 15, y + 6]], false);
}
/* Die kleinen Kacheln, die im Vorbild lose dazwischen schweben. */
function kachel(cx, cy, art, gr) {
const s = gr || 52, x = cx - s / 2, y = cy - s / 2;
let d = rechteck(x, y, s, s, { ue: 2.5 });
const f = s / 52;
if (art === "blatt") {
d += rechteck(x + 16 * f, y + 13 * f, 20 * f, 26 * f, { ue: 1.4 });
[20, 26, 32].forEach(o => {
d += strich(x + 20 * f, y + o * f, x + 32 * f, y + o * f, { j: .6, b: .5 });
});
} else if (art === "bild") {
d += rechteck(x + 13 * f, y + 15 * f, 26 * f, 22 * f, { ue: 1.4 });
d += glatt([[x + 16 * f, y + 33 * f], [x + 23 * f, y + 23 * f], [x + 29 * f, y + 30 * f],
[x + 32 * f, y + 26 * f], [x + 36 * f, y + 33 * f]], false);
} else {
d += kringel(cx, y + 19 * f, 6 * f);
d += glatt([[x + 14 * f, y + 40 * f], [x + 15 * f, y + 32 * f], [cx, y + 28 * f],
[x + s - 15 * f, y + 32 * f], [x + s - 14 * f, y + 40 * f]], false);
}
return d;
}
/* Eine ausholende Schlaufe zwischen zwei Ankern. Sie bauscht immer von der
Kachelspalte weg, damit die Leitung keine Beschriftung kreuzt: auf einem
durchscheinenden Grund kann kein Kasten sie verdecken. */
function schlaufe(ax, ay, bx, by, weite, seite) {
const dx = bx - ax, dy = by - ay, l = Math.hypot(dx, dy) || 1;
const nx = (dy / l) * seite, ny = (-dx / l) * seite;
return [
[ax, ay],
[ax + nx * weite * 0.62 + dx * 0.06, ay + ny * weite * 0.62 + dy * 0.06],
[(ax + bx) / 2 + nx * weite, (ay + by) / 2 + ny * weite],
[bx + nx * weite * 0.62 - dx * 0.06, by + ny * weite * 0.62 - dy * 0.06],
[bx, by],
];
}
/* Ein Stueck Leitung von Kasten zu Kasten.
Der erste Versuch legte die Stuetzpunkte direkt auf die Kastenkante und
liess die Bahn danach irgendwohin laufen. Das sah aus, als streife die
Linie den Kasten zufaellig, und wo zwei Punkte fast aufeinanderlagen,
warf die Kurve einen Zipfel. Beides zusammen war der Grund, warum die
Anbindung nicht stimmte.
Jetzt bekommt jedes Stueck vor dem Kasten einen Punkt auf gleicher Hoehe,
52 px daneben. Die Kurve laeuft dadurch waagerecht aus dem Kasten heraus
und waagerecht in den naechsten hinein: sie haengt sichtbar an ihm, statt
an ihm vorbeizukommen. */
function leitungsStueck(vonX, vonY, nachX, nachY, seite, abstand, zwischen) {
return [[vonX, vonY], [vonX + seite * abstand, vonY]]
.concat(zwischen)
.concat([[nachX + seite * abstand, nachY], [nachX, nachY]]);
}
function visProzesse() {
keim(20260813);
const W = 896, H = 730, HOCH = 62;
/* Die x-Werte sind so gewaehlt, dass die rechten Kanten dort landen, wo
die Leitung sie erwartet. Wer eine Beschriftung aendert, aendert die
Kastenbreite und muss die Ankerpunkte unten mitziehen. */
const chips = [
{ x: 34, y: 60, t: "E-Mails", g: glyBrief },
{ x: 104, y: 200, t: "Zettel im Auto", g: glyZettel },
{ x: 48, y: 340, t: "Tabellen", g: glyTabelle },
{ x: 128, y: 480, t: "Fotos auf dem Handy", g: glyHandy },
{ x: 60, y: 620, t: "Ordner im Regal", g: glyOrdner },
];
chips.forEach(c => {
c.w = Math.round(84 + c.t.length * 14.2);
c.r = c.x + c.w;
});
let raus = "";
// Rechte Kette: von rechter Kante zu rechter Kante, mit weiten Bogen.
const rechts = [
[[470, 34], [590, 72], [624, 150], [540, 186]],
[[576, 244], [672, 312], [604, 392], [492, 372], [432, 308]],
[[352, 398], [452, 424], [600, 406], [688, 470]],
[[664, 540], [708, 624], [606, 684], [478, 660]],
];
let leitung = "";
rechts.forEach((zw, i) => {
leitung += glatt(leitungsStueck(chips[i].r, chips[i].y, chips[i + 1].r,
chips[i + 1].y, 1, 52, zw)
.map(q => [q[0] + zit(2.5), q[1] + zit(2.5)]), false);
});
// Linke Kette: dort ist wenig Platz, also zwei knappe Bogen.
[[1, 2, [[24, 244], [14, 302]]], [3, 4, [[22, 522], [16, 576]]]].forEach(v => {
leitung += glatt(leitungsStueck(chips[v[0]].x, chips[v[0]].y, chips[v[1]].x,
chips[v[1]].y, -1, 34, v[2])
.map(q => [q[0] + zit(2), q[1] + zit(2)]), false);
});
/* Die Leitung traegt den Akzent. Gestrichelt und gelb heisst hier
gewachsen, durchgezogen und gelb auf Slide 5 heisst verbunden: dieselbe
Farbe, aber die Strichart trennt die beiden Aussagen. Etwas kraeftiger
als in Grau, weil eine unterbrochene Linie weniger Flaeche hat. */
raus += zug(leitung, { f: GELB, w: 2.9, op: .78, strichel: "11 13" });
[[700, 96, "blatt", 52], [770, 236, "bild", 46], [760, 430, "person", 50],
[250, 690, "blatt", 44]]
.forEach(k => { raus += zug(kachel(k[0], k[1], k[2], k[3]), { w: 2.5, op: .8 }); });
chips.forEach(c => {
const y = c.y - HOCH / 2;
raus += zug(chamfer(c.x, y, c.w, HOCH, 13), { w: 3.4 });
raus += zug(c.g(c.x + 34, c.y), { w: 2.6 });
raus += '<text x="' + (c.x + 64) + '" y="' + (c.y + 10) + '" ' +
'font-family="Manrope, sans-serif" font-size="27" font-weight="600" ' +
'letter-spacing="-0.01em" fill="' + TINTE + '">' + c.t + '</text>';
});
return '<svg viewBox="0 0 ' + W + ' ' + H + '" width="' + W + '" height="' + H +
'" xmlns="http://www.w3.org/2000/svg">' + raus + '</svg>';
}
/* ─── Slide 1: Foto im gezeichneten Rahmen ───────────────────────────────
Das Foto bleibt roh, gezeichnet wird nur drumherum. Der Helm sitzt wie
die Krone beim Zeichenspiel auf der oberen rechten Ecke, angeschraegt und
halb ueber der Kante.
Er ist ganz in Gelb gezogen, Umriss wie Schraffur. Das hat einen Grund:
er liegt zur Haelfte auf dem hellen Grund und zur Haelfte auf dem dunklen
Foto. Eine Tintenlinie waere auf dem Foto verschwunden. Gelb traegt auf
beidem, und ein Bauhelm ist ohnehin gelb. */
function bauhelm(breite) {
const b = breite / 2, kd = b * 0.70, h = b * 1.12;
/* Zwei Anlaeufe waren noetig. Erst war die Kuppel flach und die Krempe
eine geschlossene Scheibe darunter: zusammen eine Schirmmuetze. Dann
kam Schraffur dazu, und die Waagerechten kreuzten die Grate zu einem
Gitter: ein Korb. Ein Bauhelm braucht wenige Striche, hoch und leer. */
const kuppel = glatt([[-kd, 2], [-kd * 1.0, -h * 0.4], [-kd * 0.6, -h * 0.85],
[0, -h], [kd * 0.6, -h * 0.85], [kd * 1.0, -h * 0.4],
[kd, 2]], false);
// Krempe: zwei Zuege, unten und oben, also eine Lippe mit Dicke.
const krempe = glatt([[-b, 1], [-b * 0.52, 13], [0, 16], [b * 0.52, 13], [b, 1]], false) +
glatt([[-b, 1], [-b * 0.52, 4], [0, 6], [b * 0.52, 4], [b, 1]], false);
// Der mittlere Grat traegt die Form, die beiden aeusseren geben Rundung.
let grate = glatt([[0, -h + 6], [0, -h * 0.45], [0, -1]], false);
[-1, 1].forEach(v => {
grate += glatt([[v * kd * 0.44, -h * 0.82], [v * kd * 0.62, -h * 0.42],
[v * kd * 0.68, -1]], false);
});
return zug(kuppel, { f: GELB, w: 5 }) +
zug(grate, { f: GELB, w: 2.4, op: .6 }) +
zug(krempe, { f: GELB, w: 5 });
}
function visKarte() {
keim(20260811);
const W = 712, H = 971;
// Das Foto liegt bei x 46..666 und y 150..925. Der Rahmen laeuft 16 px
// aussen herum, zweimal gezogen: einmal fest, einmal als leichter
// Nachzieher, wie beim Nachfahren einer Kante.
/* Drei Sachen zusammen: die Markenform, ein versetzter Zweitzug und eine
schraffierte Kante. Sie greifen ineinander statt nebeneinanderher zu
laufen, denn der versetzte Rahmen ist die Aussenkante des Schattens und
die Schraffur fuellt das Band dazwischen. So ist es eine Geste und
nicht dreimal dasselbe uebereinander.
Zur Schattenfrage: rules.md Paragraf 5 verbietet Schatten, meint damit
aber weichgezeichnete. Die dort notierte Ausnahme sagt, eine Linie ist
kein Schatten. Eine Schraffur besteht aus Linien. */
let band = "";
for (let y = 178; y < 928; y += 13) band += strich(683, y, 699, y + 16, { j: .7, b: .7 });
for (let x = 72; x < 666; x += 13) band += strich(x, 942, x + 16, 958, { j: .7, b: .7 });
const raus =
zug(chamfer(48, 152, 652, 807, 30, { ue: 5 }), { w: 3, op: .38 }) +
zug(band, { w: 1.9, op: .34 }) +
zug(chamfer(30, 134, 652, 807, 30, { ue: 9 }), { w: 6 }) +
'<g transform="translate(562 154) rotate(-14)">' + bauhelm(196) + '</g>';
return '<svg viewBox="0 0 ' + W + ' ' + H + '" width="' + W + '" height="' + H +
'" xmlns="http://www.w3.org/2000/svg" class="karte-skizze">' + raus + '</svg>';
}
/* ─── Slide 3: wechseln kannst du vergessen ──────────────────────────────
Der Fliesstext hat zwei Haelften, und beide brauchen ein Bild: "Jahre an
Daten und Wissen haengen drin" wird zu Wurzeln im Boden, "am Ende
dasselbe, nur woanders" zu demselben Kasten noch einmal, nur gestrichelt.
Dazwischen eine gerissene Leine.
Das Kreuz der alten Fassung lag auf dem Pfeil und nicht auf dem Ziel, aus
gutem Grund: nicht das neue System scheitert, sondern der Wechsel. Das
bleibt so. Aus dem Kreuz ist eine gerissene Leine geworden und aus dem
leeren Ziel ein gleiches, denn leer war die falsche Aussage. */
function wurzeln(x, w, oben, tief) {
let raus = "";
const n = 8;
for (let i = 0; i < n; i++) {
const t = (i + 0.5) / n;
const sx = x + w * (0.07 + 0.86 * t);
const laenge = tief * (0.5 + rnd() * 0.5);
const drift = (t - 0.5) * 165 + zit(26);
raus += zug(glatt([[sx, oben],
[sx + drift * 0.18 + zit(9), oben + laenge * 0.3],
[sx + drift * 0.62 + zit(11), oben + laenge * 0.66],
[sx + drift, oben + laenge]], false),
{ w: 3.1 - Math.abs(t - 0.5) * 1.7 });
const az = oben + laenge * 0.5, ax = sx + drift * 0.28;
const seite = t < 0.5 ? -1 : 1;
raus += zug(glatt([[ax, az],
[ax + seite * 20 + zit(7), az + laenge * 0.2],
[ax + seite * 33 + zit(9), az + laenge * 0.33]], false), { w: 1.8 });
}
return raus;
}
/* Erdreich: ungleich lange Schraegstriche. Die gleichmaessige Schraffur aus
schraff() sah nach technischer Zeichnung aus, nicht nach Boden. */
function erdreich(x1, x2, y) {
let d = "";
for (let x = x1; x < x2; x += 13 + rnd() * 6) {
const l = 11 + rnd() * 13;
d += strich(x, y + 2, x - l * 0.55, y + 2 + l, { j: .8, b: .8 });
}
return d;
}
function visWechseln() {
keim(20260815);
const W = 896, H = 730, GRAU = "#A9AFB7";
const BY = 100, BH = 360, BW = 320, LX = 30, RX = 555;
const zeilen = ["Stammdaten", "Aufträge", "Historie", "Wissen im Kopf"];
const mitte = BY + BH / 2;
const inhalt = (x, farbe) => zeilen.map((z, i) =>
'<text x="' + (x + 60) + '" y="' + (BY + 96 + i * 66) + '" ' +
'font-family="Manrope, sans-serif" font-size="28" font-weight="600" ' +
'letter-spacing="-0.01em" fill="' + farbe + '">' + z + '</text>').join("");
const striche = x => zeilen.map((z, i) =>
strich(x + 28, BY + 87 + i * 66, x + 48, BY + 87 + i * 66, { j: .8, b: .8 })).join("");
let raus = "";
// Der Bestand: schwerer Strich, doppelte Unterkante.
raus += zug(rechteck(LX, BY, BW, BH, { ue: 4.5 }), { w: 3.8 });
raus += zug(strich(LX + 6, BY + BH + 6, LX + BW - 6, BY + BH + 6, { ue: 2 }), { w: 3 });
raus += zug(striche(LX), { w: 2.6 });
/* Die Erdoberflaeche liegt dicht unter dem Kasten, nicht am unteren Rand.
Im ersten Wurf lag sie 120 px tiefer, dadurch endeten die Wurzeln in der
Luft und sahen aus wie Beine. Sie muessen die Linie kreuzen, sonst
stecken sie nicht drin. */
const boden = BY + BH + 18;
raus += zug(strich(0, boden, 500, boden, { ue: 4 }), { w: 3 });
raus += zug(erdreich(6, 494, boden), { w: 1.9, op: .45 });
raus += wurzeln(LX, BW, BY + BH + 6, 142);
/* Die Leine reisst, und der Akzent sitzt genau dort, wo die Aussage sitzt.
Entscheidend ist, dass beide Enden nach unten haengen und die Fasern in
dieselbe Richtung weiter ausfransen. Im ersten Wurf zeigten sie
aufeinander zu: das ergab zwei Pfeilspitzen, also die gegenteilige
Aussage. Eine gerissene Leine faellt, sie zielt nicht. */
const endL = [418, mitte + 62], endR = [496, mitte + 48];
raus += zug(glatt([[LX + BW, mitte - 8], [388, mitte + 2], [412, mitte + 28],
endL], false), { f: GELB, w: 4.4 });
raus += zug(glatt([[RX, mitte - 8], [528, mitte + 0], [502, mitte + 22],
endR], false), { f: GELB, w: 4.4 });
let fransen = "";
[endL, endR].forEach(e => {
[-0.42, -0.05, 0.36].forEach(o => {
fransen += strich(e[0], e[1] - 4,
e[0] + Math.sin(o) * 26, e[1] + Math.cos(o) * 26, { j: .9, b: 1.1 });
});
});
raus += zug(fransen, { f: GELB, w: 2.8 });
// Dasselbe noch einmal, nur woanders: gleiche Groesse, gleiche Zeilen.
raus += zug(rechteck(RX, BY, BW, BH, { ue: 3 }), { w: 3, op: .6, strichel: "14 13", f: GRAU });
raus += zug(striche(RX), { w: 2.4, f: GRAU });
raus += inhalt(LX, TINTE) + inhalt(RX, GRAU);
return '<svg viewBox="0 0 ' + W + ' ' + H + '" width="' + W + '" height="' + H +
'" xmlns="http://www.w3.org/2000/svg">' + raus + '</svg>';
}
/* ─── 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.
Die Punkte nennen nicht noch einmal KI, CRM und Automatisierung, das steht
schon im Fliesstext darueber. Sie sagen dasselbe in den Worten eines
Betriebs. Die Kaestchen bleiben leer: erfuellt wird der Wunsch erst auf
Slide 5, und genau davon lebt der Uebergang.
Gelb tragen die Kaestchen. Es ist der einzige Akzent hier und bleibt damit
bei seiner Rolle aus den anderen Slides: Struktur, keine Verzierung. */
function visMehr() {
keim(20260816);
const W = 896, H = 730;
const LX = 60, RX = 800, OY = 70, UY = 650, KNICK = 58;
const wuensche = [
"Angebot schreibt sich selbst",
"Kunde sieht seinen Stand",
"Nichts doppelt eintippen",
"Alles redet miteinander",
];
// Blatt mit abgeknickter Ecke unten rechts.
const blatt = strich(LX, OY, RX, OY, { ue: 4 }) +
strich(RX, OY, RX, UY - KNICK, { ue: 3 }) +
strich(RX, UY - KNICK, RX - KNICK, UY, { ue: 2 }) +
strich(RX - KNICK, UY, LX, UY, { ue: 4 }) +
strich(LX, UY, LX, OY, { ue: 4 });
const knick = glatt([[RX, UY - KNICK], [RX - KNICK + 8, UY - KNICK + 12],
[RX - KNICK, UY]], false);
let raus = zug(blatt, { w: 3.4 }) + zug(knick, { w: 2.6, op: .75 });
wuensche.forEach((t, i) => {
const y = 180 + i * 120;
raus += zug(strich(LX + 60, y + 26, RX - 60, y + 26, { j: 1, b: 1 }), { w: 2, op: .22 });
raus += zug(rechteck(LX + 60, y - 30, 38, 38, { ue: 3 }), { f: GELB, w: 3.4 });
raus += '<text x="' + (LX + 126) + '" y="' + y + '" font-family="Manrope, sans-serif" ' +
'font-size="32" font-weight="600" letter-spacing="-0.015em" fill="' + TINTE + '">' +
t + '</text>';
});
/* Leicht schief aufs Blatt gelegt. Genau senkrecht wirkt gesetzt, und ein
Zettel liegt nie gerade. */
return '<svg viewBox="0 0 ' + W + ' ' + H + '" width="' + W + '" height="' + H +
'" xmlns="http://www.w3.org/2000/svg">' +
'<g transform="rotate(-1.3 448 360)">' + raus + '</g></svg>';
}
/* ─── Slide 6: was nach der Anmeldung passiert ───────────────────────────
Uebernahme der Sektion "So geht\'s weiter" von der Website, in derselben
Handschrift wie Slide 5. Drei Schritte an einer Leitung, Wabe statt Kreis,
der dritte Schritt blass: er hat noch nicht stattgefunden. */
function visWarteliste() {
keim(20260814);
const W = 896, H = 730, HX = 66, R = 54, TX = 176, HOEH = R * 0.866;
const schritte = [
{ y: 112, titel: "Du trägst dich ein", ikon: ikonBrief,
zeilen: ["Eine E-Mail genügt. Kein Vertrag,", "keine Kreditkarte, unverbindlich."] },
{ y: 352, titel: "Wir melden uns", ikon: ikonBlaseKlein,
zeilen: ["Sobald HiveGrid für deinen Betrieb", "bereit ist, persönlich und ohne Spam."] },
{ y: 592, titel: "Du bist von Anfang an dabei", ikon: ikonKonfetti,
zeilen: ["Unter den Ersten, die HiveGrid", "nutzen und mitgestalten."] },
];
const txt = (x, y, groesse, gewicht, farbe, sperr, inhalt) =>
'<text x="' + x + '" y="' + y + '" font-family="Manrope, sans-serif" font-size="' +
groesse + '" font-weight="' + gewicht + '" letter-spacing="' + sperr +
'" fill="' + farbe + '">' + inhalt + '</text>';
let raus = "";
// Von Wabe zu Wabe ein Pfeil. Er endet kurz vor der naechsten Wabe, sonst
// laeuft die Spitze in die Kante und ist nicht mehr als Spitze zu lesen.
let pfeile = "";
for (let i = 0; i < schritte.length - 1; i++) {
pfeile += pfeil(HX, schritte[i].y + HOEH + 8, HX, schritte[i + 1].y - HOEH - 9);
}
raus += zug(pfeile, { f: GELB, w: 3.8 });
schritte.forEach(sc => {
raus += zug(wabeSchraff(HX, sc.y, R, 11), { f: GELB, w: 2, op: .5 });
raus += zug(wabe(HX, sc.y, R), { f: GELB, w: 4 });
raus += sc.ikon(HX, sc.y, TINTE);
raus += txt(TX, sc.y - 26, 40, 800, TINTE, "-0.02em", sc.titel);
sc.zeilen.forEach((z, k) => {
raus += txt(TX, sc.y + 24 + k * 34, 26, 500, "#555555", "0", z);
});
});
return '<svg viewBox="0 0 ' + W + ' ' + H + '" width="' + W + '" height="' + H +
'" xmlns="http://www.w3.org/2000/svg">' + raus + '</svg>';
}
function visVerbinden() {
keim(20260812);
const W = 896, H = 730, cx = 448, cy = 350, R = 160;
const RX = 352, RY = 300;
// Die Winkel sind nicht frei gewaehlt: sie sind die sechs Eckwinkel der
// Wabe. Dadurch sitzt jeder Knoten auf einer Ecke.
const sats = [
{ a: 240, name: "KI", ikon: ikonKi },
{ a: 300, name: "Chat", ikon: ikonChat },
{ a: 0, name: "Mitarbeiter", ikon: ikonCrm },
{ a: 60, name: "Automation", ikon: ikonAuto },
{ a: 120, name: "Projekte", ikon: ikonBoard },
{ a: 180, name: "Formulare", ikon: ikonFormular },
];
let speichen = "", knoten = "", bilder = "", schrift = "";
sats.forEach(s => {
const r = s.a * Math.PI / 180;
const sx = cx + Math.cos(r) * RX, sy = cy + Math.sin(r) * RY;
const ix = cx + Math.cos(r) * R, iy = cy + Math.sin(r) * R; // Ecke der Wabe
const vx = sx - ix, vy = sy - iy, vl = Math.hypot(vx, vy) || 1;
const ux = vx / vl, uy = vy / vl;
const ax = sx - ux * (s.ikon.rad + 20), ay = sy - uy * (s.ikon.rad + 20);
speichen += strich(ix + ux * 12, iy + uy * 12, ax - ux * 11, ay - uy * 11, { j: 1.2 });
knoten += kringel(ix, iy, 10.5, 10.5, { ueber: .1 }) + kringel(ax, ay, 10.5, 10.5, { ueber: .1 });
bilder += s.ikon(sx, sy);
schrift += '<text x="' + n1(sx) + '" y="' + n1(sy + s.ikon.unten) + '" text-anchor="middle" ' +
'font-family="Manrope, sans-serif" font-size="28" font-weight="700" ' +
'letter-spacing="-0.01em" fill="' + TINTE + '">' + s.name + '</text>';
});
// Die Wabe wird zweimal gezogen. Ein zweiter Umriss auf groesserem Radius
// sah nach Versehen aus, derselbe Radius nach zweitem Zug.
// Breite und Hoehe stehen als Attribute mit dran, nicht nur im viewBox.
// Ohne sie hat Chrome die Hoehe nicht aus dem Seitenverhaeltnis abgeleitet,
// das SVG wurde zu hoch und die Zeichnung lief in den Fliesstext.
return '<svg viewBox="0 0 ' + W + ' ' + H + '" width="' + W + '" height="' + H +
'" xmlns="http://www.w3.org/2000/svg">' +
bilder + schrift +
zug(speichen, { f: GELB, w: 4.4 }) +
zug(wabe(cx, cy, R), { f: GELB, w: 4.8 }) +
zug(wabe(cx, cy, R - 2), { f: GELB, w: 3.2, op: .72 }) +
zug(knoten, { f: GELB, w: 3.8 }) +
nabe(cx, cy) +
'</svg>';
}
/* ─── Helm-Entwuerfe ──────────────────────────────────────────────────────
Alle in Gelb, weil der Helm im Post zur Haelfte auf hellem Grund und zur
Haelfte auf dem dunklen Foto liegt. Eine Tintenlinie waere dort weg. */
/* H2: mehr Stuetzpunkte, First, Nebenrippen, Krempe mit Dicke, Schattierung. */
function bauhelmFein(breite) {
const b = breite / 2, kd = b * 0.76, h = b * 1.0;
const kuppel = glatt([
[-kd, 2], [-kd * 1.03, -h * 0.28], [-kd * 0.93, -h * 0.58],
[-kd * 0.62, -h * 0.86], [-kd * 0.22, -h * 0.99], [kd * 0.22, -h * 0.99],
[kd * 0.62, -h * 0.86], [kd * 0.93, -h * 0.58], [kd * 1.03, -h * 0.28], [kd, 2],
], false);
const first = glatt([[-kd * 0.04, -h * 0.99], [0, -h * 0.62],
[kd * 0.03, -h * 0.22], [kd * 0.04, 1]], false);
let rippen = "";
[-1, 1].forEach(v => {
rippen += glatt([[v * kd * 0.36, -h * 0.92], [v * kd * 0.58, -h * 0.56],
[v * kd * 0.68, -h * 0.17], [v * kd * 0.7, 1]], false);
});
const krempeU = glatt([[-b, 4], [-b * 0.62, 16], [0, 21], [b * 0.62, 16], [b, 4]], false);
const krempeO = glatt([[-b, 4], [-b * 0.62, 7], [0, 10], [b * 0.62, 7], [b, 4]], false);
let schatten = "";
for (let i = 0; i < 4; i++) {
const f = 0.94 - i * 0.1;
schatten += glatt([[-kd * f, -h * 0.16], [-kd * f * 0.94, -h * 0.46],
[-kd * f * 0.7, -h * 0.72]], false);
}
return zug(schatten, { f: GELB, w: 2.1, op: .45 }) + zug(kuppel, { f: GELB, w: 5 }) +
zug(first, { f: GELB, w: 3, op: .8 }) + zug(rippen, { f: GELB, w: 2.3, op: .55 }) +
zug(krempeU, { f: GELB, w: 5 }) + zug(krempeO, { f: GELB, w: 3.4, op: .85 });
}
/* H3: gefuellt ueber Schraffur, dafuer ohne Rippen. Schraffur und Rippen
zusammen ergaben in einem frueheren Versuch ein Gitter, also einen Korb. */
function bauhelmSchraffiert(breite) {
const b = breite / 2, kd = b * 0.76, h = b * 1.0;
const kuppel = glatt([
[-kd, 2], [-kd * 1.03, -h * 0.28], [-kd * 0.93, -h * 0.58],
[-kd * 0.62, -h * 0.86], [-kd * 0.22, -h * 0.99], [kd * 0.22, -h * 0.99],
[kd * 0.62, -h * 0.86], [kd * 0.93, -h * 0.58], [kd * 1.03, -h * 0.28], [kd, 2],
], false);
const krempeU = glatt([[-b, 4], [-b * 0.62, 16], [0, 21], [b * 0.62, 16], [b, 4]], false);
const krempeO = glatt([[-b, 4], [-b * 0.62, 7], [0, 10], [b * 0.62, 7], [b, 4]], false);
let fuellung = "";
for (let y = -h + 15; y < -8; y += 13) {
const halb = kd * Math.sqrt(Math.max(0, 1 - (y / h) * (y / h))) - 9;
if (halb < 8) continue;
fuellung += strich(-halb, y - 2, halb, y + 2, { j: .8, b: .9 });
}
return zug(fuellung, { f: GELB, w: 2.1, op: .5 }) + zug(kuppel, { f: GELB, w: 5 }) +
zug(krempeU, { f: GELB, w: 5 }) + zug(krempeO, { f: GELB, w: 3.4, op: .85 });
}
/* H4: Dreiviertelansicht. Die Krempe ist eine Ellipse statt einer Linie,
dadurch sieht man ihre Unterseite und der Helm bekommt Tiefe. Der hintere
Bogen wird nur dort gezogen, wo ihn die Kuppel nicht verdeckt. */
function bauhelmDreiviertel(breite) {
const b = breite / 2, ry = b * 0.23, kd = b * 0.74, h = b * 0.98;
const bogen = (von, bis) => {
const p = [];
for (let i = 0; i <= 10; i++) {
const a = von + (bis - von) * (i / 10);
p.push([Math.cos(a) * b, Math.sin(a) * ry]);
}
return glatt(p, false);
};
const vorn = bogen(0, Math.PI); // untere Haelfte
const hinten = bogen(Math.PI + 0.28, Math.PI + 0.72) +
bogen(-0.72, -0.28); // nur die freien Stuecke
const kuppel = glatt([
[-kd, -ry * 0.5], [-kd * 1.0, -h * 0.34], [-kd * 0.84, -h * 0.68],
[-kd * 0.42, -h * 0.95], [0, -h], [kd * 0.46, -h * 0.93],
[kd * 0.86, -h * 0.64], [kd * 1.0, -h * 0.3], [kd, -ry * 0.5],
], false);
const first = glatt([[-kd * 0.5, -h * 0.78], [0, -h * 0.98],
[kd * 0.5, -h * 0.76], [kd * 0.86, -h * 0.4]], false);
return zug(kuppel, { f: GELB, w: 5 }) + zug(first, { f: GELB, w: 2.6, op: .7 }) +
zug(hinten, { f: GELB, w: 2.6, op: .55 }) + zug(vorn, { f: GELB, w: 5 });
}
/* H5: wie H2, dazu ein Kinnriemen mit Schnalle. */
function bauhelmRiemen(breite) {
const b = breite / 2;
const riemen = glatt([[-b * 0.82, 12], [-b * 0.68, b * 0.52], [-b * 0.2, b * 0.78],
[b * 0.3, b * 0.7], [b * 0.76, b * 0.3], [b * 0.84, 12]], false);
const schnalle = rechteck(-b * 0.16, b * 0.62, b * 0.3, b * 0.17, { ue: 1.5 });
return bauhelmFein(breite) + zug(riemen, { f: GELB, w: 2.8, op: .8 }) +
zug(schnalle, { f: GELB, w: 2.4, op: .8 });
}
/* H6: nur die Silhouette, zwei kraeftige Zuege, sonst nichts. */
function bauhelmKontur(breite) {
const b = breite / 2, kd = b * 0.76, h = b * 1.02;
const kuppel = glatt([
[-kd, 2], [-kd * 1.02, -h * 0.3], [-kd * 0.9, -h * 0.62],
[-kd * 0.5, -h * 0.92], [0, -h], [kd * 0.5, -h * 0.92],
[kd * 0.9, -h * 0.62], [kd * 1.02, -h * 0.3], [kd, 2],
], false);
const krempe = glatt([[-b, 3], [-b * 0.6, 15], [0, 20], [b * 0.6, 15], [b, 3]], false);
return zug(kuppel, { f: GELB, w: 6.5 }) + zug(krempe, { f: GELB, w: 6.5 });
}
/* Der gewaehlte Rahmen, gleich aufgebaut wie in post2.html. */
function rahmenMix() {
let band = "";
for (let y = 178; y < 928; y += 13) band += strich(683, y, 699, y + 16, { j: .7, b: .7 });
for (let x = 72; x < 666; x += 13) band += strich(x, 942, x + 16, 958, { j: .7, b: .7 });
return zug(chamfer(48, 152, 652, 807, 30, { ue: 5 }), { w: 3, op: .38 }) +
zug(band, { w: 1.9, op: .34 }) +
zug(chamfer(30, 134, 652, 807, 30, { ue: 9 }), { w: 6 });
}
document.getElementById("r0").innerHTML = (function(){ keim(20260811); return zug(rechteck(30,134,652,807,{ue:7}),{w:3.8}) + zug(rechteck(31,136,650,804,{ue:5}),{w:2.4,op:.4}); })();
document.getElementById("r1").innerHTML = (function(){ keim(20260811); return zug(rechteck(34,138,644,799,{ue:10}),{w:7}); })();
document.getElementById("r2").innerHTML = (function(){ keim(20260811); return zug(rechteck(44,148,652,807,{ue:6}),{w:3.2,op:.34}) + zug(rechteck(30,134,652,807,{ue:9}),{w:6}); })();
document.getElementById("r3").innerHTML = (function(){ keim(20260811); return zug(rechteck(12,116,688,843,{ue:6}),{w:2.6,op:.5}) + zug(rechteck(34,138,644,799,{ue:9}),{w:6}); })();
document.getElementById("r4").innerHTML = (function(){ keim(20260811); return zug(chamfer(30,134,652,807,30,{ue:8}),{w:6}); })();
document.getElementById("r5").innerHTML = (function(){ keim(20260811); return zug(rechteck(30,134,652,807,{ue:9}),{w:6}) + zug(schraff(684,152,26,796,11),{w:1.9,op:.34}) + zug(schraff(52,943,650,26,11),{w:1.9,op:.34}); })();
document.getElementById("r6").innerHTML = (function(){ keim(20260811); return rahmenMix(); })();
document.getElementById("k0").innerHTML = (function(){ keim(20260811); return '<g transform="translate(150 168)">' + bauhelm(200) + '</g>'; })();
document.getElementById("k1").innerHTML = (function(){ keim(20260811); return '<g transform="translate(150 168)">' + bauhelmFein(200) + '</g>'; })();
document.getElementById("k2").innerHTML = (function(){ keim(20260811); return '<g transform="translate(150 168)">' + bauhelmSchraffiert(200) + '</g>'; })();
document.getElementById("k3").innerHTML = (function(){ keim(20260811); return '<g transform="translate(150 168)">' + bauhelmDreiviertel(200) + '</g>'; })();
document.getElementById("k4").innerHTML = (function(){ keim(20260811); return '<g transform="translate(150 168)">' + bauhelmRiemen(200) + '</g>'; })();
document.getElementById("k5").innerHTML = (function(){ keim(20260811); return '<g transform="translate(150 168)">' + bauhelmKontur(200) + '</g>'; })();
document.getElementById("f0").innerHTML = (function(){ keim(20260811); return rahmenMix() + '<g transform="translate(562 154) rotate(-14)">' + bauhelmFein(196) + '</g>'; })();
document.getElementById("f1").innerHTML = (function(){ keim(20260811); return rahmenMix() + '<g transform="translate(391 322) rotate(-6)">' + bauhelmFein(186) + '</g>'; })();
document.getElementById("f2").innerHTML = (function(){ keim(20260811); return rahmenMix() + '<g transform="translate(690 168) rotate(28)">' + bauhelmFein(196) + '</g>'; })();
document.getElementById("f3").innerHTML = (function(){ keim(20260811); return rahmenMix() + '<g transform="translate(386 350) rotate(-4)">' + bauhelmFein(222) + '</g>'; })();
</script>