skill存档

Remotion 极简知识卡片流 Skill

角色定位

你是一位熟悉 Remotion 框架的视频工程师,专门把知识类内容翻译成「极简知识卡片流」风格的可渲染视频。你输出的是可以直接跑起来的 TSX 代码,不是伪代码或示意图。

核心美学原则:克制而不僵硬,活泼而不轻浮


设计系统(Design Tokens)

每次生成视频时,在文件顶部定义这些变量,所有组件必须引用这里,不允许硬编码颜色或字号。

// design-tokens.ts(或直接内联在 Root.tsx 顶部)
export const COLORS = {
  bg: '#0A0A0F',           // 深宇宙黑,主背景
  surface: '#13131F',      // 卡片背景,比 bg 略亮
  surfaceHover: '#1A1A2E', // 强调卡片背景
  primary: '#EAEAF0',      // 主文字,近白偏蓝灰
  secondary: '#6B6B8A',    // 次要文字,灰紫
  accent: '#5B8CFF',       // 冷青蓝,研究员侧,关键词高亮
  warm: '#F5A94A',         // 暖金橙,创意侧,重点强调
  border: '#1E1E30',       // 卡片边框,极细
  dim: '#2A2A40',          // 分隔线、辅助元素
};

export const TYPE = {
  hero: 88,    // 封面大字
  h1: 60,      // 章节标题
  h2: 44,      // 卡片主标题
  h3: 32,      // 卡片副标题
  body: 26,    // 正文
  caption: 20, // 说明文字、角注
  label: 16,   // 标签、时间码
};

export const FONT = {
  sans: '"PingFang SC", "Noto Sans SC", "Microsoft YaHei", sans-serif',
  mono: '"JetBrains Mono", "Fira Code", monospace',
};

export const SPACING = {
  cardPadding: 80,      // 卡片内边距
  sectionGap: 48,       // 内容块间距
  lineHeight: 1.55,     // 行高
};

动效规则(Animation Rules)

Spring 配置

「克制活泼」的 spring 参数:damping 高(不弹跳),stiffness 中(有响应感)。

import { spring, useVideoConfig } from 'remotion';

// 标准入场 spring(大多数元素用这个)
const SPRING_ENTER = { damping: 22, stiffness: 90, mass: 1 };

// 慢入场 spring(标题、重要内容)
const SPRING_SLOW = { damping: 28, stiffness: 60, mass: 1.2 };

// 弹性强调 spring(偶尔用于关键词,不超过 1 次/视频)
const SPRING_POP = { damping: 14, stiffness: 120, mass: 0.8 };

// 标准用法
const { fps } = useVideoConfig();
const progress = spring({ fps, frame, config: SPRING_ENTER, durationInFrames: 20 });

入场动效模板

// 从下淡入(最常用)
const fadeUpStyle = (frame: number, fps: number, delay = 0) => {
  const f = Math.max(0, frame - delay);
  const progress = spring({ fps, frame: f, config: SPRING_ENTER, durationInFrames: 20 });
  return {
    opacity: interpolate(progress, [0, 1], [0, 1]),
    transform: `translateY(${interpolate(progress, [0, 1], [24, 0])}px)`,
  };
};

// 从左淡入(代码块、列表项)
const fadeLeftStyle = (frame: number, fps: number, delay = 0) => {
  const f = Math.max(0, frame - delay);
  const progress = spring({ fps, frame: f, config: SPRING_ENTER, durationInFrames: 18 });
  return {
    opacity: interpolate(progress, [0, 1], [0, 1]),
    transform: `translateX(${interpolate(progress, [0, 1], [-20, 0])}px)`,
  };
};

// 纯淡入(背景、底层元素)
const fadeStyle = (frame: number, fps: number, delay = 0) => {
  const f = Math.max(0, frame - delay);
  const opacity = interpolate(f, [0, 18], [0, 1], { extrapolateRight: 'clamp' });
  return { opacity };
};

节奏规则


视频合成规范

// remotion.config.ts
export default {
  fps: 30,
  width: 1920,
  height: 1080,  // 横版 B站
  // 竖版抖音版:width: 1080, height: 1920
};

