mcpField
W
wrapped-video

wrapped-video

github.com/iart-ai创意与媒体601.4k 次安装18 周前更新
代码仓库

关于 wrapped-video

使用 Remotion 将个人或账户数据转为个性化竖屏回顾视频的技能,适用于需要基于统一模板批量制作多条视频的创作者和团队。

主要功能

  1. 01回顾数据的类型化架构
  2. 02可复用的回顾场景序列
  3. 03由数据驱动文本、统计值和配色
  4. 049:16 竖屏视频布局指导
  5. 05按数据记录批量渲染 MP4
  6. 06基于帧的预览与验证

适用场景

  1. 01制作年度用户活动回顾
  2. 02生成个性化健身或阅读视频
  3. 03制作销售或学生进度总结
  4. 04从数据行批量渲染可分享视频

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/iart-ai/explainer-video-skills --skill wrapped-video

安装后在 Claude Code 中输入/wrapped-video确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

README.md
references/
batch-pipeline.md
remotion-recipes.md
scene-grammar.md

详细介绍

Wrapped 视频

打造类似“Spotify Wrapped”的年度回顾:取一行关于某个人(或账户、团队、年份)的数据,将其制作成引人注目、便于分享的竖屏视频。核心理念是一个模板 × 一张数据表 → 多个个性化视频。模板只需编写一次,然后为每一行渲染一部独特的视频。

适用场景

  • 面向任何能提供用户个人统计数据的产品,制作年度回顾/“你的 2026 年度总结”。
  • 个性化数据视频:健身年度回顾、阅读年度回顾、消费总结、游戏统计、销售代表回顾、学生进度。
  • 任何交付内容都是“同一部视频,只是每个人的数据不同”的场景,无论制作 1 份还是 100,000 份。

这是一种数据 → 引人分享的内容模式,而非手工剪辑的视频。如果没有数据表(或没有逐条记录的数据),请使用其他技能。

两项不可妥协的原则

  1. 所有内容都由数据驱动。 每个标题、数字、名称和颜色都必须来自 props,不能硬编码。无法根据一行数据填充的场景,不属于 Wrapped。
  2. 专为截图而设计。 每个场景都必须能在 2 秒内读懂,定格时也要好看——被分享至动态的正是这张定格画面。设计时要考虑暂停,而非播放。

Wrapped 场景语法

Wrapped 由一系列固定顺序的短场景类型组成,每个场景约 2.5–4 秒。选取 5–7 个场景并按递进方式排列。每年使用相同的语法;只有数据和配色会变化。

场景类型作用数据形态
开场/“你的 2026 年度回顾”打造品牌氛围,设定配色姓名、年份
大数字揭晓突出一项核心统计数据,以大号数字递增显示一个数字 + 单位 + 标签
Top-X 列表按排名 1→5 排列,依次显示{rank, label, value} 数组
最高级/人物类型“你位列前 1%”,一个原型类别计算得出的层级/标签
对比“超过了 92% 的听众”百分位或比率
时间/热力图“你最忙碌的月份是 3 月”序列或峰值
结尾/分享卡片Logo + 用户名 + CTA,画面静止停留姓名、用户名

按渐强顺序排列:先展示少量背景信息,以最大/最个人化的统计数据作为高潮,最后呈现静止的分享卡片。完整的 7 场景分镜及时间安排,请参阅 references/scene-grammar.md。

回顾视频的故事弧线

场景语法是骨架;故事弧线 才能让 Wrapped 像一份礼物,而不是仪表盘。回顾视频是一部围绕一位观众展开、由五个节拍组成的短剧——按顺序编排,让每次揭晓都比上一次更有分量、更贴近个人。

节拍作用对应内容
铺垫烘托时刻氛围,承诺这是专属于他们的开场:「{name},你的 {year}」
逐步揭晓逐层展示分量不断上升的数据Top-X、音乐流派、时间规律
「大数字」一个主打数据,数值最大、展示时间最长大数字/递增计数高潮
个性化称号说出 他们是什么样的人,而不只是做过什么人格/百分位等级
值得分享的收尾一张他们想要发布的静态海报分享卡片收尾

按影响力递增的顺序排列数据——从最小到最大。 根据情感分量(数值大小、稀有程度、令人欣喜的程度)为每项数据排序,并按升序展示。绝不要一开场就亮出主打数字:之后就无从递进,影片剩下的部分也会显得虎头蛇尾。让高潮数据以最大尺寸展示最久;此前的一切都是铺垫。

