Loading...
Loading...
Compare original and translation side by side
undefinedundefined
---
---// src/styles/theme.ts
export const colors = {
primary: '#2D3748', // ダークグレー(メインUI)
accent: '#6366F1', // インディゴ(CTAボタン等)
background: '#1A202C', // ダークBG
backgroundLight: '#2D3748',
text: '#E2E8F0', // ライトグレー(本文)
textMuted: '#A0AEC0', // ミュートテキスト
hoo: '#FFFFFF', // Hooは白ラインアート
success: '#48BB78', // 成功
error: '#F56565', // エラー
};// src/styles/theme.ts
export const colors = {
primary: '#2D3748', // ダークグレー(メインUI)
accent: '#6366F1', // インディゴ(CTAボタン等)
background: '#1A202C', // ダークBG
backgroundLight: '#2D3748',
text: '#E2E8F0', // ライトグレー(本文)
textMuted: '#A0AEC0', // ミュートテキスト
hoo: '#FFFFFF', // Hooは白ラインアート
success: '#48BB78', // 成功
error: '#F56565', // エラー
};Noto Sans JP Boldfont-weight: 700Noto Sans JP Regularfont-weight: 400JetBrains MonoNoto Sans JP Boldfont-weight: 700Noto Sans JP Regularfont-weight: 400JetBrains Mono#FFFFFF/public/logo.png#FFFFFF/public/logo.png| パーツ | 説明 | アニメーション |
|---|---|---|
| left-reel | 左目(テープリール) | 回転 |
| right-reel | 右目(テープリール) | 回転(逆方向) |
| tape | リール間のテープ | 流れる動き |
| body | 本体輪郭 | 揺れ、傾き |
| ears | 耳(羽角) | 軽い揺れ |
| 部件 | 说明 | 动画效果 |
|---|---|---|
| left-reel | 左眼(磁带卷轴) | 旋转 |
| right-reel | 右眼(磁带卷轴) | 反向旋转 |
| tape | 卷轴间的磁带 | 流动效果 |
| body | 身体轮廓 | 晃动、倾斜 |
| ears | 耳朵(羽角) | 轻微晃动 |
| 状態 | 用途 | アニメーション |
|---|---|---|
| idle | 待機 | リールゆっくり回転 + 軽い呼吸 |
| recording | 録音中 | リール高速回転 + テープ流れ |
| curious | 興味・説明 | 首を傾ける + リール回転 |
| happy | 喜び・完了 | リール高速 + 上下バウンス |
| 状态 | 用途 | 动画效果 |
|---|---|---|
| idle | 待机 | 卷轴缓慢旋转 + 轻微呼吸效果 |
| recording | 录音中 | 卷轴高速旋转 + 磁带流动 |
| curious | 好奇・讲解 | 歪头 + 卷轴旋转 |
| happy | 喜悦・完成 | 卷轴高速旋转 + 上下弹跳 |
// リール回転(常時)
const reelRotation = (frame / fps) * 30; // 1秒で30度
// 首傾げ(curious時)
const tilt = spring({
frame: frame - startFrame,
fps,
config: { damping: 15, stiffness: 80 },
}) * 15;
// リール高速回転(recording/happy時)
const fastRotation = (frame / fps) * 180;
// テープ流れ(strokeDashoffsetで表現)
const tapeOffset = (frame / fps) * 50;hoo-animation.md// リール回転(常時)
const reelRotation = (frame / fps) * 30; // 1秒で30度
// 首傾げ(curious時)
const tilt = spring({
frame: frame - startFrame,
fps,
config: { damping: 15, stiffness: 80 },
}) * 15;
// リール高速回転(recording/happy時)
const fastRotation = (frame / fps) * 180;
// テープ流れ(strokeDashoffsetで表現)
const tapeOffset = (frame / fps) * 50;hoo-animation.md構成:
├── Hook (0-5秒)
│ └── 問題提起テキスト + Hooが右下から登場
├── Problem (5-12秒)
│ └── 課題の可視化 + Hoo心配顔
├── Solution (12-25秒)
│ └── MUEDnote機能デモ + Hooが説明
└── CTA (25-30秒)
└── ダウンロード促し + Hoo喜びMUEDnoteの30秒プロモ動画を作成。
Hook: "音楽制作、記録してる?"
Problem: アイデアが消えていく様子
Solution: MUEDnoteの3つの機能をハイライト
CTA: App Storeへ誘導
Hooを各シーンで使用。结构:
├── 钩子部分(0-5秒)
│ └── 问题引导文本 + Hoo从右下角登场
├── 问题呈现(5-12秒)
│ └── 问题可视化 + Hoo担忧表情
├── 解决方案(12-25秒)
│ └── MUEDnote功能演示 + Hoo讲解
└── 行动号召(25-30秒)
└── 引导下载 + Hoo喜悦表情制作MUEDnote的30秒推广视频。
钩子部分: "你在制作、记录音乐吗?"
问题呈现: 创意逐渐消失的场景
解决方案: 突出MUEDnote的3项功能
行动号召: 引导至App Store
在每个场景中使用Hoo。構成:
├── タイトル (0-3秒): 機能名 + アイコン
├── デモ (3-12秒): 操作画面のアニメーション
└── 締め (12-15秒): Hoo「ほほう」+ ロゴ结构:
├── 标题(0-3秒): 功能名称 + 图标
├── 演示(3-12秒): 操作界面动画
└── 结尾(12-15秒): Hoo「ほほう」+ 品牌Logo構成:
├── 導入 (0-5秒): Hoo挨拶「こんにちは!」
├── ステップ1 (5-20秒): 最初の操作説明
├── ステップ2 (20-35秒): 次の操作説明
├── ステップ3 (35-50秒): 最後の操作説明
└── まとめ (50-60秒): Hoo「ほほう、簡単でしょう?」结构:
├── 开场(0-5秒): Hoo问候「你好!」
├── 步骤1(5-20秒): 首次操作说明
├── 步骤2(20-35秒): 下一步操作说明
├── 步骤3(35-50秒): 最后一步操作说明
└── 总结(50-60秒): Hoo「ほほう,很简单吧?」muednote-videos/ # 別ディレクトリ推奨
├── src/
│ ├── Root.tsx
│ ├── compositions/
│ │ ├── PromoVideo.tsx
│ │ ├── FeatureDemo.tsx
│ │ └── Tutorial.tsx
│ ├── components/
│ │ ├── Hoo/
│ │ │ ├── HooCharacter.tsx
│ │ │ ├── HooExpressions.tsx
│ │ │ └── animations.ts
│ │ ├── Text/
│ │ │ ├── TitleText.tsx
│ │ │ ├── TypewriterText.tsx
│ │ │ └── HighlightText.tsx
│ │ ├── Transitions/
│ │ │ ├── FadeSlide.tsx
│ │ │ ├── ScaleIn.tsx
│ │ │ └── WipeTransition.tsx
│ │ └── UI/
│ │ ├── PhoneMockup.tsx
│ │ ├── AppStoreBadge.tsx
│ │ └── Logo.tsx
│ ├── styles/
│ │ └── theme.ts
│ └── utils/
│ └── animations.ts
├── public/
│ └── assets/ # ロゴ、スクリーンショット等
└── out/ # レンダリング出力muednote-videos/ # 推荐使用独立目录
├── src/
│ ├── Root.tsx
│ ├── compositions/
│ │ ├── PromoVideo.tsx
│ │ ├── FeatureDemo.tsx
│ │ └── Tutorial.tsx
│ ├── components/
│ │ ├── Hoo/
│ │ │ ├── HooCharacter.tsx
│ │ │ ├── HooExpressions.tsx
│ │ │ └── animations.ts
│ │ ├── Text/
│ │ │ ├── TitleText.tsx
│ │ │ ├── TypewriterText.tsx
│ │ │ └── HighlightText.tsx
│ │ ├── Transitions/
│ │ │ ├── FadeSlide.tsx
│ │ │ ├── ScaleIn.tsx
│ │ │ └── WipeTransition.tsx
│ │ └── UI/
│ │ ├── PhoneMockup.tsx
│ │ ├── AppStoreBadge.tsx
│ │ └── Logo.tsx
│ ├── styles/
│ │ └── theme.ts
│ └── utils/
│ └── animations.ts
├── public/
│ └── assets/ # 存放Logo、截图等资源
└── out/ # 渲染输出目录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 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 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 scaleValue = spring({
frame: frame - delay,
fps,
config: {
damping: 10,
stiffness: 100,
mass: 0.5,
},
});npx remotion render src/index.ts CompositionName out/video.mp4npx remotion render src/index.ts CompositionName out/video.mp4npx remotion render src/index.ts CompositionName out/video-hq.mp4 \
--codec=h264 \
--quality=100npx remotion render src/index.ts CompositionName out/video-hq.mp4 \
--codec=h264 \
--quality=100undefinedundefinedundefinedundefinednpx remotion render src/index.ts ShortLoop out/loop.gif \
--codec=gifnpx remotion render src/index.ts ShortLoop out/loop.gif \
--codec=gifhoo-animation.mdremotion-handson-glasswerks.mdhoo-animation.mdremotion-handson-glasswerks.md