Communitygithub.com

devlucasalm/motion-promo-video-skill

Erstellt hochwertige Motion-Design-Promovideos (9:16 / 16:9, 60fps, mit SFX/Musik) für Produkte, SaaS, Uhren etc. basierend auf HTML+Playwright+ffmpeg. Ideal für Motion-Design-Aufträge, Werbevideos, Reels, animierte Promos.

Was ist motion-promo-video-skill?

Dieses Skill generiert professionelle Motion-Promovideos in MP4 (H.264, yuv420p, AAC) aus HTML+Playwright+ffmpeg. Es unterstützt die Formate 9:16 (1080×1920, Standard) und 16:9 (1920×1080) mit 60fps und einem deterministischen HTML-Rendering-Ansatz. Der Workflow umfasst die Vorbereitung von Assets (z. B. Hintergrundentfernung mit rembg, Upscaling von Screenshots mit Lanczos), eine PHP-basierte Engine mit einem globalen `seek(T)`-Mechanismus für frame-genaue Animationen und eine synthetische Audioerzeugung mit numpy/scipy. Für die Renderpipeline wird Playwright Chromium verwendet, um Screenshots zu erstellen, die dann per ffmpeg zu Videosegmenten zusammengefügt werden – mit 2 parallelen Prozessen und Wiederaufnahme-Feature. Der Benutzer kann über die Timeline (variable Geschwindigkeit) und verschiedene SFX-Profile (jugendlich/SaaS vs. premium/edel) den Stil steuern. Das Skill wurde für Aufgaben wie Werbevideos, Reels und animierte Promos entwickelt und ist besonders geeignet für Use Cases, bei denen eine konsistente, hochwertige Motion-Design-Ästhetik ohne manuelles Nachbearbeiten erforderlich ist.

Funktioniert mit~Claude Code~Codex CLI~Cursor
npx skills add devlucasalm/motion-promo-video-skill

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Motion-Promo-Video (HTML → MP4)

Lieferung: Fertiges MP4 (H.264, yuv420p, AAC), gesendet per SendUserFile. Antwort auf Deutsch (kurz und prägnant).

1. Minimales Briefing (nicht zu viel nachfragen)

Als Standard definieren und nur das abfragen, was das Ergebnis ändert:

  • Format: 9:16 (1080×1920) Standard; 16:9 (1920×1080) auf Wunsch. Dauer: Insta-Anzeige 20–35 s; Pacing: LANGSAM (jeder Schritt ~1,5–4 s) – der Benutzer hat bereits kritisiert, dass es „wie 2x“ wirkt.
  • Zielgruppe: jung/SaaS → helle SFX (Glocken, Pops, Klicks). Älteres/premium Publikum (Uhren, Schmuck) → dezent: Pads, sanfte Impacts, Whooshes, Shimmers; KEIN kindischer Pop.
  • Marke: Palette, Schriftart, Logo, CTA (WhatsApp/URL), Screenshots/Fotos. Musik: Wenn der Benutzer einen bestimmten Titel (Spotify etc.) erwähnt, rufen Sie das Audio NICHT ab – weisen Sie darauf hin, verwenden Sie die Original-Track und bieten Sie an, sie zu synchronisieren, wenn er die MP3 sendet (und erinnern Sie an die Lizenz für Werbung).

2. Assets vorbereiten

  • Produktfotos: Hintergrund mit rembg (Modell isnet-general-use) entfernen → PNG mit Alpha für 3D-Effekt (schweben, rotateY/rotateX mit Perspektive, Glanz sheen maskiert durch das Alpha des PNG via -webkit-mask-image).
  • Niedrigauflösende Screenshots: Upscaling mit Lanczos 3× + Unscharf maskieren. Entfernen Sie Werbetexte aus dem Originalfoto, wenn der Benutzer „ohne Werbung“ wünscht.
  • Schriftarten: Inter / Inter Display ExtraBold (SaaS, flacher Stil), Lora Serif + Gold-Kursiv (Premium), Poppins.

3. Vom Benutzer genehmigter Stil

  • Flächige Farbblöcke, große Karten, gigantische Typografie mit maskiertem Wort-Reveal, viel kontinuierliche Bewegung (langsamer Parallax, langsamer Zoom 1→1.15, Sterne/Partikel), Schnitte durch Wipes mit 3 farbigen Panels, synchron zum Beat.
  • KEINE Kamerawackler (Benutzer hat abgelehnt): Shake maximal ×0.12, keine Kamerarotation, Drift ≤3 px.
  • Narrative Struktur: Haken/Problem → Lösung → 2–3 Features/Integration → Beweis/Nutzen → CTA. Jede Szene 3–5 s, Wipe zwischen den Szenen. Bei SaaS das PROBLEM konkret zeigen (unbeantwortete Nachricht, verlorener Umsatz −R$) vor der Lösung.
  • Kurze Texte, 2–4 Wörter pro Zeile, auf Deutsch, mit einem hervorgehobenen Wort (Farbe/Kursiv). Safe Zone von Instagram respektieren (~250 px oben und ~400 px unten bei 9:16 für CTA/Untertitel vermeiden).

