VHS 復古片頭
仿照老式 VHS 錄影帶質感,畫面帶有水平抖動與掃描線,左上角顯示閃爍 REC 紅點與即時時間碼,主標題以 RGB 色差三層渲染,呈現強烈的復古錄像風格。
片頭VHS復古RGB 色差
提示詞(可直接修改內容)
import React from "react";
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from "remotion";
function frameToTimecode(frame: number, fps: number): string {
const totalSeconds = Math.floor(frame / fps);
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
const frames = frame % fps;
const pad = (n: number, len = 2) => String(n).padStart(len, "0");
return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}:${pad(frames)}`;
}
export const VhsRetroIntro: React.FC = () => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// 畫面水平抖動
const jitterX = frame % 7 === 0 ? 3 : frame % 7 === 1 ? -2 : 0;
// REC 指示:frame 0-15 fade in,然後每 20 frames 閃爍
const recFadeIn = interpolate(frame, [0, 15], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const recBlink = Math.floor(frame / 20) % 2 === 0 ? 1 : 0;
const recOpacity = frame < 15 ? recFadeIn : recBlink;
// 主標題:frame 30-60 fade in(用 spring)
const titleSpring = spring({
frame: frame - 30,
fps,
config: { damping: 20, stiffness: 60 },
});
const titleOpacity = interpolate(titleSpring, [0, 1], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// 副標題:frame 80-110 fade in
const subtitleOpacity = interpolate(frame, [80, 110], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// 底部 PLAY:frame 120 fade in
const playOpacity = interpolate(frame, [120, 135], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const timecode = frameToTimecode(frame, fps);
return (
<AbsoluteFill
style={{
background: "#0a0a0a",
overflow: "hidden",
}}
>
{/* 主要內容(含水平抖動) */}
<div
style={{
position: "absolute",
inset: 0,
transform: `translateX(${jitterX}px)`,
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
}}
>
{/* 主標題(RGB 色差三層) */}
<div style={{ position: "relative", display: "inline-block" }}>
{/* 紅色偏移層 */}
<div
style={{
position: "absolute",
inset: 0,
opacity: titleOpacity * 0.6,
fontSize: 80,
fontWeight: 700,
color: "#ff0000",
fontFamily: "sans-serif",
letterSpacing: "0.08em",
textTransform: "uppercase",
whiteSpace: "nowrap",
transform: "translate(-4px, 2px)",
mixBlendMode: "screen",
}}
>
YOUR CHANNEL
</div>
{/* 藍色偏移層 */}
<div
style={{
position: "absolute",
inset: 0,
opacity: titleOpacity * 0.6,
fontSize: 80,
fontWeight: 700,
color: "#0000ff",
fontFamily: "sans-serif",
letterSpacing: "0.08em",
textTransform: "uppercase",
whiteSpace: "nowrap",
transform: "translate(4px, -2px)",
mixBlendMode: "screen",
}}
>
YOUR CHANNEL
</div>
{/* 主白色層 */}
<div
style={{
position: "relative",
opacity: titleOpacity,
fontSize: 80,
fontWeight: 700,
color: "#ffffff",
fontFamily: "sans-serif",
letterSpacing: "0.08em",
textTransform: "uppercase",
whiteSpace: "nowrap",
}}
>
YOUR CHANNEL
</div>
</div>
{/* 副標題 */}
<div
style={{
opacity: subtitleOpacity,
fontSize: 28,
color: "#aaaaaa",
fontFamily: "sans-serif",
fontWeight: 400,
letterSpacing: "0.1em",
marginTop: 24,
textTransform: "uppercase",
}}
>
Est. 2024 · Video Production
</div>
{/* 底部 PLAY */}
<div
style={{
opacity: playOpacity,
fontSize: 20,
color: "#ffffff",
fontFamily: "monospace",
letterSpacing: "4px",
marginTop: 60,
textTransform: "uppercase",
}}
>
PLAY ▶
</div>
</div>
{/* 掃描線層(覆蓋全畫面,不受抖動影響) */}
<div
style={{
position: "absolute",
inset: 0,
background:
"repeating-linear-gradient(0deg, transparent, transparent 3px, rgba(0,0,0,0.15) 3px, rgba(0,0,0,0.15) 4px)",
pointerEvents: "none",
}}
/>
{/* HUD 層(REC + 時間碼,不受抖動影響) */}
<div
style={{
position: "absolute",
top: 40,
left: 48,
display: "flex",
alignItems: "center",
gap: 10,
opacity: recOpacity,
}}
>
{/* 紅點 */}
<div
style={{
width: 16,
height: 16,
borderRadius: "50%",
background: "#ff2222",
boxShadow: "0 0 8px #ff2222",
}}
/>
{/* REC 文字 */}
<span
style={{
fontSize: 24,
color: "#ffffff",
fontFamily: "monospace",
fontWeight: 700,
letterSpacing: "2px",
}}
>
REC
</span>
</div>
{/* 左上角時間碼 */}
<div
style={{
position: "absolute",
top: 80,
left: 48,
fontSize: 22,
color: "#ffffff",
fontFamily: "monospace",
letterSpacing: "2px",
opacity: 0.85,
}}
>
{timecode}
</div>
</AbsoluteFill>
);
};登入後查看完整程式碼