2LAZZZY 작업 노트2026-10-09 기준
Claude Code→HyperFrames 영상→Astro 사이트→배포

영상으로 웹사이트 만들기

todah.dev처럼 스크롤하면 영상처럼 재생되는 한 페이지를 Claude로 만드는 순서예요. Claude로 영상을 먼저 만들고, 그 영상을 주고 Astro로 사이트를 만들게 해요.

영상이 먼저 있으면 색, 글꼴, 장면 순서, 움직임이 이미 정해져 있어요. 그래서 사이트를 요청할 때 말로 설명할 게 줄고, 결과를 영상 캡처와 나란히 놓고 맞춰 볼 수 있어요. todah.dev도 HyperFrames로 먼저 만든 20초 영상 "귀찮으니까, 만든다"를 스크롤로 재생되는 한 페이지로 옮긴 거예요.

HyperFrames는 무료 오픈 소스이고 로컬 렌더는 HeyGen 크레딧을 쓰지 않아요. Claude Code 사용료와, 골라서 쓰는 음성이나 생성 미디어 서비스 요금은 따로예요.

이렇게 되면 성공이에요

  1. 1
    영상npx hyperframes render 로 mp4가 나오고, 장면 캡처가 있어요
  2. 2
    스크롤스크롤을 내리면 장면이 영상처럼 이어서 움직여요
  3. 3
    JS 꺼도자바스크립트를 꺼도 모든 글이 보여요
  4. 4
    배포내 도메인으로 접속하면 같은 페이지가 떠요

한눈에 보는 진행 순서

다섯 단계예요. 단계를 누르면 자세한 설명으로 가요.

  1. 영상 만들기

    Claude Code + HyperFrames로 내 직업이나 만들고 싶은 사이트를 짧은 영상으로 만들어요.

    자세히 보기 →
  2. 영상을 장면으로 나누기

    장면마다 캡처를 남기고, 장면 순서와 문구를 적어 둬요.

    자세히 보기 →
  3. 영상을 주고 Astro로 사이트 요청

    SPEC.md를 먼저 쓰게 하고, 장면 하나씩 만들게 해요.

    자세히 보기 →
  4. 확인하고 고치기

    데스크톱과 폰 크기로 스크린샷을 찍어 눈으로 확인해요.

    자세히 보기 →
  5. 배포

    npm run build 다음 Cloudflare Workers 또는 Coolify로 올려요.

    자세히 보기 →

1단계, Claude로 영상부터 만들기

HyperFrames는 HTML로 영상을 만드는 도구예요. Claude Code에 스킬로 붙여 쓰면 돼요.

설치

준비물: Claude Code, Node.js 22 이상(npm 포함), FFmpeg. FFmpeg는 mp4로 렌더할 때 필요해요.

영상 폴더에서 스킬을 추가하고, 고르는 화면에서 Core Skills를 선택해요. 그다음 그 폴더에서 Claude Code를 다시 켜요.

npx skills add heygen-com/hyperframes

미리 보기와 mp4 만들기는 이 두 명령이에요.

npx hyperframes preview
npx hyperframes render --output video.mp4

Claude Code 플러그인으로 설치해도 돼요(claude plugin marketplace add heygen-com/hyperframes, claude plugin install hyperframes@hyperframes). 설치 뒤 새 세션을 열거나 /reload-plugins를 하고, 아래 프롬프트 앞의 /hyperframes 를 /hyperframes:hyperframes 로 바꿔요. 스킬과 플러그인 중 하나만 설치해요.

요청할 때 적을 네 가지

항목적는 법
길이15~20초 정도. 짧을수록 사이트로 옮기기 쉬워요
화면 비율세로 1080x1920(폰 중심) 또는 가로 1920x1080
장면 수5~8개. 장면마다 문구 한 줄
색과 분위기배경색, 강조색 하나, 글꼴 느낌(굵은 고딕 등), 움직임 속도

그대로 복사해 쓰는 프롬프트

예시 1: 직업 소개 포트폴리오

