feat(film): theme tokens, blueprint background, caption component
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
import { AbsoluteFill } from "remotion";
|
||||||
|
import { theme } from "../theme";
|
||||||
|
|
||||||
|
export const BlueprintBg: React.FC<{ opacity?: number }> = ({ opacity = 0.4 }) => {
|
||||||
|
const line = "rgba(59,130,246,0.10)";
|
||||||
|
return (
|
||||||
|
<AbsoluteFill
|
||||||
|
style={{
|
||||||
|
backgroundColor: theme.bg,
|
||||||
|
backgroundImage: `linear-gradient(${line} 1px, transparent 1px), linear-gradient(90deg, ${line} 1px, transparent 1px)`,
|
||||||
|
backgroundSize: "48px 48px",
|
||||||
|
opacity,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { useCurrentFrame, interpolate, AbsoluteFill } from "remotion";
|
||||||
|
import { theme } from "../theme";
|
||||||
|
|
||||||
|
type Position = "bottom" | "center";
|
||||||
|
|
||||||
|
export const Caption: React.FC<{
|
||||||
|
text: string;
|
||||||
|
startFrame: number;
|
||||||
|
durationInFrames: number;
|
||||||
|
position?: Position;
|
||||||
|
}> = ({ text, startFrame, durationInFrames, position = "bottom" }) => {
|
||||||
|
const frame = useCurrentFrame();
|
||||||
|
const local = frame - startFrame;
|
||||||
|
if (local < 0 || local > durationInFrames) return null;
|
||||||
|
|
||||||
|
const opacity = interpolate(
|
||||||
|
local,
|
||||||
|
[0, 12, durationInFrames - 12, durationInFrames],
|
||||||
|
[0, 1, 1, 0],
|
||||||
|
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }
|
||||||
|
);
|
||||||
|
const y = interpolate(local, [0, 12], [20, 0], { extrapolateRight: "clamp" });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AbsoluteFill
|
||||||
|
style={{
|
||||||
|
justifyContent: position === "bottom" ? "flex-end" : "center",
|
||||||
|
alignItems: "center",
|
||||||
|
paddingBottom: position === "bottom" ? 90 : 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
opacity,
|
||||||
|
transform: `translateY(${y}px)`,
|
||||||
|
maxWidth: 1200,
|
||||||
|
textAlign: "center",
|
||||||
|
fontFamily: theme.font,
|
||||||
|
fontWeight: 800,
|
||||||
|
fontSize: position === "center" ? 64 : 44,
|
||||||
|
lineHeight: 1.15,
|
||||||
|
color: theme.text,
|
||||||
|
background: "rgba(9,9,11,0.55)",
|
||||||
|
backdropFilter: "blur(8px)",
|
||||||
|
padding: "18px 36px",
|
||||||
|
borderRadius: 18,
|
||||||
|
border: `1px solid ${theme.border}`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</div>
|
||||||
|
</AbsoluteFill>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
export const theme = {
|
||||||
|
bg: "#09090b",
|
||||||
|
surface: "rgba(255,255,255,0.03)",
|
||||||
|
border: "rgba(255,255,255,0.10)",
|
||||||
|
text: "#ffffff",
|
||||||
|
textDim: "rgba(255,255,255,0.55)",
|
||||||
|
blue: "#3b82f6",
|
||||||
|
cyan: "#22d3ee",
|
||||||
|
emerald: "#10b981",
|
||||||
|
amber: "#f59e0b",
|
||||||
|
red: "#ef4444",
|
||||||
|
font: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Inter, sans-serif',
|
||||||
|
mono: 'ui-monospace, SFMono-Regular, Menlo, monospace',
|
||||||
|
brandGradient: "linear-gradient(90deg, #60a5fa, #3b82f6, #22d3ee)",
|
||||||
|
} as const;
|
||||||
Reference in New Issue
Block a user