{currentSegment.words.map((word, index) => {
const isHighlighted = index <= currentWordIndex;
return (
+ key={`${word.word}-${index}`}
+ style={{
+ color: isHighlighted ? highlightColor : normalColor,
+ textShadow: buildTextShadow(strokeColor, strokeSize),
+ transition: 'color 0.05s ease',
+ }}
+ >
{word.word}
);
diff --git a/remotion/src/components/Title.tsx b/remotion/src/components/Title.tsx
index 6fd816b..08990d8 100644
--- a/remotion/src/components/Title.tsx
+++ b/remotion/src/components/Title.tsx
@@ -4,22 +4,62 @@ import {
interpolate,
useCurrentFrame,
useVideoConfig,
+ staticFile,
} from 'remotion';
+export interface TitleStyle {
+ font_file?: string;
+ fontFamily?: string;
+ font_family?: string;
+ fontSize?: number;
+ font_size?: number;
+ color?: string;
+ strokeColor?: string;
+ stroke_color?: string;
+ strokeSize?: number;
+ stroke_size?: number;
+ letterSpacing?: number;
+ letter_spacing?: number;
+ topMargin?: number;
+ top_margin?: number;
+ fontWeight?: number;
+ font_weight?: number;
+}
+
interface TitleProps {
title: string;
duration?: number; // 标题显示时长(秒)
fadeOutStart?: number; // 开始淡出的时间(秒)
+ style?: TitleStyle;
}
/**
* 片头标题组件
* 在视频顶部显示标题,带淡入淡出效果
*/
+const getFontFormat = (fontFile?: string) => {
+ if (!fontFile) return 'truetype';
+ const ext = fontFile.split('.').pop()?.toLowerCase();
+ if (ext === 'otf') return 'opentype';
+ return 'truetype';
+};
+
+const buildTextShadow = (color: string, size: number) => {
+ return [
+ `-${size}px -${size}px 0 ${color}`,
+ `${size}px -${size}px 0 ${color}`,
+ `-${size}px ${size}px 0 ${color}`,
+ `${size}px ${size}px 0 ${color}`,
+ `0 0 ${size * 2}px rgba(0,0,0,0.7)`,
+ `0 4px 8px rgba(0,0,0,0.6)`
+ ].join(',');
+};
+
export const Title: React.FC
{title}