Communitygithub.com

gbax316/vidtsx-2d-generator

根据镜头、场景或视频描述,生成可用于 VidTSX(基于 Remotion)的生产级 2D TSX 视频文件。

vidtsx-2d-generator 是什么?

此技能能够根据用户对镜头、场景或视频的描述,自动生成生产就绪的 2D TSX 视频文件,这些文件是 VidTSX 平台(基于 Remotion)使用的 React 组件。它支持多种尺寸预设(横屏、竖屏、正方形)和六种风格预设(极简、孟菲斯、新粗野主义、玻璃拟态、霓虹/赛博朋克、企业商务)。该技能严格遵循一系列硬性规则以确保渲染成功,例如仅使用基于帧的动画(禁止 useState/useEffect/setTimeout)、interpolate 输入范围必须严格单调递增、Easing 必须使用 Easing.bezier() 而不能使用包装语法,以及 chroma-js 和 @remotion/paths 的正确导入方式。它适用于从文字描述创建标题卡片、动画片段或运动图形,但不适用于 3D/three.js 合成、普通 React 开发或视频编辑。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/gbax316/shorts-director/tree/main/.claude/skills/vidtsx-2d-generator

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

VidTSX 2D 视频生成器

根据镜头或视频的描述,为 VidTSX 生成生产就绪的 2D TSX 视频文件。这些文件是 Remotion 合成组件,VidTSX 会逐帧渲染它们,因此正确性比精巧更重要:单个非单调的 interpolate 范围或一个多余的 useState 都会导致渲染崩溃。

此技能涵盖 2D 运动图形。3D 工作(@remotion/three / React Three Fiber)不在范围内。

如何使用此技能

  1. 明确的单个镜头 → 直接生成 .tsx 文件。
  2. 复杂、多镜头或视觉描述模糊的请求 → 先简短确认镜头拆分或视觉方向,然后再生成。不要过度询问,一行确认就足够了。
  3. 交付为实际的 .tsx 文件,而非内联代码。这些 TSX 组件通常超过 20 行,用户会直接编辑这些文件。默认每个文件一个镜头(原子化,易于编辑),除非用户要求一个统一的交付物。
  4. 文件仅包含组件代码 — 欢迎添加下面标注的结构性节注释,但文件内不要有 Markdown 围栏或散文式解释。
  5. 渲染并查看后再宣布完成 — 请参阅 验证渲染结果。仅凭推理得出的镜头不算完成;静帧(对于亮相和滚动动画,还需每个提示点的帧)是验收标准。

输出规范

尺寸预设

格式宽度高度用途
横屏19201080YouTube、演示文稿
竖屏10801920TikTok、Reels、短视频
正方形10801080Instagram 信息流

默认值

  • 格式: 横屏 (1920×1080)
  • 时长: 5 秒
  • 帧率: 30
  • 风格: 极简(参见 references/style-presets.md)

强制性文件结构

每个生成的文件都遵循此骨架。带标签的节注释是有意为之的——它们能让大文件保持可导航性。

import React from 'react';
import {
  useCurrentFrame,
  useVideoConfig,
  interpolate,
  Easing,
  AbsoluteFill,
  Sequence,
} from 'remotion';

// =============================================================================
// 合成配置
// =============================================================================
export const compositionConfig = {
  id: 'ComponentName', // 仅限帕斯卡命名法 — 不能包含连字符或下划线
  durationInSeconds: 5,
  fps: 30,
  width: 1920,
  height: 1080,
};

// =============================================================================
// 样式常量
// =============================================================================
const COLORS = {
  primary: '#6366f1',
  secondary: '#8b5cf6',
  accent: '#06b6d4',
  background: '#0f0f23',
  text: '#ffffff',
} as const;

const TYPOGRAPHY = {
  fontFamily: 'Inter, system-ui, sans-serif',
} as const;

const EASINGS = {
  easeOut: Easing.bezier(0.33, 1, 0.68, 1),
  easeIn: Easing.bezier(0.32, 0, 0.67, 0),
  easeInOut: Easing.bezier(0.37, 0, 0.63, 1),
  overshoot: Easing.bezier(0.34, 1.56, 0.64, 1),
} as const;

// =============================================================================
// 预生成数据(在模块级别计算一次,而非渲染期间)
// =============================================================================
const seededRandom = (seed: number): number => {
  const x = Math.sin(seed * 9999) * 10000;
  return x - Math.floor(x);
};

