// ===== demos/outro/edit-hook-moves/LogoStingButton.tsx =====
// logo-sting-button —— 收尾按钮镜头(button ending)
// 上一镜收黑 → 黑场 → LOGO 入场定住(观众以为结束)→ 12f UI 特写彩蛋硬切 →
// 硬切回黑底 LOGO 定格。节奏是全部:彩蛋段短促像眨眼。收尾真静止 ≥40f。
import React from 'react';
import { useCurrentFrame, interpolate, Easing } from 'remotion';
import { FakeDashboard } from '../../_fixtures/Fixtures';
// 时间轴(30fps,共 142f)
const T = {
shotAEnd: 24, // 0–24f 上一镜(B),f14–24 压暗到纯黑
darkenStart: 14,
blackEnd: 30, // 24–30f 黑场 6f
logoInEnd: 40, // 30–40f LOGO 入场 10f
holdEnd: 70, // 40–70f 定住 30f(观众以为结束)
eggEnd: 82, // 70–82f 彩蛋硬切 12f
total: 142, // 82–142f 黑底 LOGO 真静止 60f
};
const LogoLockup: React.FC<{ opacity: number; scale: number }> = ({ opacity, scale }) => (
{/* 方块内一个黑色小标记,避免纯白块太空 */}
ACME
);
export const LogoStingButton: React.FC = () => {
const frame = useCurrentFrame();
// —— 段 1:上一镜(FakeDashboard B)压暗收黑 ——
if (frame < T.shotAEnd) {
const dark = interpolate(frame, [T.darkenStart, T.shotAEnd - 1], [0, 1], {
extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
easing: Easing.in(Easing.cubic),
});
return (
);
}
// —— 段 2:黑场 6f ——
if (frame < T.blackEnd) {
return ;
}
// —— 段 4:彩蛋硬切 12f(variant A 按钮区 2.4x 裁切 + 角落小圆点 tick 闪 2f)——
if (frame >= T.holdEnd && frame < T.eggEnd) {
const egg = frame - T.holdEnd; // 0..11
// tick 圆点:第 4–5f 亮 2f,像眨眼
const tickOn = egg >= 4 && egg < 6;
return (
);
}
// —— 段 3 + 段 5:黑底 LOGO(入场 → 定住 → 彩蛋后定格收尾,真静止)——
const opacity = interpolate(frame, [T.blackEnd, T.logoInEnd], [0, 1], {
extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
easing: Easing.out(Easing.cubic),
});
const scale = interpolate(frame, [T.blackEnd, T.logoInEnd], [0.96, 1], {
extrapolateLeft: 'clamp', extrapolateRight: 'clamp',
easing: Easing.out(Easing.cubic),
});
return ;
};