4. Engine (deterministisch, HTML)

Eine Datei video.html mit window.seek(T), die ALLES in Abhängigkeit von der Zeit T positioniert (ohne requestAnimationFrame/CSS-Animationen). Kern:

const cl=(x,a=0,b=1)=>Math.min(b,Math.max(a,x)),lerp=(a,b,p)=>a+(b-a)*p;
const E={outBack:(p,c=1.8)=>1+(c+1)*Math.pow(p-1,3)+c*Math.pow(p-1,2),outExpo:p=>p>=1?1:1-Math.pow(2,-10*p),outQuart:p=>1-Math.pow(1-p,4),inOutQuart:p=>p<.5?8*p**4:1-Math.pow(-2*p+2,4)/2,inOutCubic:p=>p<.5?4*p**3:1-Math.pow(-2*p+2,3)/2,lin:p=>p,inCubic:p=>p**3,inOutSine:p=>-(Math.cos(Math.PI*p)-1)/2};
const ez=(T,a,d,f=E.outExpo)=>f(cl((T-a)/d));
function mk(parent,html,cls='',style=''){const d=document.createElement('div');d.className='abs '+cls;d.style.cssText=style;d.innerHTML=html;parent.appendChild(d);return d} // .abs{position:absolute;left:50%;top:50%}
function P(el,o){const x=o.x||0,y=o.y||0,s=o.s==null?1:o.s,op=o.o==null?1:o.o,r=o.r||0,rx=o.rx||0,ry=o.ry||0;el.style.transform=`perspective(2400px) translate(-50%,-50%) translate(${x}px,${y}px) rotateX(${rx}deg) rotateY(${ry}deg) rotate(${r}deg) scale(${s})`;el.style.opacity=op;el.style.visibility=op<=.003?'hidden':'visible'}
function words(el,arr){el.innerHTML=arr.map(w=>`<span class="mk"><span class="wd ${w[1]||''}">${w[0]}</span></span>`).join(' ')} // .mk{display:inline-block;overflow:hidden;padding:.14em .05em .24em;margin:-.14em -.05em -.24em}
function lineIO(el,T,tin,tout,step=.1,d=1.0){[...el.querySelectorAll('.wd')].forEach((w,i)=>{const a=ez(T,tin+i*step,d,E.outQuart),b=tout?ez(T,tout+i*step*.5,.5,E.inCubic):0;w.style.transform=`translateY(${(1-a)*118-b*118}%)`;w.style.opacity=cl(a*2.2,0,1)*(1-b)})}
function addScene(a,b,bg,build,upd,cam){/* erstellt div.sc mit bg, inner; scenes.push({a,b,root,inner,obj:build(inner),upd,cam}) */}
function runScenes(T){/* anzeige nur wenn T in [a-.02,b+.02]; inner.style.transform=translate/scale der cam(t,T); s.upd(t,obj,T) */}
// wipes: 3 Panels [dunkle Farbe, Gold/Akzent, Hintergrundfarbe der nächsten Szene], jedes ez(T,t0+i*.09,.38,E.inOutQuart) beim Ein- und Auslaufen (t0=wipe-.55); Richtung x / xr wechseln
function seek(T){runScenes(T);drawWipes(T);drawFX(T);drawGrain(T);/* schwarzer Fade am Ende */}

Feste Ebenen über der Welt: Canvas für Staub/Partikel, Wipes, Filmkorn (Alpha .07), Vignette, schwarzer Schleier für Ein-/Ausblendungen. 3D-Produkteffekt: P(hero,{ry:Math.sin(T*.7)*8, rx:Math.sin(T*.5)*3, y:Math.sin(T*1.1)*14, s}) + sweep() (Glanzstreifen mit mix-blend-mode:soft-light, maskiert durch das PNG) + radialer Gold-Glow dahinter + Schatten drop-shadow. Uhr-ähnlicher Intro (vom Benutzer in v1 der Uhren genehmigt): SVG 760 px mit 60 Ticks (alle 5 dicker/golden), goldenem Bogen, der sich zeichnet (stroke-dashoffset), Zeiger, der alle 0,5 s um 6° mit E.outBack vorrückt, bereits durchlaufene Ticks leuchten auf; Text „Die Zeit vergeht für jeden. / Wenige hinterlassen Spuren.“; kleine Sterne ✦, die sich drehen. Dieses thematische Intro wiederverwenden, wenn das Produkt es erlaubt. Timeline mit variabler Geschwindigkeit: SEG=[[start,ende,faktor],…], angewendet in seek UND in der Funktion M(t) des Audios, damit die SFX den Schnitten folgen.

