promo-video
Record a high-FPS autonomous promo video of a Phaser game using Playwright. Triggers on: promo video, gameplay recording, marketing video, game capture.
By playableintelligence · 728 installs
npx skills add playableintelligence/game-creator --skill promo-video
Source repository · Upstream listing
Promo Video Recording
Record smooth, autonomous promo footage of a Phaser game for marketing / social media. The output is a 50 FPS MP4 in mobile portrait (9:16) — ready for TikTok, Reels, Moltbook, or X.
Technique
Playwright's recordVideo caps at 25 FPS with no config option. We work around it:
1. Slow the game to 0.5× by patching all 5 Phaser time subsystems
2. Record for 2× the desired duration at Playwright's native 25 FPS
3. FFmpeg speed up 2× → effective 50 FPS output
Parameter Default Effect
SLOW MO FACTOR 0.5 Game runs at half speed → 50 FPS output
WALL CLOCK DURATION DESIRED GAME DURATION / SLOW MO FACTOR Record for 2× to get correct game time
VIEWPORT { width: 1080, height: 1920 } 9:16 mobile portrait (always default unless user specifies otherwise)
DESIRED GAME DURATION 13000 (ms) ~13s of game time → ~6.5s promo clip
Prerequisites
Playwright — must be installed ( npm install D @playwright/test && npx playwright install chromium )
FFmpeg — must be available on PATH ( brew install ffmpeg on macOS)
Dev server running — game must be served on localhost
Check both before starting:
If FFmpeg is not found, warn the user and skip the promo video step (it's non blocking — the game still works without it).
Capture Script — Game Specific Adaptation
Every game gets a custom scripts/capture promo.mjs . The subagent must read the game's source files to determine:
1. Death/Failure Patching (CRITICAL)
The video must show continuous gameplay — never game over. Read GameScene.js (or equivalent) to find the death/failure method and monkey patch it out.
How to find it : Search for the method called on collision/death. Common patterns:
this.triggerGameOver() — dodge games
this.takeDamage() → this.lives <= 0 — multi life games
this.gameOver() — direct call
eventBus.emit(Events.PLAYER HIT) / eventBus.emit(Events.GAME OVER) — event driven
Patch template (adapt per game):
2. Input Sequence Generation
The video must show dynamic, natural looking gameplay. Read the game's input handling to determine:
Which keys — ArrowLeft/ArrowRight? Space? WASD? Mouse clicks?
Input style — continuous hold (movement), tap (jump/shoot), or both?
Movement pattern — should the player sweep across the screen, dodge reactively, jump rhythmically?
Input patterns by game type:
Game Type Input Keys Pattern
Side dodger ArrowLeft, ArrowRight Alternating holds (150 600ms) with variable pauses, occasional double taps
Platformer / Flappy Space Rhythmic taps (80 150ms hold) with variable gaps (200 800ms)
Top down WASD / Arrows Mixed directional holds, figure eight patterns
Shooter ArrowLeft/Right + Space Movement interleaved with rapid fire
Clicker/Tapper Mouse click / Space Rapid bursts separated by brief pauses
Randomize timing to avoid robotic looking movement:
Add a pause at the start (1 2s) to let the entrance animation play — this is the hook.
3. Game Boot Detection
All Phaser games built with the /viral game or /make game pipelines expose these globals:
window. GAME — Phaser.Game instance
window. GAME STATE — GameState singleton
window. EVENT BUS — EventBus singleton
Wait for both boot and active gameplay:
4. Time Scaling Injection
Slow all 5 Phaser time subsystems for the recording:
The 5 subsystems:
1. Update delta — scene.update(time, delta factor) slows frame delta dependent logic
2. Tweens — scene.tweens.timeScale slows all tween animations
3. Scene timers — scene.time.timeScale slows scene.time.addEvent() timers
4. Physics — scene.physics.world.timeScale slows Arcade/Matter physics (uses inverse: 1/factor )
5. Animations — scene.anims.globalTimeScale slows sprite animation playback
5. Video Finalization
Full Capture Script Template
FFmpeg Conversion
After recording, convert the raw slow mo WebM to a high FPS MP4. The convert highfps.sh script is bundled with this skill at skills/promo video/scripts/convert highfps.sh .
The script:
Applies setpts to speed up the video by 1/factor
Sets output framerate to 25 / factor (= 50 FPS for 0.5× slow mo)
Encodes H.264 with crf 23 , yuv420p , faststart
Verifies output duration, frame rate, and file size
Viewport Defaults
Always record in mobile portrait (9:16) unless the user explicitly requests otherwise. Rationale:
Games are played on phones — promo footage should show the real mobile experience
9:16 is native for TikTok, Instagram Reels, YouTube Shorts
1080×1920 is the standard resolution
Aspect Ratio Viewport Use Case
9:16 (default) 1080 × 1920 Mobile portrait — TikTok, Reels, Shorts, Moltbook
1:1 1080 × 1080 Square — Instagram feed, X posts
16:9 1920 × 1080 Landscape — YouTube, trailers, desktop games
Duration Guidelines
Game Type Recommended Duration Why
Arcade / dodger 10 15s Fast action, multiple dodge cycles
Platformer 15 20s Show jump timing, level progression
Shooter 12 18s Show targeting, enemy waves
Puzzle 8 12s Show one solve sequence
Checklist
Before running the capture:
[ ] Dev server is running and responding
[ ] FFmpeg is installed on the system
[ ] Playwright is installed with Chromium
[ ] Game boots directly into gameplay (no menu blocking)
[ ] Death/failure method identified and patched
[ ] Input keys match the game's actual controls
[ ] Entrance animation pause is included (1 2s)
[ ] Output directory exists
After capture:
[ ] Raw WebM exists in output/
[ ] FFmpeg conversion produces valid MP4
[ ] Duration is ~half the raw recording (speed up worked)
[ ] Frame rate is 50 FPS
[ ] Video shows gameplay (not a black screen)