





2026년 11월 14일 토요일 오후 2시
저희의 새로운 시작을 함께해 주세요.
더 채플 청담 · 3F 그랜드홀
서울 강남구 청담동




참석이 어려우신 분들을 위해 마음 전하실 곳을 안내드립니다.
두 사람에게 따뜻한 축복을 남겨주세요.
아무것도 없는 새 컴퓨터에 Claude Code만 깔린 상태 기준이에요. 아래 키 3개를 처음부터 발급받고, 프롬프트를 순서대로 복붙하면 Claude Code가 영상 생성·합성·배포까지 다 합니다.
새 컴퓨터에 Claude Code만 있어. 이 작업에 필요한 도구를 설치/준비해줘: ffmpeg, node, wrangler(cloudflare), 헤드리스 QA용 puppeteer-core + chromium, yt-dlp. 그리고 방금 발급받은 키를 연결할게: Pexels 키는 저장소 밖 안전한 곳에, GCP Vertex 키 파일은 ~/.claude/.gcp-vertex-key.pem 로, Cloudflare는 'wrangler login'으로 로그인하게 안내해줘.
버건디 청첩장용 자산을 만들어줘. 1) 봉투: Imagen(imagen-3.0-generate-002, 9:16)으로 "딥버건디 청첩장 봉투+금박 왁스실+말린 장미·유칼립투스, 어두운 벨벳 배경" 이미지 생성. 2) 봉투 개봉 영상: 그 이미지를 Veo 3.1 i2v로 "왁스실 떼지고 → 플랩 열리며 → 카드·황금빛·꽃잎 나오는" 8초 영상으로. 3) 식장: Veo로 "골든아워 야외 결혼식장을 카메라가 꽃길 따라 전진 비행" 8초. 4) 주마등 배경: Veo 가성비(veo-3.0-fast)로 "버건디·골드 보케가 떠다니는" 배경 루프. 5) 스냅: Pexels에서 'couple sunset', 'wedding proposal' 등 세로 사진 6장. GCP 키는 ~/.claude/.gcp-vertex-key.pem 사용. 다 docs 아래 저장해줘.
위 자산으로 세로 9:16 시네마틱 스크롤 청첩장(버건디)을 만들어줘. 스크롤하면 5막이 심리스하게 이어진다: ①봉투 개봉 ②주마등(스냅이 하나씩 앞으로 지나가고 배경 보케가 움직임) ③식장으로 날아 들어가며 긴 세로팬(버진로드) ④카운트다운·예식일정·오시는길·마음전하실곳 ⑤이름·날짜 피날레. 규칙: GSAP ScrollTrigger + Lenis. ★봉투·식장 스크럽은 'canvas 프레임 시퀀스'로(아래 비결). 핀 높이 100dvh, overflow-x:clip, 막 사이 어두운 veil 크로스페이드. 헤드리스 chromium으로 스크롤 지점별 스크린샷 찍어 검증하고 보여줘. Cloudflare Pages로 배포(파일당 25MB 이하로 압축). 이름·날짜·사진은 우선 더미.
이 두 기능은 프롬프트·코드·함정까지 따로 아주 자세히 정리해뒀어요. → 방명록·배경음악 상세 가이드 보기 (맨 아래)
스크롤에 맞춰 영상을 재생(video의 currentTime 조작)하면 폰(특히 사파리)에서 끊기거나 아예 안 돌아갑니다. 데스크톱에선 멀쩡해 보여서 속기 쉬워요.
그래서 우리는 영상을 ffmpeg로 사진 80장으로 쪼개고(fps=10), 전부 미리 불러둔 뒤, 스크롤 위치에 맞는 사진 한 장을 canvas에 그립니다. 디코딩·탐색이 없어서 폰에서 버터처럼 부드러워요. 카메라 줌·위빙·세로팬은 그 canvas에 CSS로 얹고요. (자동재생 배경 루프만 video 그대로 둬도 됨)
· overflow-x:hidden 쓰면 position:sticky가 깨져요(핀이 그냥 스크롤돼 화면이 텅 빔) → overflow-x:clip 사용.
· 핀 높이 100vh는 모바일 주소창 때문에 점프 → 100dvh.
· 세로팬이 캔버스 높이보다 크면 영상 아래 검정 노출 → 캔버스 높이에 맞춰 팬 폭 제한.
· Cloudflare Pages는 파일당 25MB 한도 → 영상 압축.
· 추측 금지: 헤드리스 브라우저로 스크롤별 스크린샷을 찍어 눈으로 확인하며 진행.
이 청첩장의 방명록(서버·DB 없이 작동)과 배경음악(아이폰에서도 재생)을, Claude Code에 프롬프트만 복붙해서 그대로 만드는 법입니다. 코딩 몰라도 됩니다.
wrangler login으로 Cloudflare 로그인 안내해줘"라고 시키세요.하객이 이름과 축하 메시지를 남기면 실시간으로 목록에 쌓입니다. 핵심은 전통적인 서버·데이터베이스가 전혀 없다는 것.
/api/guestbook)가 조회(GET)·등록(POST) 처리. 배포하면 함수가 자동으로 작동.내 청첩장 사이트에 방명록을 붙일 거야. 데이터는 Cloudflare KV에 저장해. 1) `GUESTBOOK` 이라는 KV 네임스페이스를 만들어줘 (wrangler로). 2) 프로젝트 wrangler.toml에 그 KV를 binding 이름 `GUESTBOOK` 으로 연결해줘. 3) 이 사이트는 Cloudflare Pages이고 빌드 출력 폴더는 정적 폴더(예: _site)야. pages_build_output_dir 도 맞춰줘. 완료되면 wrangler.toml 내용을 보여줘.
name = "내사이트이름" pages_build_output_dir = "_site" compatibility_date = "2025-12-01" [[kv_namespaces]] binding = "GUESTBOOK" id = "자동으로-생성된-KV-아이디"
Cloudflare Pages Function으로 방명록 API를 만들어줘.
경로는 functions/api/guestbook.js (URL은 /api/guestbook). KV 바인딩 이름 GUESTBOOK.
- GET : 최근 메시지 최대 200개를 최신순 JSON으로. KV.list로 한 번에 가져오되
내용은 각 키의 metadata에 저장해서 목록을 KV 호출 1번으로 끝내.
(키 형식 m:<타임스탬프>_<랜덤>)
- POST : { name, message, website } 받아 저장. 스팸 방지 필수:
1) 허니팟: website(화면 숨김)가 채워지면 봇이니 조용히 무시(성공인 척).
2) 길이: 이름 1~20자, 메시지 2~200자. 공백 정리.
3) 링크 차단: http/www/.com/.kr, 텔레그램·카톡아이디 패턴 거부.
4) IP 레이트리밋: 같은 IP 60초 1번 (KV에 rl:<ip> 60초 TTL).
- 응답은 항상 JSON, no-store. KV 미연결이면 error:"kv_unbound".export async function onRequestGet({ env }) {
if (!env.GUESTBOOK) return J({ ok:false, error:"kv_unbound", items:[] });
const list = await env.GUESTBOOK.list({ prefix:"m:", limit:1000 });
const items = list.keys.map(k => k.metadata).filter(Boolean)
.sort((a,b) => b.t - a.t).slice(0,200);
return J({ ok:true, items });
}
export async function onRequestPost({ request, env }) {
const b = await request.json();
if (clean(b.website,50)) return J({ ok:true }); // 허니팟
const name = clean(b.name,20), msg = clean(b.message,200);
if (name.length<1 || msg.length<2) return J({ok:false,error:"too_short"},400);
if (hasLink(name+" "+msg)) return J({ok:false,error:"no_links"},400);
const ip = request.headers.get("cf-connecting-ip") || "0"; // 레이트리밋
if (await env.GUESTBOOK.get("rl:"+ip)) return J({ok:false,error:"rate_limited"},429);
await env.GUESTBOOK.put("rl:"+ip, "1", { expirationTtl:60 });
const t = Date.now(), key = `m:${t}_${Math.random().toString(36).slice(2,8)}`;
await env.GUESTBOOK.put(key, "", { metadata:{ n:name, m:msg, t } });
return J({ ok:true, item:{ n:name, m:msg, t } });
}list() 한 번으로 내용까지 다 받아와서 200개를 KV 호출 1회로 끝낼 수 있어요(무료 한도 절약 + 빠름).청첩장에 방명록 섹션을 추가해줘 (기존 버건디·골드 톤에 맞춰서). - 입력: 이름(max 20), 메시지(textarea, max 200), '남기기' 버튼. - 봇 방지 허니팟 input(website)을 화면 밖(left:-9999px)에 숨겨 같이 전송. - 열리면 GET /api/guestbook 로 목록을 카드로 렌더(이름·상대시간·메시지). - 남기면 POST 후 성공 시 방금 글을 목록 맨 위에 바로 끼우고 입력칸 비우기. 실패 시 에러코드별 한국어 안내(too_short/no_links/rate_limited/kv_unbound). - 시간은 '방금/N분 전/N시간 전/M.D'. - XSS 방지: 사용자 입력은 textContent로만, innerHTML 금지.
textContent(있는 그대로 글자로). innerHTML 쓰면 누가 스크립트를 적었을 때 실행될 수 있어요.audio/bgm.mp3. 크면 Claude Code에게 압축 시키기.배경음악을 넣을 거야. 저작권free 음원(mp3)을 audio/bgm.mp3 에 둘게. (또는 무료·상업가능 음원 출처와 받는 법을 추천해줘.) 1MB 넘으면 ffmpeg로 96~128kbps로 압축해 용량 줄여줘. loop, playsinline, preload="none" 인 <audio id="bgm"> 태그를 추가해줘.
배경음악 재생 로직을 만들어줘 (iOS 자동재생 정책에 맞게).
- 우하단 동그란 사운드 토글(🔇/🔊), 처음엔 은은한 펄스 + "탭하여 음악과 함께 ♪" 힌트.
- 첫 탭(버튼이든 화면 아무데든)에서 시작. 단 볼륨 0에서 1.7초에 걸쳐
0.34까지 페이드인(갑자기 안 터지게).
- 버튼으로 켜고 끄기. 끄면 다음 방문 때 자동으로 안 켜지게
localStorage('wed_muted')에 음소거 기억.
- iOS: click은 유효 제스처, scroll은 무효 → '첫 클릭 자동시작'은 document click(once)로.var on=false, muted=localStorage.getItem('wed_muted')==='1';
function enable(){ on=true; localStorage.setItem('wed_muted','0');
bgm.play().then(()=>fade(bgm,0.34,1700)).catch(()=>{}); setIcon(); }
function disable(){ on=false; localStorage.setItem('wed_muted','1'); bgm.pause(); setIcon(); }
btn.addEventListener('click', e=>{ e.stopPropagation(); on?disable():enable(); });
document.addEventListener('click', ()=>{ if(!on&&!muted) enable(); }, { once:true });봉투의 왁스 씰을 탭하면 그 탭으로 음악이 같이 시작되게 하면 자연스럽습니다(별도 안내 없이 입장 = 재생).
입장 동작과 음악을 연결해줘. - window.__weddingEnter() 전역 함수: 호출되면 이전에 음소거였어도 무시하고 음악을 강제 시작(enable). - 봉투 가운데 '왁스 씰' 탭 핫스팟을 두고, 탭하면 __weddingEnter() 호출. - 씰 위치는 봉투 이미지가 object-fit:cover로 잘리는 걸 감안해 JS로 화면좌표를 계산해 정확히 씰 위에 오게(모바일·웹 둘 다). 헤드리스 chromium으로 모바일·데스크탑 스크린샷을 찍어 씰에 맞는지 확인해서 보여줘(추측 금지).
효과음도 넣어줘 (음악이 켜져 있을 때만). - 봉투 개봉 구간 진입 시 '종이 스치는 소리' 1회, 피날레 진입 시 '반짝' 1회. - IntersectionObserver로 섹션이 보일 때 1회만 재생. - 효과음은 Web Audio API(AudioContext+decodeAudioData)로 미리 디코드해 지연 없이, 볼륨 0.26 정도로 작게.
preload="none"이라야 가볍게 뜸. ② 볼륨은 꼭 페이드인. ③ iOS는 playsinline 필수. ④ 음소거는 localStorage로 기억해 재방문 존중. ⑤ 효과음은 <audio> 여러 개보다 Web Audio가 끊김 없이 깔끔.이제 Cloudflare Pages로 배포해줘 (wrangler pages deploy). 배포 끝나면: 1) 사이트 URL 알려줘. 2) /api/guestbook 에 테스트 글을 하나 남겨보고 다시 조회해 저장·조회 확인. 3) KV 바인딩(GUESTBOOK)이 Pages 프로젝트에 실제 연결됐는지 확인 (안 됐으면 대시보드 Settings에서 연결하는 법 안내). 4) 모바일에서 음악이 탭으로 시작되는지, 방명록이 보이는지 점검 포인트 알려줘.
GUESTBOOK으로 연결하고 다시 배포하면 됩니다.막히는 데 있으면 → @aitigermask
코드 한 줄 없이 AI로 만든 청첩장입니다.
만드는 법 → @aitigermask