Nahtlose Bewegungsloops in Code, mit Ihrem Motiv aus Scenario MCP
Überblick
Ein Loop hier ist eine reine Funktion der Zeit. draw(ctx, w, h, t, P) malt den Frame zum Zeitpunkt t Sekunden, und jede Bewegung darin wiederholt sich mit einer Periode, die die Loop-Länge (12 s) teilt – daher ist der Frame bei 12 s identisch mit dem Frame bei 0 s, und der Clip loopt nahtlos. Nichts wird generiert: nichts verzerrt oder flackert, eine Farbänderung rebrandet ihn, und derselbe Code rendert in jeder Größe. Die Motion Loops-Erkundung auf scenario.com zeigt 80 auf diese Weise erstellte Loops (40 Hintergründe, 40 Formanimationen), jeweils mit ihrem Code. scripts/loop-template.html enthält dieselben Helfer (M.*), die Palette (P) und die tile(...)-Registrierung, gegen die diese Loops geschrieben wurden, sodass ihr Tile-Code unverändert darin läuft.
Scenario MCP erstellt, was Code nicht zeichnen kann: das Motiv des Benutzers. Ein Maskottchen, Produkt oder Charakter kommt aus Scenario als Freisteller auf transparentem Hintergrund, und die Loop-Seite zeichnet es über den Loop mittels der Loop-eigenen Uhr, sodass es dieselbe Bewegungsunschärfe erhält und die Composite immer noch loopt. Für ein Motiv, das sich wirklich bewegt, wird aus diesem Freisteller ein KI-Videoclip generiert, sein Hintergrund in Scenario entfernt und der Clip mit ffmpeg über den gerenderten Loop gelegt. Der Loop selbst benötigt nie ein Modell und kostet nichts im Rendern.
Erfordert Node 18 oder neuer, Playwright (npm install playwright, dann npx playwright install chromium; oder --channel chrome mit installiertem Google Chrome), ffmpeg und ffprobe. Scenario MCP wird nur für das Motiv benötigt. Verbindung, Modellwahl und die Generierungsschleife: die scenario-Fertigkeit, falls installiert, andernfalls references/scenario-mcp.md.
Kurzreferenz
cp scripts/loop-template.html loop.html # ein Loop pro Datei: Einstellungen, draw(), overlay
# loop.html im Browser öffnen: Live-Vorschau; ?t=3 friert es ein, ?tone=accent oder ?tone=light wechselt den Ton
node scripts/render-loop.mjs loop.html --check # Determinismus und Loop-Naht, kein Video
node scripts/render-loop.mjs loop.html --stills look --at 0,3,6,9 # Standbilder zum Anschauen
node scripts/render-loop.mjs loop.html --out loop.mp4 # 12 s, 1920x1080, 24 fps
node scripts/render-loop.mjs loop.html --params "overlay=subject.png" --out loop.mp4 # mit einem Freisteller
node scripts/render-loop.mjs loop.html --width 1080 --height 1920 --out loop-9x16.mp4 # vertikal
node scripts/render-loop.mjs --qa loop.mp4 composite.mp4 # Naht- und Formatprüfung eines beliebigen MP4
Aus einem Ordner ausführen, in dem Playwright installiert ist. Vorhandene Dateien werden ohne --force nie überschrieben. Die Seitenprüfung rendert denselben Moment zweimal (er muss übereinstimmen), vergleicht den Frame bei exakt 12 s mit dem Frame bei 0 s und vergleicht den Schritt über den Loop-Punkt mit der Bewegung darum herum und an den anderen Zyklusgrenzen. Ein Render verweigert die Kodierung, wenn es nicht PASS ausgibt; --ignore-seam ist nur für einen Schnitt gedacht, der am Loop-Punkt sitzen soll.
| Regel | Begründung |
|---|---|
Jede Periode teilt 12 s (1, 1.5, 2, 3, 4, 6, 12); verwenden Sie M.phase(t, period, offset) | der Frame bei 12 s ist gleich dem Frame bei 0 s |
| Scrolls bewegen eine ganze Anzahl von Musterwiederholungen pro Periode | eine gebrochene Wiederholung springt an der Naht |
Zufälligkeit nur von M.rand(i, salt); kein Math.random, Date oder Zustand zwischen Frames | Bewegungsunschärfe und die Prüfungen rendern Frames außer der Reihe |
Größen von u = h / 100, Anzahlen von w | korrekt bei 16:9, 9:16, 1:1 und bei Thumbnail-Größe |
Farben nur von P (bg, fg, fg2, mid, accent, paper, ink), drei Töne pro Markenfarbe | Rebranding durch Ändern von BRAND; Kontrast durch Ändern des Tons |
Easing von M.ease, mit Antizipation, Überschwingen und Halten; konstante Geschwindigkeit nur für Scrolls | entworfene Bewegung, keine mechanische Bewegung |
Render-Einstellungen der 80 mitgelieferten Loops und die Standardeinstellungen des Skripts: 24 fps, 8 Bewegungsunschärfe-Subframes über einen 180-Grad-Verschluss, 2-faches Supersampling, H.264 High, CRF 16, 4:2:0, BT.709 limited range, faststart. Muster, die den Loop schließen, Tiefentricks und Überprüfungsgewohnheiten: references/loop-craft.md.
| Scenario MCP-Schritt | Aufrufe |
|---|---|
| Verbinden, Team und Projekt wählen | teams_list (Benutzer fragen, wenn es mehrere gibt) |
| Eigene Kunst des Benutzers einbringen | upload_asset, curl PUT jedes Teils, upload_asset_complete |
| Ein Modell wählen | recommend (txt2img, img2img, img2video, video2video), oder search |
| Seine Eingaben lesen | model_schema_get |
| Preis berechnen, dann nach Freigabe ausführen | model_run mit dry_run: true, dann model_run und jobs_wait |
| Ergebnis abrufen | asset_download, dann curl -L -o |
Ausgearbeitetes Beispiel: Ein Markenmaskottchen, das über einem codierten Loop schwebt
Ziel: ein 12-Sekunden-nahtloser 1920x1080-Loop in den Markenfarben mit dem darin schwebenden Markenmaskottchen, und optional eine Version, in der das Maskottchen winkt.
-
Verbinden. Rufen Sie
teams_listauf. Wenn mehrere Teams oder Projekte zurückkommen, fragen Sie, welches verwendet werden soll, und übergeben Sie dessenteam_idundproject_idan jeden späteren Aufruf: Mit einem angemeldeten Konto verweigernsearch,model_schema_getundmodel_rundie Ausführung ohne diese. -
Zuerst den Loop bauen (lokal, kostenlos).
cp scripts/loop-template.html mascot-loop.html, setzen SieBRAND.accentauf die Markenfarbe und behalten Sie das Beispiel-Tile (Perspective Floor, ein zum Betrachter strebendes Gitter) oder schreiben Sie Ihr eigenesdraw(). Öffnen Sie die Datei zur Vorschau, dann:node scripts/render-loop.mjs mascot-loop.html --check node scripts/render-loop.mjs mascot-loop.html --stills look --at 0,3,6,9Sehen Sie sich die Standbilder an.
--checkmuss mitPASSenden. -
Das Maskottchen einbringen. Wenn der Benutzer es als Datei hat, laden Sie es hoch:
{ "file_name": "mascot.png", "content_type": "image/png", "kind": "image", "file_size": 482113 }(
file_sizevonwc -c mascot.png.) PUTten Sie den Teil mit curl an die zurückgegebene URL, rufen Sie dannupload_asset_completemit{"upload_id": "<upload id>"}auf und behalten Sie die Asset-ID. -
Ein Modell wählen.
recommendmit:{ "capability": "img2img", "prompt": "Das Maskottchen aus dem Referenzbild, ganzer Körper, Dreiviertelansicht, eine leichte schwebende Pose, freigestellt auf transparentem Hintergrund mit sauberen Kanten, kein Schatten, kein Text", "limit": 5 }Ohne eine Datei verwenden Sie
"capability": "txt2img"und beschreiben das Maskottchen. Wennnext_step.typeask_userist, zeigen Sie die Optionen und warten Sie. Bevorzugen Sie ein Modell, dessen Schema eine Option für transparenten Hintergrund hat; planen Sie andernfalls einen Hintergrundentfernungsschritt danach ein. -
Schema lesen und Preis berechnen.
model_schema_getmit{"model_id": "<id from recommend>"}. Bauen Sie die Parameter aus dem Schema: Das Referenzbildfeld nimmt die hochgeladene Asset-ID (als Array, wenn das Schema es sagt), und die Option für transparenten Hintergrund wird gesetzt. Dann:{ "model_id": "<id from recommend>", "dry_run": true, "parameters": { "prompt": "<der obige Prompt>", "<Referenzbildfeld>": ["<Maskottchen-Asset-ID>"], "<Hintergrundfeld>": "transparent" } }Teilen Sie dem Benutzer den Preis mit und warten Sie auf eine Freigabe.
-
Ausführen und herunterladen.
model_runmit denselben Parametern und"wait": false, dannjobs_waitmit{"job_ids": ["<job id>"]}. Dannasset_downloadmit{"asset_id": "<asset id>", "format": "png"}undcurl -L -o subject.png "<url>"in den Ordner vonmascot-loop.html. Öffnen Sie das PNG über der Hintergrundfarbe des Loops bei 100 %: Heiligenscheine an der Kontur zeigen sich auf dunklen Tönen; regenerieren Sie, anstatt sie zu verstecken. -
In der Canvas compositen und rendern.
node scripts/render-loop.mjs mascot-loop.html --params "overlay=subject.png" --stills look --at 0,0.75,1.5,2.25 --force node scripts/render-loop.mjs mascot-loop.html --params "overlay=subject.png" --out mascot-loop.mp4 --psnr 4drawOverlay()lässt das Maskottchen mit einem 3-Sekunden-Auf und Ab und einem 6-Sekunden-Schwingen mit einem Kontaktschatten schweben, alle Perioden teilen 12, sodass die Composite immer noch loopt; passen Sie dort seine Größe und Platzierung an. Das Skript überprüft die Seite, rendert 288 Frames, kodiert und überprüft den Loop-Punkt der Datei.--psnrvergleicht einen kodierten Frame mit seiner verlustfreien Darstellung. -
Optional: Ein Clip, in dem sich das Maskottchen bewegt.
recommendmit"capability": "img2video", der Asset-ID des Freistellers als Startbild und einem Prompt wie „das Maskottchen winkt und dreht den Kopf, einfacher flacher Hintergrund, statische Kamera, keine Schnitte“. Schema, Trockenlauf, Los, Ausführen,jobs_wait, herunterladen. Dannrecommendmit"capability": "video2video"und „entferne den Hintergrund aus diesem Clip, behalte das Motiv mit einem Alphakanal“, wählen Sie WebM VP9 mit Alpha als Ausgabe. Schema, Trockenlauf, Los, Ausführen, herunterladen. Rendern Sie den Loop einmal ohne--params overlay=...(--out loop-plain.mp4) und legen Sie den Clip mit ffmpeg darüber (der Befehl steht in references/scenario-mcp.md). Die Composite ist so lang wie der Clip; es ist kein nahtloser Loop, es sei denn, der Clip loopt. -
Übergabe des HTML (der Loop bleibt bearbeitbar), des MP4, der Standbilder und aller Composite.
Häufige Fehler
- Ein Nahtsprung bei 12 s. Eine Periode, die 12 nicht teilt (ein 5-s-Zyklus) oder ein Scroll, der 2,5 Wiederholungen bewegt.
--checkmeldetSEAM JUMP(der Frame bei 12 s unterscheidet sich vom Frame bei 0 s). Korrigieren Sie die Periode; überblenden Sie niemals die Enden. - Zustand,
Math.randomoderDatein einem Tile. Derselbetergibt unterschiedliche Frames, die Bewegungsunschärfe-Subframes stimmen nicht überein und der Loop kann nicht schließen.--checkmeldetNOT DETERMINISTIC. Berechnen Sie alles austundM.rand(i, salt). - Farbhelfer, die nur Hex lesen.
P.midundM.mixColorgebenrgb()-Strings zurück, und ein reiner Hex-Parser macht sie stillschweigend schwarz. Die VorlageM.rgbaundM.mixColorlesen beide. - Stroboskopeffekt bei schnellen Bewegungen. Acht Subframes reichen nicht für einen Vollbild-Push; es zeigt gestufte Kopien. Ein Vollbild-Wisch im Build benötigte 40. Erhöhen Sie
--samplesfür sehr schnelle Loops. - Ein Drahtgitter, das als Unordnung gelesen wird. Ein 3D-Wellengitter tat das; als versteckte Linien-Rückenlinien (jede Reihe füllt den Hintergrund unter sich selbst, von fern nach nah gezeichnet) gelesen, erscheint es als Gelände.
- Zweimal durch die Tiefe teilen. Eine Projektion, die die Brennweite noch einmal mit der Tiefe skaliert, schrumpft die Szene zur Mitte hin. Projizieren Sie einmal mit
M.proj. - Einen 3-Sekunden-Zyklus mit Standbildern alle 1,5 s überprüfen. Das zeigt zwei Posen davon. Stichprobe innerhalb eines Zyklus und auf beiden Seiten des Loop-Punktes (
--at 11.9,11.95,0,0.05). - Jedes Flag als Fehler behandeln. Ein entworfenes Schnappen (ein Pop, eine Explosion) oder ein Halten am Loop-Punkt kann einen Naht- oder Störungsdetektor auslösen. Sehen Sie sich zuerst die Frames an. Das Skript vergleicht den Loop-Punkt mit der Bewegung darum herum und mit den anderen Zyklusgrenzen, was die meisten dieser vermeidet: alle 80 Loops des Builds bestehen ihn.
- Ein Label oder Zähler, der falsch umbricht. Alles, das nach Zyklus indiziert ist, muss mit
M.modumbrechen; im Build las ein Seitenzähler „06 / 05“ am Loop-Punkt, bis er es tat. - Niedriger Kontrast in einem Ton. Ändern Sie den Ton (dunkel, Akzent, hell) für diesen Loop, anstatt eine Farbe hinzuzufügen.
- Ein Overlay-PNG von der Festplatte. Eine Seite, die über
file://geöffnet wird, ein lokales Bild zeichnet und Pixel zurückliest, schlägt fehl, weil das Bild die Canvas verunreinigt.render-loop.mjsbedient den Ordner über eine lokale Adresse; die Browser-Vorschau zeigt nur an, daher ist sie nicht betroffen. - Text, bevor die Schriftart geladen ist. Canvas-Text wartet nicht auf Web-Schriftarten; verwenden Sie
document.fonts.load(...)vor dem ersten Frame oder zeichnen Sie keinen Text in Loops. - Bitrate jagen. Bei flachen Farben verbraucht x264 sehr wenige Bits und die Datei sieht klein aus. Im Build zeigte PSNR, dass der Encoder fast keinen Verlust hinzufügt; der einzige wirkliche Verlust ist 4:2:0 Chroma auf dünnen gesättigten Linien. Überprüfen Sie mit
--psnrund verdicken Sie dünne farbige Linien, anstatt die Bitrate zu erhöhen. - Das Alpha eines VP9-Clips verlieren. Der eingebaute VP9-Decoder von ffmpeg ignoriert Alpha; setzen Sie
-c:v libvpx-vp9vor-i shot.webm. - Den Loop mit einem Videomodell erstellen. Der letzte Frame eines generierten Clips trifft selten genau auf seinen ersten. Behalten Sie 0,1" bei 0 s und 12 s.