Communitygithub.com

Apollonny/stickman-explainer

Produce short vertical (9:16) hand-drawn stick-figure explainer/story videos (Instagram Reels / Shorts / TikTok history & anecdote style) from a script, using a Python renderer driven by a JSON storyboard. Cream paper background, black-ink stick figures, one red accent colour, optional sun motif, and captions whose red emphasis follows the spoken word when word timings are supplied. Use whenever the user wants an animated explainer, stickman video, "çöp adam" animasyon, kısa hikâye/tarih/anekdot videosu, or asks to automate this kind of video with an AI coding agent — even if they only say "make a video like this reel".

¿Qué es stickman-explainer?

Esta habilidad convierte un guion breve en un video vertical completo de 1080×1920 (formato 9:16) con dibujos animados de palitos (stick figures) sobre fondo de papel crema. El usuario escribe un guion gráfico en JSON y el renderizador Python (`render.py`) genera cada fotograma —con líneas de tinta temblorosas, efecto de "line boil" a 8 fps y transiciones suaves (fundido, barrido, aparición)— para luego codificarlo con ffmpeg. Es ideal para crear videos estilo Instagram Reels, YouTube Shorts o TikTok, especialmente para narrar historias, anécdotas o explicaciones breves con un estilo visual limpio y caricaturesco. La herramienta está pensada para agentes de IA como Claude Code, Cursor o Codex, y permite automatizar completamente la producción de video desde un script. Incluye soporte para sincronización labial mediante intervalos `karaoke`, arrastre de elementos entre escenas (carry), y un sistema de paleta de colores minimalista (tinta negra, acento rojo semántico y opcionalmente dorado para un motivo solar). El flujo de trabajo guía al usuario desde la división del guion en escenas hasta la verificación de fotogramas fijos, borrador y video final, con robusta validación de errores y manejo de audio.

Compatible con✓Claude Code✓Codex CLI~Cursor✓Antigravity✓OpenCode
npx skills add https://github.com/Apollonny/stickman-explainer/tree/main/stickman-explainer

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace stickman-explainer?

Convierte un guion breve en un archivo mp4 completo de 1080×1920. Escribes un guion gráfico JSON; scripts/render.py dibuja cada fotograma (líneas de tinta temblorosas, efecto de línea hirviente a 8 fps, revelados con fundido/barrido/pop) y lo codifica con ffmpeg.

assets/example_storyboard.json es solo un ejemplo de sintaxis (3 escenas); no copies su diseño ni los accesorios de los personajes como plantilla.

