diff --git a/post2-alt.html b/post2-alt.html index ed1057d..4507392 100644 --- a/post2-alt.html +++ b/post2-alt.html @@ -353,6 +353,22 @@ im Markup, damit beide Themes denselben Aufbau haben. */ .layer-raster { background: none; } + /* ─── Das Band ────────────────────────────────────────────────────────── + Ein durchgehendes Band ueber den ganzen Streifen, jede Slide zeigt nur + ihren Ausschnitt. Die Verschiebung laeuft ueber --slide-i, das die + Slide ohnehin schon traegt: Slide 3 zeigt also die dritten 1080 px + derselben Zeichnung. An der Naht laeuft die Linie damit weiter, statt + neu anzusetzen -- das ist der Uebergang, den ein Carousel sonst nicht + hat, weil jede Slide fuer sich steht. + + Es liegt in .bg und damit unter allem. Deckend heisst aber auch: + es deckt. Was darueber liegen soll, muss selbst deckend sein -- + Linienwerk auf Transparenz verschwindet darin. */ + .layer-band { + position: absolute; top: 0; + left: calc(var(--slide-i) * -1080px); + } + /* ─── Visualisierungen ─────────────────────────────────────────────────── Post 2 zeigt keine Screenshots, sondern das Stichwort aus dem Text als @@ -411,22 +427,23 @@ 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; } + /* Der Rahmen der Ueber-uns-Seite, Werte aus TeamCards.tsx: die Karte + traegt aussen Radius 38 auf teal-hellem Grund, das abgedunkelte Foto + sitzt 4,2 % eingerueckt mit Radius 27 (= 38 x .72). Die Person darf + ueber diesen Rand hinausragen und wird erst vom Aussenradius + beschnitten -- daher inset 0 und z-index 4. */ .karte { position: relative; aspect-ratio: 4/5; overflow: hidden; - 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 - ); + background: #E8F4F4; isolation: isolate; border-radius: 38px; } .karte-grund { - position: absolute; inset: 0; z-index: 1; overflow: hidden; - border-radius: 8px; background: #2b2d2a; + position: absolute; inset: 4.2%; z-index: 1; overflow: hidden; + border-radius: 27px; 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; + position: absolute; inset: 4.2%; border-radius: 27px; background: linear-gradient(180deg, rgba(15,26,46,.01), rgba(15,26,46,.12)); } .karte-person { @@ -871,7 +888,7 @@ text-secondary, container-bg, border-neutral. Eine erfundene Palette war der erste Fehler dieser Fassung. */ .slide[data-variant="hell"] { - background: #FFFFFF; + background: var(--surface); --head-color: #1A1A1A; --body-color: #555555; --accent-on: #C8901A; @@ -1205,14 +1222,14 @@ eyebrow: "Der Wechsel", head: 'Und wechseln?
Kannst du vergessen.', 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: 195, + vis: "ersetzen", visW: 896, visLeft: 92, visBottom: 130, }, { key: "mehr", type: "feature", layouts: [{ id: "standard", label: "Standard" }], eyebrow: "Was gefehlt hat", head: 'Wir wollten nicht weg.
Wir wollten mehr.', - body: "Ein CRM, Vertrieb, Marketing, Automatisierungen. Unsere Tools sollen endlich miteinander reden.", + body: "KI-Lösungen, Projektmanagement, Automatisierungen. Unsere Tools sollen endlich miteinander reden.", vis: "lose", visW: 988, visLeft: 92, visBottom: 120, }, { @@ -1221,7 +1238,7 @@ eyebrow: "Die Lösung", head: 'Dein Branchenprogramm
bleibt, wo es ist.', body: "Kein Ersatz, sondern der Aufbau drumherum. HiveGrid holt raus, was bisher gefehlt hat.", - vis: "verbinden", visW: 988, visLeft: 0, visBottom: 120, + vis: "verbinden", visW: 896, visLeft: 92, visBottom: 120, }, { key: "warteliste", type: "feature", @@ -1356,7 +1373,7 @@ 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"; + LINIE = "#E5E5E5", KANTE = "#D5DBE1", KARTE = "#FFFFFF"; function farbenNachziehen() { const d = variant === "dunkel"; TINTE = d ? "#FFFFFF" : "#1A1A1A"; @@ -1367,15 +1384,31 @@ ROT = "#E07B54"; ROT_HELL = d ? "rgba(224,123,84,.18)" : "#FBEAE4"; LINIE = d ? "rgba(255,255,255,.14)" : "#E5E5E5"; - KARTE = d ? "#1A2740" : "#F6F8FA"; + KANTE = d ? "rgba(255,255,255,.22)" : "#D5DBE1"; + KARTE = d ? "#1A2740" : "#FFFFFF"; } /* Der Chamfer der Marke: 16 px Schnitt, wie in lib/chamfer.ts der Website. Dort steht auch, warum eine chamferte Flaeche keinen Rand bekommt -- clip-path beschneidet ihn mit. Also fuellen statt umranden. */ const CHAMFER_C = 16; - const chamferFlaeche = (x, y, w, h, fuell, c) => - ''; + + /* Die G-Marke, Punkte woertlich aus assets/brand/g-mark.svg. Als Pfad und + nicht als Bild: ein PNG im foreignObject kann beim Export verschwinden + (rules.md §7), ein Pfad nie. Der Massstab braucht mehr als eine + Nachkommastelle, sonst schrumpft die Marke sichtbar. */ + const G_PUNKTE = "384.5,166.5 336.4,83.2 192.2,166.5 288.3,166.5 240.3,249.7 " + + "144.2,249.7 96.1,166.5 144.2,83.2 336.4,83.2 298,16.8 288.3,0 96.1,0 " + + "0,166.5 96.1,332.9 288.3,332.9"; + function gMarke(cx, cy, hoehe, farbe) { + const s = hoehe / 332.9; + return ''; + } + const chamferFlaeche = (x, y, w, h, fuell, c, rand) => + ''; const zug = (d, o) => { o = o || {}; return ' { c.w = Math.round(84 + c.t.length * 14.2); c.r = c.x + c.w; }); - let raus = ""; + // Deckender Grund: sonst laeuft das Band mitten durch die Leitung. + let raus = chamferFlaeche(0, 0, W, H, KARTE, 22, true); // Rechte Kette: von rechter Kante zu rechter Kante, mit weiten Bogen. const rechts = [ @@ -1732,14 +1766,17 @@ 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 }); }); + [[700, 96, "file-text", 52], [770, 236, "image", 46], [760, 430, "user", 50], + [250, 690, "file-text", 44]] + .forEach(k => { + raus += chamferFlaeche(k[0] - k[3] / 2, k[1] - k[3] / 2, k[3], k[3], KARTE, 9, true); + raus += feather(k[2], k[0], k[1], k[3] * 0.46, TEXT3, 2); + }); 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 += chamferFlaeche(c.x, y, c.w, HOCH, KARTE, 13, true); + raus += feather(c.i, c.x + 34, c.y, 30, TINTE, 2); raus += '' + c.t + ''; @@ -1948,7 +1985,7 @@ Ein Betrieb, der ueber einen Wechsel nachdenkt, versteht eine abgebrochene Uebernahme sofort und braucht dafuer kein Sinnbild. */ function visWechseln() { - const W = 896, H = 580, P = 52; + const W = 896, H = 700, P = 56; const zeilen = [ { t: "Stammdaten", s: "übertragen", art: "ok" }, { t: "Aufträge", s: "1.284 Konflikte", art: "warn" }, @@ -1956,15 +1993,15 @@ ]; const ton = { ok: [TEAL_HELL, TEAL], warn: [GELB_HELL, GELB_DUNKEL], fehler: [ROT_HELL, ROT] }; - let raus = chamferFlaeche(0, 0, W, H, KARTE); + let raus = chamferFlaeche(0, 0, W, H, KARTE, null, true); - raus += 'MIGRATION'; - raus += 'Alles mitnehmen'; // Fortschritt: er bleibt stehen, das ist die Aussage. - const BY = 200, BW = W - 2 * P; + const BY = 248, BW = W - 2 * P; raus += 'Fortschritt'; raus += ''; zeilen.forEach((z, i) => { - const y = 302 + i * 78, f = ton[z.art]; + const y = 366 + i * 96, f = ton[z.art]; raus += ''; const cx = P + 17, cy = y - 9; - if (z.art === "ok") { - raus += ''; - } else if (z.art === "warn") { - raus += '' + - ''; - } else { - raus += ''; - } + const zeichen = { ok: "check", warn: "alert-triangle", fehler: "x" }[z.art]; + raus += feather(zeichen, cx, cy, 19, f[1], 2.6); raus += '' + z.t + ''; @@ -1997,7 +2025,7 @@ 'font-family="Manrope, sans-serif" font-size="26" font-weight="600" fill="' + (z.art === "fehler" ? ROT : TEXT2) + '">' + z.s + ''; if (i < zeilen.length - 1) { - raus += ''; } }); @@ -2014,6 +2042,45 @@ '" xmlns="http://www.w3.org/2000/svg">' + raus + ''; } + /* ─── Feather-Icons ────────────────────────────────────────────────────── + Die Pfade stammen aus @subframe/core, dem Icon-Satz, mit dem unsere + Oberflaeche gebaut ist (siehe hivegrid-pitch). 24x24-Raster, 2 px Strich, + runde Enden. Selbst gezeichnete Zeichen sahen daneben immer eine Spur + anders aus; das hier ist dieselbe Hand. + + Die Strichstaerke wird durch den Massstab geteilt, damit sie bei jeder + Groesse gleich schwer aussieht -- sonst wird ein grosses Icon fett. */ + const FEATHER = { + "alert-triangle": '', + "check": '', + "clipboard-list": '', + "columns-3": '', + "file-text": '', + "filter": '', + "folder": '', + "image": '', + "mail": '', + "megaphone": '', + "message-square": '', + "smartphone": '', + "sparkles": '', + "sticky-note": '', + "table": '', + "user": '', + "users": '', + "workflow": '', + "x": '', + "zap": '' + }; + + function feather(name, cx, cy, groesse, farbe, staerke) { + const s = groesse / 24; + return '' + FEATHER[name] + ''; + } + /* ─── Formen fuer die zugespitzte Fassung ─────────────────────────────── Workflow-Engine, Vertrieb und Marketing brauchen eigene Zeichen: die bestehenden zeigen Dinge, die ein Branchenprogramm schon kann. @@ -2109,10 +2176,10 @@ haengen zusammen, statt nur untereinander zu stehen. */ const W = 896, H = 730, KB = 636, KH = 116, LU = 44, KX = 130; const punkte = [ - { t: "Workflow-Engine", g: (x, y) => formWorkflow(x, y, 0.82) }, - { t: "CRM", g: (x, y) => glyLeute(x, y) }, - { t: "Vertrieb", g: (x, y) => formTrichter(x, y, 0.86) }, - { t: "Marketing", g: (x, y) => formMegafon(x, y, 0.86) }, + { t: "Workflow-Engine", i: "workflow" }, + { t: "Projektmanagement", i: "columns-3" }, + { t: "Chat", i: "message-square" }, + { t: "Mitarbeiter-Management", i: "users" }, ]; const oben = (H - (punkte.length * KH + (punkte.length - 1) * LU)) / 2; const kachelGrund = TEAL_HELL; @@ -2124,15 +2191,15 @@ // Verbinder zur naechsten Karte, mit Knoten in der Mitte. if (i < punkte.length - 1) { const vy = y + KH, vm = vy + LU / 2; - raus += zug(strich(mx, vy, mx, vy + LU), { f: LINIE, w: 2 }); - raus += ''; - raus += zug(strich(mx - 5, vm, mx + 5, vm) + strich(mx, vm - 5, mx, vm + 5), - { f: TEAL, w: 2 }); + raus += zug(strich(mx, vy, mx, vy + LU), { f: TEAL, w: 2, op: .32 }); + raus += ''; + raus += zug(strich(mx - 6, vm, mx + 6, vm) + strich(mx, vm - 6, mx, vm + 6), + { f: TEAL, w: 2.4 }); } - raus += chamferFlaeche(KX, y, KB, KH, KARTE); + raus += chamferFlaeche(KX, y, KB, KH, KARTE, null, true); raus += chamferFlaeche(KX + 28, y + 26, 64, 64, kachelGrund, 10); - raus += zug(p.g(KX + 60, y + 58), { f: TEAL, w: 2.6 }); + raus += feather(p.i, KX + 60, y + 58, 34, TEAL, 2.2); raus += '' + p.t + ''; @@ -2170,14 +2237,14 @@ aktiv. */ function visWarteliste() { const W = 896, H = 600; - const HB = 86, HH = 77, HX = 0, TX = 120, ABSTAND = 84; + const HB = 86, HH = 77, HX = 52, TX = 172, ABSTAND = 84; const schritte = [ - { n: "01", t: "Du trägst dich ein", ikon: "brief", + { t: "Du trägst dich ein", ikon: "brief", z: ["Eine E-Mail genügt. Kein Vertrag,", "keine Kreditkarte, unverbindlich."] }, - { n: "02", t: "Wir melden uns", ikon: "chat", + { t: "Wir melden uns", ikon: "chat", z: ["Sobald HiveGrid für deinen Betrieb", "bereit ist, persönlich und ohne Spam."] }, - { n: "03", t: "Du bist von Anfang an dabei", ikon: "konfetti", + { t: "Du bist von Anfang an dabei", ikon: "konfetti", z: ["Unter den Ersten, die HiveGrid", "nutzen und mitgestalten."] }, ]; @@ -2224,11 +2291,12 @@ }, }; - let raus = ""; + // Deckender Grund: sonst laeuft das Band mitten durch die Liste. + let raus = chamferFlaeche(0, 0, W, H, KARTE, 22, true); const mitte = i => oben + i * (blockHoehe + ABSTAND) + HH / 2; // Die Schiene liegt hinter den Waben und verbindet ihre Mitten. - raus += ''; schritte.forEach((sc, i) => { @@ -2236,9 +2304,6 @@ raus += ''; raus += zeichen[sc.ikon](HX + HB / 2, y + HH / 2); raus += '' + - sc.n + ''; - raus += '' + sc.t + ''; sc.z.forEach((z, k) => { @@ -2266,17 +2331,18 @@ const KERN = 104, RING = 202, SATX = 344, SATY = 262, KACHEL = 88; const module = [ - { a: 240, t: "KI & MCP", ikon: (x, y) => formWorkflow(x, y, 0) }, - { a: 300, t: "Marketing", ikon: (x, y) => formMegafon(x, y, 1.0) }, - { a: 0, t: "CRM", ikon: (x, y) => glyLeute(x, y) }, - { a: 60, t: "Vertrieb", ikon: (x, y) => formTrichter(x, y, 1.0) }, - { a: 120, t: "Automatisierung", ikon: (x, y) => glyZahnrad(x, y) }, - { a: 180, t: "Workflow-Engine", ikon: (x, y) => formWorkflow(x, y, 1.0) }, + { a: 240, t: "KI", i: "sparkles" }, + { a: 300, t: "Chat", i: "message-square" }, + { a: 0, t: "Mitarbeiter", i: "users" }, + { a: 60, t: "Automation", i: "zap" }, + { a: 120, t: "Projekte", i: "columns-3" }, + { a: 180, t: "Formulare", i: "clipboard-list" }, ]; // KI hat kein eigenes Zeichen im Satz, deshalb der Funke von Slide 5 alt. module[0].ikon = (x, y) => funkeForm(x, y, 20); - let raus = ""; + // Deckender Grund: sonst laeuft das Band mitten durch das Diagramm. + let raus = chamferFlaeche(0, 0, W, H, KARTE, 22, true); // Der Ring: HiveGrid liegt um den Kern, nicht an seiner Stelle. raus += ''; raus += ''; - raus += chamferFlaeche(sx - KACHEL / 2, sy - KACHEL / 2, KACHEL, KACHEL, TEAL_HELL, 12); - raus += zug(m.ikon(sx, sy), { f: TEAL, w: 2.6 }); + raus += chamferFlaeche(sx - KACHEL / 2, sy - KACHEL / 2, KACHEL, KACHEL, KARTE, 12, true); + raus += feather(m.i, sx, sy, 42, GELB, 2.3); const ty = m.a > 180 ? sy - KACHEL / 2 - 16 : sy + KACHEL / 2 + 34; raus += 'HIVEGRID'; + const PB = 94, PH = 72, PX = CX - PB / 2, PY = CY - RING - PH / 2; + raus += chamferFlaeche(PX, PY, PB, PH, KARTE, 14, true); + raus += gMarke(CX, CY - RING, 42, GELB); return '' + raus + ''; @@ -2834,10 +2898,111 @@ ''; + /* ─── Das Band ────────────────────────────────────────────────────────── + Die Wellenlaenge ist mit Absicht kein Vielfaches von 1080. Waere sie es, + laege an jeder Naht derselbe Punkt der Welle -- meist ein Scheitel, und + ein waagerechtes Band an der Kante sagt dem Auge nichts. So trifft jede + Naht eine andere Stelle der Flanke. + + Der Querschnitt ist ein Rohr, kein Farbband. Die Rampe unten ist das, + was einen Metallzylinder von einem Bonbon unterscheidet: + + - Die Glanzstelle liegt NICHT an der Oberkante, sondern eingerueckt + bei etwa 20 %, und sie ist schmal und fast weiss. Ein breites, + weiches Hellgelb obenauf ist genau der Bonbon-Eindruck. + - Der dunkelste Punkt liegt NICHT an der Unterkante, sondern bei + etwa 78 %. Darunter kommt Licht vom weissen Grund zurueck. + - Der Tonumfang ist gross: von #6E4205 bis fast Weiss. Metall hat + Kontrast, lackierter Kunststoff nicht. + - Beide Silhouetten sind aufgehellt (Fresnel): streifendes Licht + wird staerker reflektiert. + - Ein paar Laengsstreifen als Schliff. Ohne die bleibt die Oberflaeche + zu glatt, um echt zu wirken. + + Kein SVG-Verlauf: der laeuft immer geradlinig durch die Bounding-Box, + das Band wellt sich aber, er wuerde also quer statt laengs schattieren. + Versetzte Streifen folgen der Kurve von selbst. + + Der Versatz ist senkrecht und nicht rechtwinklig zur Bahn. Dadurch wird + das Band an den Flanken um bis zu 14 % schmaler -- das liest sich als + Verkuerzung und ist erwuenscht, waehrend echte Parallelkurven an engen + Radien Selbstschnitte bekommen. */ + const BAND_RAMPE = [ + [0.00, "#D9A65E"], // Oberkante, streifendes Licht + [0.07, "#C2841C"], + [0.14, "#F0C144"], + [0.20, "#FFF6E2"], // Glanzstelle + [0.27, "#F6C94E"], + [0.40, "#EBA81E"], // Koerperton, unser Orange + [0.54, "#C68310"], + [0.68, "#985E08"], + [0.78, "#6E4205"], // Kernschatten + [0.88, "#B67B12"], // Licht vom Grund zurueck + [0.96, "#96620F"], + [1.00, "#C08B34"], // Unterkante, streifendes Licht + ]; + const BAND_STRIEME = [ + [0.11, 1.4, .16], [0.31, 1.2, -.14], [0.47, 1.8, .12], + [0.62, 1.3, -.16], [0.85, 1.5, .14], + ]; + + function mischen(x, y, t) { + const z = h => [1, 3, 5].map(i => parseInt(h.slice(i, i + 2), 16)); + const v = z(x), w = z(y); + const k = n => Math.max(0, Math.min(255, Math.round(n))).toString(16).padStart(2, "0"); + return "#" + k(v[0] + (w[0] - v[0]) * t) + k(v[1] + (w[1] - v[1]) * t) + + k(v[2] + (w[2] - v[2]) * t); + } + function rampe(stufen, p) { + for (let i = 1; i < stufen.length; i++) + if (p <= stufen[i][0]) { + const v = stufen[i - 1], w = stufen[i]; + return mischen(v[1], w[1], w[0] === v[0] ? 0 : (p - v[0]) / (w[0] - v[0])); + } + return stufen[stufen.length - 1][1]; + } + + function bandSvg() { + const W = SLIDES.length * 1080, H = 1350; + const MITTE = 880, HUB = 215, WELLE = 2650, PHASE = 700, HALB = 95, N = 40; + const y = x => MITTE + HUB * Math.sin(2 * Math.PI * (x + PHASE) / WELLE); + const xs = []; + for (let x = -180; x <= W + 180; x += 80) xs.push(x); + const punkte = v => xs.map(x => x + "," + (y(x) + v).toFixed(1)); + const bahn = v => "M" + punkte(v).join("L"); + const flaeche = "M" + punkte(-HALB).join("L") + "L" + + punkte(HALB).reverse().join("L") + "Z"; + const streifen = (p, w, f) => ''; + + let raus = ""; + // Die Woelbung: schmale Streifen, leicht ueberlappend, damit zwischen + // ihnen keine Naht stehen bleibt. + const dicke = (2 * HALB / N) * 1.3; + for (let i = 0; i < N; i++) { + const p = (i + 0.5) / N; + raus += streifen(p, dicke, rampe(BAND_RAMPE, p)); + } + // Die harte Glanzkante -- der einzige Strich mit scharfem Rand. + raus += streifen(0.20, 2.6, "#FFFDF4"); + // Schliffspuren laengs. + BAND_STRIEME.forEach(v => { + raus += streifen(v[0], v[1], + mischen(rampe(BAND_RAMPE, v[0]), v[2] > 0 ? "#FFFFFF" : "#000000", Math.abs(v[2]))); + }); + // Die Silhouette. Ohne sie franst das Band auf hellem Grund aus. + raus += ''; + + return '' + raus + ''; + } + // Positionen im 5400er Raum. Die Nähte liegen auf 1080 / 2160 / 3240 / 4320. - const BG_HTML = + const bgHtml = () => '
' + '
' + + bandSvg() + '
'; function contentHtml(s, i) { @@ -3083,7 +3248,7 @@ el.dataset.frame = frameStyle; el.dataset.editmode = editMode; el.style.setProperty("--slide-i", i); - el.innerHTML = BG_HTML; + el.innerHTML = bgHtml(); /* Jede Slide traegt das vollstaendige Blatt, nicht nur ihre Nachbarn. Vorher waren es i-1 bis i+1, und ein Element liess sich damit genau eine diff --git a/rules.md b/rules.md index 1e35f40..a93bf11 100644 --- a/rules.md +++ b/rules.md @@ -33,6 +33,12 @@ werden** — das passiert nicht automatisch. Beitrag; das Theme sagt, *wie er aussieht*. Beide Themes teilen Aufbau, Texte und Kompositionen der Visualisierungen. +> **Der Grund ist über alle Beiträge hinweg derselbe: `--surface` `#FFFFFF`.** +> Kein Theme darf ihn ändern. Im Profilraster stehen die Beiträge nebeneinander, +> und schon ein leicht getönter Grund fällt dort als Fehler auf. Ein Theme, das +> mehr Kontrast für seine Karten braucht, holt ihn sich über die Kante +> (`--border-neutral` `#D5DBE1`), nicht über den Grund. + | Theme | Erkennungszeichen | Datei | |---|---|---| | `notebook` | Rasterhintergrund, Zeichenblock-Optik, Marker in der Überschrift, handgezogene Formen | `post2.html` | @@ -45,11 +51,75 @@ nur — die Unterschiede stecken in den CSS-Werten und in den Zeichen-Primitiven | | notebook | modern | |---|---|---| -| Grund | Raster, 78 px | einfarbig, keine Textur | +| Grund | Raster, 78 px | weiß, keine Textur | +| Über alle Slides | — | ein durchgehendes Band | | Akzent in der Überschrift | Marker-Fläche | farbiges Wort | | Formen | `strich` schwingt, Ecken schießen über | exakt, keine Abweichung | | Flächen | Schraffur | Füllung | | Zweitfarbe | keine | Teal `#0D6E6E` | +| Zeichen | selbst gezeichnet | Feather aus `@subframe/core` | + +**Karten stehen weiß auf weiß und tragen über ihre Kante.** `#D5DBE1`, nicht +`#E5E5E5` — die hellere Linie verschwindet auf Weiß. Den Grund zu tönen wäre +der einfachere Weg und ist verboten, siehe oben. Auf der Website reicht +`#E5E5E5`, weil dort ein Schatten mitträgt; hier nicht (§7). + +**Das Band ist ein einziges Bild über den ganzen Streifen.** Jede Slide zeigt +ihren Ausschnitt, verschoben über `--slide-i`. An der Naht läuft es deshalb +weiter, statt neu anzusetzen — das ist der Übergang, den ein Carousel sonst +nicht hat, weil jede Slide für sich steht. Drei Punkte, die daran hängen: + +- **Die Wellenlänge darf kein Vielfaches von 1080 sein.** Sonst liegt an jeder + Naht derselbe Punkt der Welle, meist ein Scheitel, und ein waagerechtes Band + an der Kante sagt dem Auge nichts. +- **Der Querschnitt ist ein Rohr, kein Farbband.** Vierzig schmale Streifen, + versetzt entlang derselben Bahn, eingefärbt aus der Rampe `BAND_RAMPE`. Was + Metall von Bonbon unterscheidet, steht in diesen vier Punkten: + - Die **Glanzstelle liegt nicht an der Oberkante**, sondern eingerückt bei + 20 %, und sie ist schmal und fast weiß. Ein breites weiches Hellgelb + obenauf ist genau der Bonbon-Eindruck. + - Der **dunkelste Punkt liegt nicht an der Unterkante**, sondern bei 78 %. + Darunter kommt Licht vom weißen Grund zurück. + - Der **Tonumfang ist groß**: `#6E4205` bis fast Weiß. Metall hat Kontrast, + lackierter Kunststoff nicht. + - Beide **Silhouetten sind aufgehellt** (Fresnel), dazu ein paar + Längsstreifen als Schliff. +- **Kein SVG-Verlauf.** Nicht weil Verläufe verboten wären — verboten sind sie + nur beim Marker (§5) —, sondern weil ein `linearGradient` immer geradlinig + durch die Bounding-Box läuft. Das Band wellt sich, der Verlauf würde also + quer statt längs schattieren. Versetzte Streifen folgen der Kurve von selbst. +- **Der Versatz ist senkrecht, nicht rechtwinklig zur Bahn.** Dadurch wird das + Band an den Flanken um bis zu 14 % schmaler. Das liest sich als Verkürzung + und ist erwünscht; echte Parallelkurven bekommen an engen Radien + Selbstschnitte. +- **Volle Deckkraft.** Jede Abschwächung nimmt dem Band genau das wieder weg, + was es zum Körper macht. + +**Das Band läuft quer durch die Komposition, nicht am Rand entlang.** Es liegt +in `.bg` und damit unter allem. Damit das trägt, gilt für das Theme `modern`: + +> **Jede Visualisierung liegt auf einer deckenden Karte.** Linienwerk auf +> Transparenz verschwindet im Band. Alle sechs Slides von Post 2 sind deshalb +> auf `chamferFlaeche(0, 0, W, H, KARTE, 22, true)` gesetzt — das Band taucht +> dahinter ab und kommt daneben wieder hoch, wie der Schlauch in der Vorlage +> von awork. Eine weiße Ummantelung um einzelne Linien war der erste Versuch +> und sah nach Panne aus. + +Daraus folgt: **`visW` darf den Satzspiegel nicht überschreiten.** Solange eine +Visualisierung Linienwerk war, durfte sie breiter sein als 896; als Karte muss +sie auf die 92er Kante. `.vis svg` skaliert über `--vis-w` mit, die Innenmaße +bleiben also unangetastet — bei Slide 5 genügte `visW: 988 → 896`. + +**Die Zeichen kommen aus dem Icon-Satz der Software, nicht aus der Hand.** +`@subframe/core`, dieselben Feather-Icons, mit denen die Oberfläche gebaut ist +(im Pitch-Paket unter `node_modules/@subframe/core/…/icons/final/`). Sie liegen +als `FEATHER`-Tabelle in der Datei, gezogen mit dem Skript aus dem +Gesprächsverlauf. Zwei Fallen beim Ziehen: die Props stehen teils als Zahl ohne +Anführungszeichen (`x: 3`), und bei Icons mit nur einem Kind muss der +``-Rahmen weg, sonst rendert nichts. + +Ausnahme ist Slide 6 in `post2-alt.html`: deren drei Zeichen sind Nachbauten +aus `WaitlistNext.tsx` und bleiben es. **Teal ist die Zweitfarbe des Themes `modern`.** In `notebook` kommt sie nicht vor. Damit hat der bisher ungenutzte Marken-Ton eine Aufgabe: er trägt diff --git a/state/post2-alt.json b/state/post2-alt.json index 380fbdc..fc572e3 100644 --- a/state/post2-alt.json +++ b/state/post2-alt.json @@ -25,7 +25,7 @@ "int": "dezent" } ], - "current": 2, + "current": 1, "deck": [ { "ref": "titel", @@ -82,8 +82,8 @@ "dy": 3 }, "vis": { - "dx": 0, - "dy": 16 + "dx": 3, + "dy": 13 } }, { @@ -96,7 +96,7 @@ }, "vis": { "dx": 0, - "dy": -109 + "dy": 0 } }, { @@ -109,8 +109,8 @@ "dy": 3 }, "vis": { - "dx": -17, - "dy": 3 + "dx": -46, + "dy": 0 } }, { @@ -120,7 +120,10 @@ "headline": { "dy": 3 }, - "vis": {} + "vis": { + "dx": 0, + "dy": 0 + } }, { "body": { @@ -135,9 +138,9 @@ } } ], - "frameStyle": "rund", + "frameStyle": "aus", "layoutState": [ - "ecke", + "standard", "standard", "standard", "standard",