Motion as code with an agent|INEMA.CLUB-PRO

Lesson 8 · 20 min

Your piece: a 15 s opening in 16:9 and 9:16, rendered and checked

Time to put it all together into a piece you actually use: a 15 s opening with your DESIGN.md, in the two formats social networks ask for. The 9:16 doesn't come from the 16:9 through a render option: it's another composition that reuses the CSS and the choreography. In this lesson you deliver both, checked by the kit, and build the plan with dates.

Start the lesson
Two monitors in a dark editing room, one horizontal and one vertical, showing the same opening frame.

In this lesson you will

  1. 1One project, two compositions: index.html and formatos/vertical.html
  2. 2Shared CSS and choreography, only the size changes
  3. 3Render queue: one at a time, and retry only what failed
  4. 4The course map and your plan with dates

Goal: deliver a 15 s opening in 16:9 and 9:16, with the DESIGN.md, checked by the kit in both formats.

01The map of your piece

The four deliverables the opening brings together. Click a step to see the "done when".

Step 1Project

init e render

3 exercises

HyperFrames project that renders and passes the checker.

See the lesson
Step 2Brand

DESIGN.md

3 exercises

DESIGN.md with the four sections and checked colors.

See the lesson
Step 3Request

RISE e quadros

3 exercises

A composition the agent made and you checked across five frames.

See the lesson
Step 4Sound

optional

3 exercises

Narration or soundtrack in code, checked with --audio.

See the lesson
By the end of the courseAn opening of your own in 16:9 and 9:16, with a DESIGN.md, rendered locally and checked.
24 exercises
Click an exercise to see what to do and the "done when".
  1. 1/4

    Project

    The project from lesson 2, with the version pinned and telemetry turned off. This is the folder where the opening will live.

  2. 2/4

    Brand

    The DESIGN.md from lesson 4 sets the colors and the motion for both formats.

  3. 3/4

    Request

    The RISE request from lesson 3, now for 15 s and two formats. The E includes the check and the frames of both.

  4. 4/4

    Sound

    If your opening has a voice or a soundtrack, lesson 7 adds the sound. If it doesn't, skip it: the checker says "sem áudio" and it's right.

Lessons 1, 5 and 6 are the base: determinism, Remotion and libraries come in when your piece calls for them.

02The opening in both formats

abertura.css and abertura.js are shared; index.html (1920×1080) and formatos/vertical.html (1080×1920) only change the root and one class.

