用途
promo-video 用于为 Phaser 游戏自动录制平滑、自主游玩的宣传视频,面向营销与社交媒体场景。输出为 50 FPS 的 MP4,默认采用移动端竖屏 9:16 比例,可直接用于 TikTok、Reels、Moltbook 或 X。触发关键词包括:promo video、gameplay recording、marketing video、game capture。
主要能力
- 自动启动游戏并等待其完成启动与进入游玩状态。
- 通过 Playwright 录制游戏画面,并模拟按键输入生成动态、自然的游玩过程。
- 针对具体游戏屏蔽死亡/失败逻辑,确保视频展示连续游玩、不出现 game over。
- 将游戏时间放慢至 0.5 倍后录制,再用 FFmpeg 加速 2 倍,从而绕过 Playwright 25 FPS 的上限,得到等效 50 FPS 的输出。
- 默认输出 1080×1920 的 9:16 竖屏视频。
使用方式
前置条件
- Playwright 已安装:
npm install -D @playwright/test && npx playwright install chromium - FFmpeg 在 PATH 中可用(macOS 上可用
brew install ffmpeg) - 开发服务器正在运行,游戏通过 localhost 提供服务
开始前可检查:
npx playwright --version
ffmpeg -version | head -1
若未找到 FFmpeg,应警告用户并跳过宣传视频步骤(该步骤非阻塞,游戏本身仍可正常运行)。
录制脚本适配
每个游戏需要一份自定义的 scripts/capture-promo.mjs。子代理需阅读游戏源码以确定:
-
死亡/失败逻辑屏蔽(关键):视频必须展示连续游玩,绝不出现 game over。需阅读
GameScene.js(或等价文件)找到死亡/失败方法并将其 monkey-patch 掉。常见模式包括this.triggerGameOver()、this.takeDamage()→this.lives <= 0、this.gameOver(),以及事件驱动的eventBus.emit(Events.PLAYER_HIT)/eventBus.emit(Events.GAME_OVER)。 -
输入序列生成:视频需展示动态、自然的游玩。需阅读游戏的输入处理,确定使用哪些按键(ArrowLeft/ArrowRight、Space、WASD、鼠标点击等)、输入风格(持续按住、点按或两者兼有)以及移动模式。不同游戏类型的输入模式:
| 游戏类型 | 输入按键 | 模式 |
|---|---|---|
| 侧向躲避 | ArrowLeft, ArrowRight | 交替按住(150-600ms),带可变停顿,偶尔双击 |
| 平台/Flappy | Space | 有节奏的点按(按住 80-150ms),间隔可变(200-800ms) |
| 俯视 | WASD / 方向键 | 混合方向按住,八字形模式 |
| 射击 | ArrowLeft/Right + Space | 移动与快速射击交错 |
| 点击/点按 | 鼠标点击 / Space | 快速连发,中间短暂停顿 |
随机化时序以避免机械感:
const holdMs = 150 + Math.floor(Math.random() * 450);
const pauseMs = 50 + Math.floor(Math.random() * 250);
开头加入 1-2 秒停顿,让入场动画播放,作为吸引点。
- 游戏启动检测:通过
/viral-game或/make-game管线构建的 Phaser 游戏会暴露以下全局变量:window.__GAME__(Phaser.Game 实例)、window.__GAME_STATE__(GameState 单例)、window.__EVENT_BUS__(EventBus 单例)。需等待启动与游玩激活:
await page.waitForFunction(() => window.__GAME__?.isBooted, { timeout: 15000 });
await page.waitForFunction(() => window.__GAME_STATE__?.started, { timeout: 10000 });
- 时间缩放注入:为录制放慢全部 5 个 Phaser 时间子系统:
- Update delta —
scene.update(time, delta * factor)放慢依赖帧增量的逻辑 - Tweens —
scene.tweens.timeScale放慢所有补间动画 - Scene timers —
scene.time.timeScale放慢scene.time.addEvent()计时器 - Physics —
scene.physics.world.timeScale放慢 Arcade/Matter 物理(使用倒数:1/factor) - Animations —
scene.anims.globalTimeScale放慢精灵动画播放
- 视频收尾:调用
page.video()获取视频对象,必须关闭 context 以完成视频文件写入,再获取视频路径。
参数
| 参数 | 默认值 | 效果 |
|---|---|---|
| SLOW_MO_FACTOR | 0.5 | 游戏以半速运行 → 输出 50 FPS |
| WALL_CLOCK_DURATION | DESIRED_GAME_DURATION / SLOW_MO_FACTOR | 录制 2 倍时长以获得正确的游戏时间 |
| VIEWPORT | { width: 1080, height: 1920 } | 9:16 移动端竖屏(除非用户另有指定,否则始终为默认) |
| DESIRED_GAME_DURATION | 13000 (ms) | 约 13 秒游戏时间 → 约 6.5 秒宣传片段 |
FFmpeg 转换
录制完成后,将原始慢动作 WebM 转换为高帧率 MP4。convert-highfps.sh 脚本随本技能打包在 skills/promo-video/scripts/convert-highfps.sh。
# 复制到项目(由编排器执行)
cp <plugin-root>/skills/promo-video/scripts/convert-highfps.sh <project-dir>/scripts/
# 运行转换
bash scripts/convert-highfps.sh output/promo-raw.webm output/promo.mp4 0.5
该脚本会:应用 setpts 按 1/factor 加速视频;将输出帧率设为 25 / factor(0.5× 慢动作时为 50 FPS);使用 H.264 编码,crf 23、yuv420p、faststart;并验证输出时长、帧率和文件大小。
适用场景
- 为 Phaser 游戏制作营销或社交媒体宣传视频。
- 需要移动端竖屏、适合 TikTok、Instagram Reels、YouTube Shorts 的成片。
- 需要展示连续、自然游玩过程而不出现失败画面的演示视频。
视口默认值
除非用户明确要求,否则始终以移动端竖屏(9:16)录制。理由:游戏在手机上游玩,宣传素材应展示真实移动体验;9:16 是 TikTok、Instagram Reels、YouTube Shorts 的原生比例;1080×1920 是标准分辨率。
| 宽高比 | 视口 | 用途 |
|---|---|---|
| 9:16(默认) | 1080 × 1920 | 移动端竖屏 — TikTok、Reels、Shorts、Moltbook |
| 1:1 | 1080 × 1080 | 方形 — Instagram 信息流、X 帖子 |
| 16:9 | 1920 × 1080 | 横屏 — YouTube、预告片、桌面游戏 |
时长建议
| 游戏类型 | 建议时长 | 原因 |
|---|---|---|
| 街机/躲避 | 10-15s | 快速动作,多个躲避循环 |
| 平台 | 15-20s | 展示跳跃时机、关卡推进 |
| 射击 | 12-18s | 展示瞄准、敌人波次 |
| 解谜 | 8-12s | 展示一次解谜序列 |
限制
- 依赖 Playwright 与 FFmpeg,二者需预先安装;缺少 FFmpeg 时该步骤会被跳过。
- 需要游戏在本地开发服务器上运行,且能直接进入游玩(无菜单阻挡)。
- 每个游戏都需要自定义录制脚本,需阅读源码确定死亡方法和输入按键。
- Playwright 的 recordVideo 本身最高 25 FPS,需通过慢放加加速的方式间接实现 50 FPS。
- 录制脚本模板中的死亡屏蔽与输入序列需按具体游戏适配,不能直接通用。
检查清单
运行捕获前:开发服务器正在运行并响应;FFmpeg 已安装;Playwright 已安装并带 Chromium;游戏直接启动进入游玩(无菜单阻挡);已识别并屏蔽死亡/失败方法;输入按键与游戏实际控制匹配;包含入场动画停顿(1-2 秒);输出目录存在。
捕获后:原始 WebM 存在于 output/;FFmpeg 转换生成有效 MP4;时长约为原始录制的一半(加速生效);帧率为 50 FPS;视频展示的是游玩画面(而非黑屏)。