마케팅 스튜디오 에이전트
ara.so 제공 스킬 — 마케팅 스킬 컬렉션.
마케팅 스튜디오는 Claude Code를 위한 에이전트 구동 비디오 렌더링 엔진입니다. 제품 리포지토리에서 /marketing을 실행하여 전체 출시 에셋 모음(3D 로고 리빌, 스크린 캡처 제품 데모, 보이스오버/음악이 포함된 히어로 런치 비디오, 플랫폼별 소셜 클립, OG 자산)을 생성합니다. 모든 렌더링은 Remotion, Blender, Playwright, ElevenLabs를 사용하는 중앙 엔진 리포지토리에서 이루어집니다.
설치
# 엔진 리포지토리 클론
git clone https://github.com/ucsandman/marketing-studio.git
cd marketing-studio
# 의존성 설치
cd studio && npm install && cd ..
# 설정 (선택 사항: Blender 경로, ElevenLabs API 키)
cp .env.example .env
# Claude Code에 스킬 설치
node scripts/install-skills.mjs
# 도구 체인 확인
python launch.py --check
설치 스크립트는 스킬을 ~/.claude/skills에 복사하고, 클론된 엔진 경로에 연결합니다.
핵심 워크플로우
/marketing 명령
프로덕트 리포지토리에서:
claude
> /marketing
이 명령은 전체 파이프라인을 실행합니다:
- 브랜드 온보딩 – 디자인 시스템에서 브랜드 토큰을 추출하거나 프롬프트로 입력받음
- 로고 리빌 – Remotion에서 합성되는 3D Blender 애니메이션
- 프로덕트 데모 – Playwright가 실행 중인 앱을 캡처하며 카메라 줌 적용
- 런치 비디오 – 데모, 로고, 카피를 결합한 30-90초 히어로 비디오
- 오디오 트랙 – ElevenLabs 보이스오버 및 비디오에 맞춘 음악
- 소셜 클립 – 플랫폼별 컷 (X, LinkedIn, TikTok)
- OG 자산 – 정적 이미지, 애니메이션 루프, README GIF
개별 스킬
에셋 유형별로 독립 실행:
> /logo-reveal
> /product-demo
> /launch-video
> /audio-track
> /social-clip
> /og-assets
브랜드 설정
브랜드는 brands/<id>.json에 정의됩니다:
{
"id": "myproduct",
"name": "MyProduct",
"tagline": "Ship faster, break less",
"colors": {
"primary": "#3b82f6",
"secondary": "#8b5cf6",
"accent": "#f59e0b",
"background": "#000000",
"foreground": "#ffffff",
"muted": "#6b7280",
"success": "#10b981",
"warning": "#f59e0b",
"error": "#ef4444",
"text": "#f9fafb",
"textMuted": "#9ca3af",
"border": "#374151",
"surface": "#111827"
},
"fonts": {
"heading": "Inter",
"body": "Inter",
"mono": "JetBrains Mono"
},
"voice": {
"tone": "confident, technical, no fluff",
"avoid": ["AI slop", "game-changer", "revolutionary"]
}
}
브랜드를 studio/src/lib/brand.ts에 등록:
import { z } from 'zod';
export const BrandSchema = z.object({
id: z.string(),
name: z.string(),
tagline: z.string(),
colors: z.object({
primary: z.string(),
secondary: z.string(),
accent: z.string(),
// ... 13가지 색상 모두
}),
fonts: z.object({
heading: z.string(),
body: z.string(),
mono: z.string(),
}),
voice: z.object({
tone: z.string(),
avoid: z.array(z.string()),
}),
});
export type Brand = z.infer<typeof BrandSchema>;
export function getBrand(brandId: string): Brand {
const brandData = require(`../../brands/${brandId}.json`);
return BrandSchema.parse(brandData);
}
studio/src/brands/<id>Mark.tsx에 로고 마크 컴포넌트를 추가:
import React from 'react';
export const MyProductMark: React.FC<{
size?: number;
color?: string;
}> = ({ size = 100, color = '#3b82f6' }) => {
return (
<svg width={size} height={size} viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill={color} />
</svg>
);
};
수동 렌더링
Remotion 명령어
컴포지션을 직접 렌더링:
cd studio
# 로고 리빌
npx remotion render LogoReveal ../out/myproduct/logo.mp4 \
--props='{"brandId":"myproduct","cta":"Watch the launch"}'
# 프로덕트 데모
npx remotion render ProductDemo ../out/myproduct/demo.mp4 \
--props='{"brandId":"myproduct","captureVideo":"../assets/captures/demo.mp4"}'
# 런치 비디오
npx remotion render LaunchVideo ../out/myproduct/launch.mp4 \
--props='{"brandId":"myproduct","demoVideo":"../out/myproduct/demo.mp4","script":["Hook","Problem","Solution"]}'
# 소셜 클립
npx remotion render SocialClip ../out/myproduct/social-x.mp4 \
--props='{"brandId":"myproduct","platform":"x","feature":"Real-time sync"}'
# 애니메이션 OG
npx remotion render AnimatedOG ../out/myproduct/og.mp4 \
--props='{"brandId":"myproduct"}'
피더 스크립트
프로덕트 데모 캡처
cd feeders/capture
node capture.mjs \
--url http://localhost:3000 \
--output ../../assets/captures/demo.mp4 \
--brand myproduct \
--script zoom-dashboard,click-feature,pan-results
Blender 로고 렌더링
cd feeders/blender
python render_logo.py \
--brand myproduct \
--output ../../assets/blender/logo-frames/ \
--style draw-on
오디오 생성
cd feeders/audio
node generate.mjs \
--script "Ship your product in days, not months" \
--voice-id "ELEVENLABS_VOICE_ID" \
--output ../../assets/audio/voiceover.mp3
node generate.mjs \
--type music \
--mood energetic \
--duration 60 \
--output ../../assets/audio/music.mp3
.env 파일에 ELEVENLABS_API_KEY를 설정하세요.
Props 빌더
빌더 스크립트를 통해 렌더 props를 생성:
# 런치 비디오 props 빌드
node scripts/build-launch-props.mjs \
--brand myproduct \
--demo-video ./assets/captures/demo.mp4 \
--script "Hook line" "Problem statement" "Solution demo" \
--output ./props/launch-myproduct.json
# 소셜 클립 props 빌드
node scripts/build-social-props.mjs \
--brand myproduct \
--platform x \
--feature "Real-time collaboration" \
--output ./props/social-x-myproduct.json
Props 파일은 JSON 형식입니다:
{
"brandId": "myproduct",
"demoVideo": "./assets/captures/demo.mp4",
"logoRevealVideo": "./out/myproduct/logo.mp4",
"script": [
{"type": "hook", "text": "Ship in days, not months", "duration": 3},
{"type": "problem", "text": "Marketing assets take weeks", "duration": 4},
{"type": "solution", "text": "One command, full suite", "duration": 5}
],
"voiceover": "./assets/audio/voiceover.mp3",
"music": "./assets/audio/music.mp3"
}
환경 변수
# .env
BLENDER_PATH=/Applications/Blender.app/Contents/MacOS/Blender
ELEVENLABS_API_KEY=your_api_key_here
COMFYUI_URL=http://localhost:8188
모두 선택 사항이며, 피더는 없어도 정상적으로 동작합니다.
확인 및 테스트
# 전체 도구 체인 상태 확인
python launch.py --check
# 모든 컴포지션의 0번째 프레임 렌더링 (스모크 테스트)
node scripts/smoke.mjs
# 브랜드 스키마 검증
cd studio && npm test
# 대화형 미리보기를 위해 Remotion Studio 실행
python launch.py
주요 패턴
실패 시 재개
파이프라인은 실행 매니페스트를 .marketing-run.json에 기록합니다:
{
"brand": "myproduct",
"timestamp": "2026-07-10T12:00:00Z",
"completed": ["logo-reveal", "product-demo"],
"current": "launch-video",
"props": {
"logoRevealVideo": "./out/myproduct/logo.mp4",
"demoVideo": "./out/myproduct/demo.mp4"
}
}
/marketing을 다시 실행하면 마지막으로 완료되지 않은 단계부터 재개합니다.
카메라 줌 수식
프로덕트 데모 캡처는 측정된 이징을 사용하여 전문적인 줌 효과를 제공합니다:
// studio/src/lib/camera.ts
export function calculateZoom(
frame: number,
duration: number,
startScale: number = 1,
endScale: number = 1.2
): number {
const progress = frame / duration;
const eased = 1 - Math.pow(1 - progress, 3); // cubic ease-out
return startScale + (endScale - startScale) * eased;
}
끊김 없는 루프 규칙
애니메이션 OG 루프는 동일한 프레임에서 시작하고 끝나야 합니다:
// studio/src/compositions/AnimatedOG.tsx
export const AnimatedOG: React.FC<{brandId: string}> = ({brandId}) => {
const frame = useCurrentFrame();
const {durationInFrames} = useVideoConfig();
const brand = getBrand(brandId);
// 끊김 없는 루프를 위해 [0, 1)로 정규화
const progress = (frame % durationInFrames) / durationInFrames;
const rotation = progress * 360;
return (
<AbsoluteFill style={{backgroundColor: brand.colors.background}}>
<div style={{transform: `rotate(${rotation}deg)`}}>
{/* 로고 마크 */}
</div>
</AbsoluteFill>
);
};
플랫폼별 소셜 클립
플랫폼별 화면 비율 및 안전 영역:
// studio/src/compositions/SocialClip.tsx
const PLATFORM_SPECS = {
x: { width: 1280, height: 720, safeZone: 0.1 },
linkedin: { width: 1280, height: 720, safeZone: 0.1 },
tiktok: { width: 1080, height: 1920, safeZone: 0.15 },
instagram: { width: 1080, height: 1920, safeZone: 0.12 },
};
export const SocialClip: React.FC<{
brandId: string;
platform: keyof typeof PLATFORM_SPECS;
feature: string;
}> = ({brandId, platform, feature}) => {
const spec = PLATFORM_SPECS[platform];
const safeWidth = spec.width * (1 - 2 * spec.safeZone);
return (
<AbsoluteFill style={{width: spec.width, height: spec.height}}>
{/* 컨텐츠 */}
</AbsoluteFill>
);
};
문제 해결
Blender를 찾을 수 없음
Error: Blender executable not found at /Applications/Blender.app
.env 파일에 BLENDER_PATH를 설정하거나 3D 로고 리빌을 건너뜁니다 (파이프라인이 2D로 폴백).
ElevenLabs 속도 제한
Error: 429 Too Many Requests
오디오 생성은 선택 사항입니다. API가 실패하면 파이프라인이 보이스오버 없이 비디오를 렌더링합니다.
Playwright 캡처 타임아웃
Error: Page did not load within 30s
개발 서버가 올바른 포트에서 실행 중인지 확인하세요. 캡처 스크립트는 networkidle 상태를 기다립니다.
Remotion 메모리 오류
Error: JavaScript heap out of memory
Node 메모리 제한 설정:
export NODE_OPTIONS="--max-old-space-size=8192"
npx remotion render ...
브랜드 스키마 검증 실패
Error: Invalid brand JSON
cd studio && npm test를 실행하여 스키마 위반 사항을 확인하세요. 13가지 색상, 3가지 폰트, 음성 규칙이 모두 필요합니다.
파일 구조
marketing-studio/
├── brands/ # 제품별 브랜드 토큰 (JSON)
├── studio/ # Remotion 프로젝트 (모든 컴포지션)
│ ├── src/
│ │ ├── compositions/
│ │ │ ├── LogoReveal.tsx
│ │ │ ├── ProductDemo.tsx
│ │ │ ├── LaunchVideo.tsx
│ │ │ ├── SocialClip.tsx
│ │ │ └── AnimatedOG.tsx
│ │ ├── brands/ # 로고 마크 컴포넌트
│ │ └── lib/
│ │ ├── brand.ts
│ │ └── camera.ts
├── feeders/
│ ├── blender/ # 헤드리스 Blender 씬
│ ├── capture/ # Playwright 레코더
│ ├── audio/ # ElevenLabs 클라이언트
│ └── comfy/ # ComfyUI 클라이언트 (선택 사항)
├── skills/ # Claude Code 스킬
│ ├── marketing.md
│ ├── logo-reveal.md
│ ├── product-demo.md
│ └── ...
├── scripts/
│ ├── install-skills.mjs
│ ├── build-launch-props.mjs
│ ├── build-social-props.mjs
│ └── smoke.mjs
├── props/ # 생성된 렌더 props (JSON)
├── assets/ # 캡처, 오디오, Blender 프레임
├── out/ # 최종 렌더링된 비디오
└── examples/ # 출시된 제품의 실제 출력물
모범 사례
- 브랜드 변경 후 스모크 테스트 실행:
node scripts/smoke.mjs가 전체 렌더링 전에 스키마 오류를 잡아냅니다. - Props 빌더 사용: props JSON을 직접 편집하지 말고
scripts/build-*-props.mjs를 사용하세요. - UI 작업 후 데모 촬영:
/product-demo전에/polish와/frontend-verify를 실행하세요. - 픽처 락 후 오디오 스코어링: 런치 비디오 스크립트가 확정될 때까지 보이스오버를 생성하지 마세요.
/marketing전에 로컬 테스트: 개별 스킬(/logo-reveal,/product-demo)을 실행하여 브랜드 토큰을 디버그하세요.- 실행 매니페스트 유지: 활성 실행 중에는
.marketing-run.json을 삭제하지 마세요 (재개 기능 활성화).
관련 스킬
/polish– 데모 촬영 전 최종 UI 품질 점검/frontend-verify– 헤드리스 라우트 검증 (콘솔 오류, 실패한 요청)/de-vibe– 출시 전 AI 생성 핑거프린트 제거/launch– 채널별 발표 초안 생성
모든 지원 스킬은 scripts/install-skills.mjs로 설치됩니다.