트렌딩 딥다이브 · 2026-07-23 · TrendShift Daily #9 · PIREEL

pireel/pireel 딥다이브
— 서버 없이 브라우저 안에서 도는 AI 비디오 에디터, 그걸 MCP로 에이전트가 운전한다

Pireel토킹헤드(말하는 사람) 영상 전용, 백엔드 없이 브라우저 안에서 100% 도는 오픈소스 AI 비디오 에디터다. 한 줄 요약: 스토리보딩·디자인 그래픽·키네틱 자막·테마·타임라인·WebCodecs 익스포트가 전부 클라이언트(브라우저)에서 실행되고, 어떤 AI 에이전트든 MCP로 에디터를 "직접 운전"할 수 있다. 계정도, 서버 업로드도 없다.

기존 도구와 결정적으로 다른 점 — CapCut·Descript는 클라우드에 영상을 올려야 편집이 시작되고, Remotion은 영상을 React 코드로 프로그래밍해야 한다. Pireel은 반대다. 영상 바이트는 브라우저 밖으로 나가지 않고(OPFS 저장), 편집·프리뷰·익스포트가 전부 로컬에서 돈다. 그리고 에디터 자체를 MCP 툴 서버로 노출해, Claude Code·Codex 같은 외부 에이전트가 자기 모델의 지능으로 편집을 지휘한다.

(저장소 pireel/pireel · 생성 2026-07-20(분석 시점 3일 차) · ⭐ 약 411 · 언어 TypeScript · 라이선스 AGPL-3.0-only(공유 UI 패키지만 MIT) · 스택 React 19 · Vite 8 · mediabunny(WebCodecs) · MediaPipe · onnxruntime-web(MODNet) · Vercel AI SDK · pnpm 모노레포 pireel-studio v0.1.0 · shallow clone 소스 직접 분석)
목차
  1. 프로젝트 한 줄 요약
  2. 왜 주목받는가 — 백엔드리스 + 에이전트가 운전하는 에디터
  3. 기술 스택 전체 지도 — WebCodecs · React 19 · MediaPipe/ONNX · MCP
  4. 아키텍처 심화 — 컴포지션 모델 · 프리뷰=익스포트 · MCP 브리지
  5. 디렉토리 구조 해부
  6. 학습 포인트 — 여기서 훔쳐올 설계
  7. 시스템 / 실행 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한 줄 요약

"내 영상을 서버에 안 올리고, AI한테 편집을 시킬 순 없나" — 그 질문에 대한 답
한 문장으로

Pireel = 말하는 사람 영상(트랙 0) 위에, 디자인된 그래픽 카드·자막을 얹어 편집하는 브라우저 안의 비디오 스튜디오 — 그 스튜디오의 모든 버튼을 AI 에이전트가 원격으로 누를 수 있다

유튜브 쇼츠나 발표 영상을 만들 때 흐름은 늘 비슷하다. 말하는 사람을 찍고, 중요한 대목에 숫자·차트·강조 자막을 얹고, 지루한 부분을 잘라낸다. 이 반복 작업을 Pireel은 "연속된 영상(track 0) + 그 위에 시간·위치가 정해진 그래픽 블록들"이라는 단순한 데이터 구조로 모델링한다.

여기에 두 가지 반전이 있다. 첫째, 이 모든 게 브라우저 탭 하나 안에서 돈다 — 서버 렌더링도, 클라우드 업로드도 없다. 둘째, 에디터가 하는 모든 동작(자막 켜기, 블록 추가, 컷 편집, 익스포트)이 MCP 툴로 노출돼 있어서, 외부 AI 에이전트가 "이 부분에 매출 그래프 넣고, 앞의 3초 잘라줘"를 직접 실행할 수 있다.

Pireel의 정체를 정확히 잡으려면 세 단어를 기억하면 된다. backend-free(백엔드리스) · talking-head(토킹헤드 영상) · agent-drivable(에이전트가 운전 가능). README 원문은 이렇게 시작한다 — "An open-source, backend-free AI video editor for talking-head video."

용어
토킹헤드 · 백엔드리스 · WebCodecs · MCP
토킹헤드(talking-head)는 화자의 얼굴이 화면 중심에 나오는 영상(강의·리뷰·발표·쇼츠)을 말한다. 백엔드리스(backend-free)는 서버가 편집·렌더링을 대신 해 주지 않고 전부 브라우저에서 처리한다는 뜻이다. WebCodecs는 브라우저가 영상을 하드웨어로 인코딩/디코딩하게 해 주는 최신 웹 API로, "서버 없이 mp4를 뽑는" 마법의 핵심이다. MCP(Model Context Protocol)는 AI 에이전트가 외부 도구를 표준 규격으로 호출하게 하는 프로토콜 — Pireel은 자기 에디터를 이 규격의 도구로 내놓는다.

이 저장소는 사실 사설 모노레포에서 단방향으로 동기화된 공개 미러다(README 명시, 단일 스쿼시 커밋). 그래서 "브라우저에서 즉시 되는 것"과 "호스티드 서비스 전용인 것"의 경계가 뚜렷하다 — 이 구분은 4장에서 정확히 짚는다. 먼저, 왜 3일 만에 400개 넘는 별을 받았는지부터 보자.

