graphic-gif
Genera un GIF animado en bucle a partir de animaciones CSS o de una API de IA de imagen a video. Salida: animation.gif.
A diferencia de cualquier otra habilidad graphic- que genera un PNG o PDF estático, esta habilidad produce un .gif animado. Usa animaciones CSS @keyframes capturadas fotograma a fotograma mediante Playwright y la API de Animaciones Web (Opción A, por defecto), o un proceso de imagen a video con IA a través de Kling (Opción B).
Reglas críticas (leer antes de cada generación)
- El valor por defecto es css-animated. Nunca uses
ai-generateda menos que se solicite explícitamente. - El lienzo es de 800×800 px. Todos los valores
clamp()se calculan a 800 px (1vw = 8 px). - HTML único y autocontenido. Todo el CSS en línea dentro de
<style>. Solo se permite un<link>externo a una CDN de fuentes. - Nunca muestres el HTML en el chat. Guárdalo en un archivo, muestra solo un resumen.
- La captura de fotogramas usa la API de Animaciones Web para buscar posiciones. NO bucles
setTimeout, NO trucos conanimation-delay. - Número exacto de fotogramas:
Math.floor(duracion_segundos * fps)fotogramas. El fotograma ent=duracion_msNO debe capturarse: duplicat=0y provoca un parpadeo visible en el punto de bucle. - Sin cajas de marcador de posición. Solo elementos visuales generados con CSS. Sin elementos de "la imagen va aquí".
- Paletas más simples = archivos más pequeños. Usa:
clean-slate,terminal,electric-burst,brutalist. - Sin
animation-delaypara escalonar. Incorpora el escalonado en los porcentajes de@keyframes: el manejo de tiempos de los fotogramas se encarga de la sincronización. - Comprométete con la dirección de diseño antes de escribir CSS. Tono, elemento característico, estilo de movimiento, detalle inolvidable: todo decidido antes de la primera línea de código.
Paso 1: Entrada
Requerido: prompt (descripción del contenido Y resumen del movimiento)
Opcional con valores predeterminados:
| Parámetro | Valor predeterminado | Opciones |
|---|---|---|
| animation_type | css-animated | css-animated / ai-generated |
| duration | 3.0 | segundos |
| fps | 12 | fotogramas por segundo |
| loop | true | true / false |
| style | clean-slate | clean-slate / terminal / electric-burst / brutalist |
| dimensions | 800x800 | Ancho x Alto en píxeles |
| optimization | balanced | quality / balanced / filesize |
Si falta el prompt o no tiene descripción del movimiento, pregunta exactamente:
"¿Qué debe mostrar el GIF? Describe el contenido Y el movimiento (ej.: 'Las estadísticas suben: el 73% de los compradores leen 3 o más contenidos antes de comprar. Efecto de máquina de escribir, un carácter a la vez. Estilo: terminal. 3 segundos, 12 fps.')
Configuración clave (todo es opcional, se muestran los valores predeterminados):
- animation_type: css-animated (predeterminado) o ai-generated
- duration: 3.0 segundos
- fps: 12
- loop: true
- style: clean-slate (opciones: clean-slate / terminal / electric-burst / brutalist)
- dimensions: 800x800
- optimization: balanced (opciones: quality / balanced / filesize)"
Si toda la información requerida está presente → salta directamente al Paso 2.
Paso 2: Arquitectura interna (nunca se muestra al usuario)
Para css-animated:
- Elige el tipo de animación entre:
fade-in,slide-in,typewriter,counter,pulse,loop-scroll - Lee
references/animation-library.md: busca la especificación HTML/CSS completa del tipo elegido. - Lee
references/style-presets.md: carga el bloque de tokens CSS del estilo elegido. - Calcula el número de fotogramas:
Math.floor(duracion_segundos * fps)— anota este número. - Comprométete con la dirección de diseño:
| Decisión | Derivar de |
|---|---|
| Tono | Registro emocional para la audiencia (mecánico / cálido / eléctrico / profesional) |
| Elemento característico | UN recurso visual usado de forma consistente (parpadeo de cursor, número fantasma, superposición de líneas de barrido, borde de acento) |
| Estilo de movimiento | Filosofía de curva de facilidad para este tipo (resorte / lineal / escalonado / ease-in-out) |
| Detalle inolvidable | Lo ÚNICO que un espectador recordará de este GIF |
Para ai-generated:
- Genera el HTML del fotograma base estático (diseño tipo póster para el lienzo).
- Expórtalo como PNG usando una captura de pantalla.
- Llama a la API de Kling:
POST https://api.klingai.com/v1/videos/image2videoconimage_urlypromptdescribiendo el movimiento. - Consulta hasta que el trabajo termine.
- Descarga el video y conviértelo a GIF con ffmpeg:
# Paleta de dos pasos para la mejor calidad de color ffmpeg -i input.mp4 -vf "fps=12,scale=800:800:flags=lanczos,palettegen=stats_mode=diff" palette.png ffmpeg -i input.mp4 -i palette.png -vf "fps=12,scale=800:800:flags=lanczos,paletteuse=dither=bayer:bayer_scale=5" output.gif
Paso 3: Generación del HTML (ruta css-animated)
Lee references/animation-library.md y references/style-presets.md antes de generar.
Base del lienzo — requerido en cada GIF:
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
body {
width: 800px;
height: 800px;
overflow: hidden;
background: var(--bg);
font-family: var(--font-body);
}
.canvas {
width: 800px;
height: 800px;
position: relative;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
Reglas de animación:
animation-fill-mode: forwards(oboth) en TODOS los elementos animados.- Funciones de temporización por tipo:
typewriter→steps(N, end)donde N = cantidad exacta de caracterescounter→linearfade-in→cubic-bezier(0.22, 1, 0.36, 1)(ease-out)slide-in→cubic-bezier(0.34, 1.56, 0.64, 1)(resorte con rebase)pulse→ease-in-outconanimation-iteration-count: infiniteloop-scroll→linearconanimation-iteration-count: infinite
- Para animaciones de un solo disparo (fade-in, slide-in, typewriter, counter):
animation-iteration-count: 1— el bucle ocurre a nivel del GIF. - Sin
animation-delay: el escalonado se incorpora en los porcentajes de@keyframes.
Cálculo de N para typewriter: Cuenta cada carácter, incluidos espacios, puntuación y números:
- "73% of buyers" = 14 caracteres →
steps(14, end) - "Hello, World!" = 13 caracteres →
steps(13, end)
@property de CSS para counter (requerido para el tipo counter):
@property --num {
syntax: '<integer>';
inherits: false;
initial-value: 0;
}
.counter {
animation: countUp var(--duration) linear forwards;
counter-reset: num var(--num);
}
.counter::after { content: counter(num); }
@keyframes countUp {
from { --num: 0; }
to { --num: var(--target); }
}
Loop-scroll: el contenido DEBE estar duplicado:
<!-- 4 elementos originales + 4 elementos duplicados -->
<div class="ticker-track" style="--item-count: 4;">
[item1][item2][item3][item4][item1][item2][item3][item4]
</div>
translateX(0 → -50%) con linear infinite.
Reglas de calidad de diseño (del compromiso en el Paso 2):
- El elemento característico nombrado DEBE estar presente en el CSS/HTML (no solo descrito).
- Tipografía: contraste de peso mínimo 2:1 (ej.: 700 vs 400) entre el texto principal y el de apoyo.
- Fondo: sin blanco puro
#fffpara estilos oscuros: usa el valor exacto de--bgde la plantilla. - Para el estilo terminal: agrega una superposición de líneas de barrido
::afterconrepeating-linear-gradientaopacity: 0.03. - Para brutalist: borde grueso
4px solid #000o4px solid var(--accent)en un elemento clave. - Detalle inolvidable: si requiere un elemento adicional, agrégalo ahora.
Paso 4: Auto-validación (corrige cada fallo antes del Paso 5)
Lienzo:
-
bodyy.canvasexactamente de 800×800 px (o las dimensiones especificadas). -
overflow: hiddentanto enbodycomo en.canvas. - Ningún elemento sobresale del límite del lienzo.
Animaciones:
- Sin
animation-delayen ninguna parte: el escalonado está en los porcentajes de@keyframes. - Todas las animaciones comienzan en
t=0(la API de Animaciones Web buscará desde ahí). -
animation-fill-mode: forwardsobothen todos los elementos animados. - Animaciones de un solo disparo:
animation-iteration-count: 1. - Animaciones infinitas (pulse, loop-scroll):
animation-iteration-count: infinite.
Verificaciones específicas por tipo:
- Typewriter: N en
steps(N, end)= cantidad exacta de caracteres de la cadena de texto. - Counter:
@property --numdeclarado consyntax: '<integer>'yinitial-value: 0. - Counter:
counter-reset: num var(--num)y::after { content: counter(num) }. - Loop-scroll: contenido duplicado exactamente una vez en el HTML.
Diseño:
- Sin cajas de marcador de posición.
- Tokens de la plantilla de estilo aplicados desde
references/style-presets.md: sin colores hex sueltos. - El elemento característico nombrado en el Paso 2 está realmente presente en el HTML/CSS.
- El detalle inolvidable del Paso 2 está realmente implementado.
-
<link>a la CDN de la fuente presente para el estilo elegido.
Paso 5: Exportación
Determina el slug a partir del prompt (kebab-case, ≤30 caracteres). Crea el directorio de salida:
mkdir -p [slug]
Guarda el HTML:
[slug]/animation.html
Abre en el navegador para una verificación visual rápida:
open [slug]/animation.html
Ejecuta el script de exportación (reemplaza [skill-root] con la ruta real de esta habilidad):
bash [skill-root]/scripts/export-gif.sh \
[slug]/animation.html \
[slug]/animation.gif \
--duration [duracion] \
--fps [fps] \
[--no-loop si loop=false] \
--optimization [optimization] \
--width [W] \
--height [H]
El script:
- Instala
gifenc,sharp(ojimp) yplaywrighten un directorio temporal. - Descarga Chromium si no está en caché.
- Ejecuta
capture-and-encode.mjs: pausa las animaciones, busca cada fotograma, hace capturas de pantalla y ensambla el GIF. - Ejecuta un pase de optimización con
gifsiclesi está disponible. - Informa el tamaño del archivo y abre el resultado.
Si el script de exportación no se encuentra en [skill-root]/scripts/export-gif.sh, verifica que la habilidad se haya instalado con su carpeta scripts/ intacta.
Paso 6: Resumen de salida
Muestra después de una exportación exitosa:
## GIF: [descripción en una línea]
Fecha: [YYYY-MM-DD] | Estilo: [style] | Animación: [type] | [duration]s @ [fps]fps
Dimensiones: [WxH] | Fotogramas: [N] | Bucle: [true/false]
Archivos
Fuente: [slug]/animation.html
Salida: [slug]/animation.gif
Tamaño: [X] KB
Lista de verificación
- [ ] La vista previa hace bucle limpiamente en el punto de inicio/final (sin parpadeo)
- [ ] Texto legible en el tamaño de visualización previsto
- [ ] Tamaño de archivo apropiado: correo electrónico <500 KB / redes sociales <3 MB
Ruta de IA Generada (Opción B)
Usar solo cuando animation_type: ai-generated se especifique explícitamente.
Requisitos:
- Clave de API de Kling en el entorno:
KLING_API_KEY(66 créditos gratis/día, sin necesidad de tarjeta de crédito para el nivel gratuito). ffmpeginstalado localmente para la conversión de video a GIF.
Flujo de trabajo:
- Genera un HTML de fotograma base estático que coincida con el prompt (estilo póster/gráfico en las dimensiones especificadas).
- Exporta el fotograma base como PNG:
# Captura rápida con Playwright node -e " const { chromium } = require('playwright'); (async () => { const browser = await chromium.launch(); const page = await browser.newPage({ viewport: { width: W, height: H } }); await page.goto('file://[slug]/animation.html'); await page.screenshot({ path: '[slug]/base-frame.png' }); await browser.close(); })(); " - Sube al endpoint de imagen a video de Kling.
- Convierte el resultado a GIF con el proceso de paleta de dos pasos de ffmpeg.
- Aplica optimización con gifsicle.
Cuando Kling no esté disponible: Vuelve a css-animated con una nota para el usuario: "La generación con IA requiere una clave de API de Kling (KLING_API_KEY). Se recurre a css-animated. Configura la clave para habilitar la generación con IA."
Consejos para el prompt (mostrar cuando el usuario pida orientación)
"Describe el movimiento, no solo el contenido. 'Las estadísticas suben una por una' es mejor que 'mostrar estadísticas'."
"Mantenlo simple para el tamaño del archivo. De 1 a 3 elementos animados y un fondo sólido."
"Piensa en bucles. La animación debe fluir de forma invisible desde el final hasta el inicio."
"Especifica el tipo de animación explícitamente.
typewriterycounterson los más efectivos para redes sociales."✅ Bueno: "Crea un GIF animado, css-animated, efecto typewriter. Texto: 'El 73% de los compradores B2B leen 3 o más contenidos antes de contactar con ventas.' Cada carácter se escribe uno a la vez. Estilo: terminal. 3 segundos, 12 fps, loop=true."
❌ Malo: "haz un gif animado de consejos de marketing"