-
-
Save jthrilly/7c5da2eb85ec1c6848f905f213b974ed to your computer and use it in GitHub Desktop.
Record gsap animations frame by frame with puppeteer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "gsap-to-video", | |
"version": "1.0.0", | |
"main": "index.js", | |
"license": "MIT", | |
"dependencies": { | |
"fs-extra": "^7.0.0", | |
"puppeteer": "^1.7.0" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict' | |
// https://github.com/clipisode/puppeteer-recorder/blob/master/index.js | |
const puppeteer = require('puppeteer') | |
const { spawn } = require('child_process') | |
const fs = require('fs-extra') | |
const ANIM_URL = 'https://ipfs.infura.io/ipfs/QmR2gXZz98sQyAtvgK4dGEy8pVXLaKyojcQUe5FVX9WCZu/dist/' | |
const FPS = 60 | |
const WIDTH = 1280 | |
const HEIGHT = 720 | |
const SAVE_IMG = true | |
// x1.5 => 1080p | |
// x3 => 4k | |
// x6 => 8k | |
const SCALE = 1 | |
const getRes = (scale = SCALE) => ({ | |
1: 'hd', | |
'1.5': 'fullhd', | |
3: '4k', | |
6: '8k' | |
})[scale] | |
const filename = () => { | |
if (!getRes()) { | |
throw Error(`Invalid scale, must be one of these: ${Object.keys(res).join()}`) | |
} | |
return `video-${getRes()}.mov` | |
} | |
SAVE_IMG && fs.emptyDir(`./frames-${getRes()}`) | |
const args = [ | |
'-y', | |
'-f', | |
'image2pipe', | |
'-r', | |
`${FPS}`, | |
'-i', | |
'-', | |
'-pix_fmt', | |
'yuv420p', | |
'-crf', | |
'2', | |
filename() | |
] | |
const ffmpeg = spawn('ffmpeg', args) | |
const closed = new Promise((resolve, reject) => { | |
ffmpeg.on('error', reject) | |
ffmpeg.on('close', resolve) | |
}) | |
ffmpeg.stdout.pipe(process.stdout) | |
ffmpeg.stderr.pipe(process.stderr) | |
const write = (stream, buffer) => | |
new Promise((resolve, reject) => { | |
stream.write(buffer, error => { | |
if (error) return reject(error) | |
resolve() | |
}) | |
}) | |
;(async () => { | |
const browser = await puppeteer.launch({ headless: true }) | |
const page = await browser.newPage() | |
await page.setViewport({ | |
width: WIDTH, | |
height: HEIGHT, | |
deviceScaleFactor: SCALE | |
}) | |
await page.goto(ANIM_URL) | |
await page.waitForFunction(() => typeof window.timeline !== 'undefined') | |
const frames = await page.evaluate(async fps => | |
Math.ceil(window.timeline.duration() / 1 * fps) | |
, FPS) | |
let frame = 0 | |
// pause and reset | |
await page.evaluate(() => { | |
window.timeline.pause() | |
window.timeline.progress(0) | |
}) | |
const nextFrame = async () => { | |
await page.evaluate(async progress => { | |
window.timeline.progress(progress) | |
await new Promise(r => setTimeout(r, 16)) | |
}, frame / frames) | |
const filename = (`${frame}`).padStart(6, '0') | |
const opts = SAVE_IMG ? { path: `./frames-${getRes()}/frame${filename}.png` } : undefined | |
const screenshot = await page.screenshot(opts) | |
await write(ffmpeg.stdin, screenshot) | |
frame++ | |
console.log(`frame ${frame} / ${frames}`) | |
if (frame > frames) { | |
console.log('done!') | |
await browser.close() | |
ffmpeg.stdin.end() | |
await closed | |
return | |
} | |
nextFrame() | |
} | |
nextFrame() | |
})() |
i have an issue regarding two animation at a time, for example tl.from("#sample1",0.5,{y:100,optacity:0,scale:0,ease:Linear.easeOut,delay:0}).to("#sample2",0.5, {y:100,ease:Linear.easeIn,autoAlpha:0,delay:1});
what problem in this.
it's not working
This fork was just for my reference. You should post your question to the author: https://gist.github.com/mallendeo/8f589d9e828ebfec287a77be71b6c4d3
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
i have an issue regarding two animation at a time, for example tl.from("#sample1",0.5,{y:100,optacity:0,scale:0,ease:Linear.easeOut,delay:0}).to("#sample2",0.5, {y:100,ease:Linear.easeIn,autoAlpha:0,delay:1});
what problem in this.
it's not working