2왜 주목받는가

생성 3일 만에 별 400+ — 세 가지 진짜 차별점

Pireel이 트렌딩에 오른 건 "또 하나의 AI 영상툴"이라서가 아니다. 시장에 널린 AI 비디오 에디터들과 설계 철학 자체가 다른 지점이 세 곳 있다. 하나씩 뜯어보자.

차별점 ①

완전 백엔드리스 + 로컬 우선(local-first) — "아무것도 브라우저를 떠나지 않는다"

계정도 서버도 필요 없다. 편집 중인 드래프트는 브라우저 localStorage에, 영상 원본 바이트는 OPFS(Origin Private File System, 브라우저 전용 파일시스템)에 저장된다. 익스포트조차 서버 렌더팜이 아니라 브라우저의 WebCodecs로 mp4를 뽑는다. CapCut·Descript가 "클라우드에 올려야 시작"인 것과 정반대다. 프라이버시가 중요한 사내 영상·미공개 자료를 다루는 사람에게 이건 결정적 장점이다.

차별점 ②

"BYO brain" — 에디터를 MCP로 외부 에이전트가 운전한다 ← 진짜 신규성

이게 Pireel의 심장이다. Remotion(코드로 영상 정의)이나 Descript(자체 내장 AI)와 달리, Pireel은 에디터 자체를 MCP 툴 서버로 노출한다. 그래서 Claude Code·Codex 같은 외부 에이전트가 자기 구독의 모델 지능으로 편집을 지휘한다. 핵심 비즈니스 설계도 여기서 나온다 — 편집 명령을 오케스트레이션하는 건 공짜, LLM 생성(블록 HTML·나레이션 플래닝)은 사용자의 Codex/Claude 구독으로 돌아가 Pireel 크레딧을 안 태운다. 소스의 mcp.ts 헤더가 이걸 한 줄로 요약한다: "orchestration is free, generation still charges".

차별점 ③

"캔버스가 원본 푸티지를 따라간다" + 22종 완성형 디자인 시스템

세로든 가로든 소스 영상의 종횡비를 그대로 캔버스로 삼는다. 말하는 사람을 트랙 0에 두고, 그 위에 디자인된 그래픽 블록(메트릭 카드·차트·다이어그램·콜아웃)을 얹는다. 이때 MediaPipe·MODNet으로 화자의 얼굴·세이프존을 검출해 그래픽이 화자를 가리지 않게 자동 배치한다. 게다가 25개의 완성된 테마(frame)를 내장해, 초보가 디자인 감각 없이도 "시네마 레터박스"·"Y2K 크롬"·"멤피스 팝" 같은 룩을 즉시 입힌다.

비유로 이해하기

기존 AI 영상툴이 "요리사가 다 해 주는 레스토랑"이라면(재료를 주방=클라우드에 넘기고 완성품을 받음), Pireel은 "AI 조수가 딸린 내 집 주방"이다. 재료(영상)는 내 냉장고(브라우저)를 안 떠나고, 조수(외부 AI 에이전트)에게 "여기 자막 넣고 저기 잘라"라고 시키면 내 눈앞에서 직접 손질한다. 조수의 두뇌는 내가 이미 구독 중인 것(Claude·Codex)을 쓰니, 식당에 두 번 돈 낼 필요가 없다.

주의 — 공개 미러의 한계
이 저장소만으로는 "MCP 에이전트 운전"이 즉시 안 된다

이 repo는 사설 모노레포의 공개 미러라, MCP의 프로토콜 코어·툴 정의·브리지 클래스는 있지만 실제 HTTP 엔드포인트(/api/studio/mcp)·Cloudflare Worker 배선·인증은 호스티드 배포 전용이라 빠져 있다. README도 "self-hostable MCP entry는 로드맵"이라고 명시한다. 즉 OSS 셸에서 지금 당장 되는 것은 임포트·편집·프리뷰·타임라인·자막·WebCodecs 익스포트이고, 생성 기능은 provider를 직접 주입하거나 호스티드를 써야 한다. 이 문서는 그 경계를 정확히 표시한다.

3기술 스택 전체 지도

브라우저 하나에 비디오 엔진 + ML 추론 + 에이전트 브리지를 다 넣었다

Pireel은 pnpm 워크스페이스 모노레포(루트 name pireel-studio v0.1.0, "type":"module")다. 서버가 없으므로 스택의 무게중심이 전부 프론트엔드 + 브라우저 API에 쏠려 있다는 게 특징이다. 계층별로 훑어보자.

빌드 · 언어 툴링