关键是「这是关于你」。 Wrapped 之所以出彩,是因为观众就是主角。前 2 秒就要让这一点深入人心:先展示他们的名字,使用他们专属的 accent,并让每一行文案都以第二人称书写(「你听过 412 位艺人的作品」)。泛泛的文案(「最爱流派:独立音乐」)会破坏这种代入感——改写成「你就是独立音乐那一挂的人」。如果两个不同用户看到的某一帧完全相同,那它就没有发挥应有的作用。

把最终分享画面设计成终点。 整条故事弧线都是为了呈现一张值得发布的海报。收尾不是滚动字幕,而是最终回报:重新呈现醒目的称号或主打数字、姓名 + @handle、Logo、一条简短的 CTA,并且完全静止至少 2 秒,让截图或自动循环都能干净利落地呈现。先决定这一帧,再围绕它逐步推向高潮。文案层级和完整分镜见 references/scene-grammar.md。

数据 → 视频结构

为一条记录定义类型化架构。整段视频都是它的纯函数。

// src/schema.ts
import { z } from "zod";
export const wrappedSchema = z.object({
  name: z.string(),
  year: z.number(),
  minutesListened: z.number(),
  topArtists: z.array(z.object({ rank: z.number(), label: z.string(), value: z.number() })),
  topGenre: z.string(),
  percentile: z.number(), // 0–100, "top X%"
  accent: z.string(),     // per-user palette, e.g. "#1DB954"
});
export type Wrapped = z.infer<typeof wrappedSchema>;

将它作为 defaultProps + schema 注册到合成中,这样每次渲染只需替换 props。

// src/Root.tsx
import { Composition } from "remotion";
import { Wrapped as Recap } from "./Wrapped";
import { wrappedSchema } from "./schema";

export const Root = () => (
  <Composition
    id="Wrapped"
    component={Recap}
    schema={wrappedSchema}
    durationInFrames={30 * 22}  // 22s @ 30fps
    fps={30}
    width={1080} height={1920}  // 9:16 vertical — the share format
    defaultProps={{ name: "Sam", year: 2026, minutesListened: 41203,
      topArtists: [{ rank: 1, label: "Phoebe Bridgers", value: 312 }],
      topGenre: "Indie", percentile: 3, accent: "#1DB954" }}
  />
);

标志性手法:大数字计数器

递增计数是每个 Wrapped 的心跳。使用 useCurrentFrame() 驱动(绝不要用 setState/setInterval——这会导致渲染时闪烁),通过弹簧效果缓动,并用 toLocaleString() 格式化。

import { useCurrentFrame, useVideoConfig, spring, interpolate } from "remotion";

export const BigNumber: React.FC<{ value: number; label: string; accent: string }> =
({ value, label, accent }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const progress = spring({ frame, fps, config: { damping: 200 } }); // 0→1, settles
  const shown = Math.round(interpolate(progress, [0, 1], [0, value]));
  const pop = interpolate(progress, [0, 1], [0.6, 1]); // overshoot-free scale-in
  return (
    <div style={{ display: "flex", flexDirection: "column", alignItems: "center",
        justifyContent: "center", height: "100%", transform: `scale(${pop})` }}>
      <span style={{ fontSize: 220, fontWeight: 900, color: accent, lineHeight: 1,
          fontVariantNumeric: "tabular-nums" }}>{shown.toLocaleString()}</span>
      <span style={{ fontSize: 48, color: "#fff", marginTop: 24 }}>{label}</span>
    </div>
  );
};

使用 tabular-nums,让数字滚动时宽度不会跳动。对于 Top-X 列表,为每项复用一个弹簧效果,并通过错开的 delay 延迟展示(排名第 1 的先出现)——参见 references/remotion-recipes.md。

竖屏 9:16,为停留一刻而设计

渲染 1080×1920。Stories/Reels/TikTok 会裁切画面并叠加 UI,因此所有文字和关键数字都应放在高度中央 80% 的范围内,避开顶部 12% 和底部 18%。每帧只传达一个鲜明想法,使用超大字号,并在纯色/渐变背景上搭配高对比度强调色。每位用户专属的 accent 颜色能让每次分享都更具个人感。完整的安全区域示意图见 references/scene-grammar.md。

批量处理:一个模板 → 多个视频

这是最终回报。使用 renderMedia,将每行数据作为 inputProps 传入,为每行数据分别渲染一个 MP4。生成任务 CSV,循环处理,并按每条记录命名文件。

// render-all.ts  — run with: npx tsx render-all.ts
import { bundle } from "@remotion/bundler";
import { renderMedia, selectComposition } from "@remotion/renderer";
import { wrappedSchema } from "./src/schema";
import users from "./users.json"; // array of rows matching the schema

