Files
ViGent2/remotion/src/components/Title.tsx
2026-02-02 10:51:27 +08:00

94 lines
2.0 KiB
TypeScript

import React from 'react';
import {
AbsoluteFill,
interpolate,
useCurrentFrame,
useVideoConfig,
} from 'remotion';
interface TitleProps {
title: string;
duration?: number; // 标题显示时长(秒)
fadeOutStart?: number; // 开始淡出的时间(秒)
}
/**
* 片头标题组件
* 在视频顶部显示标题,带淡入淡出效果
*/
export const Title: React.FC<TitleProps> = ({
title,
duration = 3,
fadeOutStart = 2,
}) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const currentTimeInSeconds = frame / fps;
// 如果超过显示时长,不渲染
if (currentTimeInSeconds > duration) {
return null;
}
// 淡入效果 (0-0.5秒)
const fadeInOpacity = interpolate(
currentTimeInSeconds,
[0, 0.5],
[0, 1],
{ extrapolateRight: 'clamp' }
);
// 淡出效果
const fadeOutOpacity = interpolate(
currentTimeInSeconds,
[fadeOutStart, duration],
[1, 0],
{ extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
);
const opacity = Math.min(fadeInOpacity, fadeOutOpacity);
// 轻微的下滑动画
const translateY = interpolate(
currentTimeInSeconds,
[0, 0.5],
[-20, 0],
{ extrapolateRight: 'clamp' }
);
return (
<AbsoluteFill
style={{
justifyContent: 'flex-start',
alignItems: 'center',
paddingTop: '6%',
opacity,
}}
>
<h1
style={{
transform: `translateY(${translateY}px)`,
textAlign: 'center',
color: '#FFFFFF',
fontSize: '72px',
fontWeight: 900,
fontFamily: '"PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Noto Sans SC", sans-serif',
textShadow: `
0 0 10px rgba(0,0,0,0.9),
0 0 20px rgba(0,0,0,0.7),
0 4px 8px rgba(0,0,0,0.8),
0 8px 16px rgba(0,0,0,0.5)
`,
margin: 0,
padding: '0 5%',
lineHeight: 1.3,
letterSpacing: '4px',
}}
>
{title}
</h1>
</AbsoluteFill>
);
};