E1 · Criar o projeto
5 minRode o bloco "criar o projeto e ver o que veio".
Pronto quando: A saída mostra saída: 0, a lista com index.html e package.json, a linha hyperframes@0.8.176 render e Status: disabled.
Aula 2 · 15 min
HyperFrames é um motor aberto do HeyGen que renderiza HTML em vídeo. Três atributos dizem o tamanho e a duração, uma timeline GSAP pausada diz o movimento, e o check confere tudo antes do render. Nesta aula você cria o projeto, escreve a primeira composição e sai com um MP4 conferido.
Começar a aula
Objetivo: criar um projeto HyperFrames, escrever a composição com data-* e renderizar um MP4 que passa no conferidor.
Clique em cada etapa.
Quando a raiz tem data-duration, é ela que manda: uma timeline mais curta segura o último quadro.
O init sem perguntas (--non-interactive) e a telemetria desligada antes de tudo.
export HYPERFRAMES_NO_TELEMETRY=1 NO_COLOR=1
E=${TMPDIR:-/tmp}/ensaio-motion/a2; rm -rf "$E"; mkdir -p "$E"; cd "$E"
npx -y hyperframes@0.8.176 init minha-abertura --non-interactive > init.log 2>&1; echo "saída: $?"
ls minha-abertura
grep '"render"' minha-abertura/package.json
npx -y hyperframes@0.8.176 telemetry status | head -2saída: 0
AGENTS.md
CLAUDE.md
hyperframes.json
index.html
meta.json
package.json
"render": "npx --yes hyperframes@0.8.176 render",
Status: disabledO script render do package.json já chama a versão exata. A telemetria aparece desligada porque o bloco exportou HYPERFRAMES_NO_TELEMETRY=1.
Por padrão o CLI envia dados anônimos de uso. O telemetry status do 0.8.176 mostra como desligar: hyperframes telemetry disable (fica gravado) ou as variáveis HYPERFRAMES_NO_TELEMETRY=1 ou DO_NOT_TRACK=1 (só na sessão). Os blocos do curso usam a variável.
Título, filete e subtítulo entrando em ordem. Copie por cima do index.html do init.
<!doctype html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 1920px; height: 1080px; overflow: hidden; background: #0c0c10; }
#root { width: 100%; height: 100%; position: relative; font-family: ui-sans-serif, system-ui, sans-serif; }
#cena { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: center; padding-left: 200px; }
#titulo { color: #f4f4f5; font-size: 120px; font-weight: 700; line-height: 1.1; letter-spacing: -0.02em; }
#linha { width: 640px; height: 6px; margin: 36px 0; background: #e9b949; transform-origin: left center; }
#sub { color: #a1a1aa; font-size: 48px; line-height: 1.2; }
</style>
</head>
<body>
<div id="root" data-composition-id="main" data-start="0" data-duration="5" data-width="1920" data-height="1080">
<section id="cena">
<h1 id="titulo">Vídeo é código</h1>
<div id="linha"></div>
<p id="sub">Uma página HTML, um relógio, um MP4.</p>
</section>
</div>
<script>
const tl = gsap.timeline({ paused: true });
tl.fromTo("#titulo", { y: 60, opacity: 0 }, { y: 0, opacity: 1, duration: 0.8, ease: "power3.out" }, 0.3);
tl.fromTo("#linha", { scaleX: 0 }, { scaleX: 1, duration: 0.7, ease: "power2.inOut" }, 0.9);
tl.fromTo("#sub", { y: 30, opacity: 0 }, { y: 0, opacity: 1, duration: 0.6, ease: "power2.out" }, 1.4);
window.__timelines["main"] = tl;
</script>
</body>
</html>K=~/projetos/formacao-cinema-ia-motion-v72/kit
export HYPERFRAMES_NO_TELEMETRY=1 NO_COLOR=1
cd ${TMPDIR:-/tmp}/ensaio-motion/a2/minha-abertura
cp "$K/exemplos/a2-ola/index.html" index.html
npx -y hyperframes@0.8.176 check 2>&1 | grep -E "◇|✗|⚠"
npx -y hyperframes@0.8.176 render --quality draft --workers 2 --quiet --output renders/abertura.mp4 > render.log 2>&1
echo "render: $?"
python3 "$K/conferir.py" renders/abertura.mp4 5 1920x1080; echo "saída: $?"◇ 0 errors, 0 warnings ◇ 0 errors, 0 warnings ◇ 0 issues across 9 sample(s) ◇ 0 errors, 0 warnings ◇ 7/7 text checks pass WCAG AA ◇ disabled ◇ Check passed render: 0 OK: 5,0 s · 1920×1080 · 30 fps · sem áudio saída: 0
As cinco primeiras linhas ◇ são as partes do check (lint, execução, layout, movimento, contraste); a sexta, disabled, é a captura de quadros, que vem desligada (--snapshots liga). O conferidor lê o MP4 com ffprobe e compara com o que você pediu: 5 s, 1920×1080.
Pôr data-start numa seção que tem título e texto dentro fez o lint do 0.8.176 avisar nested_structure_needs_subcomposition. No exemplo, a seção é só um contêiner (sem data-start) e a timeline anima os filhos; cena com vários elementos próprios vira subcomposição.
O HyperFrames publica skills para agentes (pesquisa, §5). O init já deixa um AGENTS.md e um CLAUDE.md na pasta do projeto.
npx skills add heygen-com/hyperframes
Do init ao MP4 conferido, e uma mudança sua.
Rode o bloco "criar o projeto e ver o que veio".
Pronto quando: A saída mostra saída: 0, a lista com index.html e package.json, a linha hyperframes@0.8.176 render e Status: disabled.
Rode o bloco "check, render e conferir".
Pronto quando: ◇ Check passed, render: 0 e OK: 5,0 s · 1920×1080 · 30 fps · sem áudio com saída: 0.
No index.html do seu projeto, mude data-duration da raiz para 8, troque o título por um seu, rode check e render de novo.
Pronto quando: python3 ~/projetos/formacao-cinema-ia-motion-v72/kit/conferir.py renders/abertura.mp4 8 1920x1080; echo "saída: $?" → OK: 8,0 s · 1920×1080 · 30 fps · sem áudio e saída: 0.
A explicação aparece depois da sua resposta.
Pergunta 1 de 4
O que define a duração do MP4 no HyperFrames?
Pergunta 2 de 4
O check passou, mas o render saiu errado. Qual destes o check NÃO garante?
Pergunta 3 de 4
Por que o curso fixa hyperframes@0.8.176 em todo comando?
Pergunta 4 de 4
Como desligar a telemetria só na sessão do terminal?
Escolha uma alternativa. A explicação aparece depois da sua tentativa.