/hyperframes 로 나를 소개하는 20초 세로 영상(1080x1920)을 만들어 줘.
나는 [직업]이고, 대표 작업은 [작업 1], [작업 2], [작업 3]이야.
장면은 6개: 이름과 한 줄 소개, 작업 3개를 하나씩, 일하는 방식 한 줄, 연락 방법.
배경은 흰색, 강조색은 파란색 하나, 굵은 고딕 글꼴, 장면 전환은 빠르고 깔끔하게.
나중에 이 영상을 웹사이트로 옮길 거라 글은 모두 HTML 텍스트로 만들어 줘.
끝나면 로컬 미리 보기를 열어 줘.

예시 2: 가게나 서비스 랜딩 페이지

/hyperframes 로 [가게/서비스 이름]의 15초 가로 영상(1920x1080)을 만들어 줘.
장면은 5개: 문제 한 줄, 해결 한 줄, 특징 2개, 마지막에 '지금 예약하기' 버튼.
분위기는 [따뜻하고 차분하게], 색은 [크림색 배경 + 초록 강조색 하나].
글은 모두 HTML 텍스트로, 장면마다 문구는 한 줄만.
끝나면 로컬 미리 보기를 열어 줘.

예시 3: 개인 브랜드

/hyperframes 로 내 개인 브랜드 '[브랜드 이름]'을 보여 주는 20초 세로 영상(1080x1920)을 만들어 줘.
핵심 문장은 '[한 줄 슬로건]'이고, 이 문장이 첫 장면과 마지막 장면에 나와.
장면은 7개, 검은 배경에 강조색 하나, 글자가 크게 튀어나오는 리듬감 있는 움직임.
마지막 장면은 SNS 계정과 팔로우 버튼.
나중에 이 영상을 웹사이트로 옮길 거라 글은 모두 HTML 텍스트로 만들어 줘.
끝나면 로컬 미리 보기를 열어 줘.

부족한 정보가 있으면 Claude가 방향을 먼저 제안하고 중요한 것만 물어봐요. 답해 주면서 다듬으면 돼요.

영상을 장면으로 나누기

사이트는 장면 단위로 만들어요. 영상을 장면 목록으로 바꿔 두면 다음 단계 요청이 쉬워져요.

영상 프로젝트 폴더에서 Claude Code를 열고 요청해요. 그래야 Claude가 영상의 HTML 원본을 읽고 시간과 문구를 그대로 옮길 수 있어요. mp4만 보면 정확한 시간과 움직임을 알기 어려워요.

이 영상의 컴포지션 HTML을 읽고 장면별로 나눠 줘.
장면마다 시작 시간, 끝 시간, 화면에 나오는 문구, 움직임 설명을 HTML에 적힌 값 그대로 표로 정리해 SCENES.md에 써 줘.
그리고 npx hyperframes snapshot --at 으로 장면마다 가장 잘 보이는 순간을 1장씩 찍어 captures/ 폴더에 scene-01.png 처럼 저장해 줘.

2단계, 그 영상으로 Astro 사이트 만들기

영상, 영상 HTML 폴더, 장면 목록, 캡처를 새 폴더에 넣고 Claude Code에 요청해요. 설계 문서를 먼저 쓰고, 장면은 하나씩 만들어요.

Astro는 Node.js 22.12 이상이 필요해요(23 같은 홀수 버전은 안 돼요). 터미널에서 node -v로 확인해요.

첫 요청: SPEC.md부터

video.mp4, 영상 HTML 폴더, SCENES.md, captures/ 를 봐 줘.
색, 글꼴, 크기, 타이밍은 영상 HTML에서 그대로 가져와 줘.
이 영상을 Astro로, 스크롤하면 영상처럼 재생되는 한 페이지로 만들 거야.
코드는 아직 쓰지 말고 SPEC.md부터 써 줘. 넣을 것:
1. 꼭 지킬 것: 글은 모두 실제 HTML 텍스트, 강조색 하나, JS를 꺼도 모든 글이 보일 것, prefers-reduced-motion이면 움직임 없이 보여 줄 것, 모바일 우선, 아래 패키지 말고 새 패키지 금지
2. 쓸 것: Astro, @astrojs/sitemap, GSAP(ScrollTrigger), Lenis, @fontsource 글꼴, sharp
3. 색과 글꼴(영상에서 그대로)
4. 장면 순서와 장면마다 스크롤 길이(vh)
5. title, description, Open Graph, canonical, 사이트맵
다 쓰면 나한테 보여 주고 기다려.

