Edición de motion graphics para Reels/Shorts/TikTok
Convierte un video vertical en bruto en una edición completa de motion graphics:
configuración → analizar → PREGUNTAR: estilo (tablero de estilo) + opciones de preparación → guión de ritmo → plan.json
→ verificar + bucle de vista previa → renderizar superposición → componer → verificar → OFRECER: subtítulos + extras
La superposición es HTML/GSAP renderizada fotograma a fotograma con fondo transparente (assets/engine.html), por lo que la forma persa, las fuentes y los gradientes son perfectos en píxeles. Nunca escribes código de animación a mano: escribes un plan.json que enumera los componentes y sus tiempos. El motor los anima en el estilo preestablecido elegido, que define el aspecto, el movimiento, las transiciones y la paleta de sonido, y le da a cada componente sus efectos de sonido predeterminados.
Habla con el usuario en su idioma (generalmente persa). Mantén las actualizaciones de progreso breves.
Por qué la edición debe sentirse "exactamente en su lugar" — y no repetitiva
Los espectadores notan cuando un gráfico o sonido está desincronizado por medio segundo, o cuando no tiene nada que ver con lo que se dice. Eso es lo que hace que una edición se vea amateur. Ediciones anteriores fueron criticadas precisamente por eso: aparecían insignias decorativas sobre la cara del presentador que no coincidían con lo que decía. Posteriormente, el usuario también dijo que las ediciones comenzaban a verse repetitivas. Cuatro ideas solucionan ambos problemas, y las herramientas imponen la mayoría de ellas:
- Anclar a las palabras. Cualquier texto que se haga eco del discurso usa un ancla de palabra (
"t": "w:رایگان"), por lo que aparece en la sílaba, no cerca de ella. Los segundos escritos a mano son solo para eventos puramente visuales. - Anclar a la imagen. Los clics, cambios de página y zooms de diseño provienen de eventos de
motion.json("t": "m:m12") y de las hojas de contacto con marca de tiempo que lees tú mismo. Un efecto de sonido de clic sin un clic visible es ruido. - Proteger la cara. Declara la cara y los rectángulos de PIP en
plan.avoid. Luego,render.js checkmarca cualquier elemento que los cubra. Corrige cada advertenciaCOVERSantes de renderizar. - Deja que el usuario elija el aspecto, luego varía dentro de él. Pregunta por un estilo antes de diseñar (Paso 2). Luego, no recurras a la misma receta cada vez: varía el formato del gancho, qué componentes llevan las ideas y las transiciones.
references/styles.mdtiene el manual de juego por estilo y una lista de formatos de gancho.
Paso 0 — configuración (primera ejecución en una máquina)
python <skill>/scripts/setup.py
Instala faster-whisper, puppeteer-core y gsap en ~/.cache/reel-motion-edit/, sintetiza la biblioteca de efectos de sonido y descarga el modelo Whisper (large-v3-turbo, ~1.6 GB; se reanuda y recurre a hf-mirror.com si huggingface.co está bloqueado o se cae). Este es el paso "descargar lo que necesitas", así que hazlo sin preguntar. Dile al usuario en una línea lo que se está descargando. Ejecútalo en segundo plano: el modelo puede tardar un poco en conexiones lentas. Mientras tanto, puedes hacer el análisis visual con analyze.py --no-transcript, luego volver a ejecutarlo para obtener la transcripción más tarde. Vuelve a ejecutar scripts/sfx.py ~/.cache/reel-motion-edit/sfx después de actualizar la habilidad, para que existan los sonidos del nuevo estilo.
Si encuentras un activo adicional útil (una fuente, un conjunto de iconos, un efecto de sonido o pista de música libre de regalías), descárgalo en el directorio de trabajo. Anota su licencia en <workdir>/CREDITS.txt. Prefiere fuentes OFL/CC0 (Google Fonts, Pixabay/Freesound CC0). Fuentes incluidas: Vazirmatn (cuerpo), Lalezar (títulos), Changa (tecnológica), Lemonada (lúdica), Noto Kufi Arabic (formal). Las fuentes que el usuario tiene instaladas localmente (por ejemplo, Morabba, IRANSansX, Yekan Bakh) se pueden agregar a través de plan.fonts y suelen ser la opción más coherente con la marca. Busca en %LOCALAPPDATA%\Microsoft\Windows\Fonts y C:\Windows\Fonts.
Kit de marca. Si ~/.config/reel-motion-edit/brand.json existe, render.js lo aplica automáticamente: style, theme (colores de marca), fonts, handle (marca de agua @usuario), handleCorner, logo. El plan lo anula; "brand": false lo ignora para un video. Cuando el usuario te indique una preferencia duradera (su handle, un estilo que siempre quiere, colores de marca), ofrécele guardarlo allí.
Paso 1 — analizar
Crea un directorio de trabajo junto al video (<directorio del video>/<nombre del video>_edit/) y ejecuta:
python <skill>/scripts/analyze.py "<video>" "<workdir>" --lang fa
Luego lee analysis/transcript.txt y cada analysis/sheets/sheet_*.jpg (10 s cada uno, 0.5 s por celda, con marca de tiempo). Los eventos de movimiento impresos por el script (m0 … mN, cut/change) son candidatos. Confirma cada uno con las hojas, porque un desplazamiento también aparece como "change".
Whisper a veces escribe mal los nombres de productos en persa o inglés. Anota las correcciones (importan para los subtítulos y para las anclas de palabras: ancla en cómo Whisper deletreó la palabra).
Paso 2 — preguntar al usuario: estilo + opciones de preparación (antes de diseñar cualquier cosa)
Diferentes videos y audiencias quieren diferentes aspectos, y el usuario quiere elegir. Construye un tablero de estilo: un fotograma representativo de su video renderizado en los 7 preestablecidos, con un título, un chip de paso, una pegatina y una línea de subtítulos. Escribe primero un plan mínimo (video + un título + una palabra clave + pasos si el video los tiene), luego ejecuta:
node <skill>/scripts/render.js "<workdir>/plan.json" styleboard <T> # → build/styleboard.jpg
Elige T donde el fotograma sea típico (no una transición). Envía la imagen al usuario (SendUserFile, mostrar render), luego pregunta con AskUserQuestion. Omite la pregunta de estilo si el kit de marca ya tiene un style, a menos que el usuario pida algo diferente.
- P1 — estilo (máximo 4 opciones: recomendamos primero el que mejor se adapte a este contenido, con una razón de una línea, más tres alternativas contrastantes; di que los demás se pueden escribir con "Otro"). Preestablecidos:
gradientgradiente moderno,boldpop/Hormozi,neontech/ciber,minimallimpio como Apple,doodledibujado a mano,retroVHS,newsnoticias. Las descripciones están enassets/styles.json(label,feel). - P2 — opciones de preparación (selección múltiple), solo las que apliquen:
- Recortar pausas (cortes de salto):
tighten.pyelimina silencios de más de ~0.45 s. Mejor para videos de cabezas parlantes. En grabaciones de pantalla, advierte que los tramos silenciosos pueden ser donde ocurren los clics. Cambia la línea de tiempo, por lo que se ejecuta antes del análisis: vuelve a ejecutar el análisis en el archivo ajustado. - Limpieza de voz:
"voice": "enhance"(eliminación de ruido, corte de retumbos, presencia, compresión suave). Recomiéndalo para audio de teléfono o sala. - Marca de agua @handle: pregunta por el handle si el kit de marca no tiene uno.
- Música de fondo: solo si el usuario tiene una pista o quiere que encuentres una CC0. Se baja automáticamente debajo de la voz.
- Recortar pausas (cortes de salto):
Si el usuario solo quiere la edición y no le importa, elige por él, di qué estilo elegiste y por qué, y continúa.
Paso 3 — guión de ritmo (piensa antes de diseñar)
Escribe <workdir>/beats.md: una línea por ritmo con el rango de tiempo, lo que se dice, lo que se muestra y el diseño (cara completa / pantalla + PIP abajo a la izquierda / pantalla sostenida con la mano / …). Marca:
- el gancho (primeros 1–3 s): elige un formato de gancho de
references/styles.md, uno diferente a la última vez si lo sabes - cada paso / idea que el orador explica
- el momento de recompensa (resultado mostrado: "conectado", "hecho", el número)
- el CTA al final
- cambios de diseño (zoom entre cámara y pantalla): puntos de transición
- las zonas seguras por diseño: donde las superposiciones pueden colocarse sin ocultar la cara, el cursor o lo que se está demostrando
Lee references/styles.md (el manual de juego del estilo elegido) y references/creative-direction.md (ritmo, colocación, reglas de efectos de sonido). Son cortos y marcan la diferencia entre "recargado" y "profesional".
Paso 4 — plan.json
Escribe <workdir>/plan.json. Todos los componentes, sus propiedades y efectos de sonido predeterminados están en references/components.md. Léelo antes de escribir el plan. Forma mínima:
{
"video": "D:/videos/vpn firefox.mp4",
"size": [1080, 1920], "fps": 30,
"style": "neon",
"voice": "enhance",
"handle": {"text": "@tu_handle", "corner": "tl"},
"avoid": [{"name": "face", "from": 0, "to": 14.6, "rect": [200, 420, 680, 900]},
{"name": "pip", "from": 15, "to": 29.1, "rect": [0, 1300, 510, 620]}],
"elements": [
{"type": "title", "t": 0, "d": 3.8, "y": 90, "kicker": "آموزش ۶۰ ثانیهای", "lines": ["`VPN` *رایگان*"], "sub": "با سرورهای فایرفاکس"},
{"type": "transition", "t": "m:m3-0.1"},
{"type": "steps", "items": [{"t": "w:گوگل", "label": "جستجو در گوگل", "sub": "`vpn firefox github`"}], "hide": [[29.0, 34.1]]},
{"type": "keyword", "t": "w:رایگان", "x": 540, "y": 1640, "text": "رایگان", "emoji": "🎁"},
{"type": "success", "t": "w:وصل", "x": 405, "y": 678, "title": "وصل شدی!"},
{"type": "cta", "t": 57.4, "items": [{"text": "سیو کن", "icon": "save"}, {"text": "فالو کن", "icon": "follow"}]}
],
"camera": [{"t": "w:رایگان", "d": 1.2, "type": "punch", "scale": 1.12, "cx": 540, "cy": 700}],
"sfx": [{"t": 16.2, "name": "typing", "db": -8}],
"cover": {"lines": ["`VPN` *رایگان*"], "sub": "آموزش ۶۰ ثانیهای"}
}
Deja que el estilo decida el aspecto. Deja las propiedades visuales (colores theme, style/rotate/from de palabra clave, kind de transición, anim de título, estilo de subtítulo) sin establecer a menos que tengas una razón semántica (rojo para un error, un color de marca). El preestablecido las completa, y eso es lo que hace que los estilos se sientan diferentes. Una transición sin kind recorre las transiciones del estilo. theme en el plan solo anula el preestablecido (por ejemplo, el color de marca del producto).
Sintaxis de texto: *palabra* o *dos palabras* = resaltado, `latín` = ejecución LTR aislada (mantiene "VPN"/URLs sin invertirse dentro del texto RTL).
Paso 5 — verificar, vista previa, corregir (bucle)
node <skill>/scripts/render.js "<workdir>/plan.json" check
node <skill>/scripts/render.js "<workdir>/plan.json" preview 1 5.5 15.8 21.1 27.4 54
check imprime la línea de tiempo resuelta y verifica:
COVERS: un elemento sobre una zona protegidaOFFFRAMECLUTTER: más de 3 superposiciones a la vezSFXPILE: sonidos apilados dentro de 0.35 sORDER: un ancla de palabra golpeó una ocurrencia anterior, así que usaw:palabra#2
Corrige cada problema. Luego mira build/preview.jpg: elige tiempos a mitad de la animación para cada elemento importante y verifica que los llamados y las ondas estén exactamente sobre sus objetivos. Lee las coordenadas de los fotogramas a resolución completa (ffmpeg -ss T -i video -frames:v 1 f.png) en lugar de adivinarlas a partir de miniaturas. Itera hasta que esté bien. Las vistas previas son baratas, los renders completos no.
Paso 6 — renderizar y componer
node <skill>/scripts/render.js "<workdir>/plan.json" full # build/overlay.mov (≈3–6 min / minuto de video)
python <skill>/scripts/compose.py "<workdir>/plan.json" --out "<directorio del video>/<nombre> - edit.mp4"
node <skill>/scripts/render.js "<workdir>/plan.json" cover <T> # build/cover.jpg — portada de publicación (fotograma borroso T + título)
Ejecuta el render completo en segundo plano. compose.py hace lo siguiente:
- aplica los movimientos de cámara solo al video
- superpone los gráficos
- aplica la limpieza de
voicesi está configurada - mezcla la capa de efectos de sonido debajo de la voz, más música con reducción de volumen si está configurada:
"music": {"file": "...", "db": -20} - normaliza a −14 LUFS
Nunca sobrescribas el video original. Escribe un nuevo archivo, con un sufijo de versión (- edit v2) en re-renders.
Paso 7 — verificar
Crea una hoja de contacto de la salida (ffmpeg -i out.mp4 -vf "fps=1/2,scale=216:-1,tile=10x3" sheet.jpg) y mírala. Verifica que la duración coincida y que el audio esté presente. Informa honestamente lo que verificaste (fotogramas) y lo que no pudiste (no puedes escuchar; el tiempo de los efectos de sonido se verifica contra la lista de eventos, no de oído).
Paso 8 — ofrecer subtítulos y extras (siempre, al final)
Una vez que la edición esté entregada, pregunta con AskUserQuestion (selección múltiple donde corresponda). Solo ofrece lo que no se haya hecho ya:
- Subtítulos: 3–4 estilos de
references/caption-styles.md, con el estilo predeterminado del estilo elegido (captionsen styles.json) recomendado primero y la razón basada en este video. - Imagen de portada para la publicación (
render.js cover). - Texto de subtítulo de Instagram: escribe
<workdir>/post.txta partir de la transcripción: una línea de gancho, 2–4 líneas cortas de valor, el CTA, el enlace o la palabra clave de comentario que mencionó el orador, y 8–15 hashtags relevantes en persa e inglés. - Guardar en el kit de marca: el estilo elegido, handle y colores, para que el próximo video comience allí.
- Otra versión de estilo: re-renderizar el mismo plan con un
stylediferente para pruebas A/B (solo cambia la superposición).
Para subtítulos:
python <skill>/scripts/captions.py "<workdir>" --style karaoke --zones "0-14.6:1400,29.4-33.8:1400" --default-y 1170 --keywords "رایگان,VPN" --fix "غلط=درست,وی پی این=VPN"
Revisa los fragmentos impresos. Corrige las ortografías de Whisper con --fix; una fuente de varias palabras fusiona tokens. Agrega "captions": {"file": "captions.json"} al plan (el estilo predeterminado es el del preestablecido; configura "style" para anularlo), ejecuta check (los subtítulos no deben cubrir la cara ni las pegatinas), luego renderiza y compone de nuevo como una nueva versión.
Errores comunes
- Los elementos en coordenadas de pantalla (clic, resaltado, flechas de llamada) se desalinean si un movimiento de cámara hace zoom en la misma sección. Usa movimientos de cámara solo en secciones de cabezas parlantes.
- Los zooms animados al estilo Camtasia entre la cara y la pantalla duran ~0.5 s. Coloca el elemento de transición al inicio del zoom y no pongas texto en pantalla en esa ventana.
steps.hideoculta el chip de paso durante las secciones de cara completa y lo devuelve después.- Las marcas de tiempo de palabras de Whisper pueden ser ~0.1 s tarde en la primera palabra después de una pausa. Para golpes duros (título slam), ajusta con
-0.05. - Las fuentes que no son 1080×1920 (por ejemplo, exportaciones de teléfono 608×1080) se escalan/recortan al tamaño del plan mediante compose y preview. Las coordenadas del plan están siempre en píxeles del tamaño del plan, así que multiplica las coordenadas leídas de los fotogramas de origen por
1080 / ancho_fuente. - Metraje de teléfono sostenido con la mano de un monitor: la pantalla se desplaza, por lo que los elementos fijados en la pantalla (clic, resaltado, flechas) no se mantendrán en el objetivo. Usa estructura (pasos), pegatinas ancladas a palabras en los márgenes y transiciones de fotograma completo en su lugar.
- Los títulos obtienen una cortina superior oscura de forma predeterminada (
"scrim": falsepara eliminarla). Mantiene la legibilidad sobre pantallas brillantes. - Mantén la voz del orador intacta (sin EQ/compresión más allá de la normalización de volumen)