Was macht ipad_code?
Der Nutzer hat nur ein iPad und Claude Code, keinen Computer. Die Cloud-Session ist der Computer, und die zusätzlichen Sessions sind die Renderfarm. Diese Skill beschreibt den Weg, den wir getestet haben, um einen 10-Sekunden-Clip mit Cycles in 1080×1920 von Grund auf bis zur Veröffentlichung zu erstellen, mit allen Problemen und Lösungen.
Schreibe dem Nutzer auf einfachem Arabisch. Er hat einen kleinen Bildschirm, also halte deine Nachrichten kurz und sende ihm Bilder und Videos mit SendUserFile anstatt sie zu beschreiben.
$SK in dieser Datei bedeutet das Skill-Verzeichnis (das Verzeichnis, in dem sich diese Datei befindet). Lege es zuerst fest:
SKILL_MD=$(ls -d ~/.claude/skills/ipad_code/SKILL.md .claude/skills/ipad_code/SKILL.md 2>/dev/null | head -1)
[ -n "$SKILL_MD" ] || echo "ipad_code is not installed: follow START.md"
SK=$(dirname "$SKILL_MD")
0. Vor allem
Lese .claude/ipad_code.json.
- Vorhanden: Folge der darin enthaltenen Benutzerstufe (
level:new,someodertech;guidance:explainoderresults). Die Tabelle in START.md erklärt, was jede Stufe bedeutet. Frage nicht erneut nach. - Nicht vorhanden: Der Nutzer ist neu. Führe START.md von Anfang an aus.
Regel für alle Stufen: Was du tun kannst, tu es. Bitte den Nutzer nicht, Befehle auszuführen.
Wähle den Pfad:
| Der Nutzer bat um | Pfad | Zeit |
|---|---|---|
| Motion-Graphics, animierte Texte, Infografiken, einfache Werbung, oder keine Angabe und dies ist sein erster Clip | Der schnelle Pfad, Schritt 1.5 | Minuten |
| 3D, Blender, Zerlegung oder Zoom in ein reales Objekt | Blender, ab Schritt 2 | Stunden |
1. Was hast du in der Cloud-Session
Messen, nicht annehmen: bash $SK/scripts/doctor.sh.
Was wir gefunden haben: 4 CPU-Kerne, 15 GB RAM, keine GPU, Python 3.13, ffmpeg, Node, Chromium mit Playwright bereit. Pip- und npm-Pakete installieren normal, Google Fonts sind verfügbar. Blender ist nicht vorhanden, die Lösung unten.
| Was der Computer normalerweise macht | Alternative in der Session | Skript |
|---|---|---|
| Blender (Programm) | Blender als Python-Bibliothek von pip (bpy) ohne GUI, Cycles-Rendering auf CPU mit OpenImageDenoise | setup_blender.sh, render.py |
| Vorschau der Arbeit mit dem Auge | Miniaturansichtsseite aus Frames oder Video, dann als Bild lesen und an den Nutzer senden | contact.sh |
| After Effects (arabischer Text auf Video) | Chromium zeichnet Text mit Cairo-Schriftart aus Google Fonts mit korrekter arabischer Vokalisation als transparente PNGs | text_cards.js |
| Soundeffektbibliothek | Per Code generierter Sound: Dröhnen, Whooshes (die dem Zoom folgen), Schläge, Glanzlichter und ein "Start"-Moment | sound.py |
| Premiere (Komposition und Export) | ffmpeg: Frames, Texte mit Überblendung, Audio auf -14 LUFS, H.264 | assemble.py |
| Leistungsstarke Rendering-Workstation | Renderfarm: parallele Cloud-Sessions, jede mit 4 Kernen | farm.py + references/farm.md |
| Erzählerstimme und Musik | ElevenLabs via MCP, vorschlagen bei jedem Clip (Schritt 1.6). Skill نبرة ist nicht Teil dieser Skill, also wenn nicht vorhanden, ohne weitermachen | |
| Dateiübergabe | SendUserFile zeigt eine Karte in der App, von der aus der Nutzer das Video in den Fotos speichert | |
| Motion-Graphics (After Effects) | HTML-Seite, in der alles von der Zeit abhängt, Chromium rendert sie Frame für Frame | motion.js |
1.5 Der schnelle Pfad: Motion-Graphics mit Code
Ohne Blender und ohne langes Warten. Geeignet für den ersten Clip.
export NODE_PATH=$(npm root -g)
node -e "require('playwright').chromium.launch().then(b=>b.close()).catch(()=>process.exit(1))" 2>/dev/null || { npm i -g playwright && "$NODE_PATH/playwright/cli.js" install chromium; }
P=<Projektordner innerhalb von scratchpad>; mkdir -p $P
cp $SK/assets/examples/motion/comp.html $SK/assets/examples/motion/sound.json $P/
~/.snd-venv/bin/python -c "import numpy" 2>/dev/null || { python3 -m venv ~/.snd-venv && ~/.snd-venv/bin/pip install -q numpy; }
- Bearbeite
$P/comp.html: Texte inBEATS, Farben inCOLORS, und gestalte die Zeichnung indrawFieldunddrawRingbasierend auf der Clip-Idee. Lass nicht jeden Clip eine Kopie der Vorlage sein; die Vorlage ist ein Ausgangspunkt. - Alles muss eine Funktion von
tinnerhalb vonseek(t)sein: ohne CSS-Animationen, ohne Timer, ohneMath.randomohne Seed. - Text innerhalb von x200–880 und y270–1400 für vertikale Clips, damit die Reels- und TikTok-Buttons ihn nicht überdecken.
- Vorschau (Kontakt):
LiesNODE_PATH=$(npm root -g) node $SK/scripts/motion.js $P/comp.html $P/preview --fps 30 --seconds 8 --step 40 bash $SK/scripts/contact.sh $P/contact.png $P/preview/f_*.pngcontact.pngselbst, behebe, was du siehst, und sende es an den Nutzer. Fahre nicht fort, bevor er zustimmt. - Rendering, Sound und Komposition:
Timing vonNODE_PATH=$(npm root -g) node $SK/scripts/motion.js $P/comp.html $P/frames --fps 30 --seconds 8 ~/.snd-venv/bin/python $SK/scripts/sound.py $P/sound.json $P/sound.wav python3 $SK/scripts/assemble.py --frames $P/frames --fps 30 --audio $P/sound.wav --out $P/final.mp4 bash $SK/scripts/contact.sh $P/check.png $P/final.mp4 1 3.5 6sound.jsonauf die Anfänge vonBEATS. Das Format jedes Feldes ist am Anfang vonsound.pydokumentiert, lies es also vor der Bearbeitung (z. B.glintsdrei Zahlen:[Start, Ende, Anzahl]). Wenn du die Dauer änderst, ändereDURATION,durationund--secondszusammen. - Übergabe gemäß Schritt 8.
1.6 Der Erzähler
Schlage ihn bei jedem Clip vor, es sei denn, der Nutzer sagt, er will ihn nicht.
- ElevenLabs ist nicht verbunden: Sag ihm, er kann es in den Claude-Einstellungen verbinden und dass dies ein Konto bei ihnen erfordert, und fahre mit dem Clip mit Soundeffekten fort, bis er es verbindet. Frage ihn nicht nach einem API-Key im Chat.
- Vor der Generierung: Sag ihm, dass es von seinem Guthaben abgezogen wird, und hole seine Zustimmung. Wenn mehr als eine Version erstellt wird, verwende die erste, es sei denn, er wünscht eine andere.
- Standardstimme:
nhJWWCFdNdusuVUT3x19, es sei denn, er bittet um eine andere. Wenn es von seinem Konto aus nicht funktioniert, wähle eine Stimme, die seinem Dialekt nahe kommt, und sag ihm, welche Stimme du gewählt hast. - Dateidownload: Wenn ein 403 zurückkommt, verwende
get_environmentund dannupdate_environmentmitadd_allowed_hosts: ["elevenlabsusercontent.com"]; dann erscheint eine Zustimmungsanfrage. - Timing: Miss die Audiolänge mit
ffprobe, und setzeDURATION,durationund--secondsmindestens 0,5 Sekunden länger; stimmeBEATSmit dem Anfang jedes Satzes ab (silencedetectgibt dir die Pausen).
Füge den Erzähler über den Soundeffekten vor assemble.py hinzu:
ffmpeg -y -i $P/sound.wav -i $P/voice.mp3 -filter_complex "[0:a]volume=0.35[bed];[bed][1:a]amix=inputs=2:duration=first:normalize=0[out]" -map "[out]" -ar 48000 $P/mix.wav
Übergib dann --audio $P/mix.wav anstelle von sound.wav.
2. Baue das Projekt
bash $SK/scripts/setup_blender.sh # ~30 Sekunden, gibt aus: Blender 5.2.3 ... OK
P=<Projektordner innerhalb von scratchpad>
~/.bpy-venv/bin/python <build.py> $P # Schreibt $P/scene.blend
- Die Szene wird mit einem Python-Skript (
build.py) erstellt, dasscene.blendschreibt. Vollständiges und getestetes Beispiel: assets/examples/transistor/build.py (Zoom von einem Prozessor auf dem Motherboard bis zu einem FinFET-Transistor), mit Lösungen für Probleme bei großen Zooms: logarithmische Kameradistanz,clip_startändert sich mit der Distanz, Oberfläche verschmilzt mit Alpha, und ein "Tal" wird ausgeschnitten, durch das die Kamera fährt, ohne etwas zu treffen. - Vertikal für Reels: 1080×1920, 24 fps. 24 reichen aus und sparen 20 % Renderingzeit im Vergleich zu 30.
- Erfolgreiche Einstellungen: Cycles auf CPU, adaptives Sampling, OpenImageDenoise, AgX, leichtes Motion Blur und
use_persistent_data. - Verwende für die Beleuchtung ausschließlich Sonne (Sun) für Szenen, deren Größe sich stark ändert, da die Sonne nicht von der Entfernung beeinflusst wird. Füge kleine Punktlichter für Details hinzu.
- Emission brennt schnell durch mit AgX. Beginne mit einem Wert zwischen 0,5 und 1,5.
3. Schaue vor dem Rendern (Kontakt)
~/.bpy-venv/bin/python $SK/scripts/render.py $P/scene.blend --out $P/preview --frames 1-240/30 --pct 40 --samples 24
bash $SK/scripts/contact.sh $P/contact.png $P/preview/f_*.png
Lies contact.png selbst, sende es dann an den Nutzer. Behebe, was du siehst (verbrannte Beleuchtung, Kamera stößt an, leere Einstellung), und baue neu. Rendere nicht vollständig, bevor der Nutzer der Vorschau zustimmt.
4. Berechne die Zeit und entscheide
Rendere den schwersten Frame (normalerweise am Ende des Clips) in voller Auflösung und Qualität:
~/.bpy-venv/bin/python $SK/scripts/render.py $P/scene.blend --out $P/timing --frames 175,240 --pct 100 --samples 28
Gesamtzeit ungefähr = Anzahl der Frames × 0,75 × Zeit des schwersten Frames. In unserem Test war der schwerste Frame 100 bis 150 Sekunden, also 240 Frames ≈ 7 Stunden auf einem Gerät.
- Weniger als 90 Minuten: Rendere hier im Hintergrund (Schritt 5).
- Mehr als das: Schlage die Farm vor (Schritt 6). Sag dem Nutzer, wie viele Geräte, wie lange es dauert, dass jedes Gerät von seinem Nutzungslimit verbraucht (ungefähr ein halber Dollar Token pro Gerät in unserem Test), und dass die Frames auf temporären Branches in seinem Repository hochgeladen werden, die er selbst löschen muss. Starte die Farm erst nach seiner Zustimmung und der von ihm festgelegten Anzahl von Geräten.
5. Lokales Rendern
~/.bpy-venv/bin/python $SK/scripts/render.py $P/scene.blend --out $P/frames --frames 1-240 --pct 100 --samples 28 >> $P/render.log 2>&1
- Führe es mit einem Bash-Tool und
run_in_backgroundmit maximalem Timeout aus. Verwende nicht&, da der Prozess zwischen den Befehlen stirbt. - Der Hintergrundbefehl stoppt nach zwei Stunden, und danach darfst du ihn nicht selbst neu starten. Teile daher das Rendering in Batches auf, die jeweils weniger als 90 Minuten dauern (z. B.
--frames 1-120dann121-240). Das Skript überspringt fertige Frames, also setzt das erneute Ausführen desselben Befehls dort fort, wo es aufgehört hat. - Verfolge den Fortschritt in
render.log, der die ETA für jeden Frame enthält.
6. Die Renderfarm (mehrere Geräte)
Die detaillierten Schritte sind in references/farm.md. Du benötigst ein Repository und Tools zur Session-Verwaltung (create_session und Verwandte). Wenn du sie nicht hast, sag dem Nutzer, dass die Farm in seiner Session nicht verfügbar ist, und rendere auf einem Gerät in Batches oder schlage eine niedrigere Qualität vor. Kurz gefasst:
python3 $SK/scripts/farm.py precheck --blend $P/scene.blend; wennTOO BIGausgegeben wird, reduziere die Szene vor dem Hochladen. Wenn das Repository öffentlich ist, frage den Nutzer um Erlaubnis, da die Frames für alle sichtbar werden.- Lade
scene.blend,render.pyundsetup_blender.shauf einen Funktionsbranch (orphan) namensrender-jobhoch. python3 $SK/scripts/farm.py plan --frames 1-240 --have $P/frames --workers Nverteilt die fehlenden Frames abwechselnd, damit schwere Frames gleichmäßig aufgeteilt werden.- Für jedes Gerät:
create_sessionauf dem Repository mitsource_revision: render-job,outcome_branch: render-out-wNNund dem Prompt vonfarm.py prompt --samples <gleicher Wert wie beim endgültigen Rendern>, da die Szenendatei möglicherweise mit einem viel höheren Wert gespeichert ist. - Die Session, die fertig wird, benachrichtigt dich nicht zurück. Plane für dich selbst eine Überprüfung mit
send_laternach 25 bis 30 Minuten und überprüfe mitget_sessionundfarm.py collect. - Jedes Gerät, das stoppt, ohne etwas hochzuladen: Sende ihm
send_message, um fortzufahren. Gleichzeitig rendere seine fehlenden Frames hier von hinten nach vorne; nimm die vom ersten, das fertig ist. - Nachdem alle Frames vollständig sind, archiviere die Sessions mit
archive_session. Sag dem Nutzer, er soll die Branchesrender-jobundrender-out-w*von der GitHub-Branches-Seite löschen, da die Session keine Branches löschen kann.
7. Text, Sound und Komposition
NODE_PATH=$(npm root -g) node $SK/scripts/text_cards.js cards.json $P/text
~/.bpy-venv/bin/python $SK/scripts/sound.py sound.json $P/sound.wav
python3 $SK/scripts/assemble.py --frames $P/frames --fps 24 --cards cards.json --textdir $P/text --audio $P/sound.wav --out $P/final.mp4
bash $SK/scripts/contact.sh $P/check.png $P/final.mp4 1 3.5 6 9
- Fertige Beispiele: cards.json und sound.json. Timing von Text und Sound auf die gleichen Szenenereignisse (Sekunde = Framenummer ÷ fps).
- Text: maximal 5 Wörter pro Zeile, innerhalb von x200–880 und y270–1400, damit die Reels-Buttons ihn nicht überdecken.
text_cards.jsverkleinert großen Text, um ihn anzupassen, und schlägt fehl, wennFONT NOT LOADEDoderOUTSIDE SAFE AREAausgegeben wird; behebe die Ursache und ignoriere es nicht. - Du hörst nicht. Überprüfe den Sound mit Zahlen:
ffmpeg -i sound.wav -af ebur128=peak=true -f null -und mit dem Spektrum:showspectrumpic. Sag dem Nutzer, worauf er beim Hören achten soll. - Überprüfe vor der Übergabe: Lies
check.pngund stelle sicher, dass die Texte in jeder Einstellung sichtbar sind. assemble.py --upto Nerstellt einen Entwurf aus den fertigen Frames. Sende ihn an den Nutzer, während du auf das Rendern wartest.
8. Die Übergabe
SendUserFilemit dem Video unddisplay: render. Auf dem iPad öffnet der Nutzer es von der Karte, dann teilen, dann "Video speichern".- Scratchpad-Dateien werden gelöscht, wenn die Session endet. Übergib das Video vorher; wenn der Nutzer später bearbeiten möchte, lade die Projektskripte (nicht die Frames) auf seinen Branch hoch.
- Letzte Nachricht: Was wurde gemacht, die Spezifikationen und was noch an ihm liegt (z. B. Löschen der Branches).
Probleme, die wir hatten
Alle in references/pitfalls.md. Lies sie vor dem ersten langen Render.