Felo API PlatformFelo API Platform

Contenido

Crea un vídeo de motion graphics con HTML y Opus 5.5

Escribe un beat sheet, pide a Opus 5.5 una escena HTML determinista vía API de Felo, captura los fotogramas con Playwright y codifica un MP4 con ffmpeg. Funciona en WorkBuddy, ChatGPT con ejecución de código, Codex, Pi Agent o Claude Code.

Tiempo45 minutosNivelIntermedioActualizado2026-10-30
Para quiénCreadoresMotion designersDesarrolladores independientes

Copiar el prompt

Sustituye los campos entre corchetes y pégalo en Claude Code, Codex o cualquier IA con acceso a terminal. Instala el skill de Felo, pregunta antes de gastar créditos y ejecuta el flujo.

Crea un vídeo de [duración] segundos, formato [vertical / horizontal], sobre [idea].
Estilo: [estilo]. Audiencia: [audiencia]. Audio: [ninguno / una pista con licencia en ./audio.mp3 / TTS].

Trabajas en una carpeta con terminal y [WorkBuddy / ChatGPT con ejecución de código / Codex / Pi Agent / Claude Code]. Si no puedes ejecutar Node y un navegador headless, detente y dímelo en lugar de fingir que has renderizado.

Sigue este orden:
1. Escribe un storyboard de 3–6 beats con segundos exactos de inicio y fin.
2. Paso HTML: llama a Claude Opus 5.5 mediante la API de Felo. Usa el ID de modelo claude-opus-5-5 y mi FELO_API_KEY. No me pidas una suscripción de Claude ni otra clave de Anthropic.
3. Pide a Opus un único archivo HTML autocontenido: que defina window.DURATION y exponga async window.seek(t). Sin recursos externos, CDN, Date.now(), requestAnimationFrame(), transiciones CSS ni temporizadores. Siembra todos los valores aleatorios para que el mismo t dibuje siempre el mismo fotograma.
4. Previsualiza en t = 0, 25 %, 50 %, 75 % y el último fotograma. Revisa desbordes, recortes, fuentes y zonas seguras antes de renderizar todo.
5. Renderiza cada fotograma con Playwright, codifica en H.264 con ffmpeg y mezcla la pista de audio si existe.
6. Muestra el primer fotograma, el último y la ruta final. No publiques nada.

Reglas:
- Antes de gastar créditos, muestra las llamadas a la API de Felo y el uso estimado de tokens.
- Usa solo el texto que te doy, o marca claramente el texto de relleno inventado.
- No uses material, música, logotipos ni fuentes con copyright. Solo fuentes del sistema y formas generadas.
- Mantén el vídeo final por debajo de 30 segundos, salvo que pida explícitamente uno más largo.
- Escribe todo en ./video/ y resume los comandos ejecutados.

La copia también incluye los pasos de instalación y las reglas de seguridad.

Lo que obtienes

Salida de ejemplo de una ejecución. No es generación en vivo.

Ejemplo de informe de render (extracto)

Informe de render

Escena: video/scene.html (18 KB) Duración: 12 s · 1080x1920 · 30 fps · 360 fotogramas Comprobaciones: window.DURATION = 12 · seek(t) presente · sin Date.now / rAF / temporizadores

Vista previa: preview-0ms.png · preview-3000ms.png · preview-6000ms.png · preview-9000ms.png Codificación: video/video.mp4 (H.264, 360 fotogramas) Audio: video/final.mp4 (AAC, 12,0 s)

Las llamadas exactas

Para desarrolladores: el mismo flujo como código, en orden de ejecución.

