La fábrica de video con agentes|INEMA.CLUB-PRO

Clase 3 · 20 min

Demostración de app, clic a clic

Para mostrar una app, la pantalla real convence más que cualquier animación. El video-demonstrativo dirige un navegador por tu app, toma una foto por paso con la posición del elemento clicado, narra con voz local y arma el video con cursor y zoom. En esta clase haces todo eso, con una app de ejemplo, sin crédito.

Comenzar la clase
Portátil sobre una mesa oscura mostrando una app con un círculo resaltando el cursor, y un segundo monitor con la misma pantalla ampliada.

En esta clase vas a

  1. 1El actions.json: URL, tamaño de pantalla y un paso por clic
  2. 2La captura con agent-browser: foto y posición del objetivo de cada paso
  3. 3Narración local por paso, con voz Kokoro, sin servicio externo
  4. 4La composición generada y el render con la versión de HyperFrames fija

Objetivo: capturar una app paso a paso con el agente y renderizar la demostración narrada que pasa el verificador.

01De la app en línea al MP4

Haz clic en cada etapa.

Haz clic en cada bloque del diagrama para ver qué hace.

Etapas de la skill video-demonstrativo en el commit a87b382 (05/10/2026). Captura antes de animar: el video muestra la pantalla de verdad.

02La app y el guion de clics

Una app de una página en el kit (cuántas palabras caben en una narración) y el actions.json con cinco pasos.

Archivo · kit/exemplos/a3-demo/actions.json
{
  "url": "http://127.0.0.1:18791/",
  "viewport": [1280, 800],
  "window": { "top": 96, "titleH": 52, "urlLabel": "127.0.0.1:18791" },
  "eyebrow": "DEMONSTRAÇÃO · MINUTOS DE VÍDEO",
  "ctaNarration": "Pronto: agora você sabe quantas palavras cabem no seu vídeo.",
  "ctaCaption": "Roteiro do tamanho certo",
  "steps": [
    { "id": "home", "intro": true, "caption": "Minutos de vídeo · do zero", "narration": "Este app diz quantas palavras cabem numa narração. Vamos usar em três cliques." },
    { "id": "minutos", "do": { "type": "setValue", "selector": "#min", "value": "3" }, "target": "#min", "caption": "1 · Duração: 3 minutos", "narration": "Primeiro, a duração do vídeo: três minutos." },
    { "id": "ritmo", "do": { "type": "setValue", "selector": "#ppm", "value": "140" }, "target": "#ppm", "caption": "2 · Ritmo: 140 palavras por minuto", "narration": "Depois, o ritmo da fala. Uma narração calma fica perto de cento e quarenta palavras por minuto." },
    { "id": "calcular", "do": { "type": "clickText", "tag": "button", "text": "Calcular" }, "target": { "tag": "button", "text": "Calcular" }, "click": true, "caption": "3 · Calcular", "narration": "Agora é só clicar em calcular." },
    { "id": "resultado", "target": "#res", "zoom": true, "caption": "Cabem 420 palavras", "narration": "Cabem quatrocentas e vinte palavras. Esse é o tamanho do seu roteiro." }
  ]
}

03Capturar la app

El bloque levanta la app en un puerto local, ejecuta la captura en una sesión propia de agent-browser y cierra todo al final.

Terminal · capturar la app
K=~/projetos/formacao-cinema-ia-fabrica-v72/kit
command -v agent-browser > /dev/null || { echo "FALTA agent-browser: npm i -g agent-browser@0.6.0 && agent-browser install"; exit 1; }
E=${TMPDIR:-/tmp}/ensaio-fabrica/a3; rm -rf "$E"; mkdir -p "$E"; cd "$E"
git clone -q https://github.com/inematds/video-demonstrativo.git && git -C video-demonstrativo checkout -q a87b382
cp video-demonstrativo/skills/video-demonstrativo/scripts/capture.mjs "$K/exemplos/a3-demo/actions.json" .
python3 -m http.server 18791 --bind 127.0.0.1 --directory "$K/exemplos/a3-demo" > servidor.log 2>&1 & S=$!
until curl -s -o /dev/null http://127.0.0.1:18791/; do sleep 0.3; done
export AGENT_BROWSER_SESSION=ensaio-fabrica
node capture.mjs actions.json > captura.log 2>&1; echo "captura: $?"
agent-browser close > /dev/null 2>&1; kill $S
ls assets/shots
python3 -c "import json; s=json.load(open('steps.json')); print('passos no steps.json:', len(s['steps']))"
Ejemplo del repositorio
captura: 0
00-home.png
01-minutos.png
02-ritmo.png
03-calcular.png
04-resultado.png
passos no steps.json: 5

Una foto por paso y el steps.json con las cajas medidas. El until curl espera a que el puerto responda antes de abrir el navegador; un sleep fijo falla en una máquina cargada.