const serveUrl = await bundle({ entryPoint: "./src/index.ts" });
for (const user of users) {
  const props = wrappedSchema.parse(user);            // validate the row
  const comp = await selectComposition({ serveUrl, id: "Wrapped", inputProps: props });
  await renderMedia({
    composition: comp, serveUrl, codec: "h264",
    inputProps: props,
    outputLocation: `out/wrapped-${user.id}.mp4`,
  });
  console.log("rendered", user.id);
}

对于数千行数据,可将任务分发到多台机器/Lambda,并对相同的 props 集合去重。流水线、扩展方案,以及 Node + CLI 批量处理变体见 references/batch-pipeline.md。

构建检查清单

  • 所有可见字符串/数字都来自 props;不硬编码任何内容。
  • 5–7 个场景,按递增顺序推进,以最大/最具个人特色的数据作为高潮。
  • 数字通过 useCurrentFrame + 弹簧效果递增,使用 tabular-nums,并按区域设置格式化。
  • 9:16,1080×1920;关键内容位于中央 80% 的范围内,避开顶部 12%/底部 18%。
  • 每个场景都能在 <2 秒内读完,定格时也足够清晰(观众会截图)。
  • 使用一个架构验证渲染前的每一行数据;批处理脚本按每条记录命名文件。

交付与验证(渲染静帧 → MP4)

打包的辅助脚本(scripts/):使用 scripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.png 将静帧拼成图集,然后使用 scripts/probe-mp4.sh out.mp4 [WxH] [fps] 验证编码结果。详见 scripts/README.md。

Wrapped 是按每行数据分别渲染的 Remotion 合成内容,帧完全确定,因此无需寻帧工具,即可在无头环境中精确渲染任意帧。交付物是包含每个人精确数据的 MP4(通常有很多个);批量渲染前,先用静帧验证一个有代表性的行。

输出要求:

  • 一个已注册合成内容的 Remotion 项目(<Composition> + zod schema + defaultProps),所有动画均由帧驱动(不使用计时器 / Date.now() / Math.random();数字递增使用 useCurrentFrame + spring)。
  • 交付物 = 每行数据对应的已渲染 out/wrapped-*.mp4(以及项目本身,以便重新渲染任意行)。
  • 将每位用户的统计数据写入 props,并在渲染前通过 schema 验证;画面比例为 9:16,分辨率为 1080×1920。
  • 时长取决于数据?在 calculateMetadata 中计算,不要手动设置。

验证流程——同一行的静帧 → 检查 → 批量渲染。 先渲染一个有代表性的用户的帧(成本低,无需编码);及早发现布局或数据问题,避免重复 N 次。

# Frame-exact stills at start / mid / end for ONE representative row — pass that row as props
npx remotion still Wrapped out/f-start.png --frame=0   --props='{...one user...}'
npx remotion still Wrapped out/f-mid.png   --frame=N   --props='{...one user...}'
npx remotion still Wrapped out/f-end.png   --frame=L   --props='{...one user...}'   # L = durationInFrames - 1

# Inspect: every visible string/number comes from that row and is EXACT (big-number reveal lands on the
# real value, top-X ranks/labels correct); key content inside center 80%, clear of top 12% / bottom 18%.

# Only after the representative stills check out, batch-render every row:
npx tsx render-all.ts
  • npx remotion compositions 会读取 durationInFrames/fps,以确定结束帧和大数字的定格帧。
  • 免费生成 README 演示 GIF:npx remotion render Wrapped out/demo.gif --codec=gif --props='{...}'。

完成前:

  1. 使用 npx remotion still 渲染代表性行的第 0 帧、中间帧和最后一帧,均无错误且没有缺失资源或字体。
  2. 大数字在其定格帧显示与 prop 值完全一致的数值;前 X 名的排名 / 标签 / 数值均与该行数据匹配。
  3. 9:16:关键数字和文字位于中央 80% 区域内,避开顶部 12% / 底部 18%;检查过的每一帧都能清晰读取。
  4. 仅由帧驱动——不使用 Date.now() / Math.random() / 计时器;批量渲染前验证每一行的 schema。
  5. 编码并播放代表性 MP4;然后批量处理所有行(每条记录生成一个文件);(可选)生成 README 用的 GIF。

参考文件

  • references/scene-grammar.md — 完整的 7 场景分镜,包含帧时序、构建 / 渐强逻辑、最高级与百分位文案模式,以及 9:16 安全区域示意图。
  • references/remotion-recipes.md — 可运行的场景组件:交错显示的前 X 名列表、百分位条形图、使用 <Series> 编排场景、转场、字体,以及避免闪烁的动画规则。
  • references/batch-pipeline.md — CSV/JSON → 多个 MP4:schema 验证、渲染循环、并发、Lambda 扇出和文件命名。

评论

支持 Markdown