Mostrar las llamadas reales a la API
  1. Escribe primero el beat sheet

    Fija duración y 3–6 beats, cada uno con inicio, fin, texto en pantalla y cambio visual principal.

  2. Genera la escena HTML con Opus 5.5

    Apunta el Anthropic SDK a la base URL de Felo, usa claude-opus-5-5 y pide solo HTML con window.DURATION y async seek(t).

    generate-scene.ts
    import { mkdir, writeFile } from "node:fs/promises";
    import Anthropic from "@anthropic-ai/sdk";
    
    const SYSTEM = `You write a single, self-contained HTML video scene.
    Requirements:
    - 1080x1920 (or 1920x1080), no external assets, system fonts only.
    - set window.DURATION = <seconds>.
    - expose async window.seek(t) that draws the frame for time t.
    - no Date.now(), no requestAnimationFrame(), no CSS transitions, no timers.
    - seed every random value; the same t must always produce the same frame.
    - return only the HTML file, no markdown fences.`;
    
    const brief = `12-second vertical motion graphic about [idea].
    Beats: [0-3s hook], [3-7s point], [7-10s proof], [10-12s CTA].
    Palette: [colors]. Type: system sans. Keep text inside a 64px safe area.`;
    
    const anthropic = new Anthropic({
      apiKey: process.env.FELO_API_KEY,
      baseURL: "https://openapi.felo.ai/api",
    });
    
    const message = await anthropic.messages.create({
      model: "claude-opus-5-5",
      max_tokens: 32000,
      system: SYSTEM,
      messages: [{ role: "user", content: brief }],
    });
    
    const raw = message.content
      .filter((block) => block.type === "text")
      .map((block) => block.text)
      .join("");
    
    const html = raw.replace(/^```(?:html)?\s*/i, "").replace(/```\s*$/, "").trim();
    await mkdir("video", { recursive: true });
    await writeFile("video/scene.html", html);
    console.log(`scene.html: ${html.length} bytes`);

    Salida de ejemplo

    scene.html: 18432 bytes
  3. Comprueba determinismo y previsualiza

    Haz capturas en t=0, 25%, 50%, 75% y el último fotograma, revisando desbordes, fuentes y zonas seguras.

    preview.ts
    import { chromium } from "playwright";
    import { pathToFileURL } from "node:url";
    
    const browser = await chromium.launch();
    const page = await browser.newPage({
      viewport: { width: 1080, height: 1920 },
      deviceScaleFactor: 1,
    });
    
    await page.goto(pathToFileURL("video/scene.html").href);
    await page.waitForFunction(() => typeof (window as any).seek === "function");
    
    const duration = await page.evaluate(() => (window as any).DURATION as number);
    for (const t of [0, duration * 0.25, duration * 0.5, duration * 0.75]) {
      await page.evaluate(async (time) => {
        await (window as any).seek(time);
      }, t);
      await page.screenshot({ path: `video/preview-${Math.round(t * 1000)}ms.png` });
    }
    
    await browser.close();
    console.log(`duration ${duration}s`);

    Salida de ejemplo

    duration 12s
    video/preview-0ms.png
    video/preview-3000ms.png
    video/preview-6000ms.png
    video/preview-9000ms.png
  4. Renderiza todos los fotogramas

    Llama a seek(t) con t = frame / fps, captura y codifica H.264 con ffmpeg.

    render.ts
    import { spawn } from "node:child_process";
    import { mkdir, rm } from "node:fs/promises";
    import { pathToFileURL } from "node:url";
    import { chromium } from "playwright";
    
    const FPS = 30;
    
    const browser = await chromium.launch();
    const page = await browser.newPage({
      viewport: { width: 1080, height: 1920 },
      deviceScaleFactor: 1,
    });
    await page.goto(pathToFileURL("video/scene.html").href);
    await page.waitForFunction(() => typeof (window as any).seek === "function");
    
    const duration = await page.evaluate(() => (window as any).DURATION as number);
    const frames = Math.ceil(duration * FPS);
    
    await rm("video/frames", { recursive: true, force: true });
    await mkdir("video/frames", { recursive: true });
    
    for (let frame = 0; frame < frames; frame++) {
      await page.evaluate(async (time) => {
        await (window as any).seek(time);
      }, frame / FPS);
      await page.screenshot({
        path: `video/frames/${String(frame).padStart(5, "0")}.png`,
      });
    }
    await browser.close();
    
    const ffmpeg = spawn("ffmpeg", [
      "-y",
      "-framerate", String(FPS),
      "-i", "video/frames/%05d.png",
      "-c:v", "libx264",
      "-pix_fmt", "yuv420p",
      "-movflags", "+faststart",
      "video/video.mp4",
    ], { stdio: "inherit" });
    
    await new Promise<void>((resolve, reject) => {
      ffmpeg.on("exit", (code) => {
        if (code === 0) resolve();
        else reject(new Error(`ffmpeg exited with ${code}`));
      });
    });
    
    console.log(`${frames} frames -> video/video.mp4`);

    Salida de ejemplo

    360 frames -> video/video.mp4
  5. Mezcla audio y mira completo

    Añade la pista con licencia con -c:v copy, revisa duración y volumen y míralo entero.

    mux.sh
    ffmpeg -i video/video.mp4 -i video/audio.wav \
      -c:v copy -c:a aac -b:a 192k -shortest \
      video/final.mp4
    
    ffprobe -v error -show_entries format=duration \
      -of default=nw=1:nk=1 video/final.mp4

    Salida de ejemplo

    12.000000
  6. Itera con el mismo modelo

    Describe solo el fotograma fallido y el cambio deseado, pasa el HTML actual a Opus y relanza la previsualización antes del render completo.

