70 lines
2.0 KiB
TypeScript
70 lines
2.0 KiB
TypeScript
import React from "react";
|
|
import {
|
|
useCurrentFrame,
|
|
useVideoConfig,
|
|
interpolate,
|
|
spring,
|
|
AbsoluteFill,
|
|
} from "remotion";
|
|
import { serifFont } from "../fonts";
|
|
|
|
// 셀링포인트: 3개 독립 pill 박스를 세로로 쌓고 순차 등장.
|
|
// 컬러 지양 → 반투명 다크 pill + 흰색 텍스트. 앞 구간 단독 노출(시선 집중).
|
|
export const SellingBadge: React.FC<{
|
|
items: string[];
|
|
fromFrame: number;
|
|
toFrame: number;
|
|
}> = ({ items, fromFrame, toFrame }) => {
|
|
const frame = useCurrentFrame();
|
|
const { fps } = useVideoConfig();
|
|
const STAGGER = 9; // 박스 간 등장 간격(frame)
|
|
|
|
return (
|
|
<AbsoluteFill
|
|
style={{
|
|
justifyContent: "flex-start",
|
|
alignItems: "center",
|
|
flexDirection: "column",
|
|
paddingTop: 200, // 상단 배치 (~16%) — 이미지 가림 최소화
|
|
gap: 18,
|
|
}}
|
|
>
|
|
{items.map((item, i) => {
|
|
const start = fromFrame + i * STAGGER;
|
|
const enter = spring({
|
|
frame: frame - start,
|
|
fps,
|
|
config: { damping: 200, mass: 0.5 },
|
|
});
|
|
const rise = interpolate(enter, [0, 1], [22, 0]);
|
|
const appear = interpolate(
|
|
frame,
|
|
[start, start + 8, toFrame - 10, toFrame],
|
|
[0, 1, 1, 0],
|
|
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
|
|
);
|
|
return (
|
|
<div
|
|
key={i}
|
|
style={{
|
|
opacity: appear,
|
|
transform: `translateY(${rise}px)`,
|
|
fontFamily: serifFont,
|
|
fontWeight: 700,
|
|
fontSize: 38,
|
|
color: "#FFFFFF",
|
|
letterSpacing: 0.5,
|
|
whiteSpace: "nowrap",
|
|
// 배경 제거 → 블러리 소프트 쉐도우로 가독성 확보
|
|
textShadow:
|
|
"0 2px 22px rgba(0,0,0,0.95), 0 0 14px rgba(0,0,0,0.85), 0 0 40px rgba(0,0,0,0.6)",
|
|
}}
|
|
>
|
|
{item}
|
|
</div>
|
|
);
|
|
})}
|
|
</AbsoluteFill>
|
|
);
|
|
};
|