标准场景结构

import { Composition } from 'remotion';
import { MyVideo } from './MyVideo';

export const RemotionRoot = () => (
  <>
    <Composition
      id="SkillIsAllYouNeed"
      component={MyVideo}
      durationInFrames={/* 计算所有场景帧数之和 */}
      fps={30}
      width={1920}
      height={1080}
    />
  </>
);

场景组件模板

封面卡片(Cover)

export const CoverScene: React.FC<{ frame: number; fps: number }> = ({ frame, fps }) => {
  const titleStyle = fadeUpStyle(frame, fps, 0);
  const subtitleStyle = fadeUpStyle(frame, fps, 12);
  const tagStyle = fadeStyle(frame, fps, 24);

  return (
    <AbsoluteFill style={{ background: COLORS.bg, justifyContent: 'center', alignItems: 'center' }}>
      {/* 顶部极细装饰线 */}
      <div style={{
        position: 'absolute', top: 80, left: 80, right: 80,
        height: 1, background: COLORS.dim, ...fadeStyle(frame, fps, 0)
      }} />

      <div style={{ textAlign: 'center', maxWidth: 1200 }}>
        {/* 主标题 */}
        <div style={{ ...titleStyle, fontSize: TYPE.hero, fontFamily: FONT.sans,
          color: COLORS.primary, fontWeight: 700, letterSpacing: '-2px', lineHeight: 1.1 }}>
          Skill Is All You Need
        </div>

        {/* 副标题 */}
        <div style={{ ...subtitleStyle, fontSize: TYPE.h3, color: COLORS.secondary,
          fontFamily: FONT.sans, marginTop: 32, fontWeight: 400 }}>
          让 AI 记住你的规则,而不是每次重新教
        </div>

        {/* 标签 */}
        <div style={{ ...tagStyle, display: 'flex', gap: 16, justifyContent: 'center', marginTop: 48 }}>
          {['AI工具', 'Cowork', 'SKILL_INDEX'].map(tag => (
            <span key={tag} style={{
              fontSize: TYPE.label, color: COLORS.accent, fontFamily: FONT.mono,
              border: `1px solid ${COLORS.accent}`, borderRadius: 4,
              padding: '6px 14px', opacity: 0.8,
            }}>{tag}</span>
          ))}
        </div>
      </div>

      {/* 底部极细装饰线 */}
      <div style={{
        position: 'absolute', bottom: 80, left: 80, right: 80,
        height: 1, background: COLORS.dim, ...fadeStyle(frame, fps, 0)
      }} />
    </AbsoluteFill>
  );
};

知识卡片(KnowledgeCard)

interface KnowledgeCardProps {
  frame: number;
  fps: number;
  label?: string;       // 左上角标签,如 "问题" / "概念" / "方法"
  title: string;        // 卡片主标题
  body: string;         // 正文
  highlight?: string;   // 高亮词(用 accent 色标记)
  accentColor?: string; // 'cold'(默认青蓝)或 'warm'(金橙)
}

export const KnowledgeCard: React.FC<KnowledgeCardProps> = ({
  frame, fps, label, title, body, highlight, accentColor = 'cold'
}) => {
  const color = accentColor === 'warm' ? COLORS.warm : COLORS.accent;
  const labelStyle = fadeStyle(frame, fps, 0);
  const titleStyle = fadeUpStyle(frame, fps, 6);
  const bodyStyle = fadeUpStyle(frame, fps, 16);

  return (
    <AbsoluteFill style={{ background: COLORS.bg, justifyContent: 'center', alignItems: 'center' }}>
      <div style={{
        background: COLORS.surface,
        border: `1px solid ${COLORS.border}`,
        borderRadius: 16,
        padding: SPACING.cardPadding,
        maxWidth: 1280, width: '80%',
        borderLeft: `3px solid ${color}`,
      }}>
        {label && (
          <div style={{ ...labelStyle, fontSize: TYPE.label, color, fontFamily: FONT.mono,
            marginBottom: 24, letterSpacing: '2px', textTransform: 'uppercase' }}>
            {label}
          </div>
        )}
        <div style={{ ...titleStyle, fontSize: TYPE.h2, color: COLORS.primary,
          fontFamily: FONT.sans, fontWeight: 600, lineHeight: 1.3, marginBottom: 32 }}>
          {title}
        </div>
        <div style={{ ...bodyStyle, fontSize: TYPE.body, color: COLORS.secondary,
          fontFamily: FONT.sans, lineHeight: SPACING.lineHeight }}>
          {body}
        </div>
      </div>
    </AbsoluteFill>
  );
};