5. Rendering (deterministisch, fortsetzbar)

  • Playwright Chromium Viewport 1080×1920 (oder 1920×1080), page.evaluate('seek(t)') + screenshot(type='jpeg',quality=92).
  • 60 fps mit Bewegungsunschärfe: 2 Unterframes pro Frame (t=(f+(s+.5)/2-.5)/60), Mittelwert in numpy float32 → JPEG q95 → ffmpeg -f image2pipe -c:v mjpeg -i - -c:v libx264 -preset fast -crf 18 -pix_fmt yuv420p seg/NNNNN.mp4.
  • Chunks von 120 Frames in seg/, 2 parallele Prozesse (gerade/ungerade Chunks), vorhandene Chunks überspringen (Container kann neu starten). Ausführen mit setsid nohup ./go.sh & und Monitor mit until-Schleife in einer done-Datei (Sleep im Vordergrund wird blockiert; Monitor nach 30 min Inaktivität reaktivieren). ~0,38 s pro Screenshot, 2 CPUs: 24 s ≈ 1440 Frames ≈ 25–30 min.
  • Nur den Anfang geändert? Nur betroffene Chunks löschen und neu rendern; wenn nur das Audio geändert wurde, remuxen mit -c:v copy.
  • Concat: ffmpeg -f concat -safe 0 -i list.txt -i audio.wav -c:v libx264 -crf 21 -pix_fmt yuv420p -c:a aac -b:a 192k -shortest -movflags +faststart out.mp4.
  • Vor dem vollständigen Rendern 2–4 Screenshots von seek() zu Schlüsselzeiten machen und Textabschnitte/Überlauf in beiden Formaten PRÜFEN (ist schon bei zu großer Schrift vorgekommen) und JS-Fehler (page.on('pageerror')).

6. Audio (numpy/scipy, synthetisiert)

Helfer: lp/hp/bp (butter), add(buf,t,x,g), tt(d); Sounds: thump (Sinus 46–96 Hz abfallend), impact (thump+Rauschen lp 700), riser (Rauschen mit ansteigendem Band), swish (Rauschen bp 1.8–5.5 kHz, sin²-Fenster), shimmer (inharmonische Teiltöne mit Abklingen), tick (Sinus ~900 Hz, decay 90), pad (3 verstimmte Sinus lp 1.4 kHz mit Fade), pluck; Hall durch Faltung mit abklingendem Rauschen.

  • SaaS/jung: helle Glocken, Pops, Klicks, Whooshes – KEINE schweren Bässe verwenden (Benutzer hat „alles Bass“ abgelehnt).
  • Premium/alt: Riser+Impact bei Wipes, Swish bei Text-Reveals, Shimmer beim Produkt-Eintritt, Ticks bei Listen, Uhrtick alle 0,5 s im Uhren-Intro, Pads in langsamen Akkorden (Dm–Bb–F–C), sanfter Beat ~90 bpm. Beat 80–90 bpm passt zu Schnitten alle 4 s.
  • MASTERING (vermeidet „übersteuert“): NIEMALS tanh auf einem heißen Mix. Machen Sie x=x/np.abs(x).max()*.85, speichern Sie wav und führen Sie ffmpeg -af loudnorm=I=-16:TP=-2:LRA=11 -ar 44100 aus. Überprüfen Sie Peak < −1 dBFS und Crest-Faktor > 10 dB.

7. Lieferung und Iteration

MP4 mit 1-zeiliger Beschreibung senden; nennen, was geändert wurde und was NICHT überprüft wurde (z. B.: „Frames und Metriken geprüft, nicht gehört“). Typisches Feedback und Antwort: „zu schnell“ → Timeline um den Faktor 1.5 skalieren; „verwackelt“ → Shake reduzieren; „schlechter Sound“ → SFX-Profil wechseln (hell vs. dezent); „übersteuert“ → nur das Audio neu masterieren und remuxen; „Animation X von v1 gefällt mir“ → Szene X zurückbringen, nur betroffene Chunks neu rendern. Wenn der Benutzer ein wiederverwendbares Prompt/Dokumentation anfordert, ein Dokument mit diesem Ablauf erstellen.

Verwandte Skills