다음 요청: 장면 하나씩

SPEC.md대로 Astro 프로젝트를 만들고 1번 장면만 만들어 줘.
장면 하나 = sticky 섹션(높이는 SPEC의 vh) + GSAP ScrollTrigger scrub 타임라인.
captures/scene-01.png와 같아 보이게 하고, /dev/scene-01 개발 페이지에서 따로 볼 수 있게 해 줘.
/dev/ 페이지는 배포에서 빼 줘. 사이트맵 filter에서 제외하고, 빌드 뒤 dist/dev는 지워 줘.
끝나면 데스크톱 1440x900, 폰 390x844로 스크린샷을 찍어 캡처와 비교해 줘.

1번이 마음에 들면 "2번 장면도 같은 방식으로"처럼 하나씩 이어 가요. 다 만들면 한 페이지로 이어 붙이게 해요.

구조

  1. 장면 섹션height: 300vh 같은 스크롤 길이를 가진 섹션
  2. sticky 화면안쪽 100svh 화면이 position: sticky로 붙어 있어요
  3. scrub 타임라인GSAP ScrollTrigger의 scrub이 스크롤 진행도에 애니메이션을 맞춰요
  4. Lenis스크롤을 부드럽게, ScrollTrigger와 같은 박자로
js
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
import Lenis from 'lenis';
import 'lenis/dist/lenis.css';

gsap.registerPlugin(ScrollTrigger);

// 움직임 줄이기 설정이면 Lenis도 타임라인도 만들지 않아요
if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
  const lenis = new Lenis();
  lenis.on('scroll', ScrollTrigger.update);
  gsap.ticker.add((time) => lenis.raf(time * 1000));
  gsap.ticker.lagSmoothing(0);

  // 첫 장면: 처음엔 다 보이고, 스크롤하면 나가요
  gsap.timeline({
    scrollTrigger: { trigger: '#scene-01', start: 'top top', end: 'bottom bottom', scrub: true }
  })
    .to('#scene-01 .card', { scale: 1.2 })
    .to('#scene-01 h2', { y: -80, opacity: 0 });
}

첫 장면은 처음부터 다 보이게 두고, 스크롤하면 나가게 해요. gsap.from()은 바로 시작 값을 적용해서 첫 장면에 쓰면 제목이 숨은 채 열려요. 들어오는 움직임은 2번 장면부터 써요.

todah.dev가 쓴 것역할
Astro페이지를 HTML로 미리 만들어요
@astrojs/sitemap빌드할 때 sitemap-index.xml을 만들어요
GSAP + ScrollTrigger스크롤에 맞춰 움직이는 타임라인. GSAP는 플러그인까지 모두 무료예요
Lenis부드러운 스크롤
@fontsource글꼴을 npm 패키지로 받아 import해서 내 사이트에서 직접 제공. Astro 내장 Fonts API의 Fontsource 공급자로 해도 돼요
sharp이미지 변환과 최적화

왜 Astro인가

Astro는 랜딩 페이지, 포트폴리오, 블로그처럼 콘텐츠 중심 사이트에 현업에서 많이 쓰는 프레임워크예요. 공식 문서도 블로그, 마케팅, 쇼핑몰 같은 콘텐츠 사이트를 위해 설계했다고 설명해요.

미리 만든 HTML (정적 생성)

기본 설정에서 사이트 전체를 빌드할 때 HTML로 미리 만들어 보내요. 검색 엔진이 자바스크립트를 실행하지 않아도 글을 바로 읽을 수 있어요.