// =============================================================================
// 主组件
// =============================================================================
const ComponentName: React.FC = () => {
  const frame = useCurrentFrame();
  const { fps, durationInFrames, width, height } = useVideoConfig();

  return (
    <AbsoluteFill style={{ backgroundColor: COLORS.background }}>
      {/* 内容 */}
    </AbsoluteFill>
  );
};

export default ComponentName;

将 ComponentName 替换为描述镜头的帕斯卡命名名称,从所选风格预设设置 COLORS 块,并根据请求设置 width/height/durationInSeconds/fps。


正确性规则

这些不是风格偏好——它们是渲染成功的关键。VidTSX(通过 Remotion)通过在固定的帧号调用组件来渲染每一帧。没有事件循环,帧之间没有持久性,也没有挂钟时间。任何假设这些存在的代码都会出错。

动画始终基于帧

  • 所有运动必须由 useCurrentFrame() + interpolate() 驱动。
  • 切勿使用 useState、useEffect、setTimeout、setInterval 或 CSS 动画/过渡。它们不适合逐帧渲染模型,会产生错误或非确定性的输出。
  • 对于任何随机或程序化内容,使用 seededRandom(或等效的种子化函数),以确保给定帧的每次渲染都相同。在模块级别预生成粒子/随机数组,切勿在渲染函数内部——逐帧重新计算会导致闪烁。
  • 交错动画,使元素按顺序进入而非同时出现。这样效果更好,也是预期的外观。

interpolate — 输入范围必须严格递增

interpolate 的输入范围必须严格单调递增。重复或递减的值会在运行时抛出错误。

// ✅ 正确
interpolate(frame, [0, 30, 60], [0, 1, 0]);

// ❌ 抛出错误 — 输入范围递减
interpolate(frame, [60, 30, 0], [0, 1, 0]);

要反转映射,请翻转输出范围,切勿翻转输入范围:

// ✅ 正确 — 映射 0→100, 1→0
interpolate(value, [0, 1], [100, 0]);

// ❌ 错误
interpolate(value, [1, 0], [100, 0]);

对于基于索引的计时,确保 startFrame < endFrame 并始终进行钳位:

const startFrame = index * 30;
const endFrame = startFrame + 30;
interpolate(frame, [startFrame, endFrame], [0, 1], {
  extrapolateLeft: 'clamp',
  extrapolateRight: 'clamp',
});

始终传递 extrapolateLeft: 'clamp' 和 extrapolateRight: 'clamp',除非确实需要无界值——没有它们,值会在关键帧之前/之后超出范围。

Easing — 使用 Easing.bezier(),切勿使用包装语法

像 Easing.out(Easing.cubic) 这样的包装形式会崩溃。只定义一次命名贝塞尔曲线(请参见骨架中的 EASINGS 块)并引用它们:

// ❌ 崩溃
Easing.out(Easing.cubic);
Easing.in(Easing.quad);

// ✅ 正确
interpolate(frame, [0, 30], [0, 1], {
  easing: EASINGS.easeOut,
  extrapolateRight: 'clamp',
});

chroma-js — 仅限命名空间导入

// ✅ 正确
import * as chroma from 'chroma-js';
const color = chroma('#00bfff').brighten(0.5).hex();

// ❌ 错误 — "chroma is not a function"
import chroma from 'chroma-js';

@remotion/paths — 仅存在实际函数

这些辅助函数不存在且绝不能使用: makeCircle()、makeRect()、makeTriangle()、makeLine()、makePie()、makePolygon()、makeEllipse()、makeStar()。

只有这些导入是有效的:

import { evolvePath, getLength, getPointAtLength, getTangentAtLength } from '@remotion/paths';

手动编写 SVG 路径字符串并使用 evolvePath 对其进行动画处理:

const circlePath = 'M 50 10 A 40 40 0 1 1 49.99 10 Z';
const rectPath = 'M 0 0 L 100 0 L 100 50 L 0 50 Z';
const linePath = 'M 0 0 L 100 100';

const { strokeDasharray, strokeDashoffset } = evolvePath(progress, rectPath);

合成 ID

compositionConfig.id 仅限帕斯卡命名法 — 不能包含连字符,不能包含下划线(例如 ProductReveal,而不是 product-reveal 或 product_reveal)。


布局

安全区域

  • 顶部 10%: 为平台 UI 预留。
  • 底部 15%: 为字幕/按钮预留。
  • 将主要内容保持在垂直方向的 25%–75% 之间。

居中对齐辅助

const centered: React.CSSProperties = {
  position: 'absolute',
  top: '50%',
  left: '50%',
  transform: 'translate(-50%, -50%)',
};

