mcpField
C
countdown-video

countdown-video

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

关于 countdown-video

countdown-video 是用于制作 Remotion 视频和网页倒计时的技能,面向视频制作者与网页开发者。它按帧或时钟计算剩余时间以避免计时漂移,并涵盖数字动画、循环背景和输出检查。

主要功能

  1. 01按帧驱动 Remotion 倒计时
  2. 02基于时钟的网页计时器
  3. 03可配置时间格式
  4. 04数字滚轮与翻页效果
  5. 05无缝循环背景
  6. 06渲染与 MP4 验证

适用场景

  1. 01直播即将开始画面
  2. 02发布与限时促销倒计时
  3. 03指定日期倒计时

安装

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

$npx skills add https://github.com/iart-ai/tiktok-video-skills --skill countdown-video

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

包含的文件

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

README.md
references/
countdown-cookbook.md
digit-flip.md

详细介绍

倒计时视频

制作一个恰好在预定时刻结束的倒计时。整个技巧只有一个核心:根据帧(或单调时间戳)计算剩余时间,然后格式化并为数字添加动画——绝不要用 setInterval 倒计时。适用于直播“即将开始”画面、发布/促销倒计时和循环背景。

适用场景

  • 带 5–10 分钟计时器的“即将开始”/“马上回来”直播画面。
  • 发布和限时促销倒计时(从 dd:hh:mm:ss 倒数到目标日期;紧迫感倒计时用 mm:ss)。
  • 任何要求数字恰好在某一帧归零的动画计数器。

唯一规则:数字由时钟驱动,绝不依赖计时滴答

setInterval(fn, 1000) 倒计时会产生漂移——回调至少会在 1000 ms 后触发,而非恰好在此时触发;如果标签页受到节流或渲染帧较慢,还会不断累积偏差。每分钟少掉约 1 秒的情况很常见。无论是渲染视频还是实时网页,解决方法都相同:将剩余时间计算为权威时钟的纯函数,这样迟到的帧会在下一帧自行校正,而不是累积误差。

场景权威时钟剩余时间
Remotion 渲染useCurrentFrame()total − frame/fps
Web(实时页面)performance.now() 或 Date.now()targetMs − now
倒计时至固定日期Date.now()targetTimestamp − Date.now()

绝不要在状态中存储剩余时间并递减。每帧都重新计算。

帧级精准倒计时(Remotion → MP4)

useCurrentFrame() 是确定性的:第 N 帧始终恰好在 N/fps 秒处渲染。从总时长中减去已过时间,计时器从原理上就不会产生漂移。

import { useCurrentFrame, useVideoConfig } from "remotion";

export const Countdown: React.FC<{ durationInSeconds: number }> = ({
  durationInSeconds,
}) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();

  // remaining seconds, clamped at 0 — ceil so "1" shows for its full second
  const elapsed = frame / fps;
  const remaining = Math.max(0, Math.ceil(durationInSeconds - elapsed));

  return <div style={{ fontVariantNumeric: "tabular-nums" }}>{formatMMSS(remaining)}</div>;
};

durationInSeconds 是一个属性,而非常量——只需更改一个输入,同一个合成就能渲染 5 分钟的直播计时器或 30 秒的促销计时器。将合成的 durationInFrames 设为 durationInSeconds * fps,这样视频长度就与倒计时完全一致。

Web 计时器(实时页面,requestAnimationFrame)

对于实时页面,使用 performance.now() 驱动 rAF 循环,并且只在显示的秒数发生变化时重绘(对于 1 Hz 的数字,无需每秒工作 60 次):

const start = performance.now();
let lastShown = -1;
function tick(now) {
  const remaining = Math.max(0, Math.ceil(duration - (now - start) / 1000));
  if (remaining !== lastShown) { render(remaining); lastShown = remaining; }
  if (remaining > 0) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);

倒计时至固定日期的思路相同,只需使用 Date.now():Math.max(0, target - Date.now())。完整的日期目标版本(含时区处理)请参阅 references/countdown-cookbook.md。

时间格式化

通过除法和取模将剩余秒数拆分为各字段,然后补零。选择适合时长的格式——当分钟数已足够时,绝不要显示 00d 00h 05m。

const pad = (n) => String(n).padStart(2, "0");
const formatMMSS = (s) => `${pad(Math.floor(s / 60))}:${pad(s % 60)}`;
const formatDHMS = (s) => {
  const d = Math.floor(s / 86400), h = Math.floor((s % 86400) / 3600);
  const m = Math.floor((s % 3600) / 60), sec = s % 60;
  return `${pad(d)}:${pad(h)}:${pad(m)}:${pad(sec)}`;
};
格式用途省略字段的条件
mm:ss直播“即将开始”、短时计时(<1h)—
hh:mm:ss限时促销、当天活动dd 为 0 时隐藏
dd:hh:mm:ss发布/多日倒计时隐藏前导的 0 单位,让显示更简洁

