- Hyperframes๋ HTML์ ํ๋ ์ ๋จ์๋ก ์บก์ฒํ์ฌ ๊ฒฐ์ ๋ก ์ MP4 ๋น๋์ค๋ก ๋ณํํ๋ ์คํ์์ค ํ๋ ์์ํฌ (Apache 2.0)
- ์น ํ์ด์ง๋ฅผ ๋ง๋๋ ๋ฐฉ์์ผ๋ก ๋น๋์ค๋ฅผ ์ ์ํ๋ HTML-native ๋น๋์ค ์ ์ ๋๊ตฌ
- AI ์ฝ๋ฉ ์์ด์ ํธ๊ฐ HTML์ ์ง์ ์์ฑํ์ฌ ๋น๋์ค๋ฅผ ์์ฑํ ์ ์๋๋ก ์ค๊ณ๋ ์์ด์ ํธ ์นํ์ ๋ ๋๋ง ์์ง
ํด๋น ๊ฐ๋ ์ด ํ์ํ ์ด์
- ๊ธฐ์กด ๋น๋์ค ํธ์ง ๋๊ตฌ(Premiere, After Effects)๋ GUI ๊ธฐ๋ฐ์ด๋ผ ์๋ํยท์คํฌ๋ฆฝํ ์ด ์ด๋ ต๋ค
- Remotion์ React ๊ธฐ๋ฐ์ด๋ผ ๋น๋ ์คํ ์ด ํ์ํ๊ณ , ์์ด์ ํธ๊ฐ JSX๋ฅผ ์ ํํ ์์ฑํ๊ธฐ ์ด๋ ต๋ค
- Hyperframes๋ plain HTML๋ง์ผ๋ก ๋น๋์ค๋ฅผ ์ ์ํ๋ฏ๋ก, ์ฝ๋ฉ ์์ด์ ํธ๋ ์ฌ๋์ด๋ ์ง์ ์ฅ๋ฒฝ์ด ๋ฎ๋ค
- ๋์ผ ์ ๋ ฅ โ ๋์ผ ์ถ๋ ฅ(๊ฒฐ์ ๋ก ์ ๋ ๋๋ง)์ด ๋ณด์ฅ๋์ด CI/CD, ํ๊ท ํ ์คํธ, ์๋ํ ํ์ดํ๋ผ์ธ์ ์ ํฉํ๋ค
AS-IS
sequenceDiagram autonumber participant ์ฌ์ฉ์ participant GUIํธ์ง๊ธฐ as GUI ๋น๋์ค ํธ์ง๊ธฐ participant ์ถ๋ ฅ as MP4 ์ถ๋ ฅ ์ฌ์ฉ์->>GUIํธ์ง๊ธฐ: ์๋์ผ๋ก ํ์๋ผ์ธ ์กฐ์ GUIํธ์ง๊ธฐ->>GUIํธ์ง๊ธฐ: ํ๋ก์ ํธ ํ์ผ ์ ์ฅ (.prproj ๋ฑ) ์ฌ์ฉ์->>GUIํธ์ง๊ธฐ: ๋ด๋ณด๋ด๊ธฐ ๋ฒํผ ํด๋ฆญ GUIํธ์ง๊ธฐ->>์ถ๋ ฅ: ๋ ๋๋ง (์คํ ํ๊ฒฝ์ ๋ฐ๋ผ ๊ฒฐ๊ณผ ๋ค๋ฅผ ์ ์์) Note over GUIํธ์ง๊ธฐ,์ถ๋ ฅ: ์๋ํ ๋ถ๊ฐ, ์์ด์ ํธ ์ ๊ทผ ๋ถ๊ฐ
TO-BE
sequenceDiagram autonumber participant Agent as AI ์์ด์ ํธ / ์ฌ์ฉ์ participant HTML as index.html (Composition) participant CLI as Hyperframes CLI participant Chrome as Headless Chrome participant FFmpeg participant ์ถ๋ ฅ as MP4 ์ถ๋ ฅ Agent->>HTML: HTML + data attributes ์์ฑ Agent->>CLI: npx hyperframes render CLI->>Chrome: ํ๋ ์๋ณ seekFrame(N) ํธ์ถ Chrome->>Chrome: beginFrame API๋ก ๊ฒฐ์ ๋ก ์ ์บก์ฒ Chrome->>FFmpeg: PNG ํ๋ ์ ์คํธ๋ฆผ ์ ๋ฌ FFmpeg->>์ถ๋ ฅ: x264 ์ธ์ฝ๋ฉ โ MP4 Note over Chrome,์ถ๋ ฅ: ๋์ผ ์ ๋ ฅ = ๋์ผ ์ถ๋ ฅ (๊ฒฐ์ ๋ก ์ )
์ํคํ ์ฒ โ 6๊ฐ ํจํค์ง ๊ตฌ์กฐ
Hyperframes๋ ๋ชจ๋ ธ๋ ํฌ ๊ตฌ์กฐ๋ก, ๊ฐ ํจํค์ง๊ฐ ๋ช ํํ ์ญํ ์ ๋ด๋นํ๋ค:
| ํจํค์ง | ์ญํ |
|---|---|
| @hyperframes/core | ํ์ ์์คํ , HTML ํ์/์ ๋๋ ์ดํฐ, ๋ฆฐํฐ, ๋ฐํ์, Frame Adapter |
| @hyperframes/engine | Puppeteer ๊ธฐ๋ฐ Headless Chrome ํ๋ ์ ์บก์ฒ ์์ง |
| @hyperframes/producer | ์บก์ฒ + FFmpeg ์ธ์ฝ๋ฉ + ์ค๋์ค ๋ฏน์ฑ ํตํฉ ํ์ดํ๋ผ์ธ |
| @hyperframes/studio | ๋ธ๋ผ์ฐ์ ๊ธฐ๋ฐ ๋น์ฃผ์ผ ์๋ํฐ UI |
| @hyperframes/player | ์๋ฒ ๋ ๊ฐ๋ฅํ <hyperframes-player> ์น ์ปดํฌ๋ํธ |
| hyperframes (CLI) | init, preview, lint, render ๋ฑ CLI ๋ช ๋ น์ด |
ํจํค์ง ์์กด ๊ด๊ณ:
CLI โ Producer โ Engine โ Core
Studio โ Core
Player โ Core
Composition โ ๋น๋์ค์ ๋จ์
Composition์ Hyperframes ๋น๋์ค์ ๊ธฐ๋ณธ ๋จ์๋ก, ํ๋์ HTML ํ์ผ์ด ํ๋์ ๋น๋์ค(๋๋ ๋น๋์ค ๋ด ์ฅ๋ฉด)๋ฅผ ์ ์ํ๋ค. ๋ณ๋์ ํ๋ก์ ํธ ํ์ผ ํฌ๋งท์ด ์๋๋ผ plain HTML ์์ฒด๊ฐ ๋น๋์ค์ ๋จ์์ด๋ฉฐ, data-* ์์ฑ์ผ๋ก ํ์ด๋ฐ๊ณผ ๋ ์ด์ด๋ง ์ ๋ณด๋ฅผ ์ถ๊ฐํ ๊ฒ์ด๋ค.
ํ์ ๊ตฌ์กฐ
<div id="root" data-composition-id="my-video"
data-start="0" data-width="1920" data-height="1080">
<!-- ํ์ด๋ฐ์ด ์ง์ ๋ ํด๋ฆฝ ์์ -->
<h1 id="title" class="clip"
data-start="0" data-duration="5" data-track-index="0">
Hello!
</h1>
</div>3๊ฐ์ง ํต์ฌ ๊ท์น
- ๋ฃจํธ ์์์
data-composition-id,data-width,data-heightํ์ - ํ์ด๋ฐ ์์์
data-start,data-duration,data-track-index,class="clip"ํ์ - GSAP ํ์๋ผ์ธ์
{ paused: true }๋ก ์์ฑํ๊ณwindow.__timelines์ ๋ฑ๋ก
ํด๋ฆฝ ํ์ 4๊ฐ์ง
| ํ์ | HTML ์์ | ์ฉ๋ |
|---|---|---|
| Video | <video> | B-roll, A-roll ์์ |
| Image | <img> | ์ ์ ์ค๋ฒ๋ ์ด, ๊ทธ๋ํฝ |
| Audio | <audio> | ๋ฐฐ๊ฒฝ์์ , ํจ๊ณผ์ |
| Nested Composition | <div data-composition-src="..."> | ์๋ธ ์ฌ, ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ ๋๋ฉ์ด์ |
2-Layer ์ํคํ ์ฒ
Composition์ ๋ ๋ ์ด์ด๋ก ๋ถ๋ฆฌ๋๋ค:
- HTML Layer (Primitives): ๋ฌด์์ด ์ธ์ ์ด๋ค ํธ๋์์ ์ฌ์๋๋์ง ์ ์ธ โ
data-*์์ฑ์ผ๋ก ์ ์ด - Script Layer (Effects): ์ ๋๋ฉ์ด์ , ํธ๋์ง์ , ๋์ DOM ์กฐ์ โ GSAP ํ์๋ผ์ธ์ผ๋ก ๊ตฌํ
์คํฌ๋ฆฝํธ์์ ํด๋ฆฝ์ ํ์/์จ๊น์ด๋ ๋ฏธ๋์ด ์ฌ์์ ์ง์ ์ ์ดํ๋ฉด ์ ๋๋ค. ์ด๋ ํ๋ ์์ํฌ๊ฐ ์๋์ผ๋ก ๊ด๋ฆฌํ๋ค.
Frame Adapter โ ์ ๋๋ฉ์ด์ ๋ฐํ์ ์ถ์ํ
Frame Adapter๋ โํ๋ ์ N์์ ํ๋ฉด์ด ์ด๋ป๊ฒ ๋ณด์ฌ์ผ ํ๋๊ฐ?โ๋ผ๋ ์ง๋ฌธ์ ๋ตํ๋ ์ธํฐํ์ด์ค๋ค. ๋ค์ํ ์ ๋๋ฉ์ด์ ๋ฐํ์(GSAP, Lottie, Three.js ๋ฑ)์ ํต์ผ๋ ๋ฐฉ์์ผ๋ก ํตํฉํ๋ค.
type FrameAdapter = {
id: string;
init?: (ctx: FrameAdapterContext) => Promise<void> | void;
getDurationFrames: () => number; // ์ด ํ๋ ์ ์ ๋ฐํ
seekFrame: (frame: number) => Promise<void> | void; // ํด๋น ํ๋ ์์ผ๋ก ์ด๋
destroy?: () => Promise<void> | void;
};๊ฒฐ์ ๋ก (Determinism) ๊ณ์ฝ
- ์ ๊ท ์๊ณ:
t = frame / fps Date.now()๊ฐ์ wall-clock ์์กด ๊ธ์ง- ์๋ ์๋ ๋๋ค ๊ธ์ง
- ๋ ๋๋ง ์ค ๋คํธ์ํฌ ์์ฒญ ๊ธ์ง
seekFrame()์ ๋ฉฑ๋ฑ(idempotent) โ ๊ฐ์ ํ๋ ์ ์ ๋ ฅ์ด๋ฉด ํญ์ ๋์ผํ ์ถ๋ ฅ
์ง์ ๋ฐํ์ 6์ข
| ๋ฐํ์ | Seek ๋ฐฉ์ |
|---|---|
| GSAP | timeline.totalTime(seconds) |
| Anime.js | instance.seek(timeMs) |
| CSS Keyframes | Animation.currentTime |
| Lottie | goToAndStop(timeMs, false) |
| Three.js/WebGL | hf-seek ์ด๋ฒคํธ + window.__hfThreeTime |
| WAAPI | animation.currentTime |
๋ ๋๋ง ํ์ดํ๋ผ์ธ โ ํ๋ ์ ์บก์ฒ์์ MP4๊น์ง
ํต์ฌ ๊ณต์
frame = floor(time ร fps)
๋ ๋๋ง ํ๋ฆ
- CLI๊ฐ Producer๋ฅผ ํธ์ถ
- Producer๊ฐ Engine์ ํตํด Headless Chrome ์ธ์คํด์ค ์์ฑ
- Composition HTML์ Chrome์ ๋ก๋
- ๊ฐ ํ๋ ์์ ๋ํด:
- Frame Adapter์
seekFrame(N)ํธ์ถ - Chrome
beginFrameAPI๋ก ํด๋น ํ๋ ์ ์บก์ฒ (PNG)
- Frame Adapter์
- ์บก์ฒ๋ ํ๋ ์ ์ํ์ค๋ฅผ FFmpeg์ ํ์ดํ
- FFmpeg๊ฐ x264๋ก ์ธ์ฝ๋ฉ โ MP4 ์ถ๋ ฅ
๋ ๋๋ง ๋ชจ๋ 2๊ฐ์ง
| ๋ชจ๋ | ํน์ฑ |
|---|---|
| Local | ์์คํ Chrome + FFmpeg ์ฌ์ฉ, ๋น ๋ฆ, GPU ๊ฐ์ ๊ฐ๋ฅ |
| Docker | ๊ณ ์ ๋ Chrome/FFmpeg/ํฐํธ, ํ๋ซํผ ๋ฌด๊ด ๋์ผ ์ถ๋ ฅ, CI/CD์ฉ |
Quality ํ๋ฆฌ์
| ํ๋ฆฌ์ | CRF | ์๋ | ์ฉ๋ |
|---|---|---|---|
| Draft | 28 | ultrafast | ๋ฐ๋ณต ์์ ์ฉ ๋น ๋ฅธ ๋ฏธ๋ฆฌ๋ณด๊ธฐ |
| Standard | 18 | medium | ๊ธฐ๋ณธ๊ฐ, 1080p์์ ์๊ฐ์ ๋ฌด์์ค |
| High | 15 | slow | ์ต์ข ๋ฉํ์ฉ |
GSAP ํ์๋ผ์ธ โ ์ ๋๋ฉ์ด์ ์ ํต์ฌ ํจํด
Hyperframes์์ GSAP ํ์๋ผ์ธ์ ๋ฐ๋์ paused ์ํ๋ก ์์ฑํ๊ณ , ํ๋ ์์ํฌ๊ฐ ํ๋ก๊ทธ๋๋งคํฑํ๊ฒ ์คํฌ๋ฌ๋นํ๋ค:
// 1. paused ํ์๋ผ์ธ ์์ฑ
const tl = gsap.timeline({ paused: true });
// 2. ์ ๋ ์์น ํ๋ผ๋ฏธํฐ๋ก ์ ๋๋ฉ์ด์
๋ฐฐ์น
tl.from("#title", { opacity: 0, y: -50, duration: 1 }, 0); // 0์ด๋ถํฐ
tl.to("#subtitle", { opacity: 1, duration: 0.5 }, 1.5); // 1.5์ด๋ถํฐ
// 3. composition-id์ ๋งค์นญํ์ฌ ๋ฑ๋ก
window.__timelines = window.__timelines || {};
window.__timelines["my-video"] = tl;Composition์ duration = GSAP ํ์๋ผ์ธ์ duration. ๋น๋์ค๊ฐ 30์ด์ธ๋ฐ ์ ๋๋ฉ์ด์ ์ด 8์ด์ ๋๋๋ฉด ๋น๋์ค๋ 8์ด์์ ์๋ฆฐ๋ค. ๋น tween์ผ๋ก ์ฐ์ฅ:
tl.set({}, {}, 30); // ํ์๋ผ์ธ์ 30์ด๋ก ํ์ฅ๊ฐ๋ฐ ์ํฌํ๋ก์ฐ
# 1. ํ๋ก์ ํธ ์์ฑ
npx hyperframes init my-video
# 2. ๋ธ๋ผ์ฐ์ ์์ ์ค์๊ฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
npx hyperframes preview
# 3. HTML ํธ์ง (์์ด์ ํธ ๋๋ ์ง์ )
# index.html ์์ โ ์๋ ํซ ๋ฆฌ๋ก๋
# 4. ๋ฆฐํธ ๊ฒ์ฌ
npx hyperframes lint
# 5. MP4 ๋ ๋๋ง
npx hyperframes render --output output.mp4Hyperframes vs Remotion
| Hyperframes | Remotion | |
|---|---|---|
| ์ ์ ๋ฐฉ์ | HTML + CSS + seekable ์ ๋๋ฉ์ด์ | React ์ปดํฌ๋ํธ |
| ๋น๋ ์คํ | ์์ โ index.html์ด ๊ณง ํ๋ ์ด ๊ฐ๋ฅ | ๋ฒ๋ค๋ฌ ํ์ |
| ์์ด์ ํธ ํธ๋์คํ | Plain HTML ํ์ผ | JSX / React ํ๋ก์ ํธ |
| ๋ผ์ด์ ์ค | Apache 2.0 | Remotion License (source-available) |
| ๋ถ์ฐ ๋ ๋๋ง | Local + AWS Lambda | Remotion Lambda |