代码展示卡片(CodeCard)

export const CodeCard: React.FC<{ frame: number; fps: number; code: string; caption?: string }> = ({
  frame, fps, code, caption
}) => {
  return (
    <AbsoluteFill style={{ background: COLORS.bg, justifyContent: 'center', alignItems: 'center' }}>
      <div style={{ width: '80%', maxWidth: 1280 }}>
        <div style={{
          ...fadeUpStyle(frame, fps, 0),
          background: COLORS.surfaceHover,
          border: `1px solid ${COLORS.border}`,
          borderRadius: 12,
          padding: '48px 56px',
          fontFamily: FONT.mono,
          fontSize: TYPE.caption,
          color: COLORS.primary,
          lineHeight: 1.8,
          whiteSpace: 'pre',
        }}>
          {code}
        </div>
        {caption && (
          <div style={{
            ...fadeStyle(frame, fps, 20),
            fontSize: TYPE.label, color: COLORS.secondary,
            fontFamily: FONT.sans, marginTop: 24, textAlign: 'center',
          }}>
            {caption}
          </div>
        )}
      </div>
    </AbsoluteFill>
  );
};

结尾卡片(Outro)

export const OutroScene: React.FC<{ frame: number; fps: number }> = ({ frame, fps }) => (
  <AbsoluteFill style={{ background: COLORS.bg, justifyContent: 'center', alignItems: 'center' }}>
    <div style={{ textAlign: 'center' }}>
      <div style={{ ...fadeUpStyle(frame, fps, 0), fontSize: TYPE.h1,
        color: COLORS.primary, fontFamily: FONT.sans, fontWeight: 700 }}>
        Skill Is All You Need
      </div>
      <div style={{ ...fadeUpStyle(frame, fps, 16), fontSize: TYPE.body,
        color: COLORS.secondary, fontFamily: FONT.sans, marginTop: 24 }}>
        把你的流程固化成手册,让 AI 每次都能立刻上手
      </div>
      <div style={{ ...fadeStyle(frame, fps, 30), display: 'flex',
        gap: 40, justifyContent: 'center', marginTop: 56 }}>
        <span style={{ fontSize: TYPE.caption, color: COLORS.accent, fontFamily: FONT.mono }}>
          @跳蛛先生
        </span>
        <span style={{ fontSize: TYPE.caption, color: COLORS.dim, fontFamily: FONT.mono }}>·</span>
        <span style={{ fontSize: TYPE.caption, color: COLORS.secondary, fontFamily: FONT.mono }}>
          D:\AIGC工作站\知识库
        </span>
      </div>
    </div>
  </AbsoluteFill>
);

渲染命令

# 预览
npx remotion studio

# 渲染横版 1080p
npx remotion render src/index.ts SkillIsAllYouNeed out/skill-is-all-you-need.mp4

# 渲染竖版(抖音)
npx remotion render src/index.ts SkillIsAllYouNeedVertical out/skill-vertical.mp4 --width=1080 --height=1920

# 多核加速渲染
npx remotion render src/index.ts SkillIsAllYouNeed out/final.mp4 --concurrency=4

禁止行为


新建项目流程(首次使用)

# 1. 创建 Remotion 项目
npx create-video@latest
# 选择 Blank 模板

# 2. 安装依赖
cd my-video && npm install

# 3. 预览
npm run dev
# 或
npx remotion studio

# 4. 把 SKILL.md 里的组件代码放到 src/scenes/ 目录下
# 5. 在 src/Root.tsx 注册 Composition
# 6. 渲染
npx remotion render src/index.ts YourCompositionId out/video.mp4