排版

元素字号字重
标题72–120px700–900
副标题36–48px500–700
正文28–36px400–500

始终在文本元素上设置 margin: 0 — 浏览器默认值会使布局偏离中心。


风格预设

在此仓库中,默认使用品牌风格,而非某个预设。 镜头从 remotion/src/brand.ts 导入 COLORS、GRADIENT、RADIUS、SHADOW、EASINGS,并从 remotion/src/fonts.ts 导入 FONT_HEADLINE、FONT_DISPLAY、FONT_BODY、FONT_MONO,而非使用骨架中的本地 COLORS/TYPOGRAPHY 块,并遵循 brand.md。FONT_HEADLINE (Instrument Serif) 只有一个字重:决不要给它设置 fontWeight。除非镜头的 compositionConfig 指定了 ground: 'night',否则镜头位于日间底板上;工具包组件(lib/shorts.tsx、BrandBg)从中选取颜色,因此对于您自己设置的任何颜色,请从 brand.ts 中读取 useGround()。

当用户指定风格时,从 references/style-presets.md 加载其调色板和特性,并将 COLORS 对象放入骨架中。六种预设为:极简、孟菲斯、新粗野主义、玻璃拟态、霓虹/赛博朋克和企业商务。如果未指定风格,则使用上述品牌风格。


验证渲染结果(不可跳过)

在查看过之前,镜头不算完成。编写完 .tsx 后,至少渲染一张静帧并打开它——永远不要交付仅凭推理得出的镜头。渲染成功且数字看起来正确,但文本溢出其卡片、图像裁剪位置错误、元素超出屏幕或两个元素重叠。只有截图才能捕获这些问题。

  • 渲染一张静帧(例如 node scripts/render-all.mjs --still --scale=1 <ShotId>)并读取 PNG。
  • 对于基于时间的呈现(元素在提示点进入、滚动、分段阶段),仅渲染一张 60% 时长处的静帧是不够的——渲染完整剪辑并在每个关键时刻提取帧(ffmpeg -ss <t> -i out/<id>.mp4 -frames:v 1 f.jpg),或在多个偏移处渲染静帧。验证每个提示点的状态,而不仅仅是一帧。
  • 特别检查:图像适合其槽位(没有重要内容被裁剪;对于异构真实图像,优先使用匹配背景上的 objectFit: contain),文本未被裁剪或溢出,没有元素超出安全区域,并且每个动画元素在其应该可见时确实可见。
  • 如果它与其他素材合成,请也抽查最终合成输出的一帧,而不仅仅是孤立的镜头。

修复截图揭示的问题,然后重新渲染并再次查看。将“我渲染了它,看起来正确”并附上显示的帧视为完成的验收标准。


最终输出

生成完整的 .tsx 文件,文件内不包含其他任何内容——文件本身中没有周围的 Markdown、没有代码前后的注释。在聊天中移交文件时,可以附带简短的一行说明。

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

gbax316/make-ai-short

Build a GENERATIVE-pixels vertical short (1080×1920, ~35-40s) end-to-end — a recurring locked character animated by a fal video model (Seedance 1.5 Pro default) under a philosophical/story VO, composited in Remotion with word-synced captions, SFX audition, seamless frame-0==last-frame loop. Use when the user wants to "make an AI video short", "make an ai short", "make a blue-man video", or any short where the pixels come from a VIDEO MODEL — not TSX animation (that is make-short) and not layered collage (that is make-vox). Defers model choice re-litigating to ai-shorts/IDEAS.md, TSX crash rules to vidtsx-2d-generator, SFX taste to suggest-sfx + brand §7. For a NEW short (writers' room, dialogue skits, documentaries, mixed render paths), start with shorts-director, which calls this track as an engine.

gbax316/shorts-director

Directs a faceless vertical short from idea to finished, mastered file, and gets better with every run. Picks a format, writes the episode in a writers' room (three premises judged as the buyer), voices it, gates on an animatic, then decides beat by beat how each moment is made: drawn in code in Remotion, a cut-out from a generated still, a generated clip, or one of the engine tracks. Modes: series, writers-room, produce, sound, finish, bakeoff, effects (/effects), improve (the learning loop after every short). Formats so far: character skit with dialogue and synced mouths, photoreal mini documentary with sourced figures. Triggers on "make a short", "next episode", "make a video about X", "faceless video", "reel for this offer". Do NOT trigger for editing an existing video file, for a pure code-drawn explainer with no writers' room (make-short), or for collage (make-vox).

相关技能