FrameVelo
FrameVelo는 코드로 프레임을 그리는 페이지를 MP4로 변환합니다. 프레임은 GPU에 그대로 유지되고(drawElementImage 또는 페이지의 캔버스) 하드웨어 인코더로 바로 전송되므로, 스크린샷 기반 렌더러보다 훨씬 적은 CPU와 메모리로 렌더링합니다. HyperFrames 프로젝트는 공식 HyperFrames 파이프라인에 의해 컴파일되며, FrameVelo는 캡처와 인코딩만 대체합니다.
호출하기
이 플러그인의 MCP 도구를 사용할 수 있으면 사용하세요. 첫 번째 시작 시 플러그인이 ~/.cache/framevelo에 FrameVelo를 설치합니다(약 1분 소요). 플러그인 설치 직후 도구가 보이지 않으면 잠시 기다렸다가 다시 연결(/mcp)하거나 아래 CLI를 사용하세요.
render: 렌더링하며 출력 경로, 프레임 수, 크기, 소요 시간, 경고, 마지막 로그 라인을 반환합니다.doctor: Node, FFmpeg, Chrome,drawElementImage, 하드웨어 인코더 및 HyperFrames 지원 여부를 확인합니다.install_browser: Chrome 151+가 설치되지 않은 경우 chrome-headless-shell(약 100MB)을 다운로드합니다.
도구 없이 CLI를 실행하세요. --json은 결과(또는 {"error": ...})를 stdout에 출력합니다:
npx -y -p github:gnipbao/framevelo -p @hyperframes/[email protected] -p @hyperframes/[email protected] framevelo render /abs/project -o /abs/out.mp4 --json -q
첫 npx 실행 시 약 30초 동안 설치합니다. 자주 렌더링한다면 사용자에게 한 번만 설치할 것을 권장하세요: npm install -g github:gnipbao/framevelo @hyperframes/[email protected] @hyperframes/[email protected]. CLI는 도구와 동일한 옵션을 플래그로 받습니다(--frames 30 --quality draft). framevelo render --help를 실행하면 전체 목록을 볼 수 있습니다.
절대 경로를 사용하세요. 한 번에 하나의 렌더만 실행하세요. 단일 하드웨어 인코더를 공유하며, MCP 서버는 어차피 대기열로 처리합니다.
워크플로우
- 입력 찾기:
index.html이 포함된 프로젝트 디렉토리 또는.html파일. 지속 시간, FPS, 크기는 페이지에서 가져옵니다(HyperFramesdata-duration/data-fps/data-width,window.__framevelo.duration, GSAP 타임라인 길이,window.__comp). 재정의하려면 명시적으로 전달하세요. - 새로운 합성 또는 변경된 경우 일부 미리보기:
{ input, output: "/tmp/preview.mp4", start: 2, frames: 30, quality: "draft" }. 몇 초면 완료됩니다. 프레임 확인:ffmpeg -v error -ss 0.5 -i /tmp/preview.mp4 -frames:v 1 /tmp/preview.png, 이어서 PNG를 봅니다. - 기본값으로 전체 렌더링. 1080p 레이아웃에서 4K를 원하면
scale: 2를 추가하고, 모션 블러는subframes: 3을 추가합니다. - 결과 확인:
frames는 예상한 프레임 수와 일치해야 하며,audio는 합성에 사운드가 있을 때 true입니다.warnings를 읽으세요.screenshotFrames > 0은 일부 구간이 검증에 실패하여 스크린샷으로 캡처되었음을 의미합니다(여전히 정확하지만 더 느림). - 보고하기: 출력 경로, 길이, 크기 및 소요 시간(
wallMs)을 보고하세요.
페이지 렌더 가능하게 만들기
모든 프레임은 시간의 순수 함수여야 합니다. FrameVelo는 다음 중 첫 번째로 발견되는 것을 통해 페이지를 탐색합니다:
window.__framevelo = { seek(t), duration, fps }.seek는 프라미스를 반환할 수 있습니다.window.__seek(t), 선택적으로window.__duration을 포함합니다.window.__timelines.main(또는 첫 번째 키)에 있는 일시 정지된 GSAP 타임라인.
<canvas id="scene" width="1920" height="1080"></canvas>
<script>
const g = document.getElementById("scene").getContext("2d");
function draw(t) {
g.fillStyle = "#05060a";
g.fillRect(0, 0, 1920, 1080);
g.fillStyle = "#6cf";
g.fillRect(200 + 300 * t, 500, 120, 120);
}
window.__framevelo = { duration: 4, seek: draw };
</script>
- 타임라인에 푸티지를
<video data-start="1.5" src="clip.mp4">(선택적data-media-start,data-duration,data-playback-rate)로 배치하세요. FrameVelo는 정확한 프레임으로 탐색하며, 긴 GOP 소스는 캐시된 올-인트라 프록시를 얻습니다. Math.random은 시드가 지정되어 렌더가 반복 가능합니다.requestAnimationFrame루프, CSS 트랜지션,Date.now()및performance.now()애니메이션은 탐색할 수 없습니다. 이를seek(t)또는 일시 정지된 GSAP 타임라인으로 옮기세요.- 드라이버를 노출하기 전에 페이지 내의 자산(폰트, 이미지)을 기다리거나
seek에서 프라미스를 반환하세요.
알아두면 좋은 옵션
| 필요 상황 | 인자 |
|---|---|
| 빠른 확인 | frames: 30, quality: "draft", start: <s> |
| 1080p 레이아웃에서 4K | scale: 2 |
| 크기가 선언되지 않은 세로 페이지 | viewport: "1080x1920" |
| 더 작은 파일 | codec: "hevc" |
| 모션 블러 | subframes: 3 (그리고 shutter, 기본값 0.5) |
| 사운드트랙 교체 | audio: "/abs/music.m4a" |
| 단일 요소 캡처 | selector: "#stage" |
| 색상 위에 투명 DOM | background: "#000" |
| code-video 스킬을 찾을 수 없음 | mounts: {"/@skill/": "/abs/path/to/code-video"} |
| HyperFrames 프로젝트를 일반 페이지로 | hyperframes: false |
실패 시
| 메시지 | 조치 |
|---|---|
Chrome not found | install_browser 호출(또는 framevelo browser install 실행) 후 다시 렌더링하세요. |
FFmpeg / FFprobe failing in doctor | 사용자에게 FFmpeg 설치(brew install ffmpeg)를 요청하세요. 시스템 소프트웨어를 직접 설치하지 마세요. |
The page exposes no way to seek time | 페이지에 시간 드라이버가 필요합니다. "Making a page renderable"을 참조하세요. |
Unknown duration | duration 또는 frames를 전달하거나 페이지에서 지속 시간을 선언하세요. |
The composition failed to set up | 합성에서 스크립트 오류가 발생했습니다. 페이지를 수정하세요. 메시지에 페이지 오류가 포함되어 있습니다. |
No element matches selector / Nothing to capture / has no size | selector를 크기가 있는 보이는 요소로 지정하거나 레이아웃을 수정하세요. |
Rendering a HyperFrames project needs ... @hyperframes/producer | 위의 npx -p @hyperframes/... 명령어를 사용하거나 FrameVelo 옆에 패키지를 설치하세요. |
No paint event within ... | 페이지가 더 이상 페인트하지 않습니다. 보통 스크립트가 멈춤. 브라우저에서 확인하세요. |
렌더는 원자적입니다: 실패하거나 취소된 렌더는 출력 파일을 남기지 않습니다.