youtube/remotion/README.md
2026-11-04 11:07:11 +00:00

185 lines
10 KiB
Markdown
Raw Permalink 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.

# Remotion – Szenen aus Figuren-Grafiken
Animiert die freigestellten Figuren (Pino, Noa, Lulu) per Code, ohne
Higgsfield-Clips. Erster Test: `LaterneTest` (14 s, Abendspaziergang mit
Noas Laterne, ohne Ton).
## Aufbau
| Pfad | Inhalt |
| --- | --- |
| `public/figuren/` | freigestellte PNGs der Figuren |
| `src/figuren.ts` | Bildmaße, Augenpositionen (fürs Blinzeln), Noas Hand |
| `src/teile/Figur.tsx` | Figur an den Füßen verankert: verschieben, drehen, stauchen, blinzeln |
| `src/teile/Laterne.tsx` | Laternenstab mit pendelnder Papierlaterne |
| `src/teile/Abendhuegel.tsx` | Hintergrund in Aquarell-Optik (SVG), Vordergrund, Papierstruktur |
| `src/szenen/LaterneTest.tsx` | die Testszene mit Zeitplan |
## Benutzen
```bash
npm install
npx remotion studio # Vorschau im Browser
npx remotion render src/index.ts LaterneTest /shared/youtube/tests/laterne-test.mp4
```
Fertige Videos gehören nach `/shared/youtube/`, nicht ins Git.
Im VPS-Container fehlen Chrome einige Systembibliotheken. Sie liegen ohne
Root-Rechte unter `~/.local/chrome-libs` (Debian-Pakete, nur entpackt) und
werden so eingebunden:
```bash
export LD_LIBRARY_PATH=$HOME/.local/chrome-libs/root/usr/lib/x86_64-linux-gnu
```
Fehlt der Ordner (neuer Container, kein `apt`-Index): Paketliste
`https://deb.debian.org/debian/dists/bookworm/main/binary-amd64/Packages.xz`
laden, daraus die Pfade von libnss3, libnspr4, libatk1.0-0, libatk-bridge2.0-0,
libatspi2.0-0, libxcomposite1, libxdamage1 holen, die `.deb` von
`https://deb.debian.org/debian/<Pfad>` laden und mit
`dpkg-deb -x <paket>.deb ~/.local/chrome-libs/root` entpacken. Welche
Bibliotheken fehlen, zeigt `ldd node_modules/.remotion/chrome-headless-shell/linux64/chrome-headless-shell-linux64/chrome-headless-shell | grep "not found"`.
## Figuren freistellen
Mit `rembg` (Modell `isnet-general-use`), danach Maske härten, nur die größte
Fläche behalten, Rand um 2 px einziehen (sonst heller Saum vor dunklem
Hintergrund). Am besten funktionieren Einzelbilder vor hellem Papier.
## Körperteil-Masken (Rig)
`werkzeuge/rig.py` zerlegt jede Figur in Körperteile und erzeugt:
| Pfad | Inhalt |
| --- | --- |
| `public/figuren/<figur>/teile/<teil>.png` | harte Maske, genau an der Kontur |
| `public/figuren/<figur>/einfluss/<teil>.png` | weiche Maske für die Verformung: Teil + alles, was daran hängt, weicher Übergang am Gelenk, reicht über die Kontur hinaus |
| `public/figuren/<figur>/uebersicht.png` | alle Teile farbig, zum Prüfen |
| `src/rigs.ts` | Gelenkpunkte und Hierarchie (automatisch erzeugt) |
Teile: Lulu – kopf, hals, ohr_links/rechts, horn_links/rechts, rumpf,
bein_vorne_links/rechts, bein_hinten_links/rechts, schwanz, schal_schlinge,
schal_ende, schal_boden. Pino – koerper, kopf, ohr_links/rechts, bauch,
arm_links/rechts, fuss_links/rechts, muetze, bommel. Noa – kopf,
zopf_links/rechts, rumpf, arm_links/rechts, hand_links/rechts,
bein_links/rechts, stiefel_links/rechts.
Zuordnung: Accessoires über ihre Farbe, alles andere über Kernflächen pro
Teil, die bis zur Kontur wachsen – nur innerhalb der Figur, also nie über
Lücken (Schwanz ↔ Bein). Neue Figur oder neues Bild: Skelett und Flächen in
`rig.py` eintragen, dann
```bash
python3 werkzeuge/rig.py # braucht numpy, scipy, pillow
```
und `uebersicht.png` prüfen. In einer Szene: `gelenk('lulu', 'hals', grad)`
(siehe `src/szenen/VerformTest.tsx`).
## Folgen bauen (Baukasten)
Eine Folge besteht aus Szenen, jede Szene aus Sprechzeilen und Bewegungen,
die an diesen Zeilen hängen. Alles Wiederverwendbare liegt in
`src/baukasten/`, jede Folge hat einen eigenen Ordner (`src/folge02/`).
Untertitel stehen für die Stimmen, solange es keine Aufnahmen gibt;
Mitmach-Pausen zeigen ein „?“.
| Pfad | Inhalt |
| --- | --- |
| `src/baukasten/figur.tsx` | `Figur` (Standbilder mit Posenwechsel), `ClipFigur` (freigestellte Clips), `Kamera` |
| `src/baukasten/helfer.tsx` | Kamerafahrt, Atmen, Gehen, Hüpfen, Wackeln, Blenden, Ankerpunkte |
| `src/baukasten/natur.tsx` | Blätter, Nest, Vögel, Schnee, Zzz, Funkeln, große Rufe |
| `src/baukasten/orte.tsx` | Orte als SVG (Garten Tag/Nacht, Blick von oben, Noas Zimmer, Kalender); vorberechnet nach `public/orte/` |
| `src/baukasten/buch.tsx` | Bilderbuch-Intro und -Outro |
| `src/baukasten/zeit.ts` | Zeitplan aus den Zeilen (geschätzt oder aus den Aufnahmen) |
| `src/baukasten/untertitel.tsx` | Untertitel, Mitmach-Pause, Stimmen abspielen |
| `src/baukasten/folge.tsx` | macht aus der Szenenliste die Kompositionen |
| `src/baukasten/posen.ts` | automatisch erzeugt von `werkzeuge/posen.py` |
| `src/baukasten/sprache.ts` | gewählte Sprache und die Wörter des Baukastens je Sprache |
| `src/folge02/` | Folge 2: `Folge02.tsx` (Szenenliste), `szene2.tsx` … `szene7.tsx`, `lied.tsx`, `plan.ts`, `texte/<sprache>.json` (Sprechtexte), `stimmen/<sprache>.json` (Aufnahmen) |
| `public/bibliothek/figuren/` | freigestellte Standbilder (WebP, im Git) |
| `public/bibliothek/clips/` | freigestellte Clips (WebM mit Alpha, nicht im Git; VPS: Link auf `/shared/youtube/figuren_bibliothek/clips_frei/`) |
| `public/stimmen/` | Sprachaufnahmen (nicht im Git; VPS: Link auf `/shared/youtube/stimmen/`) |
**Kompositionen:** `F02` ist die ganze Folge, `F02-01-Intro`,
`F02-02-Gaehnen-ueberall` … jede Szene einzeln.
**Neue Folge:** Ordner `src/folgeNN/` anlegen, `plan.ts` aus Folge 2 kopieren,
`stimmen/de.json`, `es.json`, `fr.json` mit `{}` anlegen, `texte/<sprache>.json`
mit den Sprechtexten füllen, Ordnernamen anpassen, Szenen nach dem
Muster von `szene2.tsx` schreiben (oben die Zeilen mit `plane('sX', [...])`,
darunter Posenfolgen und Kamerafahrt, die sich auf `z.<zeile>.start/ende`
beziehen), in `FolgeNN.tsx` auflisten und in `src/Root.tsx` eintragen.
### Rendern
```bash
node werkzeuge/render.mjs F02 --entwurf # schnelle Fassung zum Begutachten
node werkzeuge/render.mjs F02 # volle Qualität
node werkzeuge/render.mjs F02 --szene 3 # nur Szene 3 neu
```
Mit `--sprache es` bzw. `fr` entsteht die jeweilige Fassung (siehe unten).
Das Skript rendert jede Szene einzeln nach `out/F02/<sprache>/` und klebt sie
zusammen. Szenen, deren Code, Bilder oder Aufnahmen sich nicht geändert
haben, werden übersprungen. Im Entwurf stehen oben links Gesamtzeit, Szene,
Szenenzeit und Zeilen-ID – für Rückmeldungen einfach diese Angaben nennen
(z. B. „2:47, Szene 4, Zeile l1: Lulus Kopf zu weit links“).
Auf dem VPS: vorher `export LD_LIBRARY_PATH=$HOME/.local/chrome-libs/root/usr/lib/x86_64-linux-gnu`.
### Vorschau ohne Rendern
`npx remotion studio` öffnet alle Kompositionen im Browser; Änderungen am
Code sind sofort zu sehen. Anleitung für einen Windows-PC: `ANLEITUNG_PC.md`.
### Sprachen (DE, ES, FR)
Die Sprechtexte stehen **nur** in `src/folgeNN/texte/de.json`, `es.json`,
`fr.json` (Titel der Folge, Liedtitel und jede Zeile unter ihrem Schlüssel
`szene/zeile`, z. B. `s2/e1`). Die Szenendateien enthalten nur Ablauf und
Bewegung: `{id: 'e1', wer: 'ERZ'}` ohne Text. Wörter, die der Baukasten selbst
mitbringt (Kanalname, „Heute: …“, Sprechernamen im Untertitel, Kalendertitel,
„Hatschi!“), stehen in `src/baukasten/sprache.ts`.
Die Sprache wird beim Rendern gewählt; der Zeitplan richtet sich nach der
Länge der Texte bzw. Aufnahmen dieser Sprache, die Bewegungen rutschen mit.
```bash
npx tsx werkzeuge/texte.mts F02 # fehlt in einer Sprache etwas?
npx tsx werkzeuge/texte.mts F02 --tabelle # alle Sprachen nebeneinander zum Gegenlesen
node werkzeuge/render.mjs F02 --sprache es # spanische Fassung → out/F02/F02-es.mp4
npx remotion studio --props='{"sprache":"fr"}'
```
Orte mit Schrift im Bild (bisher nur `kalender`) gibt es je Sprache als
`public/orte/kalender_es.webp` usw. (vorberechnen mit
`--props='{"sprache":"es"}'`). Fehlt eine Übersetzung, zeigt der Untertitel
`[fehlt: s2/e1]`.
### Stimmen (ElevenLabs)
1. Stimmen-IDs je Sprecher in `werkzeuge/stimmen.config.json` eintragen
(`ALLE` und `NOA_LULU` verweisen auf einen anderen Sprecher). Andere Stimmen
für eine Sprache unter `"sprachen": {"es": {"stimmen": {"ERZ": "…"}}}`.
2. `npx tsx werkzeuge/stimmen.mts F02 --probe` zeigt, welche Zeilen erzeugt
würden, und zählt die Zeichen (kostet nichts).
3. `ELEVENLABS_API_KEY=… npx tsx werkzeuge/stimmen.mts F02 --sprache es` erzeugt die
Aufnahmen nach `public/stimmen/folge02/es/` und trägt ihre Länge in
`src/folge02/stimmen/es.json` ein (ohne `--sprache`: Deutsch). Der Zeitplan richtet sich danach; ändert
sich ein Text, wird nur diese Zeile neu erzeugt.
Untertitel ausblenden: `--props='{"untertitel": false}'` (bzw. in
`render.mjs` die `props.json`).
### Neue Standbilder oder Clips
```bash
python3 werkzeuge/freistellen.py <zielordner> bild1.png … # ohne Zuschneiden
python3 werkzeuge/clip_freistellen.py <arbeitsordner> <clips_frei> clip1.mp4 …
python3 werkzeuge/posen.py <zielordner> <clips_frei> # Posen und Clips eintragen
```
Mit `pip install "rembg[gpu]"` nutzt `rembg` eine Nvidia-Grafikkarte
automatisch (auf dem VPS gibt es keine; dort ca. 3 s pro Bild).
Orte neu vorberechnen (nach Änderungen in `orte.tsx` bzw. am Nest in `natur.tsx`):
`npx remotion still src/index.ts F2Ort-garten public/orte/garten.webp --image-format=webp`
Bilder mit durchsichtigem Hintergrund (Zimmerwand, Tisch, Nest) als PNG
rendern (`--image-format=png`): Remotions WebP-Ausgabe speichert keine
Transparenz.
### Was das Rendern bremst
Gemessen im Entwurf (halbe Auflösung, 4 Kerne auf dem VPS): die meisten
Szenen schaffen 3,5–5,5 Bilder/s. Teuer sind viele einzeln gezeichnete
Elemente (z. B. über 70 Blätter im Nest) und CSS-Filter oder Mischmodi über
das ganze Bild. Darum: Fertiges wie das Nest als Bild vorberechnen
(`F2Nest-…`), Filter nur auf die Figuren legen (`filter`-Prop von `Figur`/
`ClipFigur`/`Nest`), keine `mixBlendMode`-Ebenen über das ganze Bild.
## Bekannte Grenzen
- Die Figuren haben nur die Pose ihres Bildes. Neue Posen brauchen ein neues
Bild (z. B. aus Gemini).
- Die SVG-Filter im Hintergrund werden pro Frame neu berechnet und machen das
Rendern langsam. Für lange Folgen die Hintergrund-Ebenen einmal als PNG
vorberechnen.