JS는 필요한 곳에만

Astro 컴포넌트는 기본으로 HTML과 CSS로만 나가요. 스크롤 애니메이션 같은 JS는 .astro 파일 안 <script>에 쓰면 Astro가 처리해서 묶고, 같은 컴포넌트를 한 페이지에 여러 번 써도 한 번만 넣어요. client:load, client:visible 같은 지시어는 React, Svelte 같은 UI 프레임워크 컴포넌트를 쓸 때 붙이는 거예요. 보내는 JS가 적어서 로딩이 빨라요.

SEO에 필요한 것들을 넣기 쉬워요

항목방법
사이트맵npx astro add sitemap, astro.config에 site 주소. 빌드하면 sitemap-index.xml이 생겨요
title, description레이아웃의 <head>에 페이지마다 props로 넣어요
Open Graphog:title, og:description, og:image 메타 태그를 같은 레이아웃에
canonical<link rel="canonical">에 Astro.site 기준 주소
구조화 데이터<script type="application/ld+json" set:html={JSON.stringify(data)} />로 JSON-LD를 넣어요
이미지src/ 안에 두고 import한 이미지를 astro:assets의 <Image />로 넣으면 크기와 형식을 바꾸고 width, height를 자동으로 넣어 레이아웃 밀림(CLS)을 막아요. loading="lazy"도 붙어요. public/에 둔 이미지는 변환 없이 그대로 나가요
js
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';

export default defineConfig({
  site: 'https://example.com',
  integrations: [sitemap()],
});

움직여도 글은 진짜 HTML

영상처럼 보여도 글을 이미지나 캔버스에 그리지 않고 HTML 텍스트로 두면, 검색 엔진도 화면 낭독기도 읽을 수 있어요. todah.dev가 지킨 원칙이에요.

다른 선택지와 비교

단일 페이지 앱(클라이언트 렌더링)Astro (기본 정적 생성)
HTML 만드는 곳브라우저에서 JS가 화면을 그려요빌드할 때 미리 HTML로
기본 JS앱 전체를 위한 JS를 보내요없음. 내가 넣은 <script>와 아일랜드만
검색 엔진이 보는 글JS가 실행된 뒤에 생겨요처음 받은 HTML에 이미 있어요
잘 맞는 곳로그인 뒤 복잡한 앱, 대시보드랜딩, 포트폴리오, 블로그

Astro 공식 문서는 Next.js, SvelteKit 같은 프레임워크가 복잡한 앱에는 강하지만 콘텐츠 사이트에는 클라이언트 렌더링 때문에 복잡성과 성능 부담이 생길 수 있다고 설명해요.

확인하고 고치기

장면마다 눈으로 보고 고쳐요. 숫자보다 화면이 먼저예요.

  1. 장면별 개발 페이지

    /dev/scene-01 처럼 장면 하나만 보는 페이지에서 먼저 맞춰요.

  2. 장면 스크린샷
    Playwright로 /dev/scene-01/ 을 스크롤 진행도 0, 0.5, 1에서 데스크톱 1440x900, 폰 390x844로 찍는 스크립트를 만들어 줘.
    찍은 사진을 captures/scene-01.png와 나란히 보여 줘.

    장면 페이지를 스크롤 진행도 몇 군데에서 데스크톱 1440x900, 폰 390x844 두 크기로 찍어 영상 캡처와 나란히 봐요. 찍는 스크립트는 Claude에게 만들게 해요. todah.dev도 scripts/shoot.mjs로 장면 페이지를 진행도별로 찍어요.

  3. Lighthouse

    npm run build, npm run preview 로 띄운 뒤 Chrome 개발자 도구의 Lighthouse로 성능, 접근성, SEO를 봐요.

1440x900과 390x844 스크린샷을 captures/scene-03.png와 비교해서 다른 점을 적고 고쳐 줘.
고친 뒤 다시 찍어서 보여 줘.

배포

빌드하면 dist/ 폴더에 정적 파일이 생겨요. 이걸 올리면 끝이에요.

