Vier Unsplash-Aufnahmen unter assets/eigene, die avatarKreis() nimmt, sobald sie da sind -- vorher stand dort das Kuerzel. Nur Menschen bekommen eins, Projektkanal und Gruppe behalten ihr Sinnbild. portrait-sk Sandra Koch unsplash.com/photos/SJvDxw0azqw portrait-mb Maike Berger unsplash.com/photos/ZAo0cKz_IKM portrait-tw Tobias Wagner unsplash.com/photos/TTdJV-K1IUg portrait-ms Michael Schuster unsplash.com/photos/7YVZYZeITc8 Ausgewaehlt nicht nach Gesicht, sondern nach Unterscheidbarkeit im Kreis von 42 px: dort zaehlt der Gesamtwert und die Silhouette. Die vier decken hell, mittelhell, dunkel und mittel ab, dazu kurze Locken, schulterlang, Schiebermuetze mit Bart, kurz und glatt. WAS DARAN OFFEN BLEIBT, UND ZWAR WISSENTLICH Die Unsplash-Lizenz deckt das Urheberrecht des Fotografen, kein Model Release. Ein fremdes Gesicht als "Sandra Koch, Projektleitung" auf dem Firmenkanal beruehrt 22 KUG und die DSGVO. Ein Zwischenstand wich deshalb auf erzeugte Gesichter aus (StyleGAN2) und ist zugunsten echter Aufnahmen zurueckgenommen worden. Rechtssicher waere nur model-released Stock. Steht in POST-6.md 4. Geprueft ist jede der vier Seiten einzeln: Unsplash-Lizenz vermerkt, keine KI-Kennzeichnung, benannter Fotograf, Datum zwischen 2017 und 2023. DREI FALLEN Von 56 Suchtreffern waren 32 Profilbilder der Fotografen, nicht deren Aufnahmen -- ein figure img greift das Avatarbild des Urhebers mit ab, und die sehen aus wie Portraits, weil sie welche sind. Zwei davon waren schon eingesetzt, bevor es beim Aufschreiben der Herkunft auffiel. Erkennbar an photo- gegen profile- in der URL. Zwei gegenlaeufige Teilstuecke in einem Pfad loeschen ihren Ueberlapp weg, und ein Rechteck in Zeichnungsgroesse trifft nicht, was darueber hinaussteht. Beides gehoert zum Band davor, beides fiel erst hier auf. Zuschnitt braucht keinen Fuellton: ein Business-Portrait hat Luft ueber dem Kopf. Skaliert mit lanczos plus leichtem unsharp, 320 x 320 JPEG -- was beim Verkleinern an Schaerfe verlorengeht, holt keine Renderqualitaet zurueck. Bewegtbild neu gebaut, die Avatare stehen auch darin. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U7RZ6ZpLD8Dp84Rtt4KHfv
596 lines
30 KiB
Markdown
596 lines
30 KiB
Markdown
# HiveGrid Social — Design-Library & Post-Generator
|
||
|
||
Eigenständige Werkbank für HiveGrid-Social-Grafiken. Slides werden im Browser
|
||
als HTML gebaut, im Canvas bearbeitet und pixelgenau als Instagram-taugliche
|
||
PNGs exportiert.
|
||
|
||
**Das Repo ist bewusst autark.** Keine CDN-Verweise, keine Google-Fonts zur
|
||
Laufzeit, keine Pfade in andere Repos. Alles, was ein Post braucht — Schrift,
|
||
Logos, Mockups, Screenshots, Bibliotheken — liegt hier.
|
||
|
||
## Starten
|
||
|
||
```sh
|
||
./serve.sh # http://127.0.0.1:4321
|
||
```
|
||
|
||
Downloads landen direkt in `~/Downloads`, ohne Browser-Dialog.
|
||
|
||
## Projekte
|
||
|
||
| Projekt | Datei | Inhalt | Übergabe |
|
||
|---|---|---|---|
|
||
| Post 1 · Lösung | `post1.html` | Carousel, Anzahl frei | |
|
||
| Post 2 · Die Geschichte | `post2.html` | Carousel, 6 Slides, erscheint 12.08. | [`POST-2.md`](./POST-2.md) |
|
||
| Post 2 · Alternative | `post2-alt.html` | Derselbe Beitrag im Theme `modern` | |
|
||
| Post 3 · Verbinden statt ersetzen | `post3.html` | Einzelbild, Theme `modern`, erscheint 17.08. | |
|
||
| Post 4 · Workflow-Engine | `post4.html` | Carousel, 4 Slides, Theme `modern`, erscheint 19.08. | [`POST-4.md`](./POST-4.md) |
|
||
| Post 5 · Projektmanagement | `post5.html` | Carousel, 5 Slides, Theme `modern`, erscheint 21.08. | [`POST-5.md`](./POST-5.md) |
|
||
| Post 6 · Team-Chat | `post6.html` | Carousel, 5 Slides, Theme `modern`, erscheint 26.08. | [`POST-6.md`](./POST-6.md) |
|
||
|
||
**Alle Streifen nebeneinander** zeigt `uebersicht.html`, erreichbar über
|
||
*Projekt → Alle Projekte im Streifen*. Die Seite baut die Slides nicht selbst
|
||
nach: jedes Projekt kommt als `iframe` mit `?nur=streifen`, und in diesem Modus
|
||
blendet die Post-Seite ihre Bedienoberfläche aus, zeigt den Streifen in
|
||
natürlicher Größe und **speichert nichts** — drei Kacheln, die beim Schließen
|
||
ihren Stand zurückschreiben, wären genau die Falle aus [`POST-2.md`](./POST-2.md) §6.
|
||
Jeder Streifen ist auf die Fensterbreite eingepasst, gescrollt wird nur
|
||
hoch und runter — kein Zoom, weder außen noch im Streifen.
|
||
|
||
**Post 2 gibt es zweimal, in zwei Themes.** Projekt und Theme sind zwei
|
||
verschiedene Dinge: das Projekt sagt, welcher Beitrag, das Theme, wie er
|
||
aussieht. `notebook` ist die Zeichenblock-Optik mit Raster und Marker,
|
||
`modern` der ruhige Grund mit farbigem Akzentwort und schwebenden Karten.
|
||
Beide zeigen denselben Beitrag mit denselben Texten.
|
||
|
||
Die Themes stehen in [`rules.md`](./rules.md) §1a mit ihren Unterschieden.
|
||
Wer eine Visualisierung ändert, muss an beide Dateien denken.
|
||
|
||
**Post 3 ist ein Einzelbild**, keine Slidefolge: eine Haltung, die man
|
||
durchwischen muss, ist keine. Sein Bild ist das **Wabenfeld der Startseite**,
|
||
nachgebaut aus `HoneycombSection.tsx` — dieselbe Achsrechnung, dieselben
|
||
Zellnummern, dieselbe Belegung, damit es wiedererkennbar bleibt und keine
|
||
Anmutung davon ist. Die vier Waben „In Arbeit" fehlen: auf der Startseite sind
|
||
sie ein Versprechen, im Beitrag wären sie ein Eingeständnis.
|
||
|
||
**Post 4 zeigt einen einzigen echten Ablauf**, nicht sechs Behauptungen über
|
||
Automatisierung: den Vorgang aus `assets/screens/workflow.png`. Die Bausteine
|
||
sind nachgebaut aus `NodeWorkflowEngine` und `WorkflowEngineClickDummy` des
|
||
Pitch-Pakets, in Markenfarben statt in den UI-Farben des Produkts — Teal trägt
|
||
die Arbeit, Gelb den einen Akzent, Anthrazit die Entscheidung.
|
||
|
||
**Vier Slides.** Der Redaktionsplan nennt fünf bis sieben, aber das ist eine
|
||
Spanne und kein Soll: eine Slide, die nichts hinzufügt, kostet einen Wisch und
|
||
gibt nichts zurück.
|
||
|
||
| Slide | Was sie leistet | Ansicht | Quelle der Texte |
|
||
|---|---|---|---|
|
||
| 1 | was es ist | ein Ablauf auf dem Canvas | Knoten aus `assets/screens/workflow.png`, Notiz aus `WORKFLOW_PRESETS`, Anordnung eigen |
|
||
| 2 | was ihn startet | Auslöser-Auswahl | `assets/screens/workflow-bausteine.png` |
|
||
| 3 | was dann passiert | Aktionen-Auswahl | `NodeWorkflowEngine`, Rubriken des `Katalog` |
|
||
| 4 | dass man nicht bei null anfängt | drei Vorlagen | `GENERAL_WORKFLOW_PRESETS` |
|
||
|
||
Slide 2 und 3 sind **eine Funktion mit zwei Rubriken**, weil es im Produkt eine
|
||
Auswahl ist: „Auslöser" und „Aktionen" stehen dort untereinander im selben
|
||
Feld. Getrennt gezeichnet wären es zwei Bilder, die zufällig gleich aussehen.
|
||
Die Kachelfarbe kommt dabei aus der **Kategorie**, nicht aus dem Knotentyp —
|
||
im Screenshot tragen alle Auslöser eine gelbe Kachel und die Aktion eine
|
||
blaue, samt Punkt vor der Rubrik. Auf dem Canvas ist es anders, dort färbt die
|
||
Wurzelkomponente je Art. Beides stimmt, es sind zwei Ansichten.
|
||
|
||
**Das Farbsystem stammt aus der Wurzelkomponente** und ist keine Dekoration:
|
||
grün fängt an, rot ändert Daten, blau meldet, amber macht eine Aufgabe daraus,
|
||
violett entscheidet, grau ist ein Fremdsystem. Deshalb sind auf Slide 3 alle
|
||
Kacheln grün — jede Vorlage startet mit einem Auslöser.
|
||
|
||
> **Die Kartenform auf Slide 3 ist nicht aus dem Projekt.** Im Werkzeug werden
|
||
> Vorlagen nur geladen, nicht als Galerie gezeigt; es gibt dort keine Ansicht,
|
||
> an die man sich halten könnte. Wörtlich sind die Namen, Beschreibungen und
|
||
> Startbausteine, gebaut ist die Form. Der Unterschied gehört benannt.
|
||
|
||
**Text mittig, Titel ohne Fließtext.** Die Visualisierungen sitzen 896 px breit
|
||
bei x 92, also links wie rechts 92 px Rand — ein linksbündiger Textblock
|
||
darüber steht sichtbar aus der Achse. Die Titel-Slide trägt nur die
|
||
Überschrift: der Ablauf darunter sagt, was gemeint ist, und ein Fließtext
|
||
wiederholte es in Prosa. Dafür fiel hier dieselbe Korrektur an wie in
|
||
`post3.html` — ein leerer Fließtext darf keinen leeren Absatz erzeugen, sonst
|
||
schiebt sein Zeilenabstand die Zeichnung nach unten.
|
||
|
||
> **Die Gabel auf Slide 1 kommt früher als im Screenshot, und ein Schritt
|
||
> fehlt.** Alle drei echten Abläufe verzweigen erst an Position 3 oder 4 —
|
||
> das füllt ein hochkantes Format schlecht, weil über und unter dem Stamm
|
||
> nichts steht, solange er läuft. Hier gabelt es nach dem zweiten Knoten, und
|
||
> zwischen „Formular eingegangen" und „Passender Lead?" fehlt dadurch „Daten
|
||
> vereinheitlichen". Alle sechs Knoten heißen wörtlich wie in `workflow.png`
|
||
> und tragen dessen Farben, aber diese eine Kante ist zusammengezogen: ein
|
||
> Ablauf, den es genau so gibt, ist es nicht mehr — einer, den es geben
|
||
> könnte, schon. Die Anordnung ist ohnehin eigen, im Werkzeug zieht man
|
||
> Knoten mit der Maus.
|
||
|
||
**Kein PDS im Beitrag.** Von den sechs Vorlagen nennen drei das
|
||
Branchenprogramm — zwei im Namen, eine in der Beschreibung. Der Beitrag
|
||
richtet sich an Betriebe allgemein, nicht an die, die zufällig dieses eine
|
||
Programm fahren. Übrig bleibt genau die Gruppe `GENERAL_WORKFLOW_PRESETS`, in
|
||
der das Wort kein einziges Mal vorkommt — also keine Auswahl nach Geschmack,
|
||
sondern die vollständige zweite Gruppe. Gekürzt wurde nichts: aus „Offene
|
||
Angebote aus PDS erkennen" ein „Offene Angebote erkennen" zu machen wäre die
|
||
bequeme Lösung und kein Zitat mehr. Lieber eine Karte weniger.
|
||
|
||
**Alle Produkttexte auf den Slides sind wortgleich aus der Quelle**, Titel wie
|
||
Beschreibungen. Wo ein Name nicht in eine Zeile passte, steht er zweizeilig —
|
||
gekürzt wird nicht, denn aus „Daten vereinheitlichen" ein „Prüfen" zu machen
|
||
ist keine Kürzung, sondern ein anderer Name.
|
||
|
||
**Der Knoten ist die echte Komponente.** `NodeItem` aus
|
||
`NodeWorkflowEngine.tsx` des Pitch-Pakets: quadratisch 128 × 128, `rounded-lg`,
|
||
6 px Rand, Titel und Beschreibung **unter** dem Feld, beim Auslöser die linke
|
||
Flanke voll gerundet. Genau so rendert es auch `assets/screens/workflow.png`.
|
||
Ein Zwischenstand zeichnete stattdessen breite Karten mit farbiger Kante links
|
||
und einem Block „BESCHREIBUNG" — abgemalt vom Pitch-Bild `02_Präsentation/03`.
|
||
Im Code des Projekts gibt es das nirgends, und der Kommentar behauptete
|
||
trotzdem, es sei ein Nachbau der Komponente.
|
||
|
||
**Die Farben sind die des Produkts**, nicht die der Marke. Aufgelöst aus
|
||
`ui/theme.css` über die ganze Token-Kette (`surface-ui-subtle-green-default`
|
||
→ `--color-ui-green-100` → `--color-green-100`), nicht aus dem Bild geschätzt:
|
||
|
||
| Rolle | Fläche | Zeichen |
|
||
|---|---|---|
|
||
| Auslöser | `#DCFCE4` | `#148134` |
|
||
| Daten | `#FEE2E2` | `#C52020` |
|
||
| Entscheidung | `#F0E7FF` | `#691CD4` |
|
||
| Meldung | `#D5EFFF` | `#003BEB` |
|
||
| Abschluss | `#FCF6C5` | `#9B5E0D` |
|
||
|
||
Ein Zwischenstand hatte sie durch Markenfarben ersetzt, weil `rules.md` §2 diese
|
||
Töne nicht kennt. Das ist zurückgenommen: der Beitrag zeigt die Oberfläche, und
|
||
ihre Farbe trägt Bedeutung — grün fängt an, rot arbeitet an Daten, violett
|
||
entscheidet, blau meldet, gelb schließt ab. Umgefärbt wäre es eine
|
||
Nacherzählung. Der Rand ist `border-default` `#E5E5E5`, also der Wert, vor dem
|
||
`rules.md` §5 warnt; hier trägt er, weil die Felder farbig gefüllt sind.
|
||
|
||
**Der Notizzettel auf Slide 1** ist `StickyNote.tsx` aus dem Pitch-Paket
|
||
(`rounded-md`, Kopfleiste `h-8`, Text `#424242`, sechs Farbpaare) mit dem
|
||
grünen Zettel aus dem Preset `form-to-pds`, Text unverändert. Zettel sind das,
|
||
was einen Ablauf im Werkzeug von einem Diagramm unterscheidet.
|
||
|
||
**Was hier bewusst nicht steht: ein erfundener Vorgang.** Ein Zwischenstand
|
||
hatte eine Slide mit einem Aktivitätenverlauf samt Uhrzeiten. Nichts davon war
|
||
gemessen. Bei einem Produkt vor dem Start ist eine erfundene Uhrzeit keine
|
||
Veranschaulichung, sondern ein Beleg, den es nicht gibt.
|
||
|
||
**Slide 1 trägt einen Ablauf, kein Stichwort.** Im Profilraster ist sie eine
|
||
Kachel von rund 150 px, auf 3:4 beschnitten — dort ist kein Wort lesbar. Was
|
||
ankommt, ist die Form: eine Kette, die sich gabelt.
|
||
|
||
Was über die 1080 px einer Seite hinausragt, landet auf der Nachbarslide — das
|
||
durchgehende Blatt aus `rules.md` §5 liegt in jeder Slide. Ein Prüfskript misst
|
||
das nach; alle sechs Zeichnungen bleiben auf der Sicherheitszone.
|
||
|
||
Sein Grund ist **gepunktet statt leer**: die Arbeitsfläche des Workflow-Editors,
|
||
mit den Werten aus `WorkflowEditor.tsx` der Website. Der Punktgrund steht als
|
||
dritte Stellung unter *Versuch → Punkte* und ist die Voreinstellung dieses
|
||
Projekts. Warum das Theme `modern` hier von seinem ruhigen Grund abweicht, steht
|
||
im CSS bei `.layer-raster`.
|
||
|
||
**Post 5 zeigt die Pipeline von vier Seiten.** Das Demo-Projekt hat dafür vier
|
||
Bildschirme — Schablone, Board, Liste, Detail — und jeder bekommt eine Slide,
|
||
dazu die Karte aus der Nähe. Anders als bei Post 4 wird **nichts umgefärbt**:
|
||
eine Pipeline lebt davon, dass man das Gewerk an der Farbe erkennt, ohne zu
|
||
lesen, und dass der Fuß einer Karte sich mit ihrer Priorität färbt. Die
|
||
Zuordnung Gewerk zu Ton ist `CATEGORY_TONES`, die Plättchenfarben sind
|
||
`ui/theme.css`.
|
||
|
||
| Slide | Screen | Was sie leistet |
|
||
|---|---|---|
|
||
| 1 | 4A | das Board selbst, drei Phasen mit Anzahl, Summe und Karten |
|
||
| 2 | 4A | eine Karte groß |
|
||
| 3 | 4B | „Vom Verkauf in die Abwicklung": dasselbe Projekt in `Auftragsabwicklung SHK`, mit dem Knopf für den Pipelinewechsel |
|
||
| 4 | 4C | dieselben Projekte als Tabelle |
|
||
| 5 | 3 | der Feldeditor, offen auf „Aufmaß erledigt" |
|
||
|
||
**Es sind zwei Pipelines, nicht eine.** Das Board gehört zu
|
||
`Vertrieb: Anlagen-Verkauf`, das Projekt in der Detailansicht liegt in
|
||
`Auftragsabwicklung SHK`, und ein Knopf schiebt es von der einen in die andere.
|
||
Das ist der Unterschied zwischen Vertriebs- und Abwicklungs-Projektmanagement,
|
||
und Slide 3 ist deshalb die Pointe des Beitrags. Möglich ist beides in einer
|
||
Software, weil die Felder an der Pipeline hängen und nicht am Programm — das
|
||
zeigt Slide 5.
|
||
|
||
**Alle Zahlen sind gerechnet, keine ist gesetzt.** Anzahl und Summe je Spalte
|
||
kommen aus denselben Datensätzen wie die Karten.
|
||
|
||
**Die Karte ist aus dem Code nachgebaut, nicht aus dem Screenshot.** Der erste
|
||
Anlauf war von `assets/screens/pipelines.png` abgemalt und lag an drei Stellen
|
||
daneben, die im Bild nicht zu erkennen waren. Der Rest steht in
|
||
[`POST-5.md`](./POST-5.md) §7.
|
||
|
||
> **Eine Richtigstellung.** Ein früherer Stand behauptete hier, die
|
||
> Detailansicht sei nur ein Entwurfs-PNG. Falsch: geprüft worden waren die
|
||
> Beschriftungen des Bildes `07_Screen-4b_Karten-Detail.png`, und die kommen im
|
||
> Code wirklich nicht vor — den Bildschirm gibt es trotzdem, unter
|
||
> `app/(screens)/4b/`, nur anders beschriftet. Die Abwesenheit einer
|
||
> Zeichenkette beweist die Abwesenheit eines Bildschirms nicht.
|
||
|
||
**Post 6 zeigt den Team-Chat**, nachgebaut aus `GeneralTeamChatPage` des
|
||
Pitch-Pakets. Anders als die Pipeline mit ihren vier eigenen Bildschirmen gibt
|
||
es vom Chat nur eine Fassung, unter `/allgemein/team-chat`. Die Inhalte darin
|
||
sind trotzdem aus dem Gewerk: Wärmepumpe Müller, Montagetermin,
|
||
Baustellenfotos.
|
||
|
||
| Slide | Was sie leistet |
|
||
|---|---|
|
||
| 1 | Kanalliste und Verlauf nebeneinander, mit Filterzeile und Eingabefeld |
|
||
| 2 | links das Durcheinander als Zeichnung, rechts die Kanalliste |
|
||
| 3 | Fotos, die Aufgabe daraus, die Bestätigung im Projekt |
|
||
| 4 | das Menü hinter dem Plus im Eingabefeld |
|
||
| 5 | zwei Ausschnitte der Oberfläche, versetzt übereinander, mit Absperrband |
|
||
|
||
**Slide 3 ist der Kern**, und sie ist keine Konstruktion: im Werkzeug folgen
|
||
die drei Nachrichten genau so aufeinander. Tobias schickt die Baustellenfotos,
|
||
darauf eine Nachricht mit angehängter Aufgabe, darauf die Systemzeile
|
||
„Aufgabe „Materialliste prüfen" im Projekt erstellt". Die letzte Zeile macht
|
||
den Unterschied: die Aufgabe liegt danach im Projekt, nicht nur im Verlauf.
|
||
|
||
**Slide 5 zeigt zwei Ausschnitte statt eines Geräts.** Die Machart ist die,
|
||
die Signal für solche Slides benutzt: zwei Teile der Oberfläche,
|
||
versetzt übereinander, jeder mit eigenem Schatten. Ein Zwischenstand hatte hier
|
||
ein nachgebautes Handy samt Insel und Tasten; das kostet viel Platz für etwas,
|
||
das nichts über das Produkt sagt, und der Rahmen war frei erfunden.
|
||
|
||
**Slide 2 stellt gegenüber statt zu zeigen:** links das Durcheinander als
|
||
Zeichnung, rechts die Oberfläche als Ausschnitt. Die linke Hälfte gibt es in
|
||
diesem Repo schon, in `post2.html` auf Slide 2 (`visProzesse`) — dort im
|
||
Zeichenblock-Stil, hier glatt. Die Plättchen sind Redaktionstext und keine
|
||
Produktstrings; sie beschreiben die Wirklichkeit im Betrieb.
|
||
|
||
**Die Leitung läuft über den Wisch hinweg:** sie beginnt links außerhalb der
|
||
Slide, und mit `visLeft: -102` landet dieses Stück auf Slide 1. Das ist der
|
||
Überstand, vor dem `rules.md` §5 sonst warnt — `.page` hat kein `overflow` —
|
||
hier aber gewollt. `pruef.mjs` liest einen negativen `--vis-left` als Ansage
|
||
und meldet ihn nicht mehr als Fehler.
|
||
|
||
Beide Ausschnitte auf Slide 5 sind leicht verwischt: erkennbar, aber nicht zu lesen.
|
||
Scharf bleibt allein das Band. Ein zweites Mittel von Slack, ein dicker gelber
|
||
Rahmen um die Anhangkarte auf Slide 3, ist wieder weg: die Karte trägt als
|
||
einzige eine gelbe Marke, der Blick geht ohnehin dorthin, und ein Rahmen sagt
|
||
nochmal, was die Anordnung schon sagt — [`POST-6.md`](./POST-6.md) §5c.
|
||
|
||
Dass die App noch nicht da ist, sagt das **Absperrband** von der Website:
|
||
`ChatDemoSection.tsx` hat es unter der Fahne `comingSoon`, -13° gedreht, in
|
||
`#F1B729` mit Kanten in `#171106`, darauf Schutzhelm und „BALD VERFÜGBAR". Auch
|
||
Überschrift und Fließtext sind die der Website; der Inhalt der Ausschnitte
|
||
kommt aus dem Pitch-Paket wie auf allen anderen Slides.
|
||
|
||
**Das Band läuft hinter die Ausschnitte** und ist an ihrer Silhouette
|
||
beschnitten — so hält es die Website auch, dort am Rand des Telefons. Es endet
|
||
damit nicht mehr quer zur eigenen Laufrichtung an der Bildkante, wie ein
|
||
Aufkleber, sondern an einer senkrechten Plattenkante, hinter der es
|
||
verschwindet. Die Schnittkante ist weicher als eine gezogene Linie und härter
|
||
als die unscharfen Platten.
|
||
|
||
**Und es legt sich um den Stapel, statt darauf zu liegen** — die größte
|
||
Abweichung von der Website in diesem Beitrag. Genau an der Plattenkante knickt
|
||
es um, läuft dahinter weiter und kommt an der Kante wieder hervor: tiefer,
|
||
weil es umgeschlagen ist, niedriger, weil es wegführt, flacher getönt, weil
|
||
man von dort seine Unterseite sieht. Ohne die zwei Festlichkeiten des
|
||
klassischen Spruchbands: keine Zacken, kein Bogen.
|
||
|
||
Die Stelle des Knicks wird dabei nicht gerechnet. Beide Stücke reichen weit in
|
||
die Platte hinein, und zwei Masken aus derselben Kontur schneiden sie an deren
|
||
Kante ab — die eine lässt die Fläche innen stehen, die andere die Stücke
|
||
außen, und ihre Deckungen ergänzen sich zu eins. Darüber liegt die Falzkante
|
||
als eigener Strich, senkrecht auf der Plattenkante und über beide hinweg. Drei
|
||
Anläufe hat es bis dahin gebraucht; woran die ersten beiden lagen, steht in
|
||
[`POST-6.md`](./POST-6.md) §5a.
|
||
|
||
**Die Tiefe kommt aus dem Stapel und gestaffelten Schatten, nicht aus
|
||
Flächen.** Ein Zwischenstand legte graue Flächen hinter die Elemente; das nimmt
|
||
den Zeichnungen ihre Durchsichtigkeit und setzt einen Kasten auf den
|
||
Punktgrund. Stattdessen zweierlei: die echten Schatten aus `ui/theme.css`, die
|
||
dort **gestaffelt** sind (enge dunkle Kante plus weite helle, in SVG zwei
|
||
`feDropShadow` im selben Filter), und der **Stapel** aus `post1.html`, in SVG
|
||
nachgebaut mit denselben Winkeln, die dort im CSS stehen. Die hinteren Blätter
|
||
sind leer: Andeutung, keine Kopie. Auf Slide 1 und 2, wo ein Bildschirm zu
|
||
sehen ist; nicht auf Slide 3, wo ein Ausschnitt einer Unterhaltung steht.
|
||
|
||
Dazu die Datumsmarke und die Zeile „Maike Berger schreibt gerade …" aus der
|
||
Quelle, die der Unterhaltung Struktur geben, ohne eine Fläche zu behaupten.
|
||
|
||
**Die Bildergalerie ist eine Anhangkarte, kein Bild.** Im Werkzeug lädt
|
||
`GalleryPreview` zwei Fotos von Unsplash. Fremde Fotos in einen Beitrag zu
|
||
setzen, der von der eigenen Baustelle spricht, wäre eine Behauptung über
|
||
Material, das wir nicht haben.
|
||
|
||
**Die vier Profilbilder sind Unsplash-Aufnahmen.** Sie liegen unter
|
||
`assets/eigene/` als `portrait-sk`, `-mb`, `-tw`, `-ms`, ausgewählt nicht nach
|
||
Gesicht, sondern nach Unterscheidbarkeit im Kreis von 42 px — dort zählt der
|
||
Gesamtwert und die Haarkontur, nicht die Züge.
|
||
|
||
Zum Absatz darüber steht das in einer Spannung, die benannt gehört: die
|
||
Unsplash-Lizenz deckt das Urheberrecht des Fotografen, **kein Model Release**.
|
||
Ein Zwischenstand wich deshalb auf erzeugte Gesichter aus und ist zugunsten
|
||
echter Aufnahmen zurückgenommen worden. Herkunft, Rechtslage und der einzige
|
||
Weg, der die Frage wirklich beseitigt, stehen in
|
||
[`POST-6.md`](./POST-6.md) §4.
|
||
|
||
Die vierzehn Partner-Marken liegen unter `assets/partner/` und sind, wie alles
|
||
andere hier, aus der Website **gespiegelt statt verlinkt**. Sechs davon sind
|
||
PNG und damit dieselbe Wette wie ein Screenshot (§7 in `rules.md`), deshalb
|
||
prüft der Export sie einzeln nach — `wabenZonen()` in `post3.html`.
|
||
|
||
Der Redaktionsplan für alle weiteren Beiträge liegt in
|
||
[`redaktionsplan/`](./redaktionsplan/), gebaut mit `python3 redaktionsplan/bauen.py`.
|
||
|
||
### Slides anlegen und wegnehmen
|
||
|
||
Wie viele Slides ein Post hat, steht nicht fest. Unter der Slide-Auswahl:
|
||
|
||
| Knopf | Wirkung |
|
||
|---|---|
|
||
| `+ Neu` | leere Slide dahinter einfügen |
|
||
| `Kopie` | die gewählte Slide samt Text, Bild und Verschiebungen verdoppeln |
|
||
| `Löschen` | die gewählte Slide wegnehmen (die letzte bleibt stehen) |
|
||
| `←` `→` | eine Position nach vorn oder hinten |
|
||
|
||
Bei einer einzigen Slide ist der Post ein **Einzelbild** — die Kopfzeile sagt
|
||
es, und der ZIP-Knopf verschwindet.
|
||
|
||
Unter **Inhalt (nur diese Slide)** stehen Tag, Überschrift, Fließtext und die
|
||
Auswahl des Screenshots. Getippt wird Text, keine Auszeichnung: `*Wort*` setzt
|
||
den Akzent, ein Zeilenumbruch bricht die Zeile um. Das Rahmenformat folgt beim
|
||
Wechsel automatisch dem Seitenverhältnis der gewählten Aufnahme.
|
||
|
||
> Die Tags sind gestalterisch ausgeblendet (`visibility: hidden` auf `.badge`).
|
||
> Der eingetippte Tag beschriftet deshalb vorerst nur den Slide-Knopf im
|
||
> Bedienfeld.
|
||
|
||
### Eigene Bilder importieren
|
||
|
||
Unter **Eigene Bilder** wählst du Dateien aus dem Finder, oder du ziehst sie
|
||
direkt auf eine Slide. Beim Ablegen wird das Bild dort zum **zweiten Bild** und
|
||
lässt sich im Bearbeiten-Modus frei schieben und in der Größe ändern; über den
|
||
Knopf importierst du nur und ordnest danach unter *Inhalt* zu.
|
||
|
||
Die Datei geht **byteweise unverändert** an den Server und liegt danach unter
|
||
`assets/eigene/`. Nichts wird neu kodiert, skaliert oder umbenannt — nur
|
||
Zeichen, die in einem Dateinamen nichts zu suchen haben, weichen einem
|
||
Bindestrich.
|
||
|
||
```
|
||
assets/eigene/ importierte Bilder, gehören mit in den Commit
|
||
```
|
||
|
||
> Der Umweg über den Server ist Absicht. Ein Foto als Base64 im Projektstand
|
||
> wäre größer als der gesamte übrige Stand und machte jeden Diff unlesbar. So
|
||
> steht dort nur der Pfad.
|
||
|
||
Die Auswahllisten unter *Inhalt* holt der Generator beim Start vom Server
|
||
(`/bilder`), importierte Bilder stehen deshalb sofort darin — mit `★`
|
||
gekennzeichnet.
|
||
|
||
**Mitgelieferte Slides bleiben Vorlagen.** Der Stand speichert für sie nur
|
||
einen Verweis und die Felder, die du überschrieben hast — eine Änderung an der
|
||
Vorlage im Code kommt dadurch weiterhin bei allen an, die sie nicht angefasst
|
||
haben. Selbst angelegte Slides stehen vollständig im Stand.
|
||
|
||
**Das Projekt speichert seinen Stand** — Einstellungen, Layouts, Muster und
|
||
alle Verschiebungen aus dem Canvas überleben einen Reload. „Projekt
|
||
zurücksetzen" wirft ihn weg.
|
||
|
||
### Der Stand liegt im Repo
|
||
|
||
Nicht nur im Browser: jede Änderung landet auch in `state/<projekt>.json`.
|
||
**Diese Dateien gehören mit in den Commit.** Nur so hat die andere Maschine
|
||
nach `git pull` denselben Stand.
|
||
|
||
```
|
||
state/post1.json Post 1 · Lösung
|
||
state/post1-merk.json Rückfallpunkt
|
||
```
|
||
|
||
Beim Laden gewinnt die Datei, der localStorage ist nur der Rückfall, wenn der
|
||
Server nicht läuft. Wer den Stand ändert, muss also committen und pushen —
|
||
sonst sieht ihn niemand sonst. Gibt es die Datei noch nicht, wird der Stand
|
||
aus dem Browser einmalig hineingeschrieben.
|
||
|
||
|
||
## Animation
|
||
|
||
Unter dem Canvas liegt in **jedem** Projekt, im selben Fenster, ein Bereich
|
||
„Animation". Er zeigt jede Animation als eigenes Blatt in Vorschau, mit
|
||
Zeitregler, `Abspielen` und `MP4 exportieren`.
|
||
|
||
**Ein Klick auf den Kopf klappt ihn zu**, dann bleibt eine Zeile von 40 px und
|
||
der Canvas hat den Platz. Ob er offen ist, merkt sich der Browser je Projekt
|
||
(`localStorage`) und nicht der Projektstand: es ist eine Vorliebe und keine
|
||
Gestaltung, sie hat in `state/<projekt>.json` nichts verloren, wo sie bei jedem
|
||
einen Diff machen würde.
|
||
|
||
**Eine Animation ist keine Slide.** Sie steht in `ANIMS` und nicht in
|
||
`SLIDES`, liegt also nicht im Streifen, taucht in der Slide-Auswahl nicht auf
|
||
und wird vom Bildexport nicht angefasst. Das ist der ganze Punkt: im Carousel
|
||
ist sie ein eigenes Element, und ob sie mitkommt, entscheidest du beim Posten.
|
||
|
||
```js
|
||
const ANIMS = [
|
||
{ key: "animChat", type: "feature", dauer: 6,
|
||
eyebrow: "Bewegtbild",
|
||
head: 'Getippt,<br><span class="a">und schon im Projekt.</span>',
|
||
body: "Eine Nachricht, ein Klick, und die Aufgabe hängt am richtigen Projekt.",
|
||
vis: "animChat", visW: 700, visLeft: 190, visBottom: 120 },
|
||
];
|
||
```
|
||
|
||
Dieselben Felder wie bei einer Slide, dazu `dauer` in Sekunden. Die
|
||
Zeichenfunktion aus `VIS` bekommt einen zweiten Wert `t` zwischen 0 und 1 und
|
||
zeichnet daraus den Stand zu diesem Zeitpunkt. Blatt, Überschrift,
|
||
Punktgrund und Schutzzone sind dieselben wie überall.
|
||
|
||
### Exportieren
|
||
|
||
**`MP4 exportieren`** im Bereich unter dem Canvas. Der Browser kann kein MP4
|
||
schreiben, also stößt die Seite den Bau auf dem Server an (`POST /anim`) und
|
||
fragt den Stand ab; die Zeile unter den Knöpfen zeigt den Fortschritt und am
|
||
Ende den Pfad. Getrennt vom Bildexport, in beide Richtungen: „Alle Slides als
|
||
ZIP" enthält kein Video, und dieser Knopf rendert kein Bild.
|
||
|
||
**Die Datei landet zweimal.** In `~/Downloads`, wie die Bilder, zum Hochladen.
|
||
Und in `animation/` im Repo, wo sie versioniert ist und nach einem Pull auf
|
||
der anderen Maschine liegt. In Downloads wird nichts überschrieben: eine
|
||
zweite Ausgabe heißt `…-1.mp4`, genau wie beim Bildexport.
|
||
|
||
Auf der Kommandozeile geht dasselbe:
|
||
|
||
```sh
|
||
./serve.sh # muss laufen
|
||
node animation.mjs post6.html # alle Animationen des Projekts
|
||
node animation.mjs post6.html animChat # nur diese
|
||
```
|
||
|
||
Heraus kommt `animation/post6-animChat.mp4` (auf der Kommandozeile nur dort,
|
||
ohne die Kopie in Downloads). Angesprochen wird die Animation
|
||
über ihren Schlüssel, nicht über eine Nummer: sie hat keine Position im
|
||
Streifen, die sich verschieben könnte.
|
||
|
||
Für die Aufnahme lädt das Skript die Seite als `?nur=anim&k=<key>`. In diesem
|
||
Modus zeigt sie allein das Blatt der Animation, in natürlicher Größe an 0,0 —
|
||
damit entfällt jede Ausschnittsrechnung.
|
||
|
||
### Was Instagram bei so einem Beitrag tatsächlich annimmt
|
||
|
||
Kurz: **ein MP4, kein GIF.**
|
||
|
||
| | |
|
||
|---|---|
|
||
| Format | MP4, H.264 High, `yuv420p`, `+faststart` |
|
||
| Maße | 1080 × 1350 (4:5), wie die Standbilder |
|
||
| Bildrate | 30 fps, Schlüsselbild jede Sekunde |
|
||
| Datenrate | rund 12 Mbit/s |
|
||
| Länge | mindestens 3 s, höchstens 60 s je Carousel-Element |
|
||
| Ton | eine stumme AAC-Spur |
|
||
|
||
Vier Dinge, die den Aufbau bestimmen:
|
||
|
||
- **GIF geht nicht.** Instagram nimmt keine GIF-Uploads an; die Datei landet
|
||
als Standbild. Was in der App wie ein animierter Beitrag aussieht, ist ein
|
||
kurzes Video.
|
||
- **Ein Video im Carousel wird kein Reel.** Seit 2022 wandert nur ein
|
||
*einzeln* geposteter Video-Beitrag automatisch in die Reels. Liegt das Video
|
||
in einem Carousel, bleibt der Beitrag ein Beitrag.
|
||
- **Der erste Beitrag im Carousel bestimmt den Ausschnitt für alle.** Ein
|
||
Element in einem anderen Seitenverhältnis wird beschnitten, nicht
|
||
eingepasst. Deshalb rendert die Animation in genau denselben 1080 × 1350 wie
|
||
jedes Standbild.
|
||
- **Eine stumme Tonspur muss mit.** Manche Upload-Wege lehnen ein Video ohne
|
||
Audiostrom ab. Die Spur kostet 128 kbit/s und erspart die Fehlersuche.
|
||
|
||
Die Bewegung läuft in Schleife. Das letzte Bild ist deshalb **nicht** dasselbe
|
||
wie das erste (`t = n / anzahl`, nicht `n / (anzahl − 1)`) — sonst steht der
|
||
Stoß eine Dreißigstelsekunde still.
|
||
|
||
|
||
## Bedienung
|
||
|
||
| Taste | Wirkung |
|
||
|---|---|
|
||
| `←` `→` | Slide wechseln (im Bearbeiten-Modus: Element verschieben) |
|
||
| `E` | Bearbeiten an/aus |
|
||
| `W` | Streifen ⇄ Einzelansicht |
|
||
| `V` | Variante hell/dunkel |
|
||
| `L` `M` `I` | Layout · Muster · Intensität |
|
||
| `C` `G` `T` | Durchgehend · Tag-Ausrückung · Perspektive |
|
||
| `D` `A` | Slide laden · alle als ZIP |
|
||
|
||
Im Bearbeiten-Modus lassen sich Elemente ziehen und mit den Pfeiltasten
|
||
pixelweise schieben (`⇧` = 10 px).
|
||
|
||
**Ein angeklicktes Element öffnet sein eigenes Feld rechts.** Damit ist die
|
||
Oberfläche geteilt: links die Slide und alles Allgemeine, rechts das eine
|
||
Element.
|
||
|
||
| Im Element-Feld | Wirkung |
|
||
|---|---|
|
||
| `Text` | Beschriftung des Elements, `*Wort*` setzt den Akzent |
|
||
| `Schrift` / `Breite`, `A−` `A+` | Größe |
|
||
| `X` `Y` | Stelle auf der Slide, gezählt ab der Mitte, bezogen auf die obere linke Ecke |
|
||
| `Ebene` | wie `z-index` — höher liegt weiter vorn. Leer heißt Standard |
|
||
| `Links` `Mitte` `Rechts`, `Oben` `Mitte` `Unten` | an der Slide ausrichten, 92 px Rand |
|
||
| `Position` / `Größe angleichen` | denselben Wert auf allen Slides |
|
||
| `Löschen` | nimmt es aus der Slide. Es taucht darunter als „… zurück" wieder auf |
|
||
|
||
**Der Streifen ist eine durchgehende Fläche.** Jede Slide trägt das gesamte
|
||
Blatt, ein Element lässt sich also über den ganzen Post schieben und nicht nur
|
||
in die Nachbar-Slide.
|
||
|
||
### Auf der Fläche bewegen
|
||
|
||
| Maus | Wirkung |
|
||
|---|---|
|
||
| Ziehen | Ausschnitt schieben |
|
||
| Rad | Zoomen, auf den Zeiger zu |
|
||
| `⇧` + Rad | Waagerecht schieben |
|
||
| Leertaste-Ziehen, mittlere Taste | Schieben, auch im Bearbeiten-Modus |
|
||
|
||
Ein gewöhnliches Mausrad genügt, ohne Zusatztaste. Im Bearbeiten-Modus zieht
|
||
die linke Taste das Element unter dem Zeiger — die Fläche schiebt man dort mit
|
||
gedrückter Leertaste oder der mittleren Taste. `Fit` unten rechts setzt den
|
||
Maßstab zurück.
|
||
|
||
## Aufbau
|
||
|
||
```
|
||
assets/
|
||
├── brand/ Wortmarke hell/dunkel, G-Marke (SVG + PNG), Wabe, Geerkens
|
||
├── partner/ die 14 Marken des Wabenfelds (DATEV, KWP, pds, Bauhow, Aircall,
|
||
│ Onepage, PandaDoc, Hallo Petra, Claude, OpenAI, Google Drive,
|
||
│ Google Calendar, MS Outlook, MS Teams)
|
||
├── mockups/ Geräte-Mockups (Displays ausgeknockt, Screenshot liegt dahinter)
|
||
├── screens/ Software-Screenshots
|
||
├── eigene/ selbst importierte Bilder
|
||
└── fonts/ Manrope 400–800, lokal
|
||
vendor/ html-to-image, JSZip
|
||
state/ Projektstände, gehören ins Repo
|
||
animation.mjs baut aus einem ANIMS-Eintrag ein MP4 (braucht ffmpeg)
|
||
animation/ die fertigen MP4s, ein Carousel-Element je Datei
|
||
serve.py Statischer Server + /save, /state, /upload, /bilder, /anim
|
||
rules.md Gestaltungsregeln, Farbwerte, Export-Wissen
|
||
```
|
||
|
||
### Assets werden nachgefragt, nicht neu geladen
|
||
|
||
Ein Bild, das unter demselben Namen ausgetauscht wird, muss sofort ankommen —
|
||
sonst arbeitet man gegen eine alte Kopie. Dafür stand auf allem `no-store`:
|
||
im Server und noch einmal in `preloadAssets()`. Der Browser durfte nichts
|
||
behalten.
|
||
|
||
Das Ziel war richtig, der Preis zu hoch. Jeder Reload lud alles neu, und weil
|
||
`uebersicht.html` die sechs Projekte als iframes lädt und jeder iframe für
|
||
sich vorlud, kam die Seite auf **38 MB in 435 Anfragen**.
|
||
|
||
`no-cache` leistet dasselbe billiger: der Browser behält seine Kopie, fragt
|
||
aber vor jeder Benutzung nach. Eine ausgetauschte Datei kommt genauso sofort
|
||
an, eine unveränderte kostet ein 304 ohne Rumpf — und die sechs iframes teilen
|
||
sich eine Kopie statt sechs zu ziehen.
|
||
|
||
| | vorher | jetzt |
|
||
|---|---|---|
|
||
| `uebersicht.html`, erster Aufruf | 38,1 MB | 2,2 MB |
|
||
| `uebersicht.html`, Reload | 32,8 MB | 1,9 MB |
|
||
| `post6.html`, Reload | 5,4 MB | 0,3 MB |
|
||
|
||
Nachgeprüft ist beides: unverändert antwortet der Server mit `304` und
|
||
0 Bytes, nach einem `touch` mit `200` und der vollen Datei. **Seite, Stand und
|
||
Auskünfte (`/bilder`, `/state`) bleiben bei `no-store`** — die sind klein und
|
||
dürfen nie aus einer Kopie kommen.
|
||
|
||
## Regeln
|
||
|
||
**`rules.md` ist die Arbeitsgrundlage.** Farbwerte, Geometrie, Typografie,
|
||
Layout-Template, Instagram-Export und die Liste der Fallen, in die wir schon
|
||
getappt sind. Vor jeder Änderung an der Gestaltung dort nachsehen.
|
||
|
||
Marken-Werte stammen aus der Website (`HiveGrid-Website`) und sind hier
|
||
**gespiegelt**, nicht verlinkt. Ändert sich dort etwas, muss es hier
|
||
nachgezogen werden.
|