File · kit/exemplos/a8-abertura/abertura.css
/* DESIGN.md tokens + a layout that works for both formats (16:9 and 9:16) */
:root { --fundo: #0c0c10; --superficie: #1c1c22; --linha: #3f3f47; --texto: #f4f4f5; --texto2: #a1a1aa; --destaque: #e9b949; }
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { overflow: hidden; background: var(--fundo); }
#root { width: 100%; height: 100%; position: relative; font-family: ui-sans-serif, system-ui, sans-serif; }
#luz { position: absolute; inset: 0; background: radial-gradient(ellipse at 50% 45%, var(--superficie) 0%, var(--fundo) 70%); }
#bloco { position: absolute; left: 10%; right: 10%; top: 50%; transform: translateY(-50%); }
#rotulo { color: var(--texto2); font-size: 40px; letter-spacing: 0.2em; text-transform: uppercase; line-height: 1.3; }
#titulo { color: var(--texto); font-size: 150px; font-weight: 700; line-height: 1.1; margin-top: 36px; }
#apoio { color: var(--texto2); font-size: 54px; line-height: 1.2; margin-top: 40px; }
#trilho { position: absolute; left: 10%; right: 10%; bottom: 14%; height: 4px; background: var(--linha); transform-origin: left center; }
#cabeca { position: absolute; left: 10%; bottom: calc(14% - 38px); width: 18px; height: 80px; background: var(--destaque); border-radius: 4px; }
/* 9:16: same piece, larger type relative to the width, everything stacked */
.vertical #titulo { font-size: 132px; }
.vertical #apoio { font-size: 56px; }
.vertical #rotulo { font-size: 36px; }
File · kit/exemplos/a8-abertura/abertura.js
// The same choreography in both formats: only the playhead's travel distance depends on the width.
window.criaAbertura = function () {
  const root = document.getElementById("root");
  const largura = Number(root.dataset.width);
  const corrida = largura * 0.8 - 18; // from the start to the end of the track (80% of the width)
  const tl = gsap.timeline({ paused: true });
  tl.fromTo("#trilho", { scaleX: 0 }, { scaleX: 1, duration: 1.2, ease: "power2.inOut" }, 0.4);
  tl.fromTo("#cabeca", { opacity: 0 }, { opacity: 1, duration: 0.3 }, 1.4);
  tl.fromTo("#rotulo", { y: 24, opacity: 0 }, { y: 0, opacity: 1, duration: 0.6, ease: "power2.out" }, 2.0);
  tl.fromTo("#cabeca", { x: 0 }, { x: corrida, duration: 9, ease: "power1.inOut" }, 2.0);
  tl.fromTo("#titulo", { y: 50, opacity: 0 }, { y: 0, opacity: 1, duration: 0.8, ease: "power3.out" }, 4.0);
  tl.fromTo("#apoio", { y: 30, opacity: 0 }, { y: 0, opacity: 1, duration: 0.7, ease: "power2.out" }, 7.5);
  // from 11 s to 15 s the main frame holds (DESIGN.md rule: the ending holds for at least 1.5 s)
  return tl;
};
File · kit/exemplos/a8-abertura/index.html
<!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>
    <link rel="stylesheet" href="abertura.css" />
    <style>html, body { width: 1920px; height: 1080px; }</style>
  </head>
  <body>
    <div id="root" data-composition-id="main" data-start="0" data-duration="15" data-width="1920" data-height="1080">
      <div id="luz"></div>
      <div id="bloco">
        <p id="rotulo">Formação Cinema com IA</p>
        <h1 id="titulo">Motion por&nbsp;código</h1>
        <p id="apoio">HyperFrames e Remotion, do terminal ao&nbsp;MP4</p>
      </div>
      <div id="trilho"></div>
      <div id="cabeca"></div>
    </div>
    <script src="abertura.js"></script>
    <script>window.__timelines["main"] = window.criaAbertura();</script>
  </body>
</html>
Terminal · brand, check, two renders and conferir
K=~/projetos/formacao-cinema-ia-motion-v72/kit
export HYPERFRAMES_NO_TELEMETRY=1 NO_COLOR=1
E=${TMPDIR:-/tmp}/ensaio-motion/a8; rm -rf "$E"; mkdir -p "$E"
cp -r "$K/exemplos/a8-abertura" "$E/abertura"; cd "$E/abertura"
python3 "$K/conferir-design.py" DESIGN.md abertura.css; echo "saída: $?"
npx -y hyperframes@0.8.176 check 2>&1 | grep -E "Check passed|✗"
npx -y hyperframes@0.8.176 render --quality draft --workers 2 --quiet --output renders/abertura-16x9.mp4 > render-16x9.log 2>&1
npx -y hyperframes@0.8.176 render -c formatos/vertical.html --quality draft --workers 2 --quiet --output renders/abertura-9x16.mp4 > render-9x16.log 2>&1
python3 "$K/conferir.py" renders/abertura-16x9.mp4 15 1920x1080; echo "saída: $?"
python3 "$K/conferir.py" renders/abertura-9x16.mp4 15 1080x1920; echo "saída: $?"
Example from the repository
OK: 4 seções · 6 cores · 5 regras de movimento · a composição usa só cores do DESIGN.md
saída: 0
◇  Check passed
OK: 15,0 s · 1920×1080 · 30 fps · sem áudio
saída: 0
OK: 15,0 s · 1080×1920 · 30 fps · sem áudio
saída: 0

The 9:16 render uses -c formatos/vertical.html. vertical.html is index.html with the root at 1080×1920, the vertical class, and the paths ../abertura.css and ../abertura.js.

03The error, isolated

Trying to get the 9:16 out of the 16:9 composition with a render option.

Terminal · render with --resolution portrait
export HYPERFRAMES_NO_TELEMETRY=1 NO_COLOR=1
cd ${TMPDIR:-/tmp}/ensaio-motion/a8/abertura
npx -y hyperframes@0.8.176 render --resolution portrait --quality draft --output renders/torto.mp4 2>&1 | grep -A2 "incompatible"

04The render queue

On an ordinary machine, renders run one at a time. Run it, interrupt it and run it again: only what was left over goes back in the queue.

fila/

rodando/

pronto/

falhou/

Browser simulation: nothing really renders. The failure is on purpose, to show that only the step that failed goes back.

05Practice

The rehearsal, the error, and your opening.

E1 · Two formats of the example

10 min

Run the "brand, check, two renders and conferir" block.

Done when: OK: 15,0 s · 1920×1080 · 30 fps · sem áudio and OK: 15,0 s · 1080×1920 · 30 fps · sem áudio, each with saída: 0.

E2 · The shortcut that doesn't exist

5 min

Run the --resolution portrait block.

Done when: ✗ Output resolution incompatible and the line that ends in use --resolution landscape instead.

E3 · Your opening

60 min

In your project, with your DESIGN.md: ask the agent (RISE) for the 15 s opening in index.html and formatos/vertical.html, check the frames, render both, and run the checker on both.

Done when: K=~/projetos/formacao-cinema-ia-motion-v72/kit; python3 $K/conferir.py renders/abertura-16x9.mp4 15 1920x1080; python3 $K/conferir.py renders/abertura-9x16.mp4 15 1080x1920; python3 $K/conferir-design.py DESIGN.md abertura.css; echo "saída: $?" → two lines starting with OK: 15,0 s, one with OK: 4 seções and saída: 0.

06Generate your plan with dates

Pick a start date and how much time you have per week.

07Lesson quiz

The explanation appears after you answer.

Question 1 of 3

How do you get the 9:16 out of the same opening?

08In three sentences

Two formatsTwo compositions, one style: shared CSS and choreography.
DeliveryDESIGN.md checked, check passing, and the checker run on both MP4s.
QueueOne render at a time; redo only what failed.

Next step