Files
posts/video/README.md
T
dejanandClaude Opus 5 e02e87b7e2 Video: das Wabenfeld baut sich auf, gerenderte Dateien raus
Das Video ist geschnitten. Die Einblendungen liegen auf einer externen
Platte, im Repo bleibt die Werkbank: 381 Dateien und 24 MB gerenderte
Ausgabe sind raus, png/ und sequenz/ legt bauen.mjs beim naechsten Lauf
selbst wieder an.

WABENFELD
Es blendete als Ganzes auf, und das ist bei der einen Zeichnung, die
etwas behauptet, zu wenig. Jetzt steht zuerst die Nabe, dann wachsen die
Waben in fuenf Wellen nach aussen, und die Straenge ziehen jeweils kurz
nach ihrer Zelle nach. Rueckwaerts zieht sich das Feld in die Marke
zurueck, statt von aussen zu zerfallen.

Die Bewegung ist die introTimeline aus HoneycombSection.tsx, uebernommen
und nicht erfunden: scale 0,16 auf 1, back.out(1.75), gestaffelt nach
Abstand zur Mitte, danach die Straenge mit eigener Deckungsrampe. Weil
unsere Belegung nur fuenf verschiedene Abstaende kennt, sind es fuenf
Wellen und nicht achtzehn Einzelereignisse, und das liest sich als eine
Bewegung.

Dafuer brauchte der Zeitverlauf ein zweites Mass. Bisher frass der
Verzug vom Rest der Zeit: die letzte von achtzehn Zellen haette ein
Zehntel der Zeit fuer dieselbe Bewegung gehabt und waere hereingeschnappt,
waehrend die erste hereinschwebt. Mit data-d bekommt ein Element ein
eigenes Fenster fester Laenge. Ohne data-d bleibt alles wie es war, die
anderen neun Komponenten laufen unveraendert durch den alten Pfad.

50 Bilder statt 12, bei 25 fps also zwei Sekunden herein und 1,2 hinaus.
Die Bewegung ist bei 0,94 fertig, die letzten Bilder stehen still. Masse
und Ausschnitt sind unveraendert, 2168 x 1906.

DIE PNGS WAREN IN DER ERSATZSCHRIFT
KOMP_BEREIT wartete auf document.fonts.ready, bevor die Karte im DOM
stand. Zu dem Zeitpunkt braucht die Seite keine Manrope, es laeuft kein
Ladevorgang, und das Versprechen loest sofort auf -- erfuellt, ohne dass
ein Byte Schrift da waere. Danach wurde gebaut, und ob die Schrift bis
zur Messung ankam, 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 frueher als dort
beschrieben. document.fonts.load() holt eine Schriftlage unabhaengig
davon, ob gerade jemand sie benutzt, erst danach ist ready eine Aussage.
Dieselbe Wette steckte in der Wortmarke von logo-bug, einem img mit
width:auto, deshalb wartet der Aufbau jetzt auch auf die Bilder.

Sieben der zehn zuletzt gebauten Dateien waren betroffen und 2 bis 4
Prozent zu schmal. Die reinen Zeichnungen verraten es nicht, ihr SVG hat
feste Masse -- ring-kern war gegen einen frischen Render bildgleich.

STANDBILD KOMMT AUS DER SEQUENZ
Der Dreiteiler im Schnitt haengt daran, dass -ein, Standbild und -aus an
den Stoessen dasselbe Bild zeigen. Als zweite Aufnahme war das bisher nur
wahr, weil es zufaellig stimmte. Beim Wabenfeld stimmte es nicht mehr:
dort tragen die Zellen waehrend der Bewegung ein transform, und nach dem
Wegnehmen rastert Chrome eine Spur anders als bei einem Element, das nie
eines hatte. Der Unterschied lag bei einer Stufe auf verstreuten Pixeln,
also unsichtbar, aber die Zusage war weg. bauen.mjs schreibt das
Standbild jetzt aus dem letzten Bild der Einblendung: dieselbe Datei
statt derselbe Anblick.

NEBENBEI
- Bauchbinde Betrieb, Chip "Vierte Generation" und Endkarte sind raus.
  Die Bauchbinde liess sich ueber ?name= und ?rolle= ohnehin aus der
  ersten erzeugen, ein Schlussbild gehoert in den Schnitt und nicht als
  Einblendung darauf.
- Das Wabenfeld steht ohne das blasse Feld aus leeren Waben. Auf dem
  weissen Blatt traegt das die Zeichnung, ueber Videomaterial ist ein
  Schleier aus halbdurchsichtigen Sechsecken im Weg. Der Ausschnitt wird
  seitdem aus den belegten Waben gerechnet. In post3.html bleibt beides.
- strangForm() heisst hier strangPfad() und liefert nur den Pfad: die
  Form muss je Bild neu gerechnet werden, weil ein Ende wandert. In den
  Post-Seiten bleibt strangForm(), die Rechnung darin ist dieselbe.
- liste.json und README stehen auf dem Stand der zehn Komponenten.

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

185 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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, und dafür braucht es ffmpeg. Das ist hier
nicht installiert, und eine Bildsequenz kann Premiere genauso importieren.
- **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.