04Narrar y montar

Crea el proyecto HyperFrames, copia fotos, fuentes y steps.json, genera una frase por paso y escribe la composición.

Terminal · narrar y montar
export HYPERFRAMES_NO_TELEMETRY=1 NO_COLOR=1
E=${TMPDIR:-/tmp}/ensaio-fabrica/a3; S=$E/video-demonstrativo/skills/video-demonstrativo
cd "$E" && rm -rf demo
npx -y hyperframes@0.8.176 init demo --non-interactive > init.log 2>&1; echo "init: $?"
cd demo && mkdir -p assets/audio assets/txt
cp -r ../assets/shots assets/ && cp -r "$S/assets/fonts" assets/ && cp ../steps.json .
cp "$S/scripts/composition-template.mjs" build-demo.mjs
node -e 'const d=require("./steps.json"); const l=d.steps.map(s=>s.narration); l.push(d.ctaNarration);
l.forEach((t,i)=>require("fs").writeFileSync(`assets/txt/s${i+1}.txt`, t.trim()+"\n")); console.log("falas:", l.length)'
for f in assets/txt/s*.txt; do
  n=$(basename "$f" .txt)
  npx -y hyperframes@0.8.176 tts "$f" --voice pf_dora --lang pt-br --speed 0.98 --output "assets/audio/$n.wav" > /dev/null 2>&1 || echo "falhou $n"
done
ls assets/audio | wc -l
node build-demo.mjs | head -1
Ejemplo del repositorio
init: 0
falas: 6
6
index.html gerado · 1920x1080 · TOTAL=30.389s · 6 cenas (5 passos + CTA)

Seis frases de narración (cinco pasos y el cierre), seis WAVs. El TOTAL sale de la suma de las narraciones con un margen antes y después de cada una: si cambias la narración, cambia la duración.

05Render y verificación

Check, render en borrador y el verificador con la duración que la propia composición declara.

Terminal · render y verificar
export HYPERFRAMES_NO_TELEMETRY=1 NO_COLOR=1
K=~/projetos/formacao-cinema-ia-fabrica-v72/kit
cd ${TMPDIR:-/tmp}/ensaio-fabrica/a3/demo
npx -y hyperframes@0.8.176 check 2>&1 | grep -E "◇|✗" | head -3
npx -y hyperframes@0.8.176 render --quality draft --workers 2 --quiet --output renders/demo.mp4 > render.log 2>&1
echo "render: $?"
D=$(grep -o 'id="root"[^>]*data-duration="[0-9.]*"' index.html | grep -o "[0-9.]*\"$" | tr -d \")
echo "duração pedida: $D s"
python3 "$K/conferir.py" renders/demo.mp4 "$D" 1920x1080 --audio; echo "saída: $?"
Ejemplo del repositorio
  ◇ 0 errors, 0 warnings
  ◇ 0 issues across 9 sample(s)
  ◇ 0 errors, 0 warnings
render: 0
duração pedida: 30.389 s
OK: 30,4 s · 1920×1080 · 30 fps · com áudio
saída: 0

En esta máquina el render de 30 s tardó menos de un minuto (medido fuera de la captura; render por software, --workers 2). La duración pedida sale del data-duration de la raíz, así que el verificador sirve para cualquier guion tuyo.

06Práctica

De la app de ejemplo a tu app.

E1 · Captura

5 min

Ejecuta el bloque "capturar el app".

Listo cuando: captura: 0, las cinco fotos de 00-home.png a 04-resultado.png y passos no steps.json: 5.

E2 · Demostración renderizada

10 min

Ejecuta "narrar y montar" y después "render y verificar".

Listo cuando: index.html gerado · 1920x1080, render: 0 y OK: … · 1920×1080 · 30 fps · com áudio con saída: 0.

E3 · Tu app

30 min

Pídele a tu agente un actions.json con 4 a 6 pasos para una app tuya que corre en localhost. Cambia la URL, ejecuta la captura con tu archivo y después los dos bloques siguientes.

Listo cuando: En la carpeta del ensayo, python3 -c "import json; print(len(json.load(open('steps.json'))['steps']))" → el número de pasos de tu actions.json, y el render termina en OK: … · com áudio y saída: 0.

07Prueba de la clase

La explicación aparece después de tu respuesta.

Pregunta 1 de 3

¿Por qué el viewport del actions.json es fijo?

08En tres frases

Captura antes de animaragent-browser fotografía el app real y mide dónde hacer clic.
La locución manda en el tiempocada paso dura lo que dura su narración, hecha con voz local.
Versión fijaHyperFrames 0.8.176 en los bloques, verificador sobre el MP4.

Para ir más allá

Clase anteriorPróxima clase