
Remotion
- 165 installs
- 4 repo stars
- Updated July 31, 2026
- kimny1143/claude-code-template
Programmatically compose React-based motion graphics and export videos using Remotion patterns inside Claude Code content pipelines.
About
Guides Remotion video creation in React: define compositions, sequences, props-driven templates, audio sync, and render/export workflows so Claude can build programmatic branded motion content for marketing, demos, and social pipelines.
- Remotion composition structure
- Timeline and sequence control
- React-driven video frames
- Render and export settings
- Parameterized motion templates
Remotion by the numbers
- 165 all-time installs (skills.sh)
- Ranked #673 of 1,337 Generative Media skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/kimny1143/claude-code-template --skill remotionAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 165 |
|---|---|
| repo stars | ★ 4 |
| Last updated | July 31, 2026 |
| Repository | kimny1143/claude-code-template ↗ |
What it does
Programmatically compose React-based motion graphics and export videos using Remotion patterns inside Claude Code content pipelines.
Files
Remotion Video Skill
Reactで動画を生成する Remotion を使い、動画コンテンツを制作する汎用スキル。
★ 品質原則 (Anti-Template)
「全部ちゃんとやる」がAI生成感の正体。「何を捨てるか」がデザイン。
Remotionファイルの実装時、以下の原則に従うこと。 詳細チェックリスト: references/anti-template-checklist.md
絶対に避ける6つのパターン
| # | アンチパターン | 代替 |
|---|---|---|
| 1 | 全要素が同じspring configで入場 | 要素の重さ別にdamping/massを変える (重:20/1.2, 軽:8/0.3) |
| 2 | translateY+opacity の1パターンのみ | マスクリビール、単語スタガー、ハードカット等を混ぜる |
| 3 | delay={i * 8} の均等ディレイ | [0, 5, 13, 21] のような有機的間隔 |
| 4 | 全シーンがセンター配置 | 最低1シーンは非対称レイアウト |
| 5 | 同じトランジション3回以上 | Wipe, Scale, Hard cut, Crossfade を混ぜる |
| 6 | 8秒以上構図が変わらないシーン | 途中でscale/position/ズームを変化させる |
フック・ペーシング
- 最初の3秒: パターンインタラプト(静寂→爆発、極端ズーム→引き等)
- BPM同期: カット位置を拍に合わせつつ、毎拍で切らない(cut-cut-hold-cut-hold-hold-cut-CUT)
- SFX必須: トランジション前にwhoosh、テキスト出現にimpact音、フック前に6-10f無音
- 30秒プロモにはSocial Proofビート必須(「Free」「★4.8」等)
品質チェック実行
bash .claude/skills/remotion/scripts/check-quality.sh <target-dir>このチェックはRemotionファイルの Write/Edit 時に自動実行される(hook設定済み)。
---
ブランド設定について
カラーパレット、フォント、マスコットキャラクターの仕様は、各プロジェクトの `CLAUDE.md` で定義すること。
このスキルにはブランド固有の情報を含めない。
プロジェクト側に以下のようなセクションを用意する想定:
>
```markdown
## Video Branding
- Primary: #XXXXXX
- Accent: #XXXXXX
- Background: #XXXXXX
- Font Heading: ...
- Font Body: ...
- Mascot: (キャラ名、デザイン仕様、アニメーションパターン等)
```
クイックスタート
# 1. プロジェクト初期化(スキル付属スクリプト)
bash <path-to-skill>/scripts/init-remotion.sh <project-name>
# 2. プレビュー
cd <project-name> && npx remotion studio
# 3. レンダリング
npx remotion render src/index.ts <CompositionId> out/video.mp4手動セットアップ
# 新規作成
npx create-video@latest my-video
# 既存プロジェクトに追加(依存関係が複雑になるため別ディレクトリ推奨)
npm install remotion @remotion/cli @remotion/player動画テンプレート
1. プロモーション動画(30秒)
0-5秒 : Hook — 問題提起 + キャッチーなビジュアル
5-10秒 : Problem — 課題の可視化
10-20秒 : Solution — プロダクトの世界観・機能デモ
20-28秒 : Social Proof — 数字 or ユーザーの声
28-30秒 : CTA — ロゴ + URLコンポジション設定:
- 解像度: 1920x1080(16:9)
- FPS: 30
- 総フレーム数: 900
2. 機能紹介動画(15秒)
0-3秒 : 機能名タイトル(テキストアニメーション)
3-12秒 : 実演デモ(スクリーンキャプチャ or モック)
12-15秒 : 締めのメッセージ + 次のアクション誘導コンポジション設定:
- 解像度: 1080x1080(1:1、SNS向け)or 1080x1920(9:16、リール向け)
- FPS: 30
3. チュートリアル動画(60秒)
0-5秒 : 導入 — タイトル + 挨拶
5-50秒 : ステップ1-3 — 操作説明(画面録画 + オーバーレイ)
50-58秒 : まとめ — 要点の振り返り
58-60秒 : CTA4. SNS短尺動画(5-10秒)
0-2秒 : アイキャッチ(動き or テキスト)
2-8秒 : ワンポイント情報
8-10秒 : ロゴ + CTAコンポジション設定:
- 解像度: 1080x1920(9:16)
- FPS: 30
プロジェクト構成
my-video/
├── src/
│ ├── Root.tsx # コンポジション登録
│ ├── compositions/
│ │ ├── Promo.tsx # 30秒プロモ
│ │ ├── FeatureIntro.tsx # 15秒機能紹介
│ │ ├── Tutorial.tsx # 60秒チュートリアル
│ │ └── SnsShort.tsx # 5-10秒SNS
│ ├── components/
│ │ ├── Character/ # マスコット / キャラクター
│ │ │ ├── CharacterBase.tsx
│ │ │ ├── Expressions.tsx
│ │ │ └── Animations.tsx
│ │ ├── Typography/
│ │ │ ├── TitleReveal.tsx
│ │ │ └── SubtitleFade.tsx
│ │ ├── Transitions/
│ │ │ ├── WipeTransition.tsx
│ │ │ └── FadeTransition.tsx
│ │ └── Branding/
│ │ ├── Logo.tsx
│ │ └── CallToAction.tsx
│ └── styles/
│ └── theme.ts # カラー・フォント定義
├── public/
│ ├── fonts/
│ ├── images/
│ └── audio/
├── remotion.config.ts
└── package.json開発ルール
コンポジション
- 1ファイル1コンポーネント
- アニメーションパラメータは props で外出し(後で調整しやすく)
<Sequence>でシーンを時間管理
アニメーション
interpolate()でスムーズな値の補間spring()で自然な物理アニメーション- spring configは要素の「重さ」で変える(★ Anti-Template原則 参照)
- 重い要素(mockup):
{ damping: 20, mass: 1.2 } - 軽い要素(ドット):
{ damping: 8, mass: 0.3 } - テキスト演出は1動画内で最低2種類使う(translateY以外にclipPath, per-word stagger等)
音声
- BGMは
/public/audio/に配置 <Audio>コンポーネントで同期再生
テーマ(theme.ts テンプレート)
export const theme = {
colors: {
primary: '#XXXXXX',
accent: '#XXXXXX',
background: '#XXXXXX',
text: '#XXXXXX',
subAccent: '#XXXXXX',
},
fonts: {
heading: 'Your Heading Font',
body: 'Your Body Font',
mono: 'JetBrains Mono',
},
// ★ 要素の重さ別にspring configを分ける
spring: {
heavy: { damping: 22, mass: 1.2 }, // mockup, 全画面要素
medium: { damping: 14, mass: 0.7 }, // テキスト, カード
light: { damping: 8, mass: 0.3 }, // ドット, バッジ, 小アイコン
bounce: { damping: 6, mass: 0.4, stiffness: 180 }, // CTA, 注目要素
},
fadeIn: { durationInFrames: 15 },
} as const;
// BPM同期(BGMに合わせて調整)
export const music = {
bpm: 120,
fps: 30,
framesPerBeat: (30 * 60) / 120, // 15
framesPerBar: ((30 * 60) / 120) * 4, // 60
} as const;
export type Theme = typeof theme;プロジェクトの CLAUDE.md に定義したブランドカラー・フォントで上記プレースホルダーを埋めること。マスコットキャラクター汎用パターン
プロジェクトにマスコットキャラクターがある場合の汎用アニメーションパターン。 キャラクター名や見た目はプロジェクトごとに異なるため、ここではモーションパターンのみ定義する。
状態別アニメーション
| 状態 | 用途 | アニメーション |
|---|---|---|
| idle | 待機 | 軽い呼吸(上下2px、2秒周期) + まばたき |
| curious | 興味・説明 | 首を傾ける + 目を見開く |
| happy | 喜び・完了 | バウンス + 表情変化 |
| pointing | 指し示す | 体を向ける + 腕/羽を伸ばす |
登場・退場アニメーション
// 登場: 画面外からspring付きスライドイン
const entrance = (
frame: number, fps: number,
from: 'left' | 'right' | 'bottom' = 'right'
) => {
const progress = spring({ frame, fps, config: { damping: 12, stiffness: 80 } });
const offsets = { left: { x: -300, y: 0 }, right: { x: 300, y: 0 }, bottom: { x: 0, y: 200 } };
const dir = offsets[from];
return {
translateX: dir.x * (1 - progress),
translateY: dir.y * (1 - progress),
opacity: progress,
scale: 0.5 + progress * 0.5,
};
};素材生成(mcp-image連携)
mcp-image (Nano Banana Pro) MCPサーバーが利用可能な場合、動画用の素材画像を生成できる。
用途
- 背景画像・テクスチャ
- モックアップ内のスクリーンショット風画像
- キャラクターイラスト・アイコン
- シーン別のビジュアル素材
使い方
// 生成した画像は public/images/ に配置し、staticFile() で参照
<Img src={staticFile('images/generated-bg.png')} />推奨設定
| 用途 | quality | aspectRatio | 備考 |
|---|---|---|---|
| ドラフト・検証 | fast | 動画に合わせる | 反復用、速度優先 |
| 本番素材 | balanced | 9:16 or 16:9 | 最終成果物用 |
| キービジュアル | quality | 9:16 or 16:9 | ポスター・サムネ用 |
ワークフロー
1. generate_image で素材を生成(purpose: "remotion video asset" 推奨) 2. 出力先から public/images/ にコピー 3. staticFile('images/filename.png') でRemotionから参照
---
レンダリング
# MP4(汎用)
npx remotion render src/index.ts Promo out/promo.mp4
# 高品質
npx remotion render src/index.ts Promo out/promo-hq.mp4 --codec=h264 --quality=100
# GIF(短尺・ループ用)
npx remotion render src/index.ts SnsShort out/short.gif --codec=gif
# SNS向け縦型(9:16)
npx remotion render src/index.ts VerticalComp out/vertical.mp4 --height=1920 --width=1080
# 一括レンダリング
bash <path-to-skill>/scripts/render-all.shSNS別推奨設定
- Twitter/X: 1280x720, 30fps, 最大140秒
- Instagram Reels: 1080x1920 (9:16), 30fps
- TikTok: 1080x1920 (9:16), 30fps
@remotion/player でアプリ内埋め込み
事前レンダリング不要でインタラクティブに再生できる。
import { Player } from '@remotion/player';
import { FeatureIntro } from './compositions/FeatureIntro';
<Player
component={FeatureIntro}
durationInFrames={450}
fps={30}
compositionWidth={1080}
compositionHeight={1080}
style={{ width: '100%' }}
controls
/>動的 props で制御
<Player
component={Tutorial}
inputProps={{
message: "操作してみましょう",
stepNumber: 1,
}}
durationInFrames={300}
fps={30}
compositionWidth={1920}
compositionHeight={1080}
controls
autoPlay
loop
/>ライセンス
Remotionは 3人以下の会社は無料(商用利用OK)。 4人以上になった場合は Company License($25/開発者/月)が必要。 詳細: https://www.remotion.dev/license
参考リソース
- Remotion公式ドキュメント: https://www.remotion.dev/docs
- Remotion + AI ガイド: https://www.remotion.dev/docs/ai/
- Remotion公式スキル:
npx add-skill remotion-dev/skills - アニメーションパターン集:
references/animation-patterns.md - Anti-Templateチェックリスト:
references/anti-template-checklist.md
Remotion アニメーションパターン集
基本API
interpolate — 値の補間
import { interpolate, useCurrentFrame } from 'remotion';
const frame = useCurrentFrame();
const opacity = interpolate(frame, [0, 30], [0, 1], {
extrapolateRight: 'clamp',
});spring — 物理ベースアニメーション
import { spring, useCurrentFrame, useVideoConfig } from 'remotion';
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const scale = spring({ frame, fps, config: { damping: 12, mass: 0.5 } });Sequence — シーン切り替え
import { Sequence } from 'remotion';
<Sequence from={0} durationInFrames={150}>
<Scene1 />
</Sequence>
<Sequence from={150} durationInFrames={300}>
<Scene2 />
</Sequence>---
共通パターン
テキストリビール(タイトル出現)
const TextReveal: React.FC<{ text: string }> = ({ text }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
return (
<div style={{ overflow: 'hidden' }}>
<div
style={{
transform: `translateY(${interpolate(
spring({ frame, fps, config: { damping: 15, mass: 0.8 } }),
[0, 1],
[100, 0]
)}%)`,
}}
>
{text}
</div>
</div>
);
};フェードイン(汎用)
const FadeIn: React.FC<{ delay?: number; children: React.ReactNode }> = ({
delay = 0,
children,
}) => {
const frame = useCurrentFrame();
const opacity = interpolate(frame - delay, [0, 15], [0, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
return <div style={{ opacity }}>{children}</div>;
};フェードイン + スライドアップ
const FadeSlideIn: React.FC<{ children: React.ReactNode; delay?: number }> = ({
children,
delay = 0,
}) => {
const frame = useCurrentFrame();
const adjustedFrame = frame - delay;
const opacity = interpolate(adjustedFrame, [0, 20], [0, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
const translateY = interpolate(adjustedFrame, [0, 20], [30, 0], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
return (
<div style={{ opacity, transform: `translateY(${translateY}px)` }}>
{children}
</div>
);
};タイプライター効果
const TypewriterText: React.FC<{ text: string; startFrame?: number }> = ({
text,
startFrame = 0,
}) => {
const frame = useCurrentFrame();
const adjustedFrame = frame - startFrame;
const charsToShow = Math.floor(
interpolate(adjustedFrame, [0, text.length * 3], [0, text.length], {
extrapolateRight: 'clamp',
})
);
return <span>{text.slice(0, charsToShow)}</span>;
};スケールバウンス(登場演出)
const scaleValue = spring({
frame: frame - delay,
fps,
config: {
damping: 10,
stiffness: 100,
mass: 0.5,
},
});キャラクター首傾げ
const CharacterTilt: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const tilt = spring({
frame: frame - 10,
fps,
config: { damping: 12, mass: 0.5 },
});
return (
<div
style={{
transform: `rotate(${interpolate(tilt, [0, 1], [0, -15])}deg)`,
transformOrigin: 'center bottom',
}}
>
{/* Character SVG */}
</div>
);
};キャラクター目の表情変化
// 目を細める → 元に戻る(2段階)
const CharacterSquint: React.FC = () => {
const frame = useCurrentFrame();
const eyeSquint = interpolate(frame, [0, 8, 20, 28], [1, 0.3, 0.3, 1], {
extrapolateRight: 'clamp',
});
return (
<div style={{ transform: `scaleY(${eyeSquint})` }}>
{/* Eye SVG */}
</div>
);
};ワイプトランジション
const WipeTransition: React.FC<{
direction?: 'left' | 'right';
color?: string;
}> = ({ direction = 'right', color = '#6366F1' }) => {
const frame = useCurrentFrame();
const progress = interpolate(frame, [0, 15], [0, 100], {
extrapolateRight: 'clamp',
});
const exit = interpolate(frame, [15, 30], [0, 100], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
const clipPath =
direction === 'right'
? `inset(0 ${100 - progress}% 0 ${exit}%)`
: `inset(0 ${exit}% 0 ${100 - progress}%)`;
return (
<div
style={{
position: 'absolute',
inset: 0,
backgroundColor: color,
clipPath,
}}
/>
);
};BGM同期(ビートマーカー)
// BGMのビートタイミングを定義して映像と同期
const BEAT_FRAMES = [0, 30, 60, 90, 120, 150]; // 例: BPM120 @ 30fps
const BeatPulse: React.FC<{ beatIndex: number }> = ({ beatIndex }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const beatFrame = BEAT_FRAMES[beatIndex];
const pulse = spring({
frame: frame - beatFrame,
fps,
config: { damping: 8, mass: 0.3 },
});
return (
<div style={{ transform: `scale(${1 + pulse * 0.1})` }}>
{/* ビートに合わせて少し拡大 */}
</div>
);
};---
Tips
- spring の damping: 低い値(5-8)= 弾む / 高い値(15-20)= 落ち着いた動き
- キャラクターの動き: damping: 12 を基準に統一すると一貫したキャラ性が出る
- 音と映像の同期: BPMからフレーム数を計算する(BPM120 @ 30fps = 15フレーム/拍)
- extrapolateRight: 'clamp': アニメーション終了後に値が飛ばないようにする(ほぼ必須)
Anti-Template Quality Checklist
核心原則: 「全部ちゃんとやる」がAI生成感の正体。「何を捨てるか」がデザイン。
実装完了後、レンダリング前にこのチェックリストで確認する。 自動チェック(scripts/check-quality.sh)で検出できる項目は [AUTO] マーク付き。
---
1. アニメーション多様性
[AUTO] UNIFORM_STAGGER — 均等ディレイを避ける
// ❌ Bad: 機械的な等間隔
{items.map((item, i) => <Icon delay={i * 8} />)}
// ✅ Good: 有機的なリズム
const ORGANIC_DELAYS = [0, 5, 13, 21];
{items.map((item, i) => <Icon delay={ORGANIC_DELAYS[i]} />)}[AUTO] UNIFORM_SPRING — 要素の重さでspring configを変える
| 要素タイプ | damping | mass | 例 |
|---|---|---|---|
| 重い (mockup, 全画面) | 18-25 | 1.0-1.5 | iPhone, フルスクリーン画像 |
| 普通 (テキスト, カード) | 12-16 | 0.5-0.8 | タイトル, UI要素 |
| 軽い (ドット, バッジ) | 6-10 | 0.2-0.4 | インジケーター, 小アイコン |
| バウンス要求 | 5-8 | 0.3-0.5 | CTA, 注目させたい要素 |
[AUTO] GENERIC_REVEAL — テキスト演出に種類を持たせる
1つの動画内で最低2種類のテキスト演出を使うこと:
| 技法 | 実装 | 印象 |
|---|---|---|
| マスクリビール | clipPath: inset(0 ${100-p}% 0 0) | シネマティック |
| 単語ごとスタガー | text.split(' ').map() + 個別spring | ダイナミック |
| スケール+トラッキング | scale(1.3→1) + letterSpacing(10→0) | エレガント |
| ハードカット | アニメーションなし、突然出現 | インパクト |
| タイプライター | 1文字ずつ表示 | テクニカル |
// マスクリビール実装例
const MaskReveal: React.FC<{ text: string; delay?: number }> = ({ text, delay = 0 }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const p = spring({ frame: frame - delay, fps, config: { damping: 20, mass: 1.0 } });
const clipX = interpolate(p, [0, 1], [0, 100]);
return (
<div style={{ clipPath: `inset(0 ${100 - clipX}% 0 0)` }}>
<span style={{ fontSize: 100, fontWeight: 700, color: '#fff' }}>{text}</span>
</div>
);
};---
2. 構成とペーシング
[AUTO] LONG_SCENE — 8秒以上の固定構図シーンを避ける
- 1シーン内でもカメラ的変化(scale, position, zoom)を入れる
- mockupの位置やサイズを途中で変える
- サブタイトルやラベルの切り替えでリズムを作る
[AUTO] SINGLE_TRANSITION — トランジションの種類を混ぜる
1つのコンポジション内で同じトランジションを3回以上使わない。
| 種類 | 用途 |
|---|---|
| Wipe (clipPath) | シーン間の大きな転換 |
| Scale transition | 同カテゴリ内の切り替え |
| Hard cut | 緊張感、インパクト |
| Crossfade | 柔らかい印象、同テーマ内 |
[AUTO] NO_SOCIAL_PROOF — 30秒プロモには信頼性ビートを入れる
「Free」「4.8 stars」「10K downloads」「No account needed」等
カット数の目安
| 動画長 | 推奨カット数 | 平均ショット長 |
|---|---|---|
| 15秒 | 5-7 | 2-3秒 |
| 30秒 | 8-12 | 2.5-3.5秒 |
| 60秒 | 15-20 | 3-4秒 |
BPM同期
// theme.ts に追加
export const music = {
bpm: 120,
framesPerBeat: (30 * 60) / 120, // = 15
framesPerBar: ((30 * 60) / 120) * 4, // = 60
} as const;カット位置はビートの境界に合わせつつ、毎拍で切らないこと。 cut-cut-hold-cut-hold-hold-cut-CUT のリズム変化が手作り感を生む。
---
3. レイアウト
[AUTO] ALL_CENTERED — 全シーンセンター配置を避ける
最低1シーンは非対称レイアウトにする:
- テキスト左寄せ + 右にビジュアル
- 上1/3にタイトル + 下2/3にデモ
- Rule of thirds を意識
---
4. サウンド
[AUTO] NO_SFX — BGMだけでなくSFXを使う
| タイミング | SFXの種類 |
|---|---|
| トランジション5-10f前 | ウーッシュ (whoosh) |
| テキスト出現 | インパクト音 (低域hit + 高域click) |
| フック直前 | 無音 6-10f → 最強のスクロールストッパー |
| ボタンタップ | ソフトクリック |
| 完了・成功 | チャイム |
---
5. 手動チェック項目
自動検出が難しいが重要な項目:
意味のあるアニメーション (Semantic Motion)
- [ ] "Track" → 横スライド、"Record" → 赤ドット点滅、等
- [ ] タイマー数字 → カウントアップ/ダウン
- [ ] 各単語の動きがその意味と関連している
カラーの意図的な逸脱
- [ ] Problem/Agitationシーンでブランドカラーを崩す(彩度低下、寒色寄り等)
- [ ] Solutionで元のカラーに戻すことで「解決感」を演出
フォントウェイトの対比
- [ ] 同一画面内でfontWeight 300と700が共存している箇所がある
- [ ] 全テキストが同じfontWeightではない
デモシーンのリアリティ
- [ ] タップインジケーター(指タッチシミュレーション)がある
- [ ] mockupが完全に静止していない(微フロート、微回転)
- [ ] 「Feature名」を1語ずつ急速表示 vs 1行テキストブロック
全体の「引き算」
- [ ] 少なくとも1箇所、意図的にアニメーションを使わない(ハードカット)場所がある
- [ ] backdrop-blur, glow, gradient border を使っていない
- [ ] 装飾 < コンテンツの比率になっている
#!/bin/bash
# Remotion Anti-Template Quality Checker
# Usage: bash check-quality.sh <file-or-directory>
# Exit code: 0 = pass, 1 = warnings found
set -uo pipefail
TARGET="${1:-.}"
WARNINGS=0
WARN_MSGS=""
warn() {
WARNINGS=$((WARNINGS + 1))
WARN_MSGS="${WARN_MSGS}\n⚠ $1"
}
# Collect all .tsx files
if [ -f "$TARGET" ]; then
FILES="$TARGET"
else
FILES=$(find "$TARGET" -name '*.tsx' -not -path '*/node_modules/*' -not -name 'Root.tsx' -not -name 'index.ts' 2>/dev/null || true)
fi
[ -z "$FILES" ] && echo "No .tsx files found" && exit 0
# ─── 1. Uniform stagger pattern (i * N) ───
if echo "$FILES" | xargs grep -lE 'delay[=:}]\s*\{?\s*i\s*\*\s*[0-9]+' >/dev/null 2>&1; then
MATCHED=$(echo "$FILES" | xargs grep -lE 'delay[=:}]\s*\{?\s*i\s*\*\s*[0-9]+' 2>/dev/null | xargs -I{} basename {})
warn "UNIFORM_STAGGER: 'delay={i * N}' in ${MATCHED}. Use organic delays like [0, 5, 13, 21]."
fi
# ─── 2. Same spring config reused across file ───
for f in $FILES; do
SPRING_CONFIGS=$(grep -oE 'damping:\s*[0-9]+' "$f" 2>/dev/null | sort | uniq -c | sort -rn | head -1)
if [ -n "$SPRING_CONFIGS" ]; then
COUNT=$(echo "$SPRING_CONFIGS" | awk '{print $1}')
if [ "$COUNT" -gt 3 ]; then
warn "UNIFORM_SPRING: $(basename $f) uses the same damping value ${COUNT}x. Vary spring configs by element weight (heavy: damping 18-25, light: 6-10)."
fi
fi
done
# ─── 3. Only WipeTransition used (no transition variety) ───
for f in $FILES; do
WIPE_COUNT=$(grep -c 'WipeTransition' "$f" 2>/dev/null || true)
if [ "$WIPE_COUNT" -gt 2 ]; then
OTHER_TRANSITIONS=$(grep -cE '(FadeTransition|ScaleTransition|ClipReveal|clipPath.*inset)' "$f" 2>/dev/null || true)
if [ "$OTHER_TRANSITIONS" -eq 0 ]; then
warn "SINGLE_TRANSITION: $(basename $f) uses WipeTransition ${WIPE_COUNT}x with no alternatives. Mix transition types."
fi
fi
done
# ─── 4. All-centered layout (every scene centered) ───
for f in $FILES; do
CENTER_COUNT=$(grep -c "justifyContent: 'center'" "$f" 2>/dev/null || true)
TOTAL_FILLS=$(grep -c 'AbsoluteFill\|<Sequence' "$f" 2>/dev/null || true)
if [ "$CENTER_COUNT" -gt 4 ] && [ "$TOTAL_FILLS" -gt 0 ]; then
OFF_CENTER=$(grep -cE "(justifyContent: '(flex-start|flex-end|space-between)'|textAlign: '(left|right)')" "$f" 2>/dev/null || true)
if [ "$OFF_CENTER" -eq 0 ]; then
warn "ALL_CENTERED: $(basename $f) has ${CENTER_COUNT} centered layouts with no off-center variation. Add asymmetry to at least one scene."
fi
fi
done
# ─── 5. Generic translateY + opacity reveal (template #1 pattern) ───
for f in $FILES; do
GENERIC_REVEAL=$(grep -cE 'translateY.*spring|translateY.*interpolate.*\[100.*0\]' "$f" 2>/dev/null || true)
MASK_REVEAL=$(grep -cE 'clipPath|clip-path|maskImage|mask-image' "$f" 2>/dev/null || true)
CHAR_STAGGER=$(grep -cE 'split.*map|\.charAt|charIndex|wordIndex' "$f" 2>/dev/null || true)
if [ "$GENERIC_REVEAL" -gt 2 ] && [ "$MASK_REVEAL" -eq 0 ] && [ "$CHAR_STAGGER" -eq 0 ]; then
warn "GENERIC_REVEAL: $(basename $f) uses translateY+opacity reveal ${GENERIC_REVEAL}x. Add at least one mask-reveal (clipPath) or per-word/per-char stagger."
fi
done
# ─── 6. No SFX audio (music only) ───
COMPOSITION_FILES=$(echo "$FILES" | xargs grep -lE '<Audio.*src.*bgm|<Audio.*src.*music' 2>/dev/null || true)
for f in $COMPOSITION_FILES; do
SFX_COUNT=$(grep -cE '<Audio.*src.*(sfx|impact|whoosh|hit|click)' "$f" 2>/dev/null || true)
if [ "$SFX_COUNT" -eq 0 ]; then
warn "NO_SFX: $(basename $f) has BGM but no SFX. Add impact/whoosh sounds synced to transitions and text reveals."
fi
done
# ─── 7. Long static scene (Sequence > 8s at 30fps = 240 frames) ───
for f in $FILES; do
LONG_SCENES=$(grep -oE 'durationInFrames=\{?[0-9]+' "$f" 2>/dev/null | grep -oE '[0-9]+' | while read dur; do
if [ "$dur" -gt 240 ]; then
echo "$dur"
fi
done)
if [ -n "$LONG_SCENES" ]; then
for dur in $LONG_SCENES; do
SECS=$((dur / 30))
warn "LONG_SCENE: $(basename $f) has a ${SECS}s scene (${dur} frames). Break into sub-scenes or vary the visual composition within."
done
fi
done
# ─── 8. No social proof beat in 30s promo ───
for f in $FILES; do
IS_30S=$(grep -c 'durationInFrames.*900\|Promo30\|30秒' "$f" 2>/dev/null || true)
if [ "$IS_30S" -gt 0 ]; then
HAS_SOCIAL_PROOF=$(grep -ciE 'social.proof|stars|rating|users|downloads|free.*no.*account|レビュー|評価|ユーザー' "$f" 2>/dev/null || true)
if [ "$HAS_SOCIAL_PROOF" -eq 0 ]; then
warn "NO_SOCIAL_PROOF: $(basename $f) is a 30s promo with no social proof beat. Add a 'Free. 4.8 stars.' or download count frame."
fi
fi
done
# ─── Output ───
if [ "$WARNINGS" -gt 0 ]; then
echo ""
echo "━━━ Remotion Quality Check: ${WARNINGS} warning(s) ━━━"
echo -e "$WARN_MSGS"
echo ""
echo "📖 Details: .claude/skills/remotion/references/anti-template-checklist.md"
exit 1
else
echo "✓ Remotion quality check passed"
exit 0
fi
#!/bin/bash
# Remotion プロジェクト初期化スクリプト(汎用)
# Usage: bash init-remotion.sh [project-name]
set -e
PROJECT_NAME=${1:-"my-video"}
echo "=== Remotion Video Project: $PROJECT_NAME ==="
# Remotionプロジェクト作成
npx create-video@latest "$PROJECT_NAME" --template blank
cd "$PROJECT_NAME"
# 追加パッケージ
npm install @remotion/player @remotion/google-fonts
# ディレクトリ構成
mkdir -p src/compositions
mkdir -p src/components/Character
mkdir -p src/components/Typography
mkdir -p src/components/Transitions
mkdir -p src/components/Branding
mkdir -p src/styles
mkdir -p public/fonts
mkdir -p public/images
mkdir -p public/audio
# theme.ts 生成(プレースホルダー)
cat > src/styles/theme.ts << 'EOF'
// プロジェクトのブランドに合わせてカラー・フォントを設定してください。
// CLAUDE.md の Video Branding セクションと一致させること。
export const theme = {
colors: {
primary: '#2D3748', // メインカラー — 要変更
accent: '#6366F1', // アクセントカラー — 要変更
background: '#1A202C', // 背景色 — 要変更
text: '#E2E8F0', // テキスト色 — 要変更
subAccent: '#63B3ED', // サブアクセント — 要変更
},
fonts: {
heading: 'Noto Sans JP', // 要変更
body: 'Noto Sans JP', // 要変更
mono: 'JetBrains Mono',
},
animation: {
characterSpring: { damping: 12, mass: 0.5 },
textReveal: { damping: 15, mass: 0.8 },
fadeIn: { durationInFrames: 15 },
},
} as const;
export type Theme = typeof theme;
EOF
echo ""
echo "=== Setup Complete ==="
echo "cd $PROJECT_NAME"
echo "npx remotion studio # プレビュー起動"
echo ""
echo "NOTE: src/styles/theme.ts のカラー・フォントをプロジェクトのブランドに合わせて変更してください。"
#!/bin/bash
# 一括レンダリングスクリプト
# Usage: bash render-all.sh [composition]
# 引数なしで全コンポジションをレンダリング
set -e
OUTPUT_DIR="out"
mkdir -p "$OUTPUT_DIR"
render_composition() {
local name=$1
local width=$2
local height=$3
local suffix=$4
echo "--- Rendering: ${name} (${width}x${height}) ---"
npx remotion render src/index.ts "$name" \
"${OUTPUT_DIR}/${name}${suffix}.mp4" \
--width "$width" \
--height "$height" \
--codec h264
echo "Done: ${OUTPUT_DIR}/${name}${suffix}.mp4"
}
if [ -n "$1" ]; then
# 特定のコンポジションのみ
COMP=$1
case $COMP in
Promo)
render_composition "Promo" 1920 1080 ""
;;
FeatureIntro)
render_composition "FeatureIntro" 1080 1080 "-square"
render_composition "FeatureIntro" 1080 1920 "-reel"
;;
SnsShort)
render_composition "SnsShort" 1080 1920 "-reel"
;;
Tutorial)
render_composition "Tutorial" 1920 1080 ""
;;
*)
echo "Unknown composition: $COMP"
echo "Available: Promo, FeatureIntro, SnsShort, Tutorial"
exit 1
;;
esac
else
# 全コンポジション
render_composition "Promo" 1920 1080 ""
render_composition "FeatureIntro" 1080 1080 "-square"
render_composition "FeatureIntro" 1080 1920 "-reel"
render_composition "SnsShort" 1080 1920 "-reel"
render_composition "Tutorial" 1920 1080 ""
fi
echo ""
echo "=== All renders complete ==="
ls -lh "$OUTPUT_DIR"/*.mp4