배포 전에 /dev/ 개발 페이지가 빌드와 사이트맵에서 빠지게 해 달라고 해요. 사이트맵은 기본으로 모든 페이지를 넣어요. todah.dev는 sitemap filter로 /dev/를 빼고, 빌드 명령을 astro build && node scripts/postbuild.mjs로 바꿔 빌드 뒤 dist/dev를 지워요.

js
// astro.config.mjs
integrations: [sitemap({ filter: (page) => !page.includes('/dev/') })],

// scripts/postbuild.mjs
import fs from 'node:fs';
fs.rmSync(new URL('../dist/dev/', import.meta.url), { recursive: true, force: true });

Cloudflare Workers 정적 자산

프로젝트 루트에 wrangler.jsonc를 만들어요. 정적 사이트라 Astro 어댑터는 필요 없어요. 도메인은 Cloudflare에 연결된 내 도메인이어야 해요.

jsonc
{
  "name": "my-site",
  "compatibility_date": "2026-10-09", // 배포하는 날짜로 바꿔요
  "assets": {
    "directory": "./dist",
    "not_found_handling": "404-page"
  },
  "routes": [
    { "pattern": "example.com", "custom_domain": true }
  ]
}
npm install wrangler@latest --save-dev
npm run build
npx wrangler deploy

처음 배포하면 브라우저가 열려 Cloudflare 계정으로 로그인해요. not_found_handling: "404-page"가 있어야 Astro의 404 페이지가 404로 나가요.

custom_domain을 쓰면 Cloudflare가 DNS 레코드와 인증서를 자동으로 만들어요. 같은 이름에 CNAME 레코드가 이미 있으면 만들 수 없어요.

또는 Coolify (Docker + nginx)

dockerfile
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
nginx
# nginx.conf (Dockerfile 옆에)
server {
  listen 80;
  root /usr/share/nginx/html;
  index index.html;
  location / { try_files $uri $uri/index.html $uri.html =404; }
  error_page 404 /404.html;
}

Coolify에서 저장소를 연결하고 빌드 방식을 Dockerfile로 고르면 돼요. Coolify 앱의 포트는 80으로 맞춰요(Dockerfile의 EXPOSE 80과 같게). nginx.conf의 error_page 404 /404.html; 이 있어야 Astro의 404 페이지가 나와요(todah.dev 방식).

자주 막히는 곳

증상고치는 법
애니메이션 시작 위치가 어긋나요글꼴이 늦게 로드되면 높이가 바뀌어요. document.fonts.ready 뒤에 ScrollTrigger.refresh()로 위치를 다시 재요
폰에서 옆으로 밀려요 (가로 스크롤)화면 밖으로 나가는 요소 때문이에요. 바깥 래퍼에 overflow-x: clip, 넓은 요소는 max-width: 100%
폰에서 효과가 안 보여요폰에는 hover가 없어요. hover에만 기대는 효과는 스크롤이나 탭으로 바꿔요
JS를 끄면 빈 화면처음 상태를 opacity: 0으로 CSS에 두면 그래요. 숨기는 건 JS가 실행된 뒤 gsap.from으로 하게 해요. 또는 <head>의 짧은 스크립트로 <html>에 js 클래스를 붙이고, 숨기는 CSS는 html.js 아래에만 둬요
움직임을 줄인 사용자JS에서 window.matchMedia('(prefers-reduced-motion: reduce)').matches가 참이면 타임라인을 만들지 말고 최종 화면을 그대로 보여 줘요(gsap.matchMedia()로 해도 돼요)
js
document.fonts.ready.then(() => ScrollTrigger.refresh());
출처

명령어와 설정은 2026-10-09에 각 공식 문서에서 확인했어요. 프롬프트 예시는 따라 쓰기 쉽게 만든 예시예요.

2LAZZZY / 2026-10-09 기준. 이 페이지에는 실제 계정 ID, 키, 개인 정보가 없어요. 체크 표시는 이 기기에만 저장돼요.