视频特效页面开发指南
详细说明如何在 Wananimate 中添加新的视频特效页面,包含多语言支持和组件开发。
视频特效页面开发指南
本指南详细说明如何在 Wananimate 项目中添加新的视频特效页面,包含完整的多语言支持和组件开发流程。
开发流程概览
添加新的视频特效页面需要完成以下六个步骤:
- 增强类型定义 - 更新多语言类型接口
- 更新配置文件 - 添加新特效到配置系统
- 创建编辑器组件 - 开发特效专用编辑器
- 更新效果注册表 - 集成新组件到模块化架构
- 创建页面路由 - 添加 Next.js 页面路由
- 添加多语言翻译 - 完善中英文翻译
步骤详解
第一步:增强类型定义
首先更新 src/i18n/pages/video/types.ts
文件,确保类型定义支持完整的翻译结构:
export interface VideoEffectTranslation {
label: string;
hero: {
eyebrow: string;
title: string;
description: string;
};
metadata: {
title: string;
description: string;
};
status: {
initial: string;
};
marketing?: {
showcase?: {
title: string;
description: string;
};
howTo?: {
title: string;
description: string;
steps: Array<{
title: string;
description: string;
}>;
};
useCases?: {
title: string;
description: string;
cases: Array<{
title: string;
description: string;
}>;
};
};
}
第二步:更新配置文件
在 src/config/video-effects.ts
中添加新的特效类型和配置:
// 1. 添加新的编辑器 ID
export type EffectEditorId =
| 'veo-basic'
| 'ai-air-kiss'
| 'ai-face-swap' // 新增
| 'your-new-effect'; // 你的新特效
// 2. 定义特效专用配置接口
export interface YourEffectEditorConfig {
maxImageSize?: number;
supportedFormats?: string[];
templates?: Array<{
id: string;
title: string;
description: string;
}>;
}
// 3. 添加到配置映射
const videoEffectsMap = {
'your-effect-id': {
id: 'your-effect-id',
path: '/video/your-effect-page',
copy: {
// 默认英文文案
},
marketingSections: [
{ type: 'showcase' },
{ type: 'howTo' },
{ type: 'useCases' }
],
editor: {
id: 'your-new-effect',
props: {
maxImageSize: 5,
supportedFormats: ['JPG', 'PNG', 'WEBP'],
templates: []
}
}
}
};
第三步:创建编辑器组件
在 src/components/video/
目录下创建特效专用编辑器组件:
// src/components/video/your-effect-editor.tsx
'use client';
import { Button } from '@/components/ui/button';
import { useToast } from '@/hooks/use-toast';
import { useState } from 'react';
export interface YourEffectPayload {
// 定义特效所需的数据结构
imageUrl: string;
settings: Record<string, any>;
}
interface YourEffectEditorProps {
onGenerate: (payload: YourEffectPayload) => void;
isLoading?: boolean;
// 其他配置属性
}
export function YourEffectEditor({
onGenerate,
isLoading = false,
}: YourEffectEditorProps) {
const [formData, setFormData] = useState({});
const { toast } = useToast();
// 实现组件逻辑
const handleGenerate = () => {
const payload: YourEffectPayload = {
// 构造数据
};
onGenerate(payload);
};
return (
<div className="w-full h-full bg-card text-card-foreground p-6">
{/* 组件 UI */}
<Button onClick={handleGenerate} disabled={isLoading}>
{isLoading ? '处理中...' : '生成特效'}
</Button>
</div>
);
}
第四步:更新效果注册表
在 src/components/video/effect-registries.tsx
中注册新的编辑器:
import { YourEffectEditor } from './your-effect-editor';
import type { YourEffectPayload } from './your-effect-editor';
const VIDEO_EDITOR_RENDERERS: Partial<Record<EffectEditorId, EditorRenderer>> = {
// 现有渲染器...
'your-new-effect': ({ effect, onGenerate, isLoading }) => {
const props = effect.editor.id === 'your-new-effect'
? effect.editor.props
: {};
return (
<YourEffectEditor
onGenerate={(payload: YourEffectPayload) => {
// 转换为通用格式
onGenerate(`Your effect: ${JSON.stringify(payload)}`);
}}
isLoading={isLoading}
{...props}
/>
);
},
};
第五步:创建页面路由
创建 src/app/[locale]/video/your-effect-page/page.tsx
:
import { EffectPage } from '@/components/video';
import { getVideoEffectById } from '@/config/video-effects';
import { loadPageTranslations } from '@/i18n/messages';
import type { VideoPageTranslationMessages } from '@/i18n/pages/video/types';
import { constructMetadata } from '@/lib/metadata';
import { getUrlWithLocale } from '@/lib/urls/urls';
import type { Metadata } from 'next';
import type { Locale } from 'next-intl';
export async function generateMetadata({
params,
}: {
params: Promise<{ locale: Locale }>;
}): Promise<Metadata | undefined> {
const { locale } = await params;
const effect = getVideoEffectById('your-effect-id');
if (!effect) return undefined;
const videoMessages = await loadPageTranslations<VideoPageTranslationMessages>(
locale,
'video'
);
const effectMessages = videoMessages.VideoPage?.effects?.[effect.id];
const title = effectMessages?.metadata?.title ?? effect.copy.metadata.title;
const description = effectMessages?.metadata?.description ?? effect.copy.metadata.description;
return constructMetadata({
title,
description,
canonicalUrl: getUrlWithLocale(effect.path, locale),
});
}
export default async function YourEffectPage() {
return <EffectPage effectId="your-effect-id" />;
}
第六步:添加多语言翻译
更新英文翻译 (src/i18n/pages/video/en.json
):
{
"VideoPage": {
"effects": {
"your-effect-id": {
"label": "Your Effect Name",
"hero": {
"eyebrow": "Effect Category",
"title": "Create amazing effects with AI",
"description": "Transform your images with our advanced effect."
},
"metadata": {
"title": "Your Effect - Professional Tool",
"description": "Generate stunning effects with AI technology."
},
"status": {
"initial": "Upload an image to start creating your effect."
},
"marketing": {
"showcase": {
"title": "Professional Effects",
"description": "See how our AI creates stunning visual effects."
},
"howTo": {
"title": "How to Use Your Effect",
"description": "Create professional effects in simple steps.",
"steps": [
{
"title": "Upload Image",
"description": "Choose your source image."
},
{
"title": "Configure Settings",
"description": "Adjust effect parameters."
},
{
"title": "Generate Effect",
"description": "Let AI create your effect."
}
]
},
"useCases": {
"title": "Effect Use Cases",
"description": "Discover creative ways to use this effect.",
"cases": [
{
"title": "Social Media",
"description": "Create engaging content for social platforms."
},
{
"title": "Creative Projects",
"description": "Enhance your artistic work."
}
]
}
}
}
}
}
}
更新中文翻译 (src/i18n/pages/video/zh.json
):
{
"VideoPage": {
"effects": {
"your-effect-id": {
"label": "你的特效名称",
"hero": {
"eyebrow": "特效分类",
"title": "使用 AI 创造惊人特效",
"description": "通过我们先进的特效技术转换你的图片。"
},
"metadata": {
"title": "你的特效 - 专业工具",
"description": "使用 AI 技术生成精美特效。"
},
"status": {
"initial": "上传图片开始创建你的特效。"
},
"marketing": {
"showcase": {
"title": "专业特效",
"description": "了解我们的 AI 如何创建出色的视觉特效。"
},
"howTo": {
"title": "如何使用你的特效",
"description": "通过简单步骤创建专业特效。",
"steps": [
{
"title": "上传图片",
"description": "选择你的源图片。"
},
{
"title": "配置设置",
"description": "调整特效参数。"
},
{
"title": "生成特效",
"description": "让 AI 创建你的特效。"
}
]
},
"useCases": {
"title": "特效应用场景",
"description": "探索使用此特效的创意方式。",
"cases": [
{
"title": "社交媒体",
"description": "为社交平台创建吸引人的内容。"
},
{
"title": "创意项目",
"description": "增强你的艺术作品。"
}
]
}
}
}
}
}
}
最佳实践
1. 组件设计原则
- 单一职责:每个组件只负责一个特定功能
- 可复用性:设计通用的接口和属性
- 类型安全:使用 TypeScript 定义严格的类型
2. 多语言支持
- 完整覆盖:确保所有文本都有翻译
- 结构一致:保持英文和中文翻译结构相同
- 语境适配:考虑不同语言的表达习惯
3. 错误处理
- 用户友好:提供清晰的错误消息
- 优雅降级:在出错时提供备选方案
- 日志记录:记录错误信息便于调试
4. 性能优化
- 懒加载:对大型组件使用动态导入
- 缓存策略:合理使用缓存减少请求
- 资源压缩:优化图片和文件大小
示例:AI 换脸特效
项目中已包含完整的 AI 换脸特效示例 (ai-face-swap
),你可以参考以下文件:
- 类型定义:
src/i18n/pages/video/types.ts
- 配置文件:
src/config/video-effects.ts
- 编辑器组件:
src/components/video/ai-face-swap-editor.tsx
- 注册表:
src/components/video/effect-registries.tsx
- 页面路由:
src/app/[locale]/video/ai-face-swap-video/page.tsx
- 翻译文件:
src/i18n/pages/video/{en,zh}.json
测试和验证
开发完成后,请确保:
- 功能测试:验证特效生成功能正常
- 多语言测试:检查中英文切换是否正确
- 响应式测试:确保在不同设备上显示正常
- 性能测试:验证页面加载速度和资源使用
- SEO 测试:检查元数据和 URL 结构
通过遵循本指南,你可以高效地为 Wananimate 项目添加新的视频特效页面,同时保持代码质量和用户体验的一致性。