Adds the complete "KI verstehen" presentation (36 slides), the Präsentations-Konfigurator (config.html + slides-manifest.js) for curating which slides to show, and updates DESIGN.md/PATTERNS.md/ deck-template.html to reflect the new house font (General Sans) and newly established patterns (chapter dividers, term tooltips, the mitmach game, ambient sound, and the slide configurator).
15 KiB
CANCOM HTML Deck — Design System
Verbindliche Grundlage für alle HTML-Präsentationen im CANCOM-Look.
Referenz-Implementierung: cancom-html-vs-pptx-v7.html
Ausgebautes Praxisbeispiel (36 Slides, Kapitel-Trenner, Mitmach-Spiel, Begriffs-Tooltips,
Präsentations-Konfigurator, Ambient-Sound): ki-verstehen.html + config.html + slides-manifest.js
Startpunkt für neue Decks: deck-template.html
Copy-Paste-Bausteine: PATTERNS.md
1. Grundprinzipien
- Ein File. Kein Build, kein Bundler, keine Node-Dependencies. HTML + CSS + JS in einer Datei, per Doppelklick lauffähig, per Mail/Teams/SharePoint verteilbar. Einzige externe Abhängigkeit: die Fonts von Fontshare (mit lokalem Fallback).
- Feste Bühne, skaliert. Jede Slide ist exakt 1920×1080 px. Nichts wird responsiv umgebrochen — die gesamte Bühne wird per
transform: scale()in den Viewport gerechnet. Dadurch sieht das Deck auf jedem Screen und jedem Beamer pixelidentisch aus. - Design in Tokens. Farben, Fonts, Easings stehen ausschließlich in
:root. Keine Hex-Codes im Slide-Markup. Ein neues Kunden-Theme = neue Token-Werte, kein Umbau. - Animation ist Argument. Das Deck ist ein Beweis dafür, dass HTML mehr kann als PPTX. Jede Slide sollte mindestens eine Sache tun, die eine PowerPoint-Folie nicht kann — Live-Daten, echte Interaktion, GPU-Animation.
- Ehrlichkeit im Ton. Deutsch, direkt, kein Marketing-Sprech. Headlines sind kurze Sätze mit Punkt am Ende („PPTX ist Vergangenheit."), nicht Substantiv-Ketten.
2. Farb-Tokens
| Token | Wert | Verwendung |
|---|---|---|
--cancom-red |
#E4002B |
Signalfarbe. Akzente, Zahlen, Eyebrows, genau ein Highlight pro Headline |
--cancom-red-glow |
rgba(228,0,43,0.55) |
box-shadow / text-shadow Glow |
--cancom-red-dim |
rgba(228,0,43,0.15) |
Flächige Rot-Hinterlegung, Hover-Auras |
--ink |
#0A0A0F |
Standard-Slide-Hintergrund |
--ink-soft |
#14141C |
Erhöhte Flächen, Hover-States |
--ink-line |
#23232E |
Alle Rahmen und Trennlinien |
--paper |
#F5F5F2 |
Primärtext auf Dunkel, Hintergrund der Closing-Slide |
--paper-dim |
rgba(245,245,242,0.6) |
Fließtext, Lead-Absätze |
--paper-mute |
rgba(245,245,242,0.35) |
Labels, Slide-Nummern, HUD |
--accent-cool |
#4CC9F0 |
Zweitfarbe in Charts und Code-Highlighting |
--accent-warm |
#FFB627 |
Drittfarbe, Flash-States |
Regeln
- Rot ist Signal, nicht Dekoration. Pro Slide maximal ein rotes Wort in der Headline.
- Rot nie als große Textfläche — nur Headline-Akzente, Zahlen, Linien, Glows.
- Semantische Ausnahmen sind erlaubt und stehen bewusst außerhalb der Marke:
#4ade80(grün, Kurs steigt) und#ff5060(hellrot, Kurs fällt). - Die Closing-Slide dreht das Schema um:
--paperals Hintergrund,--inkals Text. Das ist der einzige helle Slide — er markiert das Ende.
3. Typografie
Drei Schriften, drei klar getrennte Jobs:
| Token | Font | Job |
|---|---|---|
--font-display |
General Sans (700/600/500) | Alle Headlines, Zahlen, Buttons, Brand-Marks |
--font-body |
Satoshi (700/500/400) | Fließtext, Lead-Absätze, Listen |
--font-mono |
JetBrains Mono (700/500/400) | Eyebrows, Labels, HUD, Code, alles Technische |
Type-Scale (bei 1920×1080)
| Rolle | Größe | Line-Height | Letter-Spacing |
|---|---|---|---|
| Title-Headline | 220 px | 0.88 | −0.045em |
| Closing-Headline | 240 px | 0.86 | −0.045em |
| Counter-Value | 220 px | 0.90 | −0.05em |
| Slide-Title | 112 px (eng: 92 px) | 0.94 | −0.035em |
| Versus-Headline | 100 px | 0.92 | −0.035em |
| Card-Title | 42 px | 1.05 | −0.02em |
| Lead-Absatz | 30 px (eng: 22–24 px) | 1.4 | normal |
| Body / Listen | 20–24 px | 1.4–1.5 | normal |
| Eyebrow / Label | 14–18 px | — | 0.14em–0.3em, uppercase |
Regeln
- Je größer die Schrift, desto negativer das Tracking und desto enger die Line-Height. Große Display-Typo braucht optischen Zusammenzug.
- Mono ist immer uppercase mit weitem Tracking (≥ 0.14em). Es ist die „Maschinen-Stimme" des Decks.
- Body-Text nie über 1300–1500 px Breite (
max-widtham.slide-lead). - Headlines brechen manuell per
<br>. Der Zeilenumbruch ist Gestaltung, nicht Zufall. - Zahlen, die sich live ändern, brauchen
font-variant-numeric: tabular-nums, sonst springt das Layout.
Schriftwahl: Ursprünglich stand hier Clash Display. Bei sehr engem Tracking und großen
Displaygrößen (Zahlen, Zwei-Wort-Headlines) wurde die Schrift auf Distanz schwerer lesbar —
enge, kantige Formen laufen bei Beamer-Projektion schnell zusammen. General Sans ersetzt sie:
gleiche Bühnengröße und Gewichtsstufen (500/600/700), aber offenere Punzen (a, e, s) und eine
größere x-Höhe, die auch bei −0.04em Tracking klar bleibt. Fließtext (Satoshi) und Mono
(JetBrains Mono) sind unverändert. Beim Schriftwechsel testen: font-vorschau.html zeigt
Kandidaten direkt in Deck-Größe (92 px / 40 px) nebeneinander, bevor man sich festlegt.
4. Layout
Die Bühne
.deck-viewport → fixed, füllt das Browserfenster, schwarz, overflow hidden
.deck-stage → 1920×1080, transform-origin 0 0, wird per JS skaliert + zentriert
.slide → absolute inset 0, 1920×1080, default unsichtbar
Der Scale-Faktor ist Math.min(innerWidth/1920, innerHeight/1080), der Rest wird als Letterbox zentriert. Diese Struktur ist nicht optional — sie ist der Grund, warum das Deck überall gleich aussieht.
Grid & Spacing
- Slide-Padding: 100 px oben/unten, 120 px links/rechts (
.slide-content). Title- und Closing-Slide: 120 px rundum. - Spacing-Rhythmus: Vielfache von 4, praktisch 8/12/16/20/24/32/44/60. Kein 13, kein 27.
- Gap in Grids: 20 px (dichte Feature-Tiles), 32 px (Cards), 60 px (Spalten-Splits).
- Content-Bereiche nutzen
flex: 1, damit sie den Rest der Höhe füllen. Bei Grids mit fester Zeilenzahl zusätzlichmin-height: 0, sonst sprengt Inhalt die Slide-Höhe.
Layout-Archetypen
| Klasse | Struktur | Wofür |
|---|---|---|
.title-slide |
Space-between, 3 Zonen (Topbar / Headline / Meta) + Canvas-Layer | Slide 1 |
.slide-content |
Eyebrow → Titel → Lead → Content-Block | Der Standard-Slide, 80 % aller Fälle |
.versus |
2 Spalten randlos + zentraler VS-Kreis | Direktvergleich, Vorher/Nachher |
.counter-grid |
3 Spalten, große animierte Zahlen | Kennzahlen |
.code-slide |
Text links, Code-Window + Live-Preview rechts | Beweis-Slides |
.feature-grid |
4×2 Tiles, .wide = span 2 |
Feature-Showcase |
.closing-slide |
Hell, Space-between, Blur-Blob | Letzter Slide |
.section-slide |
Dunkel, zentriert, riesige „Geister-Zahl" im Hintergrund | Kapitel-Trenner bei Themenwechsel |
.game-wrap |
Satz/Lücke + Options-Buttons, JS-gesteuert | Mitmach-Slides (Publikum rät mit) |
Die Slide-Nummer kommt automatisch aus data-num="04 / 10" am .slide-content (gerendert per ::before). Sie muss beim Umbau des Decks von Hand nachgezogen werden. .section-slide, .versus, .code-slide, Title- und Closing-Slide tragen bewusst kein data-num — sie zählen als „Zwischenspiel", nicht als nummerierter Inhaltspunkt.
Kapitel-Trenner (.section-slide)
Bei mehr als ~5–6 Slides pro Thema lohnt sich ein eigener Trenner-Slide vor jedem Themenwechsel — er gibt dem Publikum eine Atempause und macht die Dramaturgie sichtbar. Aufbau: riesige, transparente Zahl mit Outline (-webkit-text-stroke) im Hintergrund, davor ein roter Mono-Kicker („Kapitel 03 / 07") und eine kurze, große Headline plus ein Satz Unterzeile. Siehe PATTERNS.md Nr. 7 für den Code.
Faustregel: ein Trenner pro inhaltlichem Kapitel, nicht pro Slide. Bei 30+ Slides sind 6–8 Trenner ein guter Rhythmus — mehr wirkt zerhackt, weniger verliert die Orientierung.
5. Motion
Reveal-System
Elemente mit .reveal starten bei opacity: 0; translateY(40px) und fahren ein, sobald die Slide .visible bekommt. Die Staffelung läuft über .d1–.d7 (100 ms → 820 ms, Schritte von ~120 ms). .reveal-slide-x macht dasselbe horizontal (−60 px), gedacht für die linke Versus-Spalte.
<span class="slide-eyebrow reveal d1">Das Problem</span>
<h2 class="slide-title reveal d2">Warum das <span class="accent">nervt.</span></h2>
<p class="slide-lead reveal d3">…</p>
<div class="pain-card reveal d4">…</div>
Regel: Reihenfolge im DOM = Reihenfolge der Delays. Nie d5 vor d3 einfahren lassen. Mehrere gleichrangige Karten dürfen sich ein Delay teilen.
Easings
| Token | Kurve | Wofür |
|---|---|---|
--ease-out-expo |
cubic-bezier(0.16, 1, 0.3, 1) |
Standard für alles, was einfährt. Schnell rein, weich aus. |
--ease-swift |
cubic-bezier(0.65, 0, 0.35, 1) |
Kurze, entschiedene Bewegungen (Durchstreichen) |
Timings
- Reveal-Einfahrt: 0.9 s
- Hover-Feedback: 0.12–0.15 s (muss sich sofort anfühlen)
- Chart-Balken: 1.2 s mit gestaffeltem
transition-delayvon 0.4 s bis 0.9 s - Counter-Zählung: 1.6 s, Easing
1 - (1-p)³ - Loops (Blob, Ticker, Cube): 4–12 s,
linearoderease-in-out, damit sie nie „getaktet" wirken
Performance
Animiert werden nur transform und opacity — die laufen auf der GPU. Kein width, height, top, left in Transitions. Ausnahme: .demo-charts-bars animiert height, aber auf 6 winzigen Divs, das ist vertretbar.
prefers-reduced-motion ist global verdrahtet: Animationen gehen auf 0.01 ms, Transitions auf 0.2 s. Slides bleiben voll funktionsfähig, nur ohne Show.
6. Interaktion
| Trigger | Wirkung |
|---|---|
→, Leertaste, PageDown |
nächster Slide |
←, PageUp |
vorheriger Slide |
Home / End |
erster / letzter Slide |
| Mausrad | Slide-Wechsel, 900 ms Cooldown |
| Swipe (> 60 px) | Slide-Wechsel auf Touch |
E |
Edit-Modus |
C |
Zum Präsentations-Konfigurator (config.html), falls vorhanden |
| Hotzone oben links | blendet Edit- und Config-Button ein (400 ms Grace-Period) |
Klick auf .term |
öffnet Begriffs-Tooltip |
Edit-Modus: Setzt contenteditable auf alle Text-Elemente, markiert sie mit rotem Dashed-Outline. Beim Verlassen wird der Stage-HTML in localStorage geschrieben. Das Zurückladen ist absichtlich auskommentiert — restauriertes HTML kollidiert mit den Animations-States. Der Edit-Modus ist ein Live-Korrektur-Werkzeug für die Bühne („Kunde will hier ein anderes Wort"), keine Persistenz-Schicht.
Begriffs-Tooltips (.term): Für Laien-Publikum unentbehrlich — Fachbegriffe (Token, LLM, MCP, GPT, ANI/AGI, …) bekommen eine gepunktete rote Unterstreichung plus kleines „?"-Badge. Klick öffnet eine kurze Erklärung. Das Tooltip-Element lebt außerhalb der 1920er-Bühne (ein einziges #globalTooltip, direkt an <body> gehängt, per JS in echten Viewport-Pixeln positioniert) — sonst schneiden overflow:hidden-Container wie .pain-card oder .feature-tile es ab. Es klappt automatisch ober- oder unterhalb des Begriffs aus, je nachdem was im Fenster noch Platz hat, und schließt bei Klick daneben, Esc, Resize oder Slide-Wechsel. Siehe PATTERNS.md Nr. 8.
Präsentations-Konfigurator: Bei Decks mit vielen Slides (Workshop-Varianten, 45/60/90-Minuten-Kürzungen) lohnt sich config.html + slides-manifest.js statt Slides von Hand zu löschen. Der Konfigurator listet alle Slides gruppiert nach Kapitel mit Checkbox; die Auswahl wird beim Wechsel zur Präsentation als ?slides=1,4,5,…-Parameter an die Deck-URL gehängt (nicht nur localStorage — das wird zwischen einzelnen file://-Dateien nicht überall geteilt, vor allem Safari trennt es strikt). Titel- und Closing-Slide sind im Manifest als locked: true markiert und immer aktiv. Siehe PATTERNS.md Nr. 11.
Ambient-Sound (optional, nur Titelfolie): Ein per Web Audio API erzeugter Klangteppich (kein externes Audio-File) kann vor Vortragsbeginn Spannung aufbauen. Läuft nur, während die Titelfolie aktiv ist, blendet beim Verlassen automatisch aus. Browser blockieren Audio ohne Nutzer-Geste — deshalb immer über einen expliziten Icon-Button starten, nie automatisch. Siehe PATTERNS.md Nr. 10.
Hover-Regel: Cards heben sich um 4–8 px (translateY) und wechseln die Border auf Rot. .pain-card zieht zusätzlich eine Radial-Aura hinter dem Cursor her (--mx/--my per JS gesetzt).
Wichtig bei Maus-Koordinaten: Die Bühne ist skaliert. e.clientX sind Bildschirm-Pixel, das Element lebt im 1920er-Raum. Immer durch den Scale-Faktor teilen:
const rect = el.getBoundingClientRect();
const scale = rect.width / el.offsetWidth;
const x = (e.clientX - rect.left) / scale;
Bei .pain-card fällt das nicht auf, weil dort in Prozent gerechnet wird — beim Ripple des Demo-Buttons schon.
7. Print / PDF
@media print löst die fixe Bühne auf: .deck-stage verliert transform, jede Slide wird position: relative mit break-after: page. HUD, Progress-Bar und Edit-Controls verschwinden. Export: Strg/Cmd+P → Ziel „Als PDF sichern" → Papierformat Querformat, Ränder: keine, Hintergrundgrafiken: an.
Ergebnis: eine Seite pro Slide. Animierte Inhalte frieren im jeweiligen Endzustand ein — Live-Daten (WebSocket) zeigen den letzten Wert.
8. Neues Deck bauen
deck-template.htmlkopieren und umbenennen.<title>, Brand-Mark, Datum, Sprecher-Name, Kontakt anpassen.- Slides aus
PATTERNS.mdzusammenstellen. Bewährte Dramaturgie: Titel → Problem → Vergleich → Zahlen → Beweis (Live) → Der ehrliche Deal → Closing. data-numan allen.slide-contentauf die neue Gesamtzahl ziehen. Das HUD zählt selbst,data-numnicht.- Durchklicken bei 1920×1080 und bei kleinem Fenster. Der Scale muss sauber greifen, Text darf nirgends aus einer Card laufen.
- Print-Preview prüfen, bevor das Deck rausgeht.
- Bei vielen Slides oder mehreren Vortrags-Längen (45/60/90 Min.):
slides-manifest.jsmit der finalen Slide-Liste anlegen (ein Eintrag pro<section class="slide" data-slide-id="…">, gleiche Reihenfolge),config.htmlaus dem Beispiel-Projekt kopieren. Damit lässt sich die Slide-Auswahl kuratieren, ohne Markup zu löschen.
Kunden-Theme
Nur die Tokens in :root tauschen: Signalfarbe, ggf. Display-Font. Alles andere bleibt. Wenn die Signalfarbe hell ist (Gelb, Cyan), zusätzlich prüfen: Kontrast von .demo-button (weißer Text auf Signalfarbe) und die Glow-Shadows — die brauchen dann weniger Alpha.
9. Do / Don't
Do
- Ein Gedanke pro Slide. Die Headline sagt ihn, alles andere belegt ihn.
- Große Zahlen groß machen. 220 px ist kein Fehler.
- Weißraum halten. Die 120 px Padding sind Design, kein Verschnitt.
- Live-Elemente bekommen immer einen Fallback (siehe WebSocket-Fallback: simuliert Ticks, wenn kein Netz da ist). Eine Demo, die auf der Bühne offline abstürzt, ist ein Eigentor gegen die eigene These.
- Ein Argument pro Slide beweisen statt behaupten.
Don't
- Keine Bullet-Point-Listen aus Gewohnheit. Wenn eine Liste, dann mit gestalteten Markern (
×/→). - Keine Hex-Codes im Markup. Token benutzen.
- Kein Scroll innerhalb einer Slide. Passt es nicht, ist es zu viel Inhalt — nicht zu wenig Platz.
- Keine externen Libraries. Das Deck beweist, dass Vanilla reicht.
- Kein Rot als Fläche hinter Text.
- Keine Animation ohne Grund. Jeder Loop, den niemand anschaut, ist verbranntes Budget an Aufmerksamkeit.