Catalog

Edit Props (live)

TEXT
TEXT
config
config

Source

160 lines
import React from "react";
import {
  AbsoluteFill,
  useCurrentFrame,
  useVideoConfig,
  interpolate,
  Easing,
  spring,
} from "remotion";
import { loadFont as loadInter } from "@remotion/google-fonts/Inter";

loadInter("normal", { weights: ["400", "600", "700", "800", "900"] });

const FONT = "'Inter', sans-serif";
const ACCENT = "#D97757";          // Claude orange
const UNDERLINE = "#C8403A";       // deeper red underline
const SURFACE = "#F4EEE0";         // cream

interface Tip { number?: number | string; label: string }
interface TipListCardProps {
  titleTop?: string;       // "3 Tricks To Cut"
  titleChip?: string;      // "CLAUDE USAGE"
  tips?: Tip[];            // 3 entries (auto-numbered if number missing)
  backgroundColor?: string;
}

const DEFAULTS: Tip[] = [
  { label: "/Model OpusPlan" },
  { label: "/Compact" },
  { label: "Ultrathink" },
];

export const TipListCard: React.FC<TipListCardProps> = ({
  titleTop = "3 Tricks To Cut",
  titleChip = "CLAUDE USAGE",
  tips,
  backgroundColor = SURFACE,
}) => {
  const frame = useCurrentFrame();
  const { fps, width, height } = useVideoConfig();
  const list = (tips && tips.length ? tips : DEFAULTS).slice(0, 5);

  const titleSpring = spring({ frame: frame - 2, fps, config: { mass: 0.7, damping: 14, stiffness: 180 } });
  const titleOp = interpolate(titleSpring, [0, 1], [0, 1]);
  const titleY = interpolate(titleSpring, [0, 1], [22, 0]);

  const underlineW = interpolate(frame, [10, 26], [0, 1], { extrapolateRight: "clamp", easing: Easing.out(Easing.cubic) });

  const chipSpring = spring({ frame: frame - 14, fps, config: { mass: 0.7, damping: 13, stiffness: 200 } });
  const chipOp = interpolate(chipSpring, [0, 1], [0, 1]);
  const chipScale = interpolate(chipSpring, [0, 1], [0.7, 1]);

  return (
    <AbsoluteFill style={{ backgroundColor, overflow: "hidden", fontFamily: FONT }}>
      {/* Top title block */}
      <div
        style={{
          position: "absolute",
          top: height * 0.13,
          left: 0, right: 0,
          textAlign: "center",
          opacity: titleOp,
          transform: `translateY(${titleY}px)`,
        }}
      >
        <div style={{ display: "inline-block", position: "relative" }}>
          <div style={{ fontSize: 96, fontWeight: 900, color: "#1a1a1a", letterSpacing: -2.5, lineHeight: 1 }}>
            {titleTop}
          </div>
          {/* Underline */}
          <div
            style={{
              position: "absolute",
              left: 0,
              bottom: -10,
              height: 8,
              borderRadius: 4,
              background: UNDERLINE,
              width: `${underlineW * 100}%`,
            }}
          />
        </div>
      </div>

      {/* Orange chip */}
      <div
        style={{
          position: "absolute",
          top: height * 0.24,
          left: 0, right: 0,
          display: "flex",
          justifyContent: "center",
          opacity: chipOp,
          transform: `scale(${chipScale})`,
        }}
      >
        <div
          style={{
            background: ACCENT,
            color: "#ffffff",
            fontWeight: 900,
            fontSize: 88,
            letterSpacing: -2,
            padding: "16px 44px",
            borderRadius: 18,
            boxShadow: "0 14px 30px rgba(217,119,87,0.45)",
          }}
        >
          {titleChip}
        </div>
      </div>

      {/* Numbered tip rows */}
      <div
        style={{
          position: "absolute",
          top: height * 0.38,
          left: 60, right: 60,
          display: "flex",
          flexDirection: "column",
          gap: 22,
        }}
      >
        {list.map((tip, i) => {
          const startF = 22 + i * 8;
          const sp = spring({ frame: frame - startF, fps, config: { mass: 0.7, damping: 14, stiffness: 180 } });
          const op = interpolate(sp, [0, 1], [0, 1]);
          const x = interpolate(sp, [0, 1], [-50, 0]);
          const num = tip.number ?? i + 1;
          return (
            <div
              key={i}
              style={{
                background: ACCENT,
                color: "#ffffff",
                borderRadius: 16,
                padding: "22px 28px",
                display: "flex",
                alignItems: "center",
                gap: 24,
                opacity: op,
                transform: `translateX(${x}px)`,
                boxShadow: "0 10px 22px rgba(217,119,87,0.30)",
              }}
            >
              <div style={{ fontSize: 60, fontWeight: 900, opacity: 0.7, minWidth: 70, textAlign: "center", letterSpacing: -2 }}>
                {num}
              </div>
              <div style={{ width: 2, height: 70, background: "rgba(255,255,255,0.45)" }} />
              <div style={{ fontSize: 78, fontWeight: 900, letterSpacing: -2.4, lineHeight: 1, flex: 1 }}>
                {tip.label}
              </div>
            </div>
          );
        })}
      </div>
    </AbsoluteFill>
  );
};

Schema (Zod)

// Auto-extracted from Props interface — see source for authoritative types.
// Component: TipListCard
// 4 props detected · 2 port(s)

Tip List Card

tip_list_card

Tip List Card — Andy's hand-crafted Remotion scene. 4 props. titleTop:TEXT, titleChip:TEXT.

Workflow Inputs (2)

  • Title Top
    titleTop
    TEXT
  • Title Chip
    titleChip
    TEXT

Config Fields (2)

  • tips
  • backgroundColor

Meta

Updated
4/21/2026