Jedes Projekt hat jetzt unter dem Canvas einen Bereich "Animation", im selben Fenster. Er zeigt jede Animation als echtes Blatt in Vorschau, mit Zeitregler, Abspielen und "MP4 exportieren". 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. Im Carousel ist sie ein eigenes Element, und ob sie mitkommt, entscheidet sich beim Posten. Ein erster Anlauf machte sie zur sechsten Slide; damit war sie in der Zaehlung und im ZIP mit drin. Der Export laeuft ueber den neuen Endpunkt POST /anim in serve.py. Er startet animation.mjs in einem eigenen Faden, die Seite fragt den Stand ueber GET /anim?id= ab und zeigt Fortschritt und Pfad. Ein Browser kann kein MP4 schreiben, und eine offene Anfrage ueber zwei Minuten geht nicht -- zumal sich animation.mjs waehrenddessen selbst Seiten von diesem Server holt. Aufgenommen wird im neuen Modus ?nur=anim&k=<key>: dort zeigt die Seite allein das Blatt der Animation, in 1080 x 1350 an 0,0. Damit entfaellt jede Ausschnittsrechnung und mit ihr die Falle, dass ein zu schmales Fenster ein leeres Bild liefert. Als erstes Beispiel post6-animChat, fuenf Sekunden: die Antwort wird Zeichen fuer Zeichen getippt, abgeschickt, waechst als Blase in den Verlauf, die Aufgabenkarte klappt auf, die Systemzeile bestaetigt, alles blendet zurueck auf den Anfang. Getippt wird VERLAUF[3].text, also die Nachricht, die im Werkzeug an dieser Stelle ohnehin folgt. H.264 High, yuv420p, 1080 x 1350, 30 fps, stumme AAC-Spur, +faststart: das nimmt Instagram fuer ein animiertes Element im Carousel an. GIF nicht, das landet als Standbild. Ein Video im Carousel wird auch kein Reel, das passiert nur bei einem einzeln geposteten Video. Nebenbei: - post4, post5 und post6 trugen im Panel noch den Kopf ihrer Vorlage. - video/README.md und video/bauen.mjs behaupteten, ffmpeg sei hier nicht installiert. Stimmt seit 9.0.1 nicht mehr; die Bildsequenz bleibt dort trotzdem, mit Begruendung. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
188 lines
9.7 KiB
Markdown
188 lines
9.7 KiB
Markdown
# Video-Komponenten
|
||
|
||
Einblendungen für den Videoschnitt, in derselben Bildsprache wie die Posts:
|
||
weiße Karten mit Haarlinie und weichem Schatten, ein gelber Akzent, Manrope.
|
||
Gedacht für Noahs Beitrag über den Betrieb, taugt aber für jeden Schnitt.
|
||
|
||
Jede Komponente liegt zweimal vor — als **Standbild** und als **Bildsequenz**
|
||
mit fertiger Ein- und Ausblendung. Alles mit Alphakanal, alles freigestellt:
|
||
kein Rand, keine Leinwand, keine Farbe hinter der Karte.
|
||
|
||
```
|
||
video/
|
||
├── komponenten.html die Vorlage, hier steht die Gestaltung
|
||
├── bauen.mjs rendert daraus die Dateien
|
||
├── liste.json was zuletzt gebaut wurde, mit Maßen
|
||
├── png/ Standbilder
|
||
└── sequenz/ je Komponente ein Ordner "-ein" und einer "-aus"
|
||
```
|
||
|
||
## In Premiere holen
|
||
|
||
**Standbild:** `png/<name>.png` in die Timeline ziehen. Ein- und Ausblendung
|
||
machst du selbst über Position und Deckkraft. Das ist der flexiblere Weg.
|
||
|
||
**Sequenz:** *Datei → Importieren*, im Ordner `sequenz/<name>-ein/` das **erste**
|
||
Bild anklicken und unten **„Bildsequenz"** ankreuzen. Premiere legt daraus
|
||
einen einzigen Clip an, nicht 20 Einzelbilder.
|
||
|
||
> **Eine Bildsequenz hat keine eigene Bildrate.** Die Dateien wissen nichts
|
||
> davon, wie schnell sie laufen sollen — Premiere vergibt sie beim Import aus
|
||
> *Einstellungen → Medien → Zeitbasis für unbestimmte Medien*. Ab Werk stehen
|
||
> dort meist 30 fps. Was das für die Dauer heißt, steht in der Tabelle unten.
|
||
> Ändern lässt es sich jederzeit: Rechtsklick auf den Clip im Projektfenster →
|
||
> *Ändern → Videomaterial interpretieren → Bildrate annehmen*. Die Bewegung
|
||
> wird davon nur schneller oder langsamer, nie ruckelig — es liegt für jedes
|
||
> Bild eine eigene Datei vor.
|
||
|
||
Der übliche Aufbau im Schnitt sind drei Teile hintereinander:
|
||
`<name>-ein` → `png/<name>.png` beliebig lang gezogen → `<name>-aus`.
|
||
Das letzte Bild von `-ein` und das erste von `-aus` sind das Standbild, die
|
||
Stöße sind also unsichtbar. Alle drei Teile haben dieselben Maße und denselben
|
||
Bildausschnitt — was du am ersten an Position und Größe einstellst, kannst du
|
||
auf die beiden anderen einfügen (*Bearbeiten → Einfügen → Attribute*).
|
||
|
||
Der Alphakanal kommt mit. Kein Keying, keine Maske, kein Mischmodus: die Karte
|
||
liegt auf einer eigenen Spur über dem Bild und der Rest ist durchsichtig.
|
||
|
||
### Dauer je Komponente
|
||
|
||
| Komponente | Bilder ein / aus | bei 25 fps | bei 30 fps |
|
||
|---|---|---|---|
|
||
| `bauchbinde-noah` | 20 / 12 | 0,80 s / 0,48 s | 0,67 s / 0,40 s |
|
||
| alle `satz-*` | 18 / 11 | 0,72 s / 0,44 s | 0,60 s / 0,37 s |
|
||
| beide `stapel-*` | 22 / 13 | 0,88 s / 0,52 s | 0,73 s / 0,43 s |
|
||
| `ring-kern` | 12 / 7 | 0,48 s / 0,28 s | 0,40 s / 0,23 s |
|
||
| `logo-bug` | 14 / 8 | 0,56 s / 0,32 s | 0,47 s / 0,27 s |
|
||
| `wabenfeld` | **50 / 30** | **2,00 s / 1,20 s** | **1,67 s / 1,00 s** |
|
||
|
||
Mehr Bilder heißt längere Bewegung, nicht flüssigere: die Staffelung steckt in
|
||
Anteilen des Verlaufs, nicht in Zeitwerten. Wer eine langsamere Einblendung
|
||
will, erhöht `bilder` bei der Komponente in `komponenten.html` und baut neu.
|
||
|
||
**Das Wabenfeld tanzt aus der Reihe, und das ist Absicht.** Alle anderen
|
||
Einblendungen setzen ein Stichwort, während Noah spricht — die dürfen nichts
|
||
wollen und blenden deshalb schlicht auf. Das Wabenfeld ist das Bild zur
|
||
Aussage und baut sich auf: die Nabe steht, dann wachsen die Waben in fünf
|
||
Wellen von innen nach außen, und die Stränge ziehen jeweils kurz danach nach.
|
||
Rückwärts zieht sich alles wieder in die Marke zurück.
|
||
|
||
Die Bewegung ist die `introTimeline` aus `HoneycombSection.tsx` der Website,
|
||
nicht neu erfunden: `scale` von 0,16 auf 1, `back.out(1.75)`, gestaffelt nach
|
||
Abstand zur Mitte, danach die Stränge mit einer eigenen Deckungsrampe. Wer an
|
||
der Zeitrechnung dreht, findet sie als `WABE_ZEIT` in `komponenten.html`.
|
||
|
||
> **Nicht skalieren, wo es nicht sein muss.** Die Dateien sind in doppelter
|
||
> Größe gerendert (`FAKTOR` in `bauen.mjs`). In einer Zeitleiste mit
|
||
> 1920 × 1080 setzt du sie also auf rund 50 % — dann sitzt jeder Pixel, und
|
||
> nach oben ist bis 4K Luft.
|
||
|
||
## Was es gibt
|
||
|
||
| Schlüssel | Was es zeigt | Wofür im Skript |
|
||
|---|---|---|
|
||
| `bauchbinde-noah` | Noah Geerkens · Gründer | wenn er sich vorstellt |
|
||
| `satz-erp-bleibt` | „Dein ERP **bleibt**." | der Einwand, direkt beantwortet |
|
||
| `satz-kein-ersatz` | „Kein **Ersatz**." / „Der Aufbau drumherum." | die Kernaussage |
|
||
| `satz-miteinander-reden` | „Die Tools reden **miteinander**." | was gefehlt hat |
|
||
| `satz-handwerksalltag` | „Kein **Startup**-Projekt." | der Abbinder |
|
||
| `stapel-haengt-drin` | Stammdaten · Aufträge · Buchhaltung | was einen Wechsel unmöglich macht |
|
||
| `stapel-was-fehlte` | KI-Lösungen · CRM · Automatisierungen | was sie wollten |
|
||
| `ring-kern` | der Kern bleibt, HiveGrid liegt darum | „kein Ersatz, sondern der Aufbau drumherum" |
|
||
| `wabenfeld` | die Marke in der Mitte, die Programme drumherum | „dass die Tools endlich miteinander reden" |
|
||
| `logo-bug` | Wortmarke für die Ecke | durchgehend oder am Anfang |
|
||
|
||
> Eine Bauchbinde für den Betrieb ließ sich über `?name=` und `?rolle=` ohnehin
|
||
> aus der ersten erzeugen und ist deshalb weg, mit ihr der Stempel „Vierte
|
||
> Generation". Eine Endkarte gab es auch einmal — ein Schlussbild gehört in den
|
||
> Schnitt und nicht als Einblendung darauf.
|
||
|
||
**Wenig Text ist Absicht.** Noah spricht das Skript, die Einblendung setzt das
|
||
Stichwort. Zwei Sätze auf einer Karte lesen sich nicht, während jemand redet.
|
||
|
||
## Texte ändern
|
||
|
||
Die Texte hängen an der Adresse, nicht am Code. Server starten (`./serve.sh`),
|
||
dann zum Beispiel:
|
||
|
||
```
|
||
http://127.0.0.1:4321/video/komponenten.html?k=satz-erp-bleibt&zeile=Dein *CRM* bleibt.
|
||
http://127.0.0.1:4321/video/komponenten.html?k=bauchbinde-noah&name=Lena Geerkens&rolle=Geschäftsführung
|
||
```
|
||
|
||
`*Wort*` setzt den gelben Akzent, **höchstens einer je Zeile** (rules.md §4).
|
||
Welche Felder eine Komponente kennt, steht bei ihr unter `felder` in
|
||
`komponenten.html`. `?alle=1` zeigt alle nebeneinander auf einem Karo-Grund.
|
||
|
||
Wer einen geänderten Text als Datei braucht, trägt ihn in `komponenten.html`
|
||
ein und baut neu — die Adresse wirkt nur im Browser.
|
||
|
||
## Neu bauen
|
||
|
||
```sh
|
||
./serve.sh # muss laufen, in einem zweiten Terminal
|
||
node video/bauen.mjs # alles
|
||
node video/bauen.mjs bauchbinde satz # nur passende Schlüssel
|
||
```
|
||
|
||
Ein paar Entscheidungen, die dahinterstehen:
|
||
|
||
- **Bildsequenz statt Video mit Alphakanal.** Ein Video mit echter
|
||
Transparenz wäre ProRes 4444. Als das hier entstand, war kein ffmpeg auf der
|
||
Maschine; inzwischen schon (siehe `animation.mjs` im Wurzelverzeichnis).
|
||
Geblieben ist die Bildsequenz trotzdem: Premiere importiert sie genauso, sie
|
||
behält die Transparenz ohne Codec-Frage, und jedes Einzelbild lässt sich
|
||
ansehen. Ein ProRes-Ausgang wäre jetzt möglich, ist aber kein Gewinn.
|
||
- **Node statt Python**, anders als sonst im Repo. Gebraucht wird eine
|
||
Steuerverbindung zu Chrome, und die hat Node ohne Zusatzpaket an Bord.
|
||
Chrome pro Einzelbild neu zu starten wäre die Alternative gewesen — bei rund
|
||
380 Bildern sind das zehn Minuten Warten für nichts.
|
||
- **Der Ausschnitt wird gemessen, nicht angegeben.** `KOMP_KASTEN()` misst
|
||
nach dem Rendern, was tatsächlich dasteht, und legt 52 px Zugabe drumherum:
|
||
der Schatten liegt außerhalb der Box, und was aufblendet, startet 26 px
|
||
tiefer. Ohne die Zugabe schneidet das PNG beides ab.
|
||
- **Die Ausblendung ist die Einblendung rückwärts**, nur kürzer. Ein eigener
|
||
Ausgang sähe eine Spur besser aus und kostete doppelt so viele Bilder.
|
||
|
||
## Drei Fallen, in die wir hier schon getappt sind
|
||
|
||
**`document.fonts.ready` war erfüllt, bevor es etwas zu laden gab.** Die Seite
|
||
hat auf die Schrift gewartet, *bevor* die Karte im DOM stand — zu dem Zeitpunkt
|
||
brauchte niemand Manrope, es lief also kein Ladevorgang, und das Versprechen
|
||
löste sofort auf. Danach wurde die Karte gebaut, Chrome fing an zu laden, und ob
|
||
es bis zur Messung fertig war, entschied der Zufall. Dieselbe Komponente
|
||
hintereinander gemessen kam abwechselnd 984 und 1010 px breit heraus.
|
||
|
||
Das ist die Falle aus `rules.md` §4, nur eine Ebene früher: dort steht „auf
|
||
`document.fonts.ready` warten", und genau das tat die Seite — nur zu früh.
|
||
`document.fonts.load()` holt eine Schriftlage unabhängig davon, ob gerade jemand
|
||
sie benutzt; erst danach ist `ready` eine Aussage. Dieselbe Wette steckt in
|
||
jedem `<img>` mit `width:auto`, deshalb wartet der Aufbau jetzt auch auf die
|
||
Bilder.
|
||
|
||
> **Woran man es merkt:** an den Maßen in `liste.json`. Eine Komponente, die
|
||
> beim Neubau plötzlich 2 bis 4 Prozent schmaler wird, hat keine Textänderung
|
||
> hinter sich, sondern die Ersatzschrift. Die reinen Zeichnungen (`ring-kern`,
|
||
> `wabenfeld`) verraten es nicht — ihr SVG hat feste Maße.
|
||
|
||
**Der Schatten war nicht da.** Die Karte trug `clip-path` für die
|
||
abgeschnittenen Ecken und `box-shadow` für den Schatten — und `clip-path`
|
||
beschneidet den Schatten mit. Genau so steht es in `rules.md` §3, und genau so
|
||
ist es passiert. Am gerenderten PNG fiel die Deckung an der Kartenkante von
|
||
255 auf 0, ohne einen einzigen Zwischenwert. Der Schatten sitzt jetzt als
|
||
`filter: drop-shadow()` auf einer Hülle. Nebenbei folgt der der Alphamaske und
|
||
legt sich um die abgeschnittenen Ecken herum statt um ein Rechteck.
|
||
|
||
**`inset(0 0 0 0)` ist nicht dasselbe wie kein Beschnitt.** Die Einblendung
|
||
zieht die Karte über `clip-path: inset()` von links auf. Am Ende steht dort
|
||
rechnerisch null — das schneidet aber weiterhin exakt auf die Box und kappt
|
||
damit wieder den Schatten. Bei vollem Verlauf fällt der Beschnitt deshalb ganz
|
||
weg.
|
||
|
||
## Was fehlt
|
||
|
||
Der Grund, warum die Marken im Wabenfeld sitzen, steht in `rules.md` §3
|
||
unter *Wabenfeld*. Wer dort etwas ändert, muss an drei Dateien denken:
|
||
`post2-alt.html`, `post3.html` und diese hier. Das ist der Preis dafür, dass
|
||
jede Datei für sich lauffähig bleibt.
|