Was macht motionkit?
Ein Film ist eine Seite plus ein Skript, dessen renderFrame(f) den Frame f (30 pro Sekunde, 1920×1080) zeichnet – und sonst nichts. Ein versteckter Chrome durchläuft die Frames, ffmpeg kodiert (das MP4 wird auf 60 Frames pro Sekunde verdoppelt, in hoher Qualität, etwa 4 bis 5 MB pro Sekunde Film), der Soundtrack wird synthetisiert.
Wo die Dinge sind
- Engine: der Ordner
engine/neben dieser Datei (Moves, Renderer, Sound, Prüfungen, Schriften). Nenne ihn$Eund verwende seinen vollständigen Pfad. Lies daraus; lege niemals Filme hinein (das Setup fügt dort sein eigenesnode_moduleshinzu, das ist normal). - Arbeitsordner: der Ordner, in dem der Benutzer arbeitet. Filme (
<name>.html,<name>.js),assets/,ref/undout-<name>/kommen alle dorthin, und jeder Befehl wird von dort ausgeführt. Eine Seite findetlib.js,moves.jsundfonts/in der Engine selbst. Wenn der Arbeitsordner ein git-Repo ist, fügeout-*/undref/zur.gitignorehinzu.
Zuerst: Einrichtung (einmal pro Rechner)
- Führe
sh $E/setup.shaus. Es prüft nur: bun, ffmpeg mit ffprobe, python3, uv, einen Chromium-Browser (Chrome, Chromium oder Edge;CHROME_PATHüberschreibt) und das eine Paket der Engine. - Wenn es
Readyausgibt, fahre fort. Fehlt nurengine package(normal bei einer frischen Installation), führesh $E/setup.sh --installohne Nachfrage aus: Es holt nur ein Paket in den eigenen Ordner des Skills. Fehlt ein Tool oder der Browser (MISSING), zeige dem Benutzer diese Liste und die ausgegebenen Installationsbefehle und frage einmal nach, bevor Software auf seinem Rechner installiert wird. - Bei Ja: führe
sh $E/setup.sh --installaus (Homebrew auf macOS, die offiziellen Installer für bun und uv), dann führe die Prüfung erneut durch. Zeilen, dierun this yourselfsagen, benötigen das Passwort des Benutzers (sudoauf Linux) oder einen manuellen Download: Führe diese niemals aus; gib dem Benutzer den genauen Befehl und warte. Schlägt eine Installation fehl, gib dem Benutzer den einen Befehl, den er selbst ausführen muss. - Beweise, dass es funktioniert: Führe vom Arbeitsordner
bun $E/build.ts helloaus und bestätige, dassout-hello/hello.mp4existiert.
Nur auf macOS getestet; sage dies, wenn der Benutzer auf Linux oder Windows ist.
Arbeitsbeispiele zum Kopieren: $E/hello.js (ein Film auf einem Beat-Raster, jeder Ton aus Clips, Szenerie in Code gezeichnet), $E/title.js (ein transparenter Titel zum Überlagern von Filmmaterial), $E/moves-demo.js (jeder Move einmal).
Erstelle einen Film: Clips zuerst
Deklariere jede Verwendung eines Moves einmal als Clip. Das Bild, der Ton und die Lesegeschwindigkeitsprüfung stammen alle aus dieser einen Zeile.
const M = window.MOVES, B = M.brand, G = M.grid(120); // 120 bpm: ein Beat ist 15 Frames, ein Takt 60
const K = { line: M.clip("words", G.bar(1) + 2, 10, { text: "Copy the motion.", x: 960, y: 590, size: 110, fam: B.display, stretch: B.wide, weight: 600, color: B.paper, until: G.bar(2) }) };
// in einer Szene: K.line.draw(X, f) K.line.on(f) ist wahr, solange es sichtbar sein soll
window.timeline = () => ({ fps: 30, total: TOTAL, bpm: G.bpm, sections: [[0, "intro"], [4, "build"], [8, "drop"], [24, "outro"]], cues: M.cues(), captions: M.captions() });
Lies für einen Launch- oder Produktfilm zuerst den Abschnitt „Launch- und Produktfilme“ unten. Beginne einen Film mit bun $E/new.ts <name>: Es schreibt <name>.html und <name>.js in den Arbeitsordner, kopiert aus dem hello-Beispiel. Schreibe die Clips, Szenen und den Text neu. bun $E/build.ts <name> führt dann in dieser Reihenfolge aus: Zeitleiste, Soundtrack (sound.py), Soundprüfung, Lesegeschwindigkeitsprüfung (lint.py), Render, Zusammenfügen, Synchronisationsprüfung (sync.py) und schreibt out-<name>/<name>.mp4. Eine Zeitleiste ohne bpm erhält einen einfacheren Soundtrack von audio.py (nur Schnitte). Zeitleisten-Schalter: sound: "fx" (nur Move-Sounds, keine Musik), sound: "none", alpha: true (transparenter Hintergrund, .mov-Ausgabe; siehe EditMax-Abschnitt).
Anatomie eines Film-Skripts
$E/hello.js ist das Vorbild; lies es einmal. Was die einzelnen Teile sind:
- Globale Werte aus
lib.js:W,H(1920, 1080),X(der Canvas-Kontext),clamp,lerp,TAU,hash,noise,txt(ctx, text, x, y, size, weight, color, fam, italic, align),rr(abgerundetes Rechteck),vignette(stärke, innenradius). M.clip(move, start, length, options):startundlengthsind Frames;lengthgibt an, wie lange der Move zum Abspielen braucht, nicht wie lange er bleibt. Es gibt{ draw(ctx, f), t(f) (0..1 während des Moves), on(f), o (die Optionen) }zurück. Nach seiner Länge zeichnet ein Clip weiterhin seinen Endzustand: Er versteckt sich nicht. Verstecke ihn durch Beenden der Szene oder mitif (K.x.on(f)), wobeionvonstartbisuntil(für immer ohneuntil) wahr ist. Um einen fertigen Text-Move innerhalb eines Übergangs'fromanzuzeigen, zeichne ihn beit = 1:M.words(ctx, 1, K.line.o). One-Shot-Effekte (burst,glitchCut) benötigen außerdemK.x.t(f) < 1.- Rufe Formen innerhalb eines Clips auf: Übergänge (transitions) benötigen
fromundtoin den Optionen; Wrapper (punch,shake,sweep,smear) benötigendraw. Alles andere (pathDraw,burst,bars,chart,callout,logoDraw,bounce,ticker) benötigt nur Optionen.meshundparallaxsind Hintergründe: rufe sie direkt auf,M.mesh(ctx, f / 240, { colors }), wobeiteinfach eine langsam wachsende Zahl ist. - Textoptionen:
xist die Mitte der Zeile (align: "center"ist standard),ydie Grundlinie.stretch: B.wideergibt den breiten Schnitt,stretch: nullschaltet es aus. Nichts misst oder umbricht Text für dich: Bei Größe 150 breit umfassen 13 Zeichen etwa 1.340 Pixel, also rendere ein Standbild und überprüfe, ob jede Zeile mit Rand innerhalb des Rahmens liegt. - Szenentabelle:
[erster Frame, draw(f), drawAfterFinish(f)].renderFramesetzt den Kontextzustand zurück (behalte diese Zeile), zeichnet die aktuelle Szene, dann Korn und Vignette, dann den dritten Slot für alles, was sauber bleiben muss (Logos). window.ready: ein Promise, auf das der Renderer wartet:Promise.all([M.fonts(), M.levels("out-<name>/levels.json"), M.load({ ... })]).M.levelswird nur fürM.eqbenötigt und ist sicher, bevor die Datei existiert.- Zeitleiste:
sectionssind[beat, name]; ein kurzer Film kann einfach[[0, "intro"], [8, "drop"], [16, "outro"]]verwenden, und jederdrop-Start erhält den halben Beat Stille (behalte oder stummschalte dort Clips).synclistet Frames auf, an denen ein Schnitt und ein Bassschlag zusammenfallen müssen: Verwende den ersten Frame jeder Szene ab dem Drop. „Änderung“ wird anhand der üblichen Frame-zu-Frame-Differenz des Films beurteilt, sodass ein Übergang, der genau auf einem Sync-Frame endet, dort nichts zu ändern hinterlässt und die PrüfungNO CHANGEausgibt: Füge einen kurzen Blitz hinzu oder starte den nächsten Move auf diesem Frame.cutsist jeder Szenenstart. - Farben: Lies alles aus
M.brand(B).M.rgba(B.ink, 0.7)ergibt eine Farbe mit Deckkraft,M.mix(a, b, t)eine Farbe zwischen zwei.M.setBrandändertM.branddirekt; rufe es auf, bevor irgendein Clip deklariert wird, und setze auchaccentOnDark(der Akzent, der auf dunklem Hintergrund verwendet wird; er folgt nichtaccent). Für eine Schrift ohne breiten Schnitt setzewide: null. - Länge: Die Lesegeschwindigkeit gibt das Minimum vor: Eine 3-Wort-Zeile benötigt etwa 1,3 s, nachdem sie erschienen ist, also eine Zeile pro Takt bei 120 bpm. Der Soundtrack läuft etwa eine halbe Sekunde über den letzten Frame hinaus und wird dort abgeschnitten; Ende mit einem
outro-Abschnitt, damit der Schnitt in dessen Ende fällt. - Build-Ergebnisse:
build.tsbeendet sich mit 0, auch wenn eine Prüfung fehlschlägt; Fehlschläge werden alsWARNING:-Zeilen mit den Details darüber ausgegeben. Behandle jede Warnung als Fehler: Lies die Ausgabe (filtere dieframe n/total-Fortschrittszeilen aus), korrigiere, baue neu, bis keine mehr vorhanden sind. Standbilder werden alsout-<name>/fNNNN.jpggeschrieben; lies sie.bun $E/pure.ts <name>bestätigt, dass Frames allein und nach anderen Frames gleich gerendert werden. sound.pybenötigt numpy und wird immer mituv runausgeführt; die anderen Python-Skripte verwenden nur die Standardbibliothek.
Launch- und Produktfilme: Zeige das Produkt
Ein Film aus großen Wörtern auf einem Hintergrund wirkt einfach. Launch-Filme, die funktionieren, halten das Produkt in einer visuellen Welt mit Tiefe und einer sich langsam bewegenden Kamera auf dem Bildschirm, verwenden kleine, kurze Texte und halten Einstellungen für 2 bis 6 Sekunden (einige Takte), nicht einen Schnitt pro Beat. Beginne für einen Launch- oder Produktfilm NICHT mit hello:
- Entscheide zuerst den Look: eine Hintergrundwelt, eine Akzentfarbe, eine Schriftfamilie. Sage es dem Benutzer in zwei Zeilen.
- Storyboard 6 bis 8 Einstellungen mit echten Dingen: den echten Bildschirm oder die Ausgabe des Produkts, echte Befehle, echter Code, echte Ergebnisse. Zeichne niemals ein Interface, das das Produkt nicht hat, erfinde niemals Zahlen und verwende niemals das Logo eines anderen Unternehmens. Beschriftungen sind kleine Etiketten (
txt, Mono, unten links), keine Schlagzeilen. - Erstelle zuerst eine Helden-Einstellung, rendere Standbilder und vergleiche mit einem echten Launch-Film, bevor der Rest gebaut wird.
Die Seite muss stage.js nach moves.js laden (Seiten, die mit new.ts erstellt wurden, tun dies). Beginne renderFrame mit M.frame(); M.reset(X);. Bühnenstücke (alle auf MOVES):
| Stück | Was es ist |
|---|---|
backdrop(ctx, f, { base, lights[], streak }) | Fast-schwarz mit langsamen Lichtpools: die Welt, in der alles sitzt |
glass(ctx, x, y, w, h, { r, top, bottom, rim, shadow }) | Eine dunkle, abgerundete Tafel mit einem Lichtrand und einem weichen Schatten |
camera(ctx, cam, draw) mit cam(a, b, t, ease) | Schau auf einen Punkt einer größeren Szene: { x, y, zoom, rot }; beginne makronah und zoom heraus, oder drifte langsam |
tilt(ctx, draw, { depth, focus, blur, fog, top, height, width, cx, roll }) | Zeichnet eine Vollbildszene als eine schräg geneigte Ebene; der ferne Rand ist kleiner, dunkler und unscharf |
tiles(ctx, f, { cells: [{ draw(ctx, t), label, bg, len, hold }], cols, x, y, w, gap }) | Ein Raster kleiner Bildschirme, die jeweils einen Move live abspielen (setze niemals einen Übergang in eine Kachel) |
term(ctx, f, { x, y, size, lines: [{ text, at, speed, prompt, mark: "ok" or "run", color }] }) | Terminalzeilen, die auf ihrem Frame eintippen oder erscheinen |
code(ctx, { lines[], x, y, size, lead, hot, shown }) | JavaScript mit ruhiger Syntaxfarbe und einer leuchtenden Zeile |
wave(ctx, { peaks, x, y, w, h, played, beats[], blocks[] }) | Die Form eines echten Soundtracks mit Abspielkopf, Beat-Ticks und Clips auf einer Spur |
Bühnenstücke erzeugen keinen eigenen Ton: Füge Cues von Hand zur Zeitleiste hinzu, { f, kind, gain } mit Arten wie type, tick, pop, ding.
Zu einem echten Song schneiden
- Der Benutzer liefert die Musikdatei und muss das Recht haben, sie zu verwenden; sage das und setze den von der Lizenz geforderten Hinweis auf die Endkarte. Reiße niemals einen Song von einer Streaming-Seite.
uv run $E/beats.py <datei>gibt das Tempo und die Lautstärke jedes Taktes aus. Wähle einen Ausschnitt, der auf einem Takt mit einem Abschnittswechsel einige Takte später beginnt, dann schreibtuv run $E/beats.py <datei> --from <sekunden> --len <sekunden> --out beats.jsondie Dateienbeats.jsonundbeats.js.- Lade
beats.jsauf der Seite vor dem Filmskript. Schreibe jeden Szenenstart als Beat-Nummer:const b = (n) => window.BEATS.frames[n]. Schneide auf Takten (alle 4 Beats), wo der Track wechselt. - Setze in der Zeitleiste
music: { file, from },sound: "fx"(die eigenen Sounds der Moves bleiben leise unter der Musik) oder"none", einbpmundsync: [frames der echten Schnitte]. Der Build mischt den Track bei -16 LUFS ein, blendet sein Ende aus und prüft, ob jeder Schnitt innerhalb eines Frames einen Bassschlag hat. Füge keine Blitze hinzu, nur um diese Prüfung zu bestehen.
Motion für EditMax (ein Clip auf einer Videobearbeitungs-Zeitleiste)
Verwende dies, wenn der Benutzer in EditMax bearbeitet und eine Bewegung im Schnitt wünscht: einen animierten Titel über Filmmaterial, eine Intro- oder Outro-Karte, einen kinetischen Typografie-Beat zwischen Aufnahmen. Es benötigt zwei Dinge in derselben Agentensitzung: eine Shell (zum Rendern) und EditMax's MCP-Tools (inspect_timeline, import_media, ...; Einrichtung über den Reiter „Agents“ in EditMax). EditMax's eigener In-App-Chat verweigert Shell-Befehle, daher kann es diesen Skill nicht ausführen: Sage das und teile dem Benutzer mit, einen Agenten wie Claude Code zu verbinden. Wenn die EditMax-Tools fehlen oder nicht antworten, rendere den Clip trotzdem und gib dem Benutzer den Dateipfad zum Ziehen.
1. Wähle den Weg. Bevorzuge EditMax' eigene Tools, wenn sie die Bewegung abdecken, weil der Text in der App bearbeitbar bleibt:
| Gewünscht | Verwende |
|---|---|
| Ein Titel oder Lower Third, der einblendet, schiebt, poppt, tippt oder wischt | add_text / add_lower_third + set_text_animation |
| Ein Dissolve, Push, Slide, Wipe oder Iris zwischen zwei Clips | set_transition |
| Ein Clip, der sich bewegt, skaliert oder einblendet | set_keyframe, set_clip_transform, set_clip_fades |
| Alles andere: Slam, Scramble, Split-Flap, Wortrad, Cross-Out, Highlight, Pfad- oder Logo-Zeichnung, Diagramme, Zähler, Bursts, Multi-Move-Sequenzen, ein komplettes Intro oder Outro | Rendere einen Clip mit diesem Skill |
2. Lies das Projekt. inspect_timeline: Notiere die Bildgröße, die Bildrate, die Spuren und den Zeitpunkt, an dem die Motion platziert werden soll. Diese Engine rendert 1920×1080 bei 30 Bildern pro Sekunde. Ein 16:9-Projekt einer anderen Größe skaliert es sauber. Bei einem vertikalen oder quadratischen Projekt sage klar, dass der Clip letterboxed oder mit set_clip_transform hochskaliert und beschnitten werden muss und dass ein nativer Titel möglicherweise besser geeignet ist.
3. Rendere.
- Overlay (liegt auf Filmmaterial):
bun $E/new.ts <name> --overlay, nach dem Vorbild von$E/title.js. Die Zeitleiste hatalpha: trueundsound: "fx"; der Build schreibtout-<name>/<name>.mov(ProRes 4444 mit transparentem Hintergrund). Regeln: den Frame leeren (X.clearRect), niemals füllen; keingrain,vignette,mesh,parallaxoder Vollbild-Übergänge; einen weichen Schatten oder eine Platte unter den Text setzen, damit er auf jedem Filmmaterial lesbar ist; Text innerhalb der mittleren 90 % des Frames halten; am Ende ausblenden. - Vollbild (Intro, Outro, eine Karte zwischen Aufnahmen):
bun $E/new.ts <name>, nach dem Vorbild von$E/hello.js; der Build schreibtout-<name>/<name>.mp4. - Sound (setze
sound:in der Zeitleiste): Lasse es weg für den vollständigen Soundtrack (ein alleinstehendes Intro oder Outro);"fx"für nur die Sounds, die die Moves machen (alles, was über Filmmaterial, Sprache oder die Musik des Benutzers läuft);"none"für Stille. Frage, was der Benutzer möchte, wenn der Schnitt bereits Musik hat. - Baue, behebe jedes
WARNINGund lies Standbilder, bevor du fortfährst.
4. Lege die Datei an einen dauerhaften Ort. EditMax referenziert importierte Dateien, es kopiert sie nicht. Kopiere die fertige Datei aus out-<name>/ in einen Ordner, den der Benutzer behält (frage einmal; schlage ~/Movies/Motions/ vor) und importiere von dort.
5. Platziere sie, ohne den Schnitt des Benutzers zu verschieben. insert_clip mit einer Zeit ist ein Riss...