본문으로 건너뛰기
5분 AI.
TRENDSHIFT WEEKLY #21 딥다이브 · 2026-10-23 분석

lemo-opuscar 딥다이브
— 시간을 함수에 넣으면 영화가 나오는 코드 제작소

스킬·렌더링 도구

빠른 판단

무엇
영상 스타일·데모·브라우저 렌더러·음성·음악 도구를 묶은 코딩 에이전트용 영상 제작 도구상자
이럴 때
주제와 스타일을 정해 Canvas·Three.js 장면을 코드로 만들고 타이밍·사운드를 맞춰 영상으로 렌더링할 때
입력
영상 주제·스타일과 코드로 구성한 웹 장면
결과
프레임 렌더링과 음성·음악을 조립한 영상 파일
lemo-opuscar는 Claude Code 같은 코딩 에이전트가 영상을 만들도록 돕는 스타일 도구상자입니다. 59종의 스타일 지시서와 데모 소스, 브라우저 렌더러, 음성·음악·검사 도구를 함께 담았습니다. 이 글은 화면을 시간의 함수로 만드는 법, JavaScript와 Python을 파일로 연결하는 법, 그리고 결과물을 검사하는 법을 실제 코드로 살펴봅니다. 저장소: lemomo-ai/lemo-opuscar · ⭐5,814 · 포크 653 · 주 언어 JavaScript · 라이선스 MIT (2026-10-23 GitHub 기준). 기술 설명은 커밋 3961ddb 기준.
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 하드웨어 / 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

59개 스타일, 공용 제작 도구, 그리고 에이전트에게 읽히는 연출 지침

lemo-opuscar는 코딩 에이전트가 그림·소리·편집을 코드로 제작하도록 돕는 영상 스타일 라이브러리입니다. 사용자는 주제와 스타일을 고르고, 에이전트는 그 스타일의 규칙을 읽어 별도의 작품을 설계합니다. 화면은 주로 Canvas 2D나 Three.js로 그리며, 완성된 웹페이지를 프레임마다 촬영해 영상 파일로 바꿉니다.

이 저장소에서 가장 중요한 발상은 동영상을 녹화하는 대신, 원하는 시각의 화면을 함수로 계산한다는 것입니다. window.render(3.5)는 3.5초 시점의 한 장면을 그립니다. 이 함수를 1/24초 간격으로 호출하면, 연속된 정지 화면이 영상이 됩니다.

한 문장 비유

완제품 영화 자판기보다, 그림체 견본과 제작 장비를 갖춘 작은 영화학교에 가깝습니다

STYLE.md는 화풍과 움직임의 규칙을 설명하는 교재, demo/는 그 규칙으로 만든 졸업 작품, core/는 여러 작품이 함께 사용하는 촬영·녹음 장비입니다.

견본 작품의 대사만 바꾸는 것으로 끝내지 않습니다. AGENTS.md는 새 이야기의 구성을 먼저 정하고, 데모에서는 구현 기법을 참고하도록 안내합니다.

용어
절차적 제작과 영상 생성 모델
절차적 제작은 좌표·색상·수식·시간표를 코드로 정해 화면을 만드는 방식입니다. 영상 생성 모델에 장면을 요청하는 방식과 제작 경로가 다릅니다. 여기서는 언어 모델이 코드를 쓰고, 브라우저가 그 코드를 실행해 픽셀을 만듭니다.

1-1. 세 층으로 나누어 보면 쉽다