始终设置 font-variant-numeric: tabular-nums(或使用等宽数字字体),让数字宽度相同,避免数字变化时布局抖动。

数字滚动/翻转过渡

直接替换数字看起来很廉价;滚轮式“里程表”效果更能体现倒计时质感。将每个数字渲染为包含 0–9 的垂直条带,并按 -digit × digitHeight 对其进行平移。为位置添加动画,而不是为文本内容添加动画,这样数字变化时就会平滑滑动,而非突然跳变。

.reel { height: 1em; overflow: hidden; }
.reel .col { transition: transform .45s cubic-bezier(.22,1,.36,1); }
/* col holds stacked 0..9; shift by -value em */

在 Remotion 中,应根据帧驱动条带偏移,而不是使用 CSS 过渡(这样才能确保结果具有确定性)。翻页卡片样式(上半部分向下翻到下半部分上方)和逐位数字转轮的详细说明及可运行组件,均见 references/digit-flip.md。

循环背景

直播画面会持续数分钟,因此背景必须无缝循环。让动画以能被时间线整除的周期运行(例如周期为 loopFrames 的渐变或粒子漂移),并通过 frame % loopFrames 读取动画进度,确保循环时没有可见接缝。保持低对比度和缓慢运动——数字才是主体,背景只是氛围。配方见 references/countdown-cookbook.md。

输出检查清单

  • 每帧都根据 useCurrentFrame() / performance.now() 重新计算剩余时间——不使用 setInterval 递减。
  • 计时器在精确的目标帧显示 00:00;durationInFrames === durationInSeconds × fps。
  • 时长是输入属性,而不是硬编码常量。
  • 数字使用 tabular-nums;数字变化时布局不会偏移。
  • 格式与时长范围相符(mm:ss 或 dd:hh:mm:ss);容易造成干扰时省略前导零单位。
  • 背景循环周期可均匀分割整个时间轴;循环衔接处没有断点。

交付与验证(渲染静帧 → 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。

倒计时以 Remotion 合成(<Composition> + zod schema + defaultProps,durationInSeconds 为属性)的形式交付——计时器是 useCurrentFrame() 的纯函数,绝不使用 setInterval / Date.now() / Math.random()。设置 durationInFrames = durationInSeconds * fps。交付物 = out/*.mp4 + 项目。默认采用 9:16 竖屏(1080×1920)。

验证流程——渲染静帧 → 检查 → 编码。 核心要求是帧精确,因此编码前请检查精确帧上的数字值。

# Stills at start / mid / end — WITH SHIPPED PROPS (the real duration you'll render)
npx remotion still Countdown out/f-start.png --frame=0   --props='{"durationInSeconds":300}'
npx remotion still Countdown out/f-mid.png   --frame=N   --props='{"durationInSeconds":300}'
npx remotion still Countdown out/f-end.png   --frame=L   --props='{"durationInSeconds":300}'  # L = durationInFrames-1

# Inspect each PNG — the digits must read EXACTLY the frame/fps math:
#  - at frame N, displayed = ceil(durationInSeconds - N/fps)  (e.g. 300s @ 30fps, frame 4500 → 150s → "02:30")
#  - last frame reads 00:00 (or the end-state hold); no drift, no off-by-one second
#  - tabular-nums: layout does not jitter between frames
#  - 9:16 safe area: the timer + brand block sit clear of top ~12% and bottom ~20-35% UI and the right action rail

npx remotion render Countdown out/countdown.mp4 --props='{"durationInSeconds":300}'   # encode once digits verify
npx remotion render Countdown out/demo.gif --codec=gif                                 # README proof clip

使用 npx remotion compositions 确认 durationInFrames / fps,然后计算要检查的任意秒数对应的帧。

完成前请确认:

  1. 第 0 帧、中间帧和最后一帧均能正常渲染静帧——没有错误。
  2. 第 N 帧的数字值精确等于 ceil(durationInSeconds - N/fps);最后一帧在目标帧显示 00:00(没有漂移或偏差一帧)。
  3. 在每个检查帧上,计时器和品牌内容均处于 9:16 安全区域内。
  4. 仅由帧驱动——不使用 setInterval / Date.now() / 计时器;使用 tabular-nums 保持布局稳定。
  5. 实际交付的 durationInSeconds(而非仅 defaultProps)能够正确渲染;MP4 已编码,GIF 可选。

参考文件

  • references/countdown-cookbook.md — 完整可运行的 Remotion <Countdown>(可配置时长、mm:ss / dd:hh:mm:ss、结束状态保持)、支持时区处理的固定日期倒计时 Web 组件、“即将开始”直播屏幕布局(品牌区块 + 社交账号 + 循环渐变背景),以及无缝循环背景图案。
  • references/digit-flip.md — 两种确定性的数字动画组件:里程表滚轮(由帧驱动的垂直 0–9 条带)和翻页卡片(上半部分折叠)效果,并说明它们分别适用于发布、促销和直播的场景。

评论

支持 Markdown