도구버전역할
Vite^8.0.16번들러/개발서버. @vitejs/plugin-react + @tailwindcss/vite + vite-tsconfig-paths 조합.
TypeScript^5.5.4target ES2022, moduleResolution Bundler, strict, noEmit. 워크스페이스 패키지가 .ts 소스를 그대로 export → 번들러가 직접 소비.
Tailwind CSS^4.0.0유틸리티 CSS. v4의 Vite 플러그인 방식.
Vitest^4.1.5테스트 러너(테스트 파일 23개).
pnpm9.12.0모노레포 패키지 매니저(packages/*, apps/*).

프론트엔드 (UI 계층)

구분기술비고
프레임워크React ^19.0.0 + react-dom 19최신 React 19. 에디터 전체가 React SPA.
UI 프리미티브radix-ui ^1.4.3 · @base-ui/react ^1.4.0 · cmdk · lucide-reactshadcn 계열 접근성 컴포넌트 + 커맨드 팔레트 + 아이콘.
마크다운/코드streamdown ^2.5.0 · shiki ^4.0.2챗의 스트리밍 마크다운(cjk/code/math/mermaid) + 코드 하이라이팅.
국제화/폰트use-intl ^4.13.0 · Geist · JetBrains Monoi18n + 가변 폰트.

AI / 에이전트

Vercel AI SDK(ai ^6.0.168 + @ai-sdk/react ^3.0.176)가 내부 챗의 useChat + streamText 툴콜링을 담당한다. 그리고 이 챗의 툴 실행면이 외부 MCP 에이전트와 정확히 같은 실행면을 공유한다는 게 핵심 설계다(4장 참고).

미디어 · 비디오 (★핵심 계층)

기술버전무엇을 하나
mediabunny^1.45.4WebCodecs 위의 mux/demux/encode 래퍼. 익스포트·씬 감지·썸네일이 전부 이걸로. Input/Output/CanvasSource/AudioSampleSource/Mp4OutputFormat 등.
@mediapipe/tasks-vision^0.10.35FaceDetector + ImageSegmenter(셀피 세그멘테이션). 화자 얼굴·세이프존 검출로 그래픽 자동 배치.
onnxruntime-web^1.27.0MODNet 인물 매팅을 WebGPU로 실행. 배경 제거/합성 품질을 끌어올림.
gsap(vendored)블록 타임라인 애니메이션. 런타임에 public/vendor/gsap.min.js를 same-origin으로 로드.
용어
mediabunny · MODNet · OPFS · foreignObject
mediabunny는 브라우저 WebCodecs의 저수준 API(VideoEncoder·muxer)를 다루기 쉽게 감싼 라이브러리다. MODNet은 인물 사진에서 배경을 분리(매팅)하는 딥러닝 모델로, 여기선 ONNX 포맷을 브라우저 WebGPU에서 돌린다. OPFS는 웹사이트마다 격리된 브라우저 전용 파일 저장소로, 큰 영상 바이트를 서버 없이 로컬에 둔다. foreignObject는 SVG 안에 HTML을 그릴 수 있게 하는 요소로, Pireel은 이걸로 HTML 오버레이를 캔버스에 "굽는다".

상태 · 데이터

fast-json-patch ^3.1.1 + jsondiffpatch ^0.7.6로 undo/버전 diff를, nanoid ^5.1.11로 ID를 만든다. 컴포지션(편집 상태)은 JSON 패치로 관리돼 실행 취소가 가볍다.

백엔드? → 사실상 없음

OSS 셸의 유일한 "서버"는 Vite 개발 플러그인 apps/studio-oss/local-assets-plugin.ts다. node:fs/node:crypto로 디스크 기반 업로드 라우트(content-addressed sha256)를 흉내 낸다 — 호스티드의 R2+CDN을 로컬로 대체하는 개발 편의 장치일 뿐이다. 실제 프로덕션 백엔드(Cloudflare Workers + Durable Objects + R2)는 이 repo에 없다. 검증 결과 "백엔드리스"는 사실이다 — 편집/프리뷰/타임라인/자막/익스포트가 전부 클라이언트다.

4아키텍처 심화 분석

세 가지 큰 그림 — 패키지 레이어 · 컴포지션 모델(프리뷰=익스포트) · MCP 브리지

Pireel의 아키텍처는 세 개의 렌즈로 보면 전부 이해된다. ① 패키지가 어떻게 층을 이루는가, ② 편집 상태(컴포지션)를 어떻게 표현해 프리뷰와 익스포트가 픽셀 단위로 같아지는가, ③ 외부 AI 에이전트가 어떻게 열린 브라우저 탭을 원격 조종하는가. 순서대로 파고든다.

① 패키지 레이어 — 순수 엔진을 UI가 감싼다

apps/studio-oss (Vite SPA 셸 · 백엔드리스 진입점) │ mounts ▼ @pireel/studio-ui (에디터: 워크벤치·프리뷰·타임라인·패널·클라 익스포트·에이전트 브리지) │ uses ├──► @pireel/studio-engine (순수 엔진: zero-React / zero-DB / zero-provider) ├──► @pireel/studio-frames (25개 테마 콘텐츠팩) └──► @pireel/ui (shadcn식 프리미티브 + ai-elements)

핵심은 studio-engineReact도 DB도 provider도 모르는 순수 로직이라는 점이다. 컴포지션 모델·자막 렌더·MCP 프로토콜·비디오 렌더가 전부 여기 있고, UI(studio-ui)는 이 엔진을 React로 감쌀 뿐이다. 이 분리 덕분에 같은 엔진 코드가 브라우저에서도, (호스티드의) 서버 오프라인 툴에서도 재사용된다.

② 컴포지션 데이터 모델 — "블록은 데이터, 렌더는 템플릿+테마"

composition-core.ts의 구조는 연속 비디오(track 0) + 멀티트랙 오버레이 블록이다. 여기서 영리한 결정 하나: 블록은 HTML을 저장하지 않고 데이터만 저장한다.

// 블록은 "무엇을" 담을지만 선언한다 (어떻게 그릴지는 나중에)
{
  templateId: "metric-card",       // 어떤 템플릿?
  slots: { title: "MRR", value: "$42k" }, // 슬롯 채우기
  startSec: 3.2, durationSec: 2.5,   // 언제부터 얼마나
  trackIndex: 1, box: {...}          // 어느 트랙, 어디에
}

실제 HTML/애니메이션은 조립(assemble) 시점에 템플릿 레지스트리 + 테마(CSS 변수)로 동적 렌더된다. 그래서 테마를 바꿔도 블록 데이터는 그대로고, CSS 변수만 교체하면 룩이 바뀐다. 또 에이전트는 자유형 HTML을 통째로 생성할 필요 없이, templateIdslots만 선언적으로 채우면 된다(자유형이 필요하면 custom 템플릿 사용).

비디오 트랙은 VideoShot[](각 {srcStart, srcEnd, treatment, src?})로, 편집 타임라인 = 각 클립의 소스 구간을 이어붙인 것이다. treatment는 full / punch-in / corner-br / split-l 같은 프레이밍이고, src가 설정되면 외부에서 삽입한 B-roll 클립이 된다.

③ 프리뷰 = 익스포트 = "같은 소스" (WYSIWYG의 진짜 비밀)

대부분의 에디터에서 "미리보기"와 "실제 출력"이 미묘하게 다른 건, 둘을 다른 코드로 그리기 때문이다. Pireel은 이걸 원천 봉쇄한다 — 프리뷰와 익스포트가 글자 그대로 같은 iframe을 구동한다.

assembleHtml(comp) ──► 완전한 HTML 문서 문자열 │ ▼ 주입 hidden <iframe srcdoc="..."> │ 내부에 gsap 타임라인들이 window.__timelines[blockId] 로 등록 │ injectPreviewRuntime → window.__hfPreview = { seek, seekTimelines, play } │ ├──[프리뷰] 부모(워크벤치)가 postMessage('hf:seekTimelines', t) │ → 재생 위치마다 오버레이 시각을 동기화 │ └──[익스포트] 같은 iframe을 seekTimelines(t)로 프레임마다 구동 → #root를 SVG foreignObject로 직렬화 → <img> → canvas.drawImage → mediabunny(WebCodecs)로 인코딩 결과: 프리뷰에 보인 화면 = 익스포트된 프레임 (픽셀 동일)

익스포트의 마법은 "브라우저 자신을 래스터라이저로 쓰는" 트릭이다. HTML 오버레이(#root)를 SVG foreignObject로 감싸 <img>로 만들면, 브라우저(Blink)가 그걸 이미지로 그려 준다. 그 이미지를 캔버스에 얹고, 그 캔버스를 WebCodecs로 인코딩한다. viewBox는 레이아웃 좌표, width/height는 출력 해상도로 잡아 4K에서도 벡터가 재래스터화되어 선명하다.

눈여겨볼 것
자막 애니메이션이 "순수 시간함수"인 이유

caption-fx.ts의 키네틱 자막은 어떤 프레임이든 오직 시각 t에만 의존한다(requestAnimationFrame도, 난수도 없다). 왜? WebCodecs 익스포트는 프레임을 시간 순서대로가 아니라 특정 t로 "시크"해서 뽑는데, 애니가 이전 상태에 의존하면 익스포트가 깨진다. t만 넣으면 결정론적으로 같은 그림이 나오도록 설계해, 프리뷰와 익스포트가 완벽히 정렬된다. 5개 이펙트(highlight / pill-karaoke / kinetic-slam / editorial-emphasis / word-pop) 전부 이 원칙을 지킨다.

④ MCP "에이전트가 운전" — 3계층 브리지

가장 독창적인 부분이다. 툴 실행이 브라우저에 깊게 묶여 있어(React state 클로저, MediaPipe, 프리뷰 iframe) 서버에서 실행할 수 없다. 그래서 Pireel은 서버가 실행하지 않고 "열린 탭으로 포워딩"한다. 아래 그림에서 ✅는 이 repo에 있는 것, ❌는 호스티드 전용이라 빠진 것이다.

[외부 에이전트: Codex / Claude Code] │ MCP streamable-HTTP (stateless: 1 요청 → 1 JSON) ▼ /api/studio/mcp ❌ HTTP 엔드포인트·라우팅은 repo에 없음(호스티드) │ handleMcpRequest(raw, deps) ✅ mcp.ts (순수함수, zero-I/O) ▼ StudioBridge (Durable Object) ✅ 클래스는 있음(bridge-do.ts) / ❌ Worker 배선은 없음 │ /ws (브라우저 소켓, 유저당 단일 활성) /call POST{tool,input} ▼ WebSocket [열린 studio 브라우저 탭] ✅ use-agent-bridge.ts │ runStudioTool(tool, input) ← 내부 챗과 "완전히 동일한" 실행면 ▼ React 컴포지션 state 변이 → 프리뷰 iframe 갱신 (사용자가 자기 화면에서 편집이 실시간으로 일어나는 걸 지켜봄)

왜 Durable Object(DO)인가? 툴 실행이 특정 브라우저 탭에 묶이므로, 유저 하나당 DO 하나(idFromName(userId))를 두고 소켓을 단일 활성으로 유지한다(새 탭이 열리면 옛 탭을 code 4000으로 kick). 외부 에이전트의 툴콜은 이 DO를 거쳐 열린 탭의 runStudioTool로 전달되고, 그 결과가 다시 소켓으로 돌아온다.

// use-agent-bridge.ts — 툴콜을 열린 탭에서 "직렬로" 실행
queue = queue.then(async () => {
  let out;
  try {
    out = tool === 'get_state'
      ? { ok: true, state: getState() }
      : await runTool(tool, input ?? {});  // 내부 챗과 동일
  } catch (e) {
    out = { ok: false, error: String(e) };
  }
  sock.send(JSON.stringify({ id, ...out }));       // 결과를 소켓으로 반환
});
용어
Durable Object · streamable-HTTP · brief(계약)
Durable Object(DO)는 Cloudflare의 "상태를 가진 단일 인스턴스" 서버 객체다 — 유저별로 하나씩 두면 소켓·순서를 안정적으로 관리할 수 있다. streamable-HTTP는 MCP의 무상태 전송 방식으로, 요청 하나에 JSON 응답 하나(SSE 없이)로 끝난다. brief(계약)는 Pireel 특유의 패턴으로, 서버가 LLM을 직접 부르지 않고 {system, prompt} 지시문만 만들어 주면 호출자(에이전트)가 자기 모델로 생성하고, 결과를 다시 검증받아 반영한다. "생성 비용은 호출자가 낸다"는 원칙의 구현이다.

편집 파이프라인 — 원본 영상이 완성작이 되기까지

import video └─ extract_asr 전사(자막 텍스트 추출) └─ analyze_narration 문장 → 씬 그룹 (유료 LLM) └─ analyze_visual MediaPipe로 씬컷·얼굴·세이프존 검출 (로컬) └─ lay_out 스토리보드: 샷 슬라이스 + treatment + placeholder 배치 └─ add_graphics / compose_block_brief → apply_block placeholder를 디자인 HTML 블록으로 채움 └─ set_captions 키네틱 자막 부착 └─ export_video WebCodecs로 mp4 인코딩

여기서 로컬로 도는 것(analyze_visual = MediaPipe, 익스포트 = WebCodecs)과 유료 LLM이 필요한 것(analyze_narration, add_graphics)이 명확히 나뉜다. 후자를 "brief 계약"으로 외부 에이전트에 넘기는 게 BYO-brain의 핵심이다.

5디렉토리 구조 해부

모노레포 3개 앱/패키지 — 셸은 얇고, 엔진은 순수하고, UI는 두껍다
pireel/ ├─ apps/studio-oss/ ← 최소 Vite 셸 (백엔드리스 진입점) │ ├─ src/main.tsx styles + providers 주입 후 render │ ├─ src/providers.ts ★백엔드 배선 유일 편집 지점(unavailableProviders + 로컬 업로드) │ ├─ src/app.tsx IntlProvider + HyperframesWorkbench + Toaster │ ├─ local-assets-plugin.ts 디스크 업로드 Vite 플러그인(node:fs/crypto) │ ├─ vite.config.ts tsconfigPaths + react + tailwind + localAssets │ └─ public/vendor/gsap.min.js 프리뷰 런타임이 same-origin으로 로드 │ ├─ packages/studio-engine/ ← 순수 엔진(zero React/DB/provider) │ └─ src/ │ ├─ composition-core.ts / assemble.ts / templates.ts 컴포지션 모델·조립·템플릿 │ ├─ trim.ts 편집↔소스 시각 매핑, 샷 CRUD │ ├─ caption-fx.ts (435줄) 키네틱 자막 엔진(캔버스, 순수 시간함수) │ ├─ caption-presets.ts 정적 자막 프리셋 18종 │ ├─ plan.ts / build-draft.ts / briefs.ts 스토리보딩·brief 조립 │ ├─ mcp.ts (457줄) ★ MCP 프로토콜 코어(JSON-RPC, buildMcpTools) │ ├─ bridge-do.ts (168줄) ★ StudioBridge Durable Object 클래스 │ ├─ server-tools.ts (581줄) 서버측 오프라인 툴 실행 │ ├─ providers.ts (134줄) 5개 capability 계약(composer/planner/transcriber/…) │ ├─ transition-gl.ts gl-transitions GLSL(프리뷰/익스포트 단일 소스) │ ├─ prompts/ ★ 1파일 = 1프롬프트 │ │ ├─ agent-tools.ts (491줄) STUDIO_TOOLS 33개 정의(스키마+설명) │ │ ├─ mcp.ts (82줄) MCP_INSTRUCTIONS + 설명 오버라이드 │ │ └─ block-system.ts / plan.ts / chat.ts / theme-brief.ts │ └─ video-edit/ mediabunny 기반 로컬 비디오 처리 │ ├─ render.ts (791줄) 타임라인 → mp4 렌더(순수 WebCodecs) │ ├─ scene-detection.ts HSV diff 씬컷 │ └─ thumbnails.ts / extract-audio.ts / probe.ts │ ├─ packages/studio-ui/ ← 에디터 UI │ └─ src/ │ ├─ hyperframes-workbench.tsx (7116줄) ★메인 워크벤치(state·프리뷰·타임라인) │ ├─ client-export.ts (689줄) ★WebCodecs 클라 익스포트 │ ├─ use-agent-bridge.ts (108줄) ★외부 에이전트 WebSocket 브리지 │ ├─ studio-timeline.tsx (1383줄) 멀티트랙 타임라인 │ ├─ person-matte.ts (187줄) MODNet WebGPU 인물 매팅 │ ├─ geometry.ts (338줄) MediaPipe 얼굴/세그 세이프존 │ ├─ local-media.ts (106줄) ★OPFS 로컬 비디오 라이브러리 │ └─ *-panel.tsx assets/captions/frame/script/transition 패널 │ ├─ packages/studio-frames/ ← 25개 테마 콘텐츠팩(content/<id>/frame.md) └─ packages/ui/ ← 공유 shadcn식 프리미티브 + ai-elements (MIT 라이선스)

구조가 말해 주는 것: 관심사가 칼같이 분리돼 있다. studio-engine순수 로직(React 无관)이라 테스트·재사용이 쉽고, studio-ui는 그걸 React로 감싼 표현 계층이다. 눈여겨볼 파일 크기의 불균형 — hyperframes-workbench.tsx가 무려 7,116줄이다. 워크벤치 하나가 state·프리뷰·타임라인·runStudioTool을 전부 쥐고 있는 "God component"에 가까운데, 이건 편집 상태가 서로 촘촘히 얽혀 있어 쪼개기 어려운 에디터의 숙명이기도 하다.

용어
frames(테마) · frame.md · playbook
Pireel의 frame(프레임)은 디자인 테마를 뜻한다. 각 테마는 content/<id>/frame.md 파일 하나로 정의되는데, frontmatter에 팔레트·디자인 토큰이 들어가고, 본문(playbook)은 LLM 시스템 프롬프트에 주입되는 영문 디자인 지침이다. 즉 테마가 "색과 규칙"만이 아니라 "AI가 이 스타일로 블록을 만들 때 따를 매뉴얼"까지 담는다. cinema-frame(레터박스), y2k-chrome, memphis-pop, neon-runner 등 25종.

6학습 포인트

비디오 편집에 관심 없어도 훔쳐올, 최신 웹/에이전트 설계 8선
배울 것 ①

WebCodecs로 "서버 없이" 영상을 인코딩하기

mediabunny가 VideoEncoder/muxer를 추상화한다. Canvas2D 합성 + DOM→SVG foreignObject 래스터화(브라우저 자체가 래스터라이저)로 HTML 오버레이를 캔버스에 굽는 기법은, 리포트·차트·명함 이미지 생성 등 "웹에서 이미지/영상을 뽑는" 어떤 작업에도 응용된다.

배울 것 ②

내 앱을 "MCP 제어면"으로 노출하는 패턴

툴 정의를 내부 챗과 외부 MCP가 한 테이블로 공유(STUDIO_TOOLS)하고, 실행은 브라우저 브리지로 포워딩한다. "stateless MCP + WebSocket DO 브리지"는 브라우저에 묶인 앱을 에이전트에게 열어 주는 정석 구조다. SaaS를 에이전트 시대에 대응시키려는 사람이 통째로 베낄 만한 청사진.

배울 것 ③

BYO-brain 계약(brief → generate → validate)

서버가 LLM을 안 부르고 {system, prompt} 계약만 조립 → 생성은 호출자 모델 → 결과는 lint 통과해야 반영. "토큰 비용을 호출자에게 넘기는" 이 설계는 오픈코어 비즈니스 모델과 직결된다. AI 기능을 넣되 비용을 통제하려는 모든 제품이 참고할 패턴.

배울 것 ④

OPFS + localStorage로 "로컬 우선" 지속성 구현

영상 바이트는 OPFS에(fileSig = name:size:mtime로 식별), 컴포지션은 localStorage에 저장. 새로고침 후 자동 재연결. 서버 없이도 "작업이 사라지지 않는" 앱을 만드는 법 — 오프라인 우선 웹앱 전반에 적용된다.

배울 것 ⑤

결정론적 시간함수 렌더링 (프리뷰 = 익스포트)

애니를 t에만 의존하는 순수 함수로 짜면, 실시간 프리뷰와 프레임 시크 익스포트가 같은 로직을 공유해 절대 어긋나지 않는다. 게임 리플레이·시뮬레이션·차트 애니 등 "결정론이 필요한" 모든 곳의 핵심 원리.

배울 것 ⑥

WebGPU ML 추론 + graceful fallback

MODNet(onnxruntime-web, WebGPU)이 실패하면 MediaPipe 셀피 세그로 폴백한다. 모델을 전부 self-host(public/models)해 외부 의존을 끊는다. "브라우저에서 ML을 돌리되, 안 되는 기기에선 우아하게 물러서는" 패턴.

배울 것 ⑦

데이터-드리븐 컴포지션 (블록=데이터, 렌더=템플릿+CSS변수)

블록이 HTML이 아니라 {templateId, slots} 데이터를 담으니, 테마 교체가 블록을 안 건드린다. 에이전트도 자유형 HTML 대신 슬롯만 채우면 돼 생성 실패율이 낮다. 선언적 UI/문서 생성의 좋은 본보기.

배울 것 ⑧

순수 엔진 / React UI 분리로 재사용성 확보

studio-engine은 React·DB·provider를 모른다. 그래서 같은 코드가 브라우저와 서버 오프라인 툴에서 재사용된다. "로직과 프레임워크를 섞지 않는다"는 오래된 교훈의 최신 실천 사례.

실습 아이디어 (짧게)

가장 먼저 packages/studio-engine/src/caption-fx.ts를 열어 drawCaptionFx(ctx, o, t, ...)가 어떻게 시각 t 하나로 자막 프레임을 그리는지 따라가 보라. 그다음 client-export.ts의 헤더 주석(오버레이를 SVG foreignObject로 굽는 과정)을 읽으면, "프리뷰와 익스포트가 왜 같은가"가 손에 잡힌다. 이 두 파일만으로도 Pireel의 렌더링 철학이 완성된다.

7시스템 / 실행 요구사항

브라우저가 곧 런타임 — 그래서 "브라우저의 능력"이 요구사항이다
항목요구사항 / 수치
브라우저 (익스포트)Chromium 계열 필수. 코드가 canClientExport() = 'VideoEncoder' in window로 체크한다(use-export.ts). WebCodecs 미지원 브라우저에선 익스포트 불가. README도 "Client export … on WebCodecs (Chromium)" 명시.
인물 매팅 (고품질)WebGPU 필요('gpu' in navigator). 없으면 MediaPipe wasm으로 폴백(품질↓). MODNet 모델 public/models/modnet_portrait.onnx(HuggingFace Xenova/modnet)가 있어야 하고, 없으면 그 기능만 우아하게 실패.
로컬 영상 라이브러리OPFS(navigator.storage.getDirectory) 지원 브라우저. 없으면 null 폴백(라이브러리 기능만 비활성).
정적 자산 계약/vendor/gsap.min.js가 same-origin으로 있어야 프리뷰 런타임이 뜬다(필수). 선택: /models/modnet_portrait.onnx, /mediapipe/*(wasm+tflite).
개발 환경pnpm 9.12.0, Node(Vite 8이 요구하는 버전). pnpm installapps/studio-oss에서 dev 서버 실행.
익스포트 성능대략 실시간(3분 영상 ≈ 3분). WebCodecs 하드웨어 디코드가 긴 프로젝트 성능에 유리(코드가 디코더 은퇴 로직으로 하드웨어 쿼터 관리).
GPU필수 아님. 있으면 WebGPU 매팅 품질↑ + 하드웨어 인코드/디코드로 익스포트 속도↑.
주의 — 처음 겪는 함정
Safari/Firefox에선 익스포트가 안 될 수 있고, 생성 기능은 provider가 필요하다

WebCodecs VideoEncoderChromium 계열에서 가장 안정적이다. Safari/Firefox는 지원 범위가 좁아 익스포트가 막힐 수 있으니 개발/사용은 Chrome·Edge 권장. 또 OSS 셸은 생성 provider를 unavailableProviders()로 비워 두므로, ASR·나레이션 분석·이미지 생성 같은 AI 생성 기능은 기본 상태에서 비활성이다 — 직접 provider를 주입하거나 외부 에이전트(BYO)를 붙여야 켜진다. "받아서 바로 AI가 다 해 줄" 것으로 기대하면 어긋난다.

8직접 해볼 수 있는 실습 과제

난이도별로 — 소스 읽기부터 나만의 캡션 이펙트·MCP 툴까지

과제 1. 로컬에서 셸 띄우고 영상 임포트·익스포트 난이도 ★☆☆

pnpm installapps/studio-oss의 dev 서버를 Chrome에서 연다. 짧은 토킹헤드 클립을 임포트해 자막을 켜고, WebCodecs 익스포트로 mp4를 뽑아 보라. 브라우저 탭 하나가 서버 없이 영상을 인코딩하는 걸 체감하는 게 목표. (익스포트 버튼이 회색이면 WebCodecs 미지원 → Chromium으로.)

과제 2. caption-fx.ts로 나만의 자막 이펙트 추가 난이도 ★★☆

caption-fx.tsdrawCaptionFx switch에 6번째 이펙트(예: "typewriter")를 추가하라. 반드시 시각 t에만 의존하는 순수 함수로 짜야 익스포트에서도 정상 동작한다. 프리뷰에서 잘 보이는데 익스포트에서 깨진다면, 어딘가 t 외의 상태(rAF·난수)에 의존한 것 — 그걸 찾아 고치는 게 학습의 핵심.

과제 3. 컴포지션 JSON을 손으로 만들어 블록 얹기 난이도 ★★☆

composition-core.ts의 타입을 보고, {templateId, slots, startSec, durationSec, trackIndex} 블록을 직접 JSON으로 작성해 컴포지션에 추가하라. 템플릿 레지스트리에서 templateId가 어떻게 실제 HTML로 렌더되는지, 테마(CSS 변수)를 바꾸면 같은 블록이 어떻게 달라지는지 확인한다.

과제 4. MODNet 매팅 파이프라인 따라가기 난이도 ★★★

person-matte.ts가 onnxruntime-web으로 MODNet을 WebGPU에서 돌리는 과정을 읽고, WebGPU 미지원 시 MediaPipe로 폴백하는 분기를 찾아라. 모델 파일이 없을 때 어떻게 우아하게 실패하는지도 확인한다. 브라우저 ML 추론의 실전 에러 핸들링을 배우는 과제.

과제 5. 나만의 STUDIO_TOOL 정의 + 브리지로 실행 난이도 ★★★

prompts/agent-tools.ts의 STUDIO_TOOLS 테이블에 새 툴(예: set_background_blur)을 스키마·설명과 함께 추가하고, runStudioTool에서 그 동작을 구현하라. 내부 챗에서 호출해 동작을 확인한 뒤, use-agent-bridge.ts의 실행 경로를 따라가며 "외부 에이전트가 부르면 어떻게 같은 코드에 도달하는지"를 이해한다.

9관련 기술 심화 학습 로드맵

이 레포를 온전히 이해하려면 밟을 5주 코스
주차주제무엇을 · 왜
1주차WebCodecs + Canvas브라우저 VideoEncoder/VideoDecoder, Canvas2D 합성, mediabunny 추상화. 서버 없이 영상을 인코딩하는 파이프라인의 기초를 잡는다.
2주차SVG foreignObject 래스터화HTML을 SVG로 감싸 이미지로 뽑는 트릭, 폰트/이미지 인라이닝(data:) 제약. client-export.ts를 읽으며 "브라우저를 래스터라이저로 쓰는" 법을 익힌다.
3주차브라우저 ML (WebGPU/ONNX/MediaPipe)onnxruntime-web으로 MODNet 매팅, MediaPipe 얼굴/세그, WebGPU EP와 wasm 폴백. person-matte.ts+geometry.ts를 짝지어 분석.
4주차MCP + 에이전트 브리지MCP 프로토콜(JSON-RPC, streamable-HTTP), Durable Object, WebSocket 포워딩. mcp.ts+bridge-do.ts+use-agent-bridge.ts로 "앱을 에이전트에 여는" 구조를 완성한다.
5주차로컬 우선 지속성 + 데이터 모델OPFS·localStorage, JSON 패치 undo(fast-json-patch), 데이터-드리븐 컴포지션. local-media.ts+composition-core.ts로 "서버 없이 상태를 안전하게 관리"하는 법을 마무리한다.

10핵심 키워드 사전

이 문서에 나온 개념들을 한 줄로
Pireel (파이릴)
토킹헤드 영상 전용, 백엔드 없이 브라우저에서 도는 오픈소스 AI 비디오 에디터. 에디터를 MCP로 노출해 외부 에이전트가 운전할 수 있다.
backend-free (백엔드리스)
서버가 편집·렌더링을 대신 하지 않고 전부 브라우저에서 처리하는 설계. 영상 바이트가 브라우저를 떠나지 않는다.
WebCodecs · mediabunny
브라우저가 영상을 하드웨어로 인코딩/디코딩하는 웹 API(WebCodecs)와, 그 위의 mux/demux/encode를 감싼 라이브러리(mediabunny). "서버 없이 mp4 뽑기"의 핵심.
OPFS (Origin Private File System)
사이트마다 격리된 브라우저 전용 파일 저장소. 큰 영상 원본을 서버 없이 로컬에 둔다(fileSig=name:size:mtime로 식별).
컴포지션(composition)
편집 상태의 데이터 모델. "연속 비디오(track 0) + 멀티트랙 오버레이 블록". 블록은 HTML이 아니라 {templateId, slots} 데이터만 저장한다.
프리뷰 = 익스포트
같은 iframe을 seekTimelines(t)로 구동해 미리보기와 출력이 픽셀 단위로 동일. HTML 오버레이는 SVG foreignObject로 캔버스에 굽는다.
키네틱 자막(caption-fx)
시각 t에만 의존하는 순수 함수로 그리는 애니 자막(5개 이펙트). rAF·난수 없이 결정론적이라 WebCodecs 프레임 시크와 정렬된다.
MCP 브리지 (agent-drivable)
외부 에이전트 → MCP HTTP → Durable Object → WebSocket → 열린 브라우저 탭의 runStudioTool. 브라우저에 묶인 툴을 에이전트가 원격 실행하게 하는 3계층 구조.
BYO brain · brief(계약)
"오케스트레이션은 공짜, 생성은 호출자 부담". 서버가 {system, prompt} 계약만 만들고 생성은 사용자의 Claude/Codex 구독으로 → 결과를 검증 후 반영.
MODNet · MediaPipe
MODNet = 인물 배경 매팅 딥러닝 모델(onnxruntime-web, WebGPU). MediaPipe = 얼굴/세그 검출(폴백 겸용). 그래픽이 화자를 안 가리게 세이프존을 잡는다.
frame(테마)
content/<id>/frame.md 한 파일로 정의되는 디자인 테마. 팔레트·토큰 + LLM에 주입되는 영문 "playbook" 지침을 함께 담는다(25종 내장).
Durable Object (DO)
Cloudflare의 상태 있는 단일 인스턴스 서버 객체. 유저당 하나(idFromName(userId))를 두어 브리지 소켓을 단일 활성으로 관리(호스티드 전용).

11참고 링크

원문으로 더 파고들기