Qué incluye

  • Storyboard y línea de tiempo escritos primero
  • Escena HTML determinista de Opus 5.5
  • Script de render de Playwright y codificación ffmpeg
  • MP4 final con pista de audio opcional
  • Bucle de revisión y corrección fotograma a fotograma

Qué no hace

  • Opus 5.5 entrega código, no fotogramas; el renderizador del navegador captura
  • No hace falta suscripción Claude, pero el uso del modelo Felo se factura por uso
  • Siguen haciendo falta Node, Playwright Chromium y ffmpeg
  • Sin recursos externos ni CDN; solo HTML/CSS/SVG/Canvas o archivos locales
  • Los vídeos largos requieren dividir escenas; no es grabación de pantalla en vivo
  • Narración y música son pasos separados; el flujo solo mezcla audio proporcionado

Preguntas

¿Opus 5.5 genera vídeo directamente?

No. Genera texto y código escribiendo la escena HTML; el navegador y ffmpeg convierten la escena en fotogramas y MP4.

¿Necesito suscripción Claude?

No. Usa la clave Felo para llamar a `claude-opus-5-5` vía API de Felo con facturación por uso; no necesitas suscripción Claude aparte.

¿En qué agents funciona?

WorkBuddy, ChatGPT con ejecución de código, Codex, Pi Agent, Claude Code o cualquier agent que ejecute Node y un navegador headless.

¿Por qué seek(t)?

La captura no es en tiempo real: el fotograma 400 puede capturarse mucho después del 399, así que cada fotograma debe ser función pura de t.

¿Puedo usar HyperFrames o Remotion?

Sí, para composiciones largas o proyectos estructurados. Esta receta mantiene un solo HTML para revisar la llamada y el bucle de render.

¿Cuánto cuesta un vídeo de 12 segundos?

Depende del prompt, tokens de salida e iteraciones. El modelo Felo factura por token; consulta precios antes de un render largo.

¿Puedo usar mi música y narración?

Sí, si tienes derechos. Renderiza primero y mezcla la pista con licencia o tu TTS con ffmpeg. El flujo no genera narración.

Referencias

Tutoriales y proyectos en los que se basa este flujo.

Flujos relacionados

Hazlo tuyo

La misma receta, adaptada a cómo entregas de verdad.

Proyecto HyperFrames o Remotion

Para composiciones largas usa estos frameworks; la llamada al modelo es igual y solo cambia el comando de render.

Versión cuadrada para redes

Mantén el beat sheet, pasa a 1080x1080 y ajusta tipografía y zonas seguras.

Tres variantes de un brief

Genera tres escenas con colores y ritmos distintos, previsualiza y renderiza solo la mejor.

Las páginas de referencia detrás de esta receta y los siguientes pasos.