층대표 파일독자가 배울 것
연출과 규칙DIRECTOR.md, TECHNIQUE.md, styles/*/STYLE.md추상적인 요구를 구체적인 제작 조건으로 바꾸기
개별 작품styles/swiss-motion/demo/main.js, styles/swiss-motion/demo/film.js, styles/swiss-motion/demo/mix.py장면·타이밍·사운드를 실제 코드로 표현하기
공용 도구core/render/, core/audio/, core/tts/여러 작품을 처리하는 재사용 가능한 제작 파이프라인

1-2. “59종”은 무엇을 세는가

styleboard/catalog.json에는 59개 항목이 있고, 실제 스타일 디렉토리도 59개입니다. STYLE.md 파일 자체는 60개인데, 하나는 새 스타일용 styles/_template/입니다. styleboard/build.py의 load_styles()가 밑줄로 시작하는 디렉토리를 제외하므로 숫자가 일치합니다. 스타일은 편집·다큐멘터리, 실증 영상, 회화, 게임, 재질·3D 등을 포함한 11개 분류에 속합니다.

읽기 목표
첫날부터 59개 데모를 모두 읽을 필요는 없습니다

먼저 core/render/page.mjs의 페이지 약속을 이해하고, styles/swiss-motion/demo/main.js가 그 약속을 구현하는 모습을 보세요. 마지막으로 core/render/video.mjs에서 한 장면이 MP4까지 가는 경로를 따라가면 됩니다.

2왜 주목받는가

화제성의 근거와, 학습자가 실제로 가져갈 수 있는 장점

2-1. 코딩 에이전트가 영상 제작의 여러 역할을 맡는다

2026-10-23 GitHub 기준 스타 5,814개, 포크 653개입니다. 저장소 생성일은 2026-09-26으로, 생성 후 27일 시점의 수치입니다. TrendShift Weekly #21의 분석 대상으로서 눈에 띄는 규모이지만, 이 숫자만으로 사용자 만족도나 영상 품질을 입증할 수는 없습니다.

관심을 끄는 지점은 결과물에 그치지 않습니다. 스타일 설명, 구현 예제, 제작 도구가 함께 있어 “어떻게 만들었는가”를 코드까지 거슬러 올라갈 수 있습니다. 에이전트가 그림뿐 아니라 음악과 믹싱까지 작성한다는 소개는 README의 주장입니다. 실제 저장소에서도 장면 코드, 악보 데이터, 효과음 합성 함수, 믹서가 각각 확인됩니다.

2-2. 최근 확장은 “예쁜 효과”에서 “자료를 설명하는 영상”으로

README의 변경 안내는 2026-10-16에 실증 영상 8종, 2026-10-22에 편집·다큐멘터리 8종과 개인 스타일 제작 기능을 소개합니다. styles/caption-news/STYLE.md는 실제 영상·보고서·통계를 배치하는 규칙을, MY-STYLES.md는 기존 스타일을 변형해 자신의 스타일로 보관하는 절차를 설명합니다.

학습 관점에서는 확장 방향이 흥미롭습니다. 같은 렌더러 위에서 직접 그린 애니메이션도 만들고, 출처가 있는 문서·사진·영상을 조합할 수도 있습니다. 외부 자료를 쓰는 스타일은 FACTS.md, CREDITS, 자료 목록을 통해 근거와 권리를 관리하도록 설계되어 있습니다. 이것이 실제 인기의 원인이라는 통계는 없으며, 소스와 공개 소개에서 읽을 수 있는 매력 요인입니다.

2-3. 다른 제작 방식과 무엇이 다른가

방식잘 맞는 일lemo-opuscar의 상대적 장점과 대가
일반 영상 편집기타임라인을 보며 손으로 컷과 효과 조정코드와 시간표를 수정해 반복 제작하기 좋음. 대신 편집 UI 대신 코드·도구를 익혀야 함
영상 생성 모델장면의 모습을 자연어로 요청좌표·숫자·문자를 코드에서 직접 지정. 대신 복잡한 실사 장면을 수식과 그림만으로 만들기는 어려움
FFmpeg 단독변환·자르기·인코딩·필터 적용스타일 규칙과 그림 엔진, 음성·음악 도구까지 제공. 최종 인코딩에서는 FFmpeg를 함께 사용
개별 그래픽 예제특정 효과나 장면을 배우기렌더링·검사·배포까지 연결된 사례가 많음. 데모마다 구조와 완성도는 다를 수 있음
비유

영상 편집기가 손으로 조작하는 주방이라면, 이 저장소는 조리법과 자동 조리 장비를 함께 공개한 주방입니다. 재료와 시간을 정확히 정할 수 있지만, 어떤 맛을 만들지 결정하는 일까지 사라지지는 않습니다.

2-4. 소개 문구를 읽을 때 구분할 세 가지

소개와 실제 범위
“영상 생성 모델을 쓰지 않는다”가 “모든 원본 소재를 코드로 만든다”는 뜻은 아닙니다

README와 TECHNIQUE.md에는 외부 영상 없이 만든다는 포괄적인 소개가 남아 있습니다. 그러나 styles/caption-news/STYLE.md는 실제 영상과 문서를 사용하며, styles/news-package/demo/CREDITS는 AI로 생성한 배경 이미지 두 장과 외부 음성 서비스를 명시합니다.

따라서 공통점은 코드로 화면을 구성하고 편집·출력한다는 데 있습니다. 모든 데모가 외부 영상·생성 이미지·온라인 서비스 없이 재현된다고 해석하면 맞지 않습니다. 또한 Claude Opus 5.5에 맞춘 스타일이라는 설명은 README 기준이며, 다른 모델과의 성능 비교표는 제시되지 않습니다.

3기술 스택 전체 지도

웹 서비스의 전형적인 앞단·뒷단 구분보다, 화면·제작 도구·배포로 나눠 보기

3-1. 프론트엔드: 웹페이지를 영상의 무대로 쓴다

기술확인한 버전·선언실제 역할과 위치
JavaScript ESM루트 package.json: type: module장면과 도구를 모듈로 분리. core/lib.js에 보간·난수 함수
Canvas 2D브라우저 내장 API, npm 버전 없음styles/swiss-motion/demo/main.js의 getContext('2d')
Three.js선언 ^0.170.0, 잠금 0.170.03D 장면과 core/three/post.js 후처리
WebGL / 셰이더브라우저 그래픽 APIcore/post/crt.js의 CRT 효과, core/three/post.js의 심도·색보정
HTML·CSS·폰트정적 페이지와 로컬 폰트각 데모의 index.html, 갤러리의 styleboard/template.html

루트 의존성에는 React·Vue·웹 프레임워크가 없습니다. 영상의 화면은 일반적인 앱 UI보다 그림을 그리는 캔버스에 가깝습니다. 다만 스타일마다 구현이 독립적이므로, 특정 데모의 구성까지 루트 의존성만으로 판단해서는 안 됩니다.

3-2. 백엔드에 해당하는 부분: 로컬 제작용 Node.js와 Python

기술버전 근거하는 일
Node.jspackage.json: >=20브라우저 제어, 프레임 분배, FFmpeg 하위 프로세스 실행
Playwright Core선언 ^1.63.0, 잠금 1.63.0core/render/page.mjs에서 Chromium을 열고 화면 캡처
PythonTECHNIQUE.md: 3.11 이상음성·사운드·자막·갤러리 생성. 설치 도구는 uv 사용 시 3.12 선택
NumPy·SciPyrequirements.txt, 버전 미고정음원 배열 생성, 필터, 합성, 믹싱
soundfile·soxr·pillowrequirements.txt, 버전 미고정음원 입출력·재표본화·검토 이미지 제작
음성 선택 구성requirements-voice.txt: kokoro-onnx, edge-tts, faster-whisper, av<19로컬 TTS, 온라인 TTS, 발화 내용 검사. 세 패키지는 버전 미고정
음악·개발 선택 구성requirements-music.txt: numba / requirements-dev.txt: librosa현악기 물리 모델의 가속 / 샘플 인덱스 재생성. 모두 버전 미고정

core/render/serve.mjs는 http.createServer()를 이용한 작은 정적 파일 서버입니다. 127.0.0.1의 빈 포트에 바인딩하고, 브라우저가 모듈·이미지·폰트를 읽을 수 있게 합니다. 계정·결제·데이터베이스를 제공하는 서비스 백엔드와 역할이 다릅니다.

용어
버전 범위와 잠금 파일
package.json의 ^1.63.0은 허용하는 버전 범위, package-lock.json의 1.63.0은 기록된 구체적인 버전입니다. Python 목록에는 대체로 이런 고정 정보가 없습니다. av<19는 정확한 버전 고정이 아니라 상한 제한입니다.

재현 가능한 결과를 배우려면 그림 코드뿐 아니라 브라우저·패키지·폰트·원본 소재의 버전도 함께 보아야 합니다. 루트 package.json의 자체 버전은 0.1.0이며 private: true입니다. 이는 GitHub의 최신 릴리스 태그 thanks와 별개의 정보입니다.

3-3. 인프라·빌드: FFmpeg와 정적 사이트 배포

Pages 워크플로는 갤러리를 만들고 영상을 다운로드한 뒤, 링크된 영상 파일이 모두 존재하는지 검사합니다. 스타일별 영화를 새로 렌더링하는 워크플로는 아닙니다. 커밋 3961ddb에는 Dockerfile, Cargo.toml, pyproject.toml, go.mod가 없으며, 공통 빌드 체계를 Docker·Rust·Go 프로젝트처럼 설명할 근거도 없습니다.

4아키텍처 심화 분석

문서로 정한 제작 규칙이 함수·파일·프로세스의 약속으로 이어지는 구조
사용자: 주제 + 스타일 + 사용할 소재 | v 코딩 에이전트: AGENTS.md / DIRECTOR.md / TECHNIQUE.md | | | styles/*/STYLE.md v | 새 작품: 장면 코드 + 시간표 + 대사 + 음악 / 믹스 코드 | | | v v v index.html lines.json 음악 / 효과음 READY core/tts/ core/audio/ DUR / render(t) TTS -> ASR 검사 | EV / TEXTS(t) | | | +------ WAV --------+ v | core/render/page.mjs v serve.mjs -> 로컬 HTTP 작품별 mix.py Playwright -> Chromium | | v +-- still.mjs -> 검토용 정지 화면 mix.wav +-- events.mjs -> events.json -----------^ +-- readcheck.mjs -> 글자 노출 시간 검사 | v video.mjs: 시각별 render(t) -> JPEG -> FFmpeg -> video.mp4 | mix.wav ----------------------+ v core/render/mux.sh -> 최종 MP4 공개 갤러리: styles/*/style.json -> styleboard/build.py + web 릴리스 영상 -> GitHub Pages

4-1. 패턴 ① 작은 인터페이스로 여러 엔진을 연결한다

core/render/page.mjs의 openDemo()는 작품 내부의 그림 엔진을 알지 못합니다. index.html을 열고 window.READY === true를 기다릴 뿐입니다. requireDemo()는 진입 파일의 존재를 확인하고, takeSize()는 화면 크기를 검사합니다.

페이지가 공개하는 값소비하는 도구약속
READYopenDemo()폰트·이미지 등 준비가 끝나면 true. 대기 상한 180초
render(t)정지 화면·동영상 도구초 단위 시각을 받아 그 시점의 화면을 그림
DUR동영상·이벤트·가독성 도구작품 전체 길이. core/render/video.mjs는 양수인지 확인
EVcore/render/events.mjs효과음·대사 등의 시각과 종류. 없으면 빈 배열
TEXTS(t)core/render/readcheck.mjs화면 글자의 식별자·전체 문구·사각형 좌표

openDemo()는 페이지의 JavaScript 오류와 스크립트·문서의 HTTP 오류 응답을 만나면 중단합니다. 반면 이미지·폰트·선택 데이터의 HTTP 오류는 경고하고 계속합니다. 대체 처리가 없는 필수 이미지를 빠뜨리면 경고만으로는 완성도를 보장할 수 없으므로, 작품 자체의 준비 조건도 중요합니다.

styles/swiss-motion/demo/main.js는 이 계약의 실제 구현입니다. 폰트를 불러오고 악보·대사·발화 시간을 읽은 뒤, renderFilm()과 buildEvents()를 전역 인터페이스에 연결합니다. 아래는 해당 파일에서 화면 계약에 해당하는 부분입니다.

window.DUR = DUR;
window.EV = buildEvents();
window.SUBS = subs();
const Q = new URLSearchParams(location.search);
window.render = t => renderFilm(g, t, {
  nosub: Q.has('nosub'), poster: Q.has('poster')
});
window.READY = true;
용어
인터페이스 계약
연결할 두 부품이 미리 정한 입력·출력의 약속입니다. 렌더러가 “이 함수와 값만 있으면 된다”고 정하면, 작품은 Canvas 2D든 3D든 내부 구현을 자유롭게 선택할 수 있습니다. 공통 인터페이스가 곧 모든 선택 기능의 구현을 뜻하지는 않습니다.

4-2. 패턴 ② 화면을 시간으로 계산해 프레임을 나눠 처리한다

core/render/video.mjs는 전체 프레임 수를 Math.round(DUR * FPS)로, 작업자당 범위를 Math.ceil(TOTAL / WK)로 정합니다. 작업자마다 별도의 브라우저를 열고 f / FPS를 render()에 전달합니다.

// video.mjs의 핵심 흐름을 줄인 학습용 의사 코드
const TOTAL = Math.round(DUR * FPS);
const per = Math.ceil(TOTAL / WK);
await Promise.all(workers.map(async w => {
  const a = w * per;
  const b = Math.min(TOTAL, a + per);
  for (let f = a; f < b; f++) {
    await page.evaluate(t => window.render(t), f / FPS);
    const jpeg = await page.screenshot({ type: 'jpeg', quality: 95 });
    // 실제 코드는 쓰기 버퍼가 차면 drain 또는 종료를 기다린다.
    await sendToEncoder(jpeg);
  }
}));

Swiss Motion 데모의 styles/swiss-motion/demo/film.js는 DUR = 44입니다. 기본 24 fps라면 1,056프레임이고, 기본 작업자 3개는 각각 352프레임을 맡습니다. 첫 작업자는 0~351번, 다음은 352~703번, 마지막은 704~1,055번을 계산합니다. 마지막 프레임의 시각은 정확히 44초가 아니라 1055 / 24초입니다.

프레임을 병렬로 만들 수 있는 이유는 각 장면이 직전 프레임의 실행 결과에 의존하지 않아야 하기 때문입니다. 위치를 매번 조금씩 더하는 대신 시각에서 바로 계산해야 합니다. 다만 결정성은 제작 규칙이며, 렌더러가 모든 장면 코드의 결정성을 자동 증명해 주지는 않습니다.

비유

“앞사람이 어디까지 그렸는지 보고 이어 그리기”는 작업을 나누기 어렵습니다. “정답 좌표가 적힌 352장의 설계도를 각각 받기”는 서로 기다리지 않고 작업할 수 있습니다. 시간으로 계산하는 화면이 바로 그 설계도입니다.

4-3. 패턴 ③ 이벤트와 파일을 경계로 그림·소리를 분리한다

styles/swiss-motion/demo/film.js의 buildEvents()는 {t, type, ...} 형태의 이벤트를 생성하고 시간순으로 정렬합니다. add(T.land, 'thump', {g: 1.1})처럼 착지 시점과 충격음을 연결하며, 대사도 type: 'voice'와 대사 식별자로 기록합니다.

core/render/events.mjs는 이를 {dur, ev} 형태의 JSON으로 내보냅니다. styles/swiss-motion/demo/mix.py 같은 작품별 믹서가 읽으면 Python에서 JavaScript의 그림 코드를 직접 이해할 필요가 없습니다. core/audio/sfx.py의 add(buf, x, at, gain, pan)는 초 단위 시각을 샘플 위치로 바꿔 소리를 섞습니다.

// events.json의 형태를 설명하는 학습용 예시
{
  "dur": 6,
  "ev": [
    {"t": 1.5, "type": "thump", "g": 0.8},
    {"t": 2.0, "type": "voice", "id": "line1"}
  ]
}

파일은 느슨한 결합을 만듭니다. JSON·WAV·MP4가 정상적으로 생성되면 다른 언어의 도구로 바꾸기도 쉽습니다. 반대로 시간표를 여러 곳에 중복해서 적으면 화면과 소리가 어긋납니다. TECHNIQUE.md가 하나의 시간표를 공유하도록 권하는 이유입니다. 모든 데모가 똑같은 이름의 timeline.js를 쓰는 것은 아닙니다.

4-4. 패턴 ④ 흐름 제어와 잠금으로 자원을 보호한다

core/render/video.mjs는 JPEG를 FFmpeg의 표준 입력으로 보냅니다. 인코딩 옵션은 libx264, -preset medium, -crf 14, yuv420p입니다. 쓰기 버퍼가 차면 drain이나 인코더 종료를 기다리며, 작업자별 영상은 마지막에 concat과 -c copy로 이어 붙입니다.

문제대응 코드범위와 한계
인코더보다 캡처가 빠름ff.stdin.write()와 drain한 파이프의 흐름을 조절. 전체 시스템의 메모리를 제한하는 기능은 아님
동일 출력에 동시 쓰기core/render/video.mjs의 .lock, flag: 'wx'출력 파일 단위 잠금. 프로세스 생존 여부와 잠금 나이를 확인
여러 작품이 동시에 렌더링core/render/slot.mjs의 acquire(), tryTake()RENDER_SLOTS 설정 시 선택적으로 작동
죽은 작업이 자리 차지core/render/slot.mjs의 stale()15초마다 생존 표시 갱신, 90초 정체 시 회수 가능

core/render/slot.mjs의 withMutex()는 디렉토리 생성의 원자성을 이용해 자리 배정을 보호합니다. 추가 작업을 시작할 때 기본 여유 메모리 기준은 30%이지만, 실행 중인 작업이 없으면 하나는 허용합니다. 따라서 이것은 강제 메모리 상한이 아닌 시작 시점의 혼잡 조절입니다. 영상 작업자 수 --workers와 전체 렌더링 수 RENDER_SLOTS도 서로 다른 값입니다.

5디렉토리 구조 해부

공용 엔진은 작고, 대부분의 구현은 스타일별 작품 안에 있다
lemo-opuscar/ ├── README.md 소개·스타일 목록·이용 조건 ├── AGENTS.md 에이전트의 진입점과 제작 순서 ├── DIRECTOR.md 이야기·장면·소리·검토 지침 ├── TECHNIQUE.md 구현 원리와 도구 연결법 ├── MY-STYLES.md 개인 스타일 생성·변형·보관 ├── MAINTAINING.md 라이브러리 유지관리 지침 ├── package.json / package-lock.json ├── requirements*.txt 기본·음성·음악·개발 의존성 ├── core/ │ ├── lib.js 난수·보간·이징 도우미 │ ├── render/ │ │ ├── serve.mjs / page.mjs 정적 파일 제공·페이지 준비 │ │ ├── browser.mjs Chromium·GPU 실행 설정 │ │ ├── video.mjs / still.mjs 영상·정지 화면 출력 │ │ ├── events.mjs 효과음 시점 추출 │ │ ├── readcheck.mjs 화면 글자 가독성 검사 │ │ ├── slot.mjs 렌더링 동시 실행 수 조절 │ │ └── mux.sh / srt.py / sheet.py │ ├── audio/ 효과음·샘플러·현악기 모델 │ ├── tts/ 음성 합성·음성 내용 검사 │ ├── three/post.js 3D 후처리 │ ├── post/crt.js CRT 화면 효과 │ └── fonts/ / assets/ 공용 폰트·3D 소재와 출처 ├── styles/ │ ├── _template/ 새 스타일의 뼈대 │ └── swiss-motion/ 실제 스타일 59종 중 하나 │ ├── STYLE.md 시각·음향 규칙 │ ├── DEMO.md 데모의 연출·구현 설명 │ ├── style.json 갤러리용 이름·분류·길이 │ ├── swiss-motion.srt 데모 자막 │ └── demo/ │ ├── index.html / main.js / film.js / ease.js │ ├── lines.json / score.json / events.json │ ├── mix.py / build.sh │ └── voices/ / fonts/ 대사 시간·폰트 설정 등 ├── styleboard/ 공개 갤러리와 생성기 ├── docs/ 소개용 이미지 ├── plugin/skills/lemo-opuscar/ 스킬 진입 문서와 설치 도구 ├── .claude-plugin/marketplace.json ├── tools/ 다운로드·게시·릴리스 도구 └── .github/workflows/pages.yml 갤러리 배포

STYLE.md는 유지할 스타일 규칙, DEMO.md는 특정 예제 작품의 설명입니다. style.json은 검색·전시용 메타데이터이며, 영상의 장면 전체를 선언하는 공통 설정 파일은 아닙니다. 예를 들어 제목과 분류를 바꾸는 일과, 이야기·그림·소리를 새로 만드는 일은 서로 다릅니다.

plugin/에는 실제 영상 엔진보다 라이브러리를 찾아 연결하는 진입점이 들어 있습니다. 설치 스크립트는 기본 안내·공용 도구를 가져오고, 필요할 때 특정 데모를 추가하는 희소 체크아웃을 사용합니다. 전체 소스를 받는 방식과 스킬의 첫 설치가 차지하는 용량이 다른 이유입니다.

5-1. 언어별 코드 규모

언어·형식파일 수물리적 줄 수
JavaScript53382,976줄 — .js, .mjs, .cjs 합계
Python31337,171줄
HTML7411,287줄
CSS378,866줄
Shell972,524줄
위 다섯 종류 합계1,054142,824줄 — 약 14.3만 줄
Markdown16418,136줄 — 위 코드 합계와 별도
JSON39655,014줄 — 위 코드 합계와 별도

커밋 3961ddb의 파일에서 빈 줄·주석을 포함한 물리적 줄을 센 값입니다. .git, node_modules, .venv, 이름이 vendor인 디렉토리와 package-lock.json은 제외했습니다. HTML 안의 JavaScript는 HTML에 포함되고, 생성된 갤러리·중복 예제·폰트 데이터가 들어간 CSS도 포함됩니다. 따라서 사람이 작성한 고유 로직의 양이나 유지보수 난도를 그대로 나타내지는 않습니다.

같은 다섯 언어·형식 기준으로 core/는 21개 파일·2,278줄, styles/는 1,017개 파일·135,497줄입니다. 데모가 전체 코드 줄 수의 약 95%를 차지합니다. 큰 공용 프레임워크 하나를 공부하기보다, 작은 공용 도구와 다양한 개별 구현을 비교하는 학습에 적합합니다.

5-2. 추천하는 소스 읽기 순서

  1. core/README.md → 도구의 입력과 출력을 정리합니다.
  2. core/render/page.mjs → 웹페이지가 준비되는 조건을 찾습니다.
  3. styles/swiss-motion/demo/main.js → 전역 함수가 실제 장면 함수에 연결되는 지점을 봅니다.
  4. styles/swiss-motion/demo/film.js → renderFilm()과 buildEvents()를 비교합니다.
  5. core/render/video.mjs → 프레임 분배·캡처·인코딩·정리 순서로 돌아옵니다.

6학습 포인트 (기술별)

파일을 읽는 데서 그치지 않고, 각 기술의 입력·출력을 직접 설명해 보기

6-1. JavaScript: 보간과 결정적인 화면

core/lib.js의 seg(t, a, b)는 시각을 0~1 진행률로 바꾸고, lerp(a, b, t)는 두 값 사이를 계산합니다. ss() 같은 이징 함수는 진행률의 속도감을 바꿉니다. 다음은 이 도우미로 작성한 학습용 장면 함수입니다.

import { seg, lerp, ss } from '/core/lib.js';

// g는 2D 문맥, w와 h는 출력 화면 크기다.
function draw(g, t, w, h) {
  const p = ss(seg(t, 1, 3));
  const x = lerp(w * 0.1, w * 0.8, p);
  g.setTransform(1, 0, 0, 1, 0, 0);
  g.clearRect(0, 0, w, h);
  g.fillStyle = '#a8452f';
  g.fillRect(x, h * 0.45, 80, 80);
}
// 1초 이전에는 시작점, 3초 이후에는 도착점에 머문다.
// draw(2초)를 여러 번 불러도 위치가 누적되지 않는다.

실습 아이디어: 시각을 2초 → 0초 → 2초 순서로 바꿔 그려 보세요. 두 번의 2초 화면이 같아야 합니다. x += speed로 위치를 누적하는 방식이 왜 이 조건을 깨는지 설명해 보세요.

mulberry(seed)는 같은 시드에서 같은 난수열을 만듭니다. 하지만 난수 생성기를 한 번만 만들고 매 프레임 소비하면 호출 순서에 따라 결과가 달라집니다. 입자 속성을 준비 단계에 고정하거나, 프레임·개체 식별자로 난수를 재구성해야 원하는 시각을 독립적으로 그릴 수 있습니다.

6-2. Canvas와 타이포그래피: 상태를 정리하는 습관

styles/swiss-motion/demo/film.js의 renderFilm()은 setTransform(1, 0, 0, 1, 0, 0)으로 좌표 변환을 초기화한 뒤 배경을 채웁니다. 장면 안에서는 save(), translate(), restore()로 변환 범위를 묶습니다. 앞선 장면의 확대·회전이 다음 장면에 남지 않게 하는 패턴입니다.

measureNumeral()은 measureText('4').actualBoundingBoxAscent로 숫자의 실제 높이를 측정합니다. 글꼴의 크기 값과 사람이 보는 글자 높이가 같지 않기 때문입니다. styles/swiss-motion/demo/main.js가 document.fonts.load()를 먼저 기다리는 것도 대체 글꼴로 측정해 배치가 달라지는 문제를 줄이기 위한 순서입니다.

실습 아이디어: 같은 100px 크기로 숫자·한글·영문을 나란히 그리고 실제 경계를 표시하세요. 한글에 필요한 글리프를 가진 폰트를 선택하고, 폰트 준비 전후의 측정값이 어떻게 다른지 비교해 보세요.

6-3. 리듬과 이징: 움직임을 음악의 단위로 바꾸기

styles/swiss-motion/demo/ease.js는 BPM = 120, BEAT = 60 / BPM, E8 = BEAT / 2, E16 = BEAT / 4를 정의합니다. 따라서 한 박은 0.5초, 8분음표는 0.25초입니다. snap(t, t1, d)는 도착 시각 t1을 기준으로 움직임이 미리 시작되게 만듭니다.

cubicBezier(.7, 0, .2, 1)은 입력 진행률에 해당하는 곡선 위치를 이분 탐색으로 구합니다. 전체 작품이 같은 곡선을 사용하면 빠르기와 도착감이 통일됩니다. 이는 웹 UI의 애니메이션 시간을 외우는 공부보다, 영상에서 리듬 규칙을 설계하는 공부에 가깝습니다.

실습 아이디어: 2초에 도착하는 도형 세 개를 각각 한 박, 반 박, 4분의 1박 전에 출발시키세요. 도착 시각을 고정한 채 출발 시각만 바꿔도 움직임의 인상이 달라지는지 관찰합니다.

6-4. WebGL·Three.js: 후처리는 여러 장의 계산이다

core/three/post.js의 makePost()는 DofScenePass → UnrealBloomPass → 색보정·비네팅 → OutputPass를 연결합니다. DofScenePass는 깊이 텍스처로 초점에서 얼마나 벗어났는지 계산하고, 선택적으로 GTAOPass의 주변 가림을 적용합니다.

용어
렌더 패스와 피사계 심도
렌더 패스는 화면을 계산하는 한 단계입니다. 장면을 먼저 그린 뒤 밝은 부분을 번지게 하거나 가장자리를 어둡게 만들 수 있습니다. 피사계 심도는 초점 거리와 다른 깊이의 물체가 흐려지는 효과입니다.

여기서 ssaa: 2는 가로·세로를 각각 두 배로 처리하므로 픽셀 수는 네 배입니다. 또한 심도 셰이더는 perspectiveDepthToViewZ()를 사용합니다. TECHNIQUE.md는 직교 카메라에 적용하려면 깊이 변환을 바꾸어야 한다고 명시합니다.

실습 아이디어: 먼저 정지한 단순 3D 장면에서 심도·블룸·주변 가림을 하나씩 켠 결과를 비교하세요. 효과를 한꺼번에 켜면 어떤 단계가 화면과 처리량을 바꿨는지 알기 어렵습니다.

6-5. Python 오디오: 소리는 시간축을 가진 숫자 배열

core/audio/sfx.py의 SR = 48000은 1초를 48,000개 표본으로 표현한다는 뜻입니다. thump()는 감쇠하는 저음과 필터링한 잡음을 섞고, whoosh()는 주파수 대역을 움직입니다. add()는 음량과 좌우 위치를 적용해 스테레오 배열에 더합니다.

# 저장소 루트의 Python 대화형 환경에서 사용할 학습용 예시
import numpy as np
from core.audio.sfx import SR, thump, add

buf = np.zeros((int(4 * SR), 2), dtype=np.float32)
add(buf, thump(v=0.8), at=1.5, gain=0.4, pan=0.0)
# 충격음은 72,000번째 표본 위치에서 시작한다.
# 저장·재생 전에는 최대 진폭과 클리핑을 확인한다.

core/audio/sampler.py의 render(events)는 시각·악기·음높이·길이·세기·좌우 위치가 담긴 악보를 스테레오 음원으로 만듭니다. credits(names)는 사용한 샘플의 출처 표기에 필요한 문구를 반환합니다. 공용 도구가 음원뿐 아니라 출처 관리도 돕는다는 점을 볼 수 있습니다.

실습 아이디어: 같은 충격음을 0.5초 간격으로 세 번 배치한 뒤, 좌우 위치와 음량만 다르게 해 보세요. 샘플 라이브러리를 쓰는 실습은 실제 악기 이름을 확인하고 필요한 라이브러리만 준비하는 편이 좋습니다.

6-6. TTS·ASR: 출력물을 다른 관측 경로로 검사하기

core/tts/tts.py는 대사별 WAV와 dur.json을 생성합니다. 기본 음성은 af_bella, 속도는 0.92, 언어는 en-us입니다. core/tts/asr_check.py는 이 소리를 다시 글로 인식해 원문과 비교하고, 단어 시각을 words.json에 기록합니다.

compare()는 영어를 정규화한 단어열로 비교하고, zh·ja·ko는 문자 유사도를 비교합니다. 기본 기준 0.92는 모델의 확신도가 아니라 difflib.SequenceMatcher의 유사도입니다. 고유명사나 숫자는 대사의 asr 필드로 비교용 표기를 따로 둘 수 있습니다.

한국어 실습의 함정
자동 언어 판별은 한국어를 별도 언어로 선택하지 않습니다

detect_lang()은 한글을 CJK 문자에 포함하지만 반환값은 zh와 en뿐입니다. 한국어 대사는 --lang ko를 명시해야 합니다. load_model()은 CPU와 int8 계산을 사용하므로 음성 검사 자체에 CUDA가 필수인 구조는 아닙니다.

TECHNIQUE.md의 기본 음성 합성 안내는 영어·중국어 중심입니다. core/tts/tts.py의 기본 언어는 영어이고, 한국어 글을 영어로 읽으려 하면 입력 검사에서 거부합니다. 한국어 실습은 먼저 사용할 음성 엔진·음성을 정하고, 짧은 문장을 직접 들어 확인해야 합니다.

6-7. 품질 검사: 보기 좋다는 말을 계산 조건으로 바꾸기

core/render/readcheck.mjs의 need()는 화면 글자에 필요한 시간을 계산합니다.

필요 시간 = max(1.5,
               한중일 문자 수 / 4.5
               + 나머지 비공백 문자 수 / 15
               + 1.5)초

예: 공백을 뺀 한글 9글자만 있으면 9 / 4.5 + 1.5 = 3.5초
검사 간격 기본값: 0.04초, 글자 사각형이 화면 안에 있어야 함

같은 식별자라도 문구가 바뀌면 새 텍스트로 처리하며, 처음 완전히 보이는 연속 구간을 검사합니다. TEXTS()가 없거나 검사할 텍스트를 한 번도 반환하지 않으면 종료 코드 2입니다. 이것은 통과가 아니라 검사 불가를 의미합니다. 또한 화면 글자를 OCR로 발견하는 도구가 아니므로 페이지가 모든 대상 문구를 정확히 보고해야 합니다.

core/render/mux.sh는 별도로 오디오 손상과 길이를 검사하고, 두 차례의 loudnorm으로 통합 음량 −14 LUFS, 실제 피크 −1.2 dB를 목표로 최종 합성합니다. 짧은 오디오는 무음으로 채우고, 음량 목표를 벗어나면 경고합니다. 자동 검사가 통과해도 발음의 자연스러움·사실 정확성·미적 완성도는 사람이 확인해야 합니다.

좋은 자동 검사는 “아무 오류도 안 났다”와 “검사할 조건을 실제로 만족했다”를 구분합니다. 실습 아이디어: 일부러 짧게 노출한 문구, 화면 밖 문구, 검사 정보가 없는 장면을 나누어 각각 어떤 결과가 나와야 하는지 먼저 예상해 보세요.

7하드웨어 / 시스템 요구사항

소스를 읽는 환경과 영상을 렌더링하는 환경의 부담은 다릅니다

7-1. 문서에 명시된 조건과 코드가 확인하는 조건

항목근거가 있는 요구사항초보자가 확인할 점
운영체제TECHNIQUE.md: Apple silicon macOS에서 개발, Linux는 동작 예상, Windows는 WSL 안내세 운영체제에서 같은 수준으로 검증되었다는 뜻은 아님
Node.js20 이상루트 engines.node와 설치 도구의 검사 조건
Python3.11 이상, 음성 구성의 kokoro-onnx는 3.11~3.13 안내설치 도구의 기본 선택은 uv 사용 시 3.12
미디어 도구FFmpeg와 ffprobe소스가 사용하는 H.264·AAC 인코더와 필터를 갖춘 빌드 필요
브라우저Playwright용 chromium-headless-shell다른 실행 파일은 PLAYWRIGHT_CHROME으로 지정 가능
GPU3D·셰이더가 많은 스타일에서 중요macOS는 기본 ANGLE Metal. 소프트웨어 WebGL이면 느릴 수 있다는 경고
CPU·RAM공식 최소 코어 수·RAM 용량·VRAM 용량 미기재작업자마다 브라우저와 FFmpeg가 생김. 작은 장면과 적은 작업자부터 확인

7-2. 해상도·작업자·후처리가 부담을 결정한다

기본 출력은 1920×1080, 24 fps, 작업자 3개입니다. takeSize()는 가로·세로 각각 16~8192 범위의 짝수만 허용합니다. 허용되는 최대 크기가 실용적으로 처리 가능한 크기를 보장하지는 않습니다.

1080p RGBA 화면 한 장은 단순 계산으로 약 7.9 MiB입니다. 가로·세로를 두 배로 그리면 한 장만 약 31.6 MiB가 됩니다. 실제 3D 처리에는 깊이·색상·중간 결과용 여러 버퍼와 브라우저 메모리가 더 필요합니다. 48 kHz 스테레오 float32 오디오 1분은 한 배열만 약 22 MiB이고, 믹싱은 여러 배열을 함께 유지합니다.

처리량은 영상 길이뿐 아니라 픽셀 수, 후처리 단계 수, 동시에 열린 브라우저 수에 함께 좌우됩니다. --workers 1은 브라우저 수를 줄이는 방법이고, --size 960x540은 출력 픽셀 수를 줄이는 방법입니다. 단, 작품 코드가 고정 좌표를 사용하면 크기 옵션만 바꿔도 자동으로 화면 구성이 맞춰지는 것은 아닙니다.

7-3. 다운로드 용량은 선택한 제작 단계에 따라 달라진다

구성문서에 적힌 대략적 용량필요한 경우
기본 도구약 350 MBNode 패키지·헤드리스 브라우저·Python 기본 구성
음성 구성약 0.55 GB + 인식 모델TTS와 음성 검사. 인식 모델은 영어 약 145 MB, 중국어 약 480 MB 안내
음악 추가 구성약 140 MBcore/audio/pluck.py의 numba 기반 현악기 모델
악기 샘플라이브러리별 약 70~400 MB샘플 악기 사용 시. 압축 해제 때는 팩 크기의 약 두 배 여유 안내
HDRI약 12 MB일부 3D 스타일의 환경 조명

용량 수치는 TECHNIQUE.md의 안내값이며, 패키지 변화나 작품별 원본 소재는 별도입니다. 중간 영상·음원·자료 캐시도 디스크를 사용합니다. README의 에이전트 제작 시간 30~60분 역시 안내치이며, 하드웨어별 렌더링 벤치마크는 아닙니다.

실행 환경의 경계
로컬 제작과 완전한 오프라인 제작을 구분하세요

Kokoro는 모델 준비 후 로컬 음성 합성이 가능하지만, core/tts/tts_zh.py의 edge-tts는 네트워크를 사용합니다. 패키지·모델·샘플·자료의 첫 다운로드와 코딩 에이전트 이용에도 별도 환경이 필요합니다.

core/tts/tts.py는 espeak-ng 데이터의 실제 경로를 확인할 수 있을 때, UTF-8 기준 160바이트 이상이면 거부합니다. 긴 한글 경로도 영향을 줄 수 있습니다. 저장소에서 확인되는 이런 제약을 무시하고 “설치만 하면 모든 데모가 즉시 재생성된다”고 기대해서는 안 됩니다.

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

새 연습 프로젝트에서 작은 결과 하나씩 완성하기

아래 명령은 학습자가 도구와 의존성을 준비한 뒤 수행할 예시입니다. 데모는 완제품 재생성보다 구현 기법을 참고하는 용도로 제공됩니다. styles/와 core/를 직접 바꾸기보다 별도의 films/learn-01/ 같은 연습 프로젝트에 필요한 코드를 작성하세요.

과제 1

시간을 위치로 바꾸는 6초 영상 입문

목표: 6-1절의 draw()를 사용해 사각형이 움직이는 장면을 만드세요. index.html에 캔버스와 모듈을 연결하고, DUR = 6, render(t), READY를 공개합니다. 배경도 매 프레임 칠해 JPEG에 투명 영역이 남지 않게 합니다.

완료 기준: 0·1·2·3초 정지 화면이 예상한 위치에 있고, 6초·24 fps 영상의 계산상 프레임 수가 144개임을 설명할 수 있습니다. 정지 화면만 만드는 단계에서는 음성·음악 모델을 준비할 필요가 없습니다.

# 저장소 루트에서, 본인이 만든 연습 프로젝트를 대상으로 실행
node core/render/still.mjs films/learn-01 0 1 2 3
node core/render/video.mjs films/learn-01 --fps 24 --workers 1
과제 2

누구나 읽을 수 있는 한글 제목 입문

목표: 9글자의 한글 제목을 그리고, TEXTS(t)에 전체 문구와 화면 좌표를 보고하세요. 한글 폰트는 실제 사용할 글자를 포함한 파일을 사용하고, 로드가 끝난 뒤 준비 완료로 표시합니다.

비교: 제목을 2초만 노출하는 경우와 4초 노출하는 경우를 나눕니다. 기본 규칙의 필요 시간은 3.5초이므로 결과가 달라져야 합니다. 제목 일부가 화면 밖으로 나가는 경우도 별도로 만드세요.

완료 기준: 가독성 실패 1과 검사 불가 2를 구분하고, 문구가 처음 보일 때부터 TEXTS()에 전체 문장을 반환하는 이유를 설명합니다.

node core/render/readcheck.mjs films/learn-01
# 이 명령은 화면 글자 검사다. 자막 파일 검사를 대신하지 않는다.
과제 3

착지와 충격음을 같은 시각에 맞추기 중급

목표: 도형이 1.5초에 착지하도록 하고, EV에도 같은 시각의 thump 이벤트를 넣습니다. events.json을 읽는 작은 믹서에서 6-5절의 add()를 사용해 6초 WAV를 만드세요.

완료 기준: 화면과 소리의 시각을 한 상수에서 정하고, 착지 시각을 바꾸면 효과음도 함께 이동합니다. 샘플 위치 1.5 * 48000 = 72000과 프레임 위치 1.5 * 24 = 36의 관계를 설명합니다.

node core/render/events.mjs films/learn-01
# events.json을 읽어 본인이 만든 믹서로 out/mix.wav를 생성한 다음
sh core/render/mux.sh films/learn-01/out/video.mp4 \
  films/learn-01/out/mix.wav films/learn-01/film.mp4 24 0
과제 4

작업자 수가 달라도 같은 화면인지 비교하기 중급

목표: 시드로 고정한 입자 20개를 추가하고 작업자 1개와 3개로 각각 출력합니다. 각 출력은 다른 파일 이름을 사용합니다.

완료 기준: 같은 시각에서 추출한 화면의 입자 위치가 일치합니다. 압축된 MP4 파일 전체의 해시가 같은지보다 장면 내용이 같은지를 확인하세요. 인코딩 구간이 달라지면 압축 결과는 달라질 수 있습니다.

관찰: 시간을 누적하거나 전역 난수를 매번 소비하는 코드를 일부러 넣었을 때 작업자 경계에서 어떤 문제가 생기는지 원인까지 기록합니다.

node core/render/video.mjs films/learn-01 --workers 1 \
  --out films/learn-01/out/one.mp4
node core/render/video.mjs films/learn-01 --workers 3 \
  --out films/learn-01/out/three.mp4
과제 5

내 자료를 설명하는 15초 미니 다큐멘터리 고급

목표: 직접 측정한 값 세 개나 재사용 조건이 명확한 자료 하나로 짧은 설명 영상을 만드세요. styles/caption-news/STYLE.md의 정보 배치 규칙을 참고하되, 새로운 도입·설명·결론을 구성합니다.

조건: 주장별 출처 또는 측정 방법을 FACTS.md에, 이미지·폰트·음원의 권리 정보를 CREDITS에 기록합니다. 음성은 사용할 권리가 있는 녹음 또는 확인한 엔진으로 준비하고, 한국어 ASR 검사는 --lang ko를 지정합니다.

완료 기준: 가독성·음성 내용·화면 경계·음량을 각각 검사한 뒤 최종 영상을 소리와 함께 확인합니다. 자동 검사로 확인하지 못한 사실과 미적 판단도 따로 적습니다.

첫 실습의 성공 기준은 화려한 영화 한 편보다, 한 시각의 그림과 소리를 의도대로 재현하고 설명할 수 있는 것입니다.

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

6주 동안 화면 한 장에서 검사 가능한 제작 파이프라인까지
주차학습 내용·읽을 소스만들 결과와 확인 질문
1주차JavaScript 모듈, 함수, 배열, JSON. core/lib.js와 styles/swiss-motion/demo/main.js한 장면을 그리는 함수. 입력 시각과 출력 화면을 설명할 수 있는가?
2주차Canvas 좌표·변환·폰트 측정. styles/swiss-motion/demo/film.js의 renderFilm()6초 제목 영상. 화면을 건너뛰어 그려도 같은가?
3주차Playwright, 비동기 처리, 프로세스·스트림. core/render/page.mjs, core/render/video.mjs정지 화면과 MP4 출력. 버퍼가 차면 누가 기다리는가?
4주차표본화, 파형, 필터, 믹싱. core/audio/sfx.py, styles/swiss-motion/demo/mix.py이벤트에 맞는 효과음. 초·프레임·표본을 서로 바꿀 수 있는가?
5주차TTS·ASR, 검사 경계, 문자 정규화. core/tts/asr_check.py, core/render/readcheck.mjs, core/render/mux.sh실패 사례를 포함한 검사 기록. 검사 불가를 통과로 오해하지 않는가?
6주차스타일 설계와 정적 사이트 생성. STYLE.md, styleboard/build.py, .github/workflows/pages.yml자기 스타일의 짧은 작품과 소개 카드. 메타데이터와 실제 파일이 일치하는가?

각 주차는 일정의 예시이며, JavaScript·Python을 처음 배우면 1~2주차를 더 길게 잡아도 됩니다. Three.js와 셰이더는 2D 파이프라인을 이해한 뒤 별도 갈래로 공부하세요. 깊이 버퍼·색 공간·렌더 타깃을 동시에 배우면 문제의 원인을 분리하기 어렵습니다.

학습 순서는 결과를 더 화려하게 만드는 순서보다, 한 단계씩 원인을 설명할 수 있게 되는 순서가 좋습니다. “그림이 틀렸는가, 캡처가 틀렸는가, 인코딩이 틀렸는가”를 나누어 질문할 수 있으면 이 저장소 밖의 자동화·데이터 처리 작업에도 같은 사고방식을 적용할 수 있습니다.

다음 공부
관심 분야별로 갈라지는 세 경로

시각 표현: 보간 → 좌표 변환 → 카메라 → 셰이더·후처리. 제작 자동화: 비동기 함수 → 스트림 → 하위 프로세스 → 잠금·작업 제한. 콘텐츠 품질: 시간표 → 글자 노출 → 음성 대조 → 출처와 최종 검토.

10핵심 키워드 사전

코드를 읽다가 막히면 돌아올 작은 사전
용어쉬운 설명
코딩 에이전트요청을 읽고 코드를 작성하거나 도구를 사용하는 AI 작업자. 여기서는 연출·그림·소리 제작을 돕습니다.
스타일 지시서색·서체·재질·움직임·소리에서 유지할 규칙. 특정 작품의 이야기와 구분합니다.
Canvas 2D브라우저의 평면 그림판 API. 선·도형·글자·이미지를 코드로 그립니다.
WebGL / 셰이더브라우저에서 GPU 계산을 사용하는 그래픽 API / GPU에서 실행하는 작은 계산 프로그램.
Three.js카메라·조명·재질·모형으로 3D 장면을 만들기 쉽게 해 주는 JavaScript 라이브러리.
헤드리스 브라우저일반 창을 띄우지 않고 자동화 도구가 제어하는 브라우저. 화면 렌더링과 캡처는 수행합니다.
결정성 / 시드같은 입력에서 같은 결과를 내는 성질 / 재현 가능한 난수열의 시작값. 시드만으로 모든 상태 의존성이 없어지지는 않습니다.
보간 / 이징두 값 사이의 값을 계산하기 / 진행률의 변화 속도를 조정하기.
타임라인 / 큐작품 전체 시간표 / 특정 동작·소리가 일어나야 하는 시점.
fps / 프레임1초당 화면 수 / 그중 한 장의 화면. 24 fps의 화면 간격은 약 0.0417초입니다.
워커일감을 나누어 처리하는 작업 단위. 이 렌더러에서는 각 작업 단위가 브라우저와 인코더를 사용합니다.
역압받는 쪽의 처리 속도에 맞춰 보내는 쪽이 잠시 기다리는 흐름 제어입니다.
뮤텍스 / 생존 표시공유 자원을 한 번에 하나만 바꾸게 하는 잠금 / 작업이 살아 있음을 주기적으로 갱신하는 표시.
TTS / ASR글을 음성으로 바꾸기 / 음성을 글로 인식하기. 두 경로를 연결해 발화 내용을 대조합니다.
표본화율소리를 1초에 몇 개의 숫자로 기록하는지 나타내는 값. 48 kHz는 초당 48,000개입니다.
덕킹 / 클리핑대사가 나올 때 배경음을 낮추기 / 신호가 허용 범위를 넘어서 잘리는 왜곡.
LUFS / 실제 피크청감에 가깝게 평가하는 음량 단위 / 재생 과정에서 표본 사이까지 고려한 최고 신호 수준.
먹싱영상과 음성을 최종 컨테이너에 합치는 과정. 여기의 core/render/mux.sh는 필터와 재인코딩도 수행합니다.
SSAA / HDRI더 크게 그렸다가 줄여 매끈하게 만들기 / 넓은 밝기 범위를 담아 환경 조명 등에 사용하는 이미지.
희소 체크아웃Git 저장소에서 필요한 경로만 선택해 파일로 펼치는 방식.
정적 사이트 생성메타데이터와 템플릿으로 HTML을 미리 만드는 방식. 갤러리는 Python으로 생성합니다.
MIT / CC BY 4.0이 저장소가 코드·문서와 데모 영상·정지 화면에 각각 안내하는 라이선스. 소재별 예외와 출처 표기도 확인합니다.

11참고 링크

공식 문서와 소스 원문으로 다시 확인하기

11-1. 프로젝트와 핵심 소스

11-2. 관련 기술의 공식 학습 자료

소스 링크는 커밋 3961ddb를 가리킵니다. 외부 기술 문서는 시간이 지나면 최신 버전으로 바뀔 수 있으므로, 예제의 동작은 이 글에 적힌 의존성 버전과 함께 비교하세요.

현재 상태 (2026-10-23 확인)

항목상태
선정TrendShift Weekly #21 · 2026-10-23 분석
스타 / 포크5,814 / 653 — 2026-10-23 GitHub 기준
주 언어JavaScript — 2026-10-23 GitHub 기준
생성일2026-09-26 — 2026-10-23 GitHub 기준
최신 릴리스thanks — 2026-10-12 (2026-10-23 GitHub 기준). package.json의 0.1.0과 별개
최근 push2026-10-22 — 2026-10-23 GitHub 기준
최근 커밋3961ddb · 2026-10-22 · README의 새 기능 소개를 데스크톱에서 한 줄에 들어가도록 줄인 변경
스타일 수59종·11개 분류. 별도로 _template 한 개
코드 규모JS 82,976 / Python 37,171 / HTML 11,287 / CSS 8,866 / Shell 2,524줄. 집계 범위는 5-1절
공용 제작 도구core/의 위 다섯 언어·형식 합계 21개 파일·2,278줄
주요 잠금 버전playwright-core 1.63.0 / three 0.170.0
라이선스MIT — 2026-10-23 GitHub 기준. README는 코드·문서에 MIT, 데모 영상·정지 화면에 CC BY 4.0을 안내하며 음성·외부 소재에 예외 명시
CI 범위정적 갤러리 생성·영상 링크 검사·Pages 배포. 루트 통합 테스트 명령은 없고 일부 데모에 개별 검사 코드 존재
쓰기 전에 알아둘 한계
소스가 공개되어 있어도 소재·모델·실행 조건까지 하나로 통일되지는 않습니다

재현 범위: 그림·음악·렌더링 코드를 읽을 수 있지만, 일부 원본 영상·폰트·모델·음원은 별도 다운로드가 필요합니다. 대표작 OPUSCAR 98은 갤러리에 소개되지만, styleboard/build.py는 해당 영화 소스가 라이브러리에 포함되지 않는다고 밝힙니다. 59종 스타일 데모와 대표작 전체 소스의 공개 범위를 혼동하지 마세요.

권리 범위: README는 Game Show Flat의 macOS 음성, Paper-cut Lightbox의 Edge TTS 내레이션, Broadcast News Package의 Doubao 내레이션을 데모의 CC BY 4.0 적용 대상에서 제외하고 재사용하지 말라고 안내합니다. 코드의 MIT와 영상·음성·폰트·외부 자료의 이용 조건을 각각 확인해야 합니다.

실행 환경: TECHNIQUE.md의 운영체제 설명과 README의 모델 적합성·제작 시간은 안내입니다. 실제 재현 여부와 처리 속도는 하드웨어, 브라우저, 원본 소재와 모델의 준비 상태에 따라 달라집니다. README의 안내를 독립적인 비교 실험 결과로 받아들이지 마세요.

검사 범위: 글자 노출 시간·음성 대조·음량 검사는 각각 제한된 조건을 확인합니다. 사실의 정확성, 자연스러운 발음, 출처의 적절성, 작품의 완성도까지 자동으로 보장하지 않습니다.