youtube/remotion
2026-11-07 09:14:44 +00:00
..
public Neue Noa-Posen: Hand als Hase und als Igel (hockend) 2026-11-06 09:54:35 +01:00
src Geräusch „klick“ (Lämpchen der Laterne, Folge 8 Szene 3) angelegt und erzeugt 2026-11-07 09:14:44 +00:00
werkzeuge render.mjs: Untertitel wieder eingebrannt (Entscheidung Nutzerin 06.11.: Eltern lesen mit), --ohne-untertitel zum Abschalten 2026-11-06 08:12:26 +00:00
.gitignore Folge 1: Geräusche synchron, Lied in DE/ES/FR gesungen (Suno) 2026-11-04 12:54:39 +01:00
ANLEITUNG_PC.md Remotion: Baukasten für alle Folgen, Szenen einzeln renderbar, Stimmen-Skript 2026-10-29 18:43:56 +00:00
package-lock.json Stimmen-Skript auf offizielles ElevenLabs-SDK und eleven_v4 umgestellt (Sprache je Aufnahme, Schlüssel aus .env.local) 2026-11-02 22:14:31 +01:00
package.json Stimmen-Skript auf offizielles ElevenLabs-SDK und eleven_v4 umgestellt (Sprache je Aufnahme, Schlüssel aus .env.local) 2026-11-02 22:14:31 +01:00
README.md Stand 04.11.2026: Folge 2 FR auf dem VPS gerendert (alter Refrain), Render-Hinweis Chrome-Bibliotheken 2026-11-04 11:07:11 +00:00
tsconfig.json Remotion-Test: Szene „Noas Laterne“ aus freigestellten Figuren 2026-10-28 19:20:01 +00:00

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

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:

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

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

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.

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

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.