Valores predeterminados del estilo visual

  • Usa un lienzo 9:16 (1080×1920, 30 fps). Mantén cada escena en una sola idea, normalmente de 2,5 a 4 segundos, con subtítulos cortos dentro de las áreas seguras de la plataforma.
  • Usa papel cálido (#f3ebdd), tinta oscura (#2b2723), y acento rojo ladrillo semántico (#b8372d). El dorado sol (#d89d48) es opcional solo para el motivo solar. Mantén el resto plano: sin degradados, sombras ni efectos 3D.
  • Dibuja figuras simples de tinta negra con rostros claros y abundante espacio negativo. No agregues cascos, coronas, capas, ropa roja u otros accesorios a menos que la historia o el usuario lo pida explícitamente. No infieras vestimenta a partir de un nombre histórico.
  • Mantén las escenas legibles: como máximo 2 personajes y 5 íconos pequeños. Haz que el sujeto principal domine; evita la superposición de subtítulos y accesorios. Usa no más de 2 líneas de subtítulos.
  • Haz reconocibles los accesorios complejos. Dibuja un nudo con bucles de cruce distintos, un centro apretado y extremos de cuerda visibles. Dale a una espada un mango claro, una guarda y una hoja puntiaguda. Después de un corte, deja un espacio visible entre los dos extremos de la cuerda.
  • Cuando se disponga de temporizaciones de narración, haz que el énfasis rojo del subtítulo siga la palabra que se está hablando en ese momento a lo largo de toda la narración. Usa un intervalo karaoke para cada palabra del subtítulo separada por espacios en blanco; las palabras no activas mantienen el color de texto normal.
  • Prefiere diseños asimétricos y deja espacio negativo deliberadamente. Las líneas de suelo, soles, tarjetas de título, burbujas de pensamiento y otros motivos son opcionales; elígelos solo cuando apoyen la escena.

Flujo de trabajo

  1. Guion → escenas. Divide la historia en escenas de una oración (≤ 6 palabras de subtítulo, 2,5–4 s cada una). Patrón: tarjeta de título → gancho/conflicto → revelación concreta. Cada escena agrega exactamente una nueva información. Cuando se proporciona narración, alinea los límites de las escenas con las oraciones habladas.
  2. Elige un elemento visual para cada oración. Una metáfora por escena: personaje + accesorio, burbuja de pensamiento o una fila de íconos (X = "no tiene"). Mantén ≤ 2 personajes y ≤ 5 íconos.
  3. Escribe el guion gráfico (esquema a continuación). Con temporizaciones de narración a nivel de palabra, agrega un intervalo karaoke por cada palabra del subtítulo separada por espacios en blanco para que el acento rojo siga la palabra que se está hablando. Usa **palabra** solo para un resaltado estático cuando no se disponga de temporización de palabra; no combines marcas estáticas con karaoke.
  4. Revisa primero los fotogramas fijos (rápido, ~2 s/escena): python scripts/render.py story.json --stills out/stills → abre cada scene_NN.png, corrige superposición/ubicación, repite.
  5. Video borrador: python scripts/render.py story.json out/draft.mp4 --draft (sin supersampling, 12 fps).
  6. Final: python scripts/render.py story.json out/final.mp4 [--audio voiceover.mp3]. Las duraciones de las escenas deben coincidir con las longitudes de las oraciones de la voz en off; mide el audio con ffprobe y establece duration en consecuencia. Los intervalos de palabras son segundos desde el inicio de su escena y deben provenir de la alineación de la narración o de una escucha cuidadosa. Verifica que cada palabra roja aparezca con su audio hablado, no antes ni después.

Mensajes de error y validación

render.py valida el guion gráfico antes de dibujar: type/pose/face/kind/font desconocido, campo obligatorio faltante, id repetido en la misma escena, duration <= 0, ruta lines de un solo punto, resolución impar (no par) e id de carry inexistente se rechazan con un mensaje claro, no con traceback. Se emite una advertencia para elementos que nunca serán visibles (at después del final de la escena). Si el archivo de audio es más corto que el video, el final se rellena con silencio; si es más largo, se recorta; la duración del video nunca cambia.

Esquema del guion gráfico

{"meta": {"width":1080,"height":1920,"fps":30,"boil_fps":8,"transition":0.18,
          "palette":{"accent":"#b8372d"}, "audio":null, "font_dirs":[]},
 "scenes":[{"duration":3.4, "caption":"Büyük **İskender**'di.",
            "caption_at":0.5, "caption_y":null, "elements":[ ... ]}]}

Para un énfasis de palabra que sigue el habla, proporciona un array karaoke con un objeto { "start": segundos, "end": segundos } por cada palabra separada por espacios en blanco en caption. Los tiempos son locales a la escena; el énfasis rojo cambia en cada intervalo. El subtítulo no debe contener marcas **...** cuando karaoke esté presente.

{"duration":2.8, "caption":"Düğümü tek hamlede kesti.", "caption_at":0.35,
 "karaoke":[{"start":0.35,"end":0.76},{"start":0.76,"end":1.02},
            {"start":1.02,"end":1.53},{"start":1.53,"end":2.15}],
 "elements":[ ... ]}

Cada elemento: type, id opcional (para carry), at (s, tiempo de aparición), dur (s de revelación), anim = fade | wipe | rise | pop, until/out_dur (desvanecimiento). Las posiciones x,x2,y,ground ≤ 2 se leen como fracciones de ancho/alto, de lo contrario píxeles. Los tamaños son siempre píxeles.

tipocampos clave
groundy (obligatorio); x, x2 opcional, si no se da, ~%2–%98 del lienzo — línea de base temblorosa
sunx,y,r,rays
texttext (marcas **accent**), x,y,size,font = sans/sans_bold/sans_light/serif, tracking, caps, color, max_w, max_lines (predeterminado 3), rules (doble línea para tarjeta de título; ancho y espacio automáticos según el texto)
figurex,ground,h,head_r, pose = stand/arms_open/point/wave/think/shrug/sit, dir (±1), face = neutral/smile/sad/surprised/angry, accessory opcional = helmet/crown/hat/glasses, cape opcional, look
propkind = barrel/bowl/bucket/house/book/box/triangle/coins/tree, x,y (esquina superior izquierda), w,h, cross (X de acento), flip
thoughtx,y,w,h, tail_to [px,py] (posición de la cabeza), inner: lista de elementos en px local de la burbuja
linespaths (lista de listas de puntos, px local), closed, smooth, color, width — válvula de escape para cualquier forma personalizada

Continuidad entre escenas (carry)

Para llevar un elemento de una escena a la siguiente, asigna un id al elemento y llámalo con carry en la siguiente escena. El elemento llevado comienza con la misma vibración de línea (misma semilla), por lo que aparece como "el mismo dibujo" aunque la escena cambie; la transición de nueva escena por defecto es un corte (sin crossfade).

"carry": [
  "ground",
  {"id": "sun",  "set": {"r": 122}},
  {"id": "alex", "set": {"x": 120, "face": "smile"}, "tween": {"at": 0.1, "dur": 0.9}},
  {"id": "diog", "until": 0.1, "out_dur": 0.5}
]

Las líneas se procesan en orden: "ground" se lleva tal cual · sun se lleva con campo modificado (el cambio es instantáneo al inicio de la escena) · alex cambia de campo y además desliza su posición durante un tiempo (tween) · diog se lleva pero se desvanece dentro de la escena.

  • "carry": "all" lleva todo ("carry_except": ["id", ...] excluye). Los subtítulos nunca se llevan.
  • Un elemento no llevado desaparece instantáneamente al inicio de la escena; para una desaparición suave, usa until/out_dur. Un elemento que se desvanece con until no puede llevarse a la siguiente escena.
  • tween solo anima posición (x y y/ground); los cambios de tamaño (r, h, w) y apariencia (face, pose) se aplican instantáneamente al inicio de la escena.
  • Los elementos llevados se dibujan debajo de los nuevos elementos. Los id deben ser únicos entre escenas para los elementos que se llevarán.
  • Un elemento con el mismo id en cada escena usa la misma semilla; para un elemento nuevo específico de una escena, no le asignes id.

Agrega nuevos accesorios/poses extendiendo PROPS / hands en render.py; mantén el mismo estilo de tinta (usa stroke(), nunca líneas simples).

Diseño: decide de nuevo para cada video

No hay coordenadas/plantillas fijas. Como el tema de cada video es diferente, deriva el diseño del contenido de la escena:

  • Primero elige la idea visual única de esa oración (comparación, lista, sueño, viaje, número…), luego construye el diseño que se ajuste. El diseño puede cambiar entre escenas del mismo video.
  • Deja espacio para el elemento importante: que el sujeto principal sea el más grande/más prominente; los elementos secundarios deben ser pequeños. Deja espacio vacío (espacio negativo) de forma deliberada.
  • El tamaño, posición y número varían según el contenido (¿1 personaje o 2? ¿hilera de íconos, objeto grande único, mapa/línea de tiempo?). Si es necesario, dibuja formas personalizadas con lines.
  • No agregues automáticamente vestimenta/tocado a figuras históricas. Las figuras se dibujan sin accesorios por defecto; solo agrega casco, corona, sombrero o capa si la narrativa o el usuario lo requiere explícitamente. No extiendas el color de acento como decoración en la ropa del personaje.
  • En escenas de nudo y corte, configura el objeto de forma legible: dibuja la cuerda con varios bucles que se crucen claramente, muestra el nudo apretado en el centro y distingue los extremos. En una espada, el mango, la guarda y la hoja puntiaguda deben ser distinguibles. Después del momento del corte, deja los dos extremos de la cuerda cortada espaciados y claramente visibles; la espada y el nudo no deben quedar ocultos por los subtítulos. Dibuja formas especiales de cuerda/espada con lines.
  • Motivos como línea de suelo, sol, tarjeta de título son opcionales; no los uses si no encajan con el tema (ej. interior, noche, concepto abstracto).
  • Coloca los subtítulos en un lugar legible y alejado de la interfaz de la plataforma; si hay conflicto, ajusta con caption_y. Verifica visualmente superposiciones y desbordes en los fotogramas fijos, no confíes solo en números.
  • Las coordenadas de dibujo se dan en píxeles (o proporción 0–2) en el lienzo de 1080×1920; planifica los valores desde cero para cada escena.

Errores comunes (Gotchas)

  • Siempre revisa los fotogramas fijos antes de codificar; los elementos superpuestos y los rayos de sol recortados son los defectos habituales. Usa --draft para borrador y renderizado completo para detalle: los fotogramas que no cambian no se redibujan, un video de 10 s tarda aproximadamente 20 s en calidad completa.
  • El subtítulo ajusta líneas hasta el 86 % del ancho (máximo 3 líneas), pero si una palabra no cabe o excede 3 líneas, se reduce. Divide oraciones de más de 2 líneas en dos escenas. La posición predeterminada del subtítulo es solo un respaldo; si es necesario, proporciona caption_y en la escena.
  • Fuentes: instala Poppins y Playfair Display (o Lora), o proporciona --font-dir. Si no se encuentra ninguna fuente TrueType, el renderizador emite una advertencia y los caracteres turcos (İ ş ğ â) pueden faltar; verifica en los fotogramas fijos. Se escanean las carpetas de fuentes de Linux, macOS y Windows.
  • Mantén el color de acento semántico (sujeto, palabra clave, negación). No agregues más colores.
  • Cuando karaoke esté presente, el énfasis rojo del subtítulo sigue la narración palabra por palabra usando los intervalos proporcionados. No dejes una palabra clave roja fija en pantalla; renderiza las palabras no activas en el color de texto del subtítulo.

Skills relacionados