maxwellito / vivus

JavaScript library to make drawing animation on SVG
MIT License
15.25k stars 1.13k forks source link

Export animated svg as .mov or .mp4 #228

Open michaelrommel opened 4 years ago

michaelrommel commented 4 years ago

Dear maxwellito,

thank you very much for the library and the vivus instant website - it is a joy to use!

I wondered, if there are any recommendations or best practises, when one wants to export the animated svg into a video with a defined resolution (FullHD or 4K).

At the moment I have embedded the resulting svg in a website and perform a screen recording while the browser plays the animation. I encountered two difficulties:

  1. Timing

When the animation is being played back too quickly, the screen recorder misses frames and the resulting video is yanky. I overcame this by having the exported animation from vivus instant set to a 4x longer time, then I post process the recorded animation and speed it up 4x. This produced good results. Also, if I record on a 4KTV with a 60HZ refresh rate, the grabbed video is more yanky, than when I record it on a 120 Hz refresh rate monitor. After the post processing, though, both are practically the same.

  1. Resolution

Because of the screen grabbing, I actually can only record in resolutions below the monitor's resolution and lose a bit of detail.

Therefore I was looking for a way to export the animated frames into a movie (or a series of image, that I could then import into Final Cut). Does anyone know about any such solution?

Thank you in advance. If this is not the right way to ask for help, please feel free to tell me, I will then close this issue.

All the best,

Michael.

maxwellito commented 4 years ago

Hello Michael,

First, thanks for your kind words. Its always nice to hear from users :)

Your issue is a very interesting one. I must admit, I had to think about a solution for a similar problem but never had the chance to implement it.

Let's start by the library constraints. Vivus uses requestAnimationFrame to time intervals between frames. Depending on your machine/SVG complexity the frame rate might vary. In this case it will be difficult to increase the frame rate as you need.

My guess, to make it possible, would be the following stack:

I dunno if it's what you had in mind. I'm happy to give more details and help you start the project.

I hope this helps :)

michaelrommel commented 4 years ago

Hi,

thank you for your speedy reply - I also thought about puppeteer, as I am using this already for GUI tests. But I looked into animTimingFunction instead of the setFrameProgress function - so I will give that a try. If I read this correctly, then let's say given I want a roughly 2 sec intro of a video in 60p I would run the argument to that function from 0 to 1 in 0.008 increments which results in 125 images. I will give that a try next weekend and let you know how it went. Right now I am busy with work...

Thanks for the helpful hint!

Michael.

maxwellito commented 4 years ago

You can definitely override window.requestAnimationFrame (before loading Vivus) by something like (fn) => setTimeout(fn, 1000/120). However your computer must be tough enough to generate the frames at the right time. Otherwise, you can slow down the timeout to 10 frames a second, and accelerate it on Final Cut.

netsi1964 commented 4 years ago

Perhaps if you added an event to Vivus, so that for every frame you triggered an event frame which people then could hook into? Using something like Puppeteer then, you might generate a screenshoot of that current frame.

maxwellito commented 4 years ago

It's something doable with the base API

// Init the Vivus instance
const duration = 200;
const myVivus = new Vivus('svgId', {duration, start: 'manual'});
let currentFrame = 0;

// Function to move to the next frame
// Will return 'true' once the last frame is reached
function nextFrame () {
  myVivus.setFrameProgress((currentFrame++)/duration);
  return currentFrame === duration;
}
jdexyz commented 3 years ago

Hi, I ended up making a super quick and dirty Electron app to solve this very issue. https://github.com/jeremypatrickdahan/vivus-electron

It is essentially a giant security hole, so never use this in production or with untrusted svg files... It is quite difficult to preserve transparency with video. I ended up using a quicktime codec (qtrle), though webm also works.

Ho, and resolution is set at 2K, although it is quite easy to change. It is easy to modify to only get the PNG sequence to import it in a video editor.

EDIT : I had some more time to play with this. This quick app is actually for a relative, who uses an iPad for video editing. So I needed to export everything as HEVC with an alpha channel, which is only possible on macOS Catalina for now. So FFMPEG is tuned for Apple ProRes4444 (and no longer qtrle) and then avconvert (the macOS version of avconv) converts to HEVC + alpha. It works well and the resulting files are very small, but everything is currently very slow.