Skip to content

Instantly share code, notes, and snippets.

@lambdaX
Forked from mallendeo/package.json
Created October 7, 2020 20:59
Show Gist options
  • Select an option

  • Save lambdaX/72995da891200c4f501e9375bb54a468 to your computer and use it in GitHub Desktop.

Select an option

Save lambdaX/72995da891200c4f501e9375bb54a468 to your computer and use it in GitHub Desktop.

Revisions

  1. @mallendeo mallendeo revised this gist Aug 14, 2018. 2 changed files with 24 additions and 16 deletions.
    3 changes: 2 additions & 1 deletion package.json
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,10 @@
    {
    "name": "gsap-to-video",
    "version": "1.0.0",
    "main": "record.js",
    "main": "index.js",
    "license": "MIT",
    "dependencies": {
    "fs-extra": "^7.0.0",
    "puppeteer": "^1.7.0"
    }
    }
    37 changes: 22 additions & 15 deletions record.js
    Original file line number Diff line number Diff line change
    @@ -4,33 +4,38 @@

    const puppeteer = require('puppeteer')
    const { spawn } = require('child_process')
    const fs = require('fs-extra')

    const ANIM_URL = 'https://ipfs.infura.io/ipfs/QmfDgbHE3Co5AUPVkhFrgVtJNKFZijEEAgFGsgqiEHeccE/dist/'
    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 = 6

    const filename = scale => {
    const res = {
    1: 'hd',
    '1.5': 'fullhd',
    3: '4k',
    6: '8k'
    }
    if (!res[scale]) {
    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-${res[scale]}.mov`
    return `video-${getRes()}.mov`
    }

    SAVE_IMG && fs.emptyDir(`./frames-${getRes()}`)

    const args = [
    '-y',
    '-f',
    @@ -43,7 +48,7 @@ const args = [
    'yuv420p',
    '-crf',
    '2',
    filename(SCALE)
    filename()
    ]

    const ffmpeg = spawn('ffmpeg', args)
    @@ -94,7 +99,9 @@ const write = (stream, buffer) =>
    await new Promise(r => setTimeout(r, 16))
    }, frame / frames)

    const screenshot = await page.screenshot()
    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++
  2. @mallendeo mallendeo revised this gist Aug 14, 2018. 1 changed file with 17 additions and 2 deletions.
    19 changes: 17 additions & 2 deletions record.js
    Original file line number Diff line number Diff line change
    @@ -14,7 +14,22 @@ const HEIGHT = 720
    // x1.5 => 1080p
    // x3 => 4k
    // x6 => 8k
    const SCALE = 3
    const SCALE = 6

    const filename = scale => {
    const res = {
    1: 'hd',
    '1.5': 'fullhd',
    3: '4k',
    6: '8k'
    }

    if (!res[scale]) {
    throw Error(`Invalid scale, must be one of these: ${Object.keys(res).join()}`)
    }

    return `video-${res[scale]}.mov`
    }

    const args = [
    '-y',
    @@ -28,7 +43,7 @@ const args = [
    'yuv420p',
    '-crf',
    '2',
    'video.mov'
    filename(SCALE)
    ]

    const ffmpeg = spawn('ffmpeg', args)
  3. @mallendeo mallendeo revised this gist Aug 14, 2018. 2 changed files with 45 additions and 30 deletions.
    2 changes: 0 additions & 2 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -4,8 +4,6 @@
    "main": "record.js",
    "license": "MIT",
    "dependencies": {
    "fluent-ffmpeg": "^2.1.2",
    "fs-extra": "^7.0.0",
    "puppeteer": "^1.7.0"
    }
    }
    73 changes: 45 additions & 28 deletions record.js
    Original file line number Diff line number Diff line change
    @@ -1,8 +1,11 @@
    'use strict'

    // https://github.com/clipisode/puppeteer-recorder/blob/master/index.js

    const puppeteer = require('puppeteer')
    const fs = require('fs-extra')
    const ffmpeg = require('fluent-ffmpeg')
    const { spawn } = require('child_process')

    const ANIM_URL = 'https://ipfs.infura.io/ipfs/QmfDgbHE3Co5AUPVkhFrgVtJNKFZijEEAgFGsgqiEHeccE/dist/'

    const FPS = 60
    const WIDTH = 1280
    @@ -11,13 +14,42 @@ const HEIGHT = 720
    // x1.5 => 1080p
    // x3 => 4k
    // x6 => 8k
    const SCALE = 6

    const url = 'https://ipfs.infura.io/ipfs/QmfHhYQnkSXmrDZbwonwbiLq8vaoQyNhjYjJ8GFbNVYVVN/dist/'
    const SCALE = 3

    const args = [
    '-y',
    '-f',
    'image2pipe',
    '-r',
    `${FPS}`,
    '-i',
    '-',
    '-pix_fmt',
    'yuv420p',
    '-crf',
    '2',
    'video.mov'
    ]

    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 () => {
    fs.emptyDirSync('./frames')

    const browser = await puppeteer.launch({ headless: true })
    const page = await browser.newPage()

    @@ -27,7 +59,7 @@ const url = 'https://ipfs.infura.io/ipfs/QmfHhYQnkSXmrDZbwonwbiLq8vaoQyNhjYjJ8GF
    deviceScaleFactor: SCALE
    })

    await page.goto(url)
    await page.goto(ANIM_URL)
    await page.waitForFunction(() => typeof window.timeline !== 'undefined')

    const frames = await page.evaluate(async fps =>
    @@ -47,7 +79,9 @@ const url = 'https://ipfs.infura.io/ipfs/QmfHhYQnkSXmrDZbwonwbiLq8vaoQyNhjYjJ8GF
    await new Promise(r => setTimeout(r, 16))
    }, frame / frames)

    await page.screenshot({ path: `./frames/${frame}.png` })
    const screenshot = await page.screenshot()
    await write(ffmpeg.stdin, screenshot)

    frame++

    console.log(`frame ${frame} / ${frames}`)
    @@ -56,30 +90,13 @@ const url = 'https://ipfs.infura.io/ipfs/QmfHhYQnkSXmrDZbwonwbiLq8vaoQyNhjYjJ8GF
    console.log('done!')
    await browser.close()

    processVideo()
    ffmpeg.stdin.end()
    await closed
    return
    }

    nextFrame()
    }

    const processVideo = () => {
    console.log('processing video...')
    ffmpeg('./frames/%d.png')
    .inputFPS(FPS)
    .addOutputOptions([
    '-pix_fmt yuv420p',
    '-crf 18'
    ])
    .outputFPS(FPS)
    .on('error', err => {
    console.log('error', err.message);
    })
    .on('end', () => {
    console.log('video converted!')
    })
    .save('./video.mov')
    }

    nextFrame()
    })()
  4. @mallendeo mallendeo created this gist Aug 14, 2018.
    11 changes: 11 additions & 0 deletions package.json
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    {
    "name": "gsap-to-video",
    "version": "1.0.0",
    "main": "record.js",
    "license": "MIT",
    "dependencies": {
    "fluent-ffmpeg": "^2.1.2",
    "fs-extra": "^7.0.0",
    "puppeteer": "^1.7.0"
    }
    }
    85 changes: 85 additions & 0 deletions record.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,85 @@
    'use strict'

    const puppeteer = require('puppeteer')
    const fs = require('fs-extra')
    const ffmpeg = require('fluent-ffmpeg')

    const FPS = 60
    const WIDTH = 1280
    const HEIGHT = 720

    // x1.5 => 1080p
    // x3 => 4k
    // x6 => 8k
    const SCALE = 6

    const url = 'https://ipfs.infura.io/ipfs/QmfHhYQnkSXmrDZbwonwbiLq8vaoQyNhjYjJ8GFbNVYVVN/dist/'

    ;(async () => {
    fs.emptyDirSync('./frames')

    const browser = await puppeteer.launch({ headless: true })
    const page = await browser.newPage()

    await page.setViewport({
    width: WIDTH,
    height: HEIGHT,
    deviceScaleFactor: SCALE
    })

    await page.goto(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)

    await page.screenshot({ path: `./frames/${frame}.png` })
    frame++

    console.log(`frame ${frame} / ${frames}`)

    if (frame > frames) {
    console.log('done!')
    await browser.close()

    processVideo()
    return
    }

    nextFrame()
    }

    const processVideo = () => {
    console.log('processing video...')
    ffmpeg('./frames/%d.png')
    .inputFPS(FPS)
    .addOutputOptions([
    '-pix_fmt yuv420p',
    '-crf 18'
    ])
    .outputFPS(FPS)
    .on('error', err => {
    console.log('error', err.message);
    })
    .on('end', () => {
    console.log('video converted!')
    })
    .save('./video.mov')
    }

    nextFrame()
    })()