Jump to content
Search Community

Animate a large sequence of png's

a13 test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hi Guys,

 

I have a bit of a conundrum so I thought I would put it past the experts!

 

I have a video sequence that has been exported as 300+ png's, some coming in at 300kb.

 

I'm looking for the most optimised method to animate the sequence. I'm already using GSAP in this project however I'm not sure it would be best suited.

 

I was thinking an image replacement method but its an awful lot of calls and combining them into a sprite will create a huge file.

 

Thanks

 

Wes

 

Link to comment
Share on other sites

Hi Wes,

 

One option could be give all the images the small name, with the exception of a number at the end (image-1, image-2, etc.).

 

Then you could attach an event to GSAP tick event while the video plays. This event basically advances the number by one on each tick and sets the opacity for that image to 1, while getting the previous image's opacity to zero. Like that you don't have to move a sprite or images, which could be very complicated performance-wise.

 

This would allow you to jump straight into the engine's timing mechanism (60 fps) and you could remove the listener to the tick event in order to pause the video, reduce the image number to reverse the video, change the tick frequency to make faster or slower, etc. Thats all with just a few lines of code, that's how powerful and flexible GSAP is.

 

Unfortunately you caught me on my phone so I can't add any code with ease to this post, hut if you search for the tick event you'll find how to do it, and perhaps another user could get you started with q little snippet.

 

Rodrigo.

  • Like 1
Link to comment
Share on other sites

If you tie directly to ticker, be aware that any fluctuations in FPS (browser, not GSAP, dependent) will affect the duration of your sequence. Something like the image sequence half of that spritesheet plugin would probably serve you well. It's probably overly commented and works with spritesheets as well which you don't need; you can boil the needed parts down to this:

<div class='animatedimage'>
    <img src='1.png' />
    <img src='2.png' />
    ...
</div>
.animatedimage {
    position: relative;
    display: inline-block;
    line-height: 0;
    overflow: hidden;
}
.animatedimage > * {
    position: absolute;
    display: inline-block;
    visibility: hidden;
    border: 0;
}
var images = $('.animatedimage').children(), // images in the sequence
    fps = 30,
    duration = 1 / fps;

var sequence = new TimelineMax({ repeat: -1 })
    .staggerTo(images, 0, { position: 'static', visibility: 'visible' }, duration, 0)
    .staggerTo(images.not(images.last()), 0, { position: 'absolute', visibility: 'hidden', immediateRender: false }, duration, duration)
    .set({}, {}, "+="+duration);
  • Like 3
Link to comment
Share on other sites

Thanks Jamie, it was created at 50fps so yes, I would want to keep as close to that as possible.

 

I've managed to halve the number of images now, but I guess I'm still going to have to deal with the issue of loading them to enable it to run smoothly.

 

Thanks for your help guys, I'm looking into this now.

Link to comment
Share on other sites

Ok, so I've managed to get the images down to 4 spritesheets with Texture Packer, It also churns out css with classes with background positions for images. Would I have to use the ticker method to cycle through classes from 001, 002, 003. 

 

Would this method work? Is it recommended?

Link to comment
Share on other sites

If you want something synchronised to actual time, don't use the ticker. It's just a logic thing - if browser FPS drops there will be less ticks so your video's length will be stretched.

 

Make a timeline (I'm assuming your frame size doesn't change throughout the sequence, so the classes aren't entirely necessary to calculate a sequence of position changes):

// 50 fps
var sequence = new TimelineMax({ repeat: -1 })
    .set(target1, {backgroundPosition:"0 0"}, "+=0.02")
    .set(target1, {backgroundPosition:"-100px 0"}, "+=0.02")
    .set(target1, {backgroundPosition:"-200px 0"}, "+=0.02")
    .set(target2, {backgroundPosition:"0 0"}, "+=0.02")
    .set(target2, {backgroundPosition:"-100px 0"}, "+=0.02")
    .set(target2, {backgroundPosition:"-200px 0"}, "+=0.02")
    // etc etc
    // it would probably make more sense to set this up in a loop or four
Setting up a timeline like this will perform VERY well, and the only bottleneck to performance would be the re-rendering the browser performs for each background position change. You also get the benefit that if FPS drops, frames will just be skipped to keep the duration correct (just like a regular video).
  • Like 1
Link to comment
Share on other sites

Hi!

I'm new to GASP and I'm trying to extend

See the Pen lykFn by jamiejefferson (@jamiejefferson) on CodePen

?

 

I want to add kinetic spinning (so it keeps spinning for a bit when you "throw" it) and I want smooth transition between two frames (fade-out current frame, while fade-in next frame) with endsnap to frame.

 

Could you explain me how to do this?

Link to comment
Share on other sites

Hi, and welcome to the GSAP forums. You know, that's quite a change to the sample, which was built with neither of those changes in mind.

 

Adding throwProps should be pretty simple (include the plugin, set throwProps:true, and add an onThrowUpdate to continue setting backgroundPosition).

See the Pen IeLGB by jamiejefferson (@jamiejefferson) on CodePen

Note: ThrowPropsPlugin is a Club GreenSock membership benefit.

 

Crossfade would require two elements; one each for the 'current' image and the 'next' image to fade between (you can't fade backgroundPosition on a single element). I don't think it would just be as simple as adding a second image and fading one out every update though. Mousemoves fire at a high rate (usually at the broswers FPS, 60, but IE fires them as often as the mouse hardware sends updates - with a sensitive mouse you could be seeing 500 or more events a second). You would need to throttle the backgroundPosition updates based on cursor velocity so that there is an adequate crossfade time at slow speeds, but a very quick (non-existant?) crossfade at high speed.

 

I can't really implement all of that for you, but feel free to take a crack at it yourself and return with your attempt at an extended version if you hit a wall. It's a deep pool to jump in if you're just beginning, but I guess you have to start somewhere yeah?

 

Also please make a new topic next time, your issue is not relevant to the creator of this topic so it works better for everyone if they are kept separate.

  • Like 5
Link to comment
Share on other sites

Thanks for the quick answer, but your sample isn't working properly on my side.

It changes to some random frame on mouse up (try to rotate without throwing).

 

About crossfade. I'm not sure how it depends on mouse update rate?

Can't we just add 100 intermediate states between frames?

For example,

0 = current image visible,

50 = both images are 50% fade,

100 = next image visible.

 

So if we have 36 images, that means 3600 states and when we rotate, we actually switch not between 36 images, but between 3600 states (and snapping end to every state % 100, so we don't stop between images)

Link to comment
Share on other sites

Thanks I missed changing onDragEnd to onThrowComplete and now it's working fine.

 

Sure, I had a different implementation in mind but you can implement it however you like. You wouldn't need to worry about creating the states between frame changes; it would just involve creating a timeline of opacity tweens, zIndex swaps and backgroundPosition changes, and using the onDrag/onThrowUpdate to set time() or progress() of that timeline.

 

Just some kind-of-pseudocode that may help

t = 0
tl.set(img2, { zIndex:1 }, "frame"+t); // last frame goes behind
tl.set(img1, { backgroundPosition:"?px ?px", zIndex:2 }, "frame"+t); // next frame
tl.to(img1, 1, { opacity: 1 }, "frame"+t);
tl.to(img2, 1, { opacity: 0 }, "frame"+t);
t++;
tl.set(img1, { zIndex:1 }, "frame"+t); // last frame goes behind
tl.set(img2, { backgroundPosition:"?px ?px", zIndex:2 }, "frame"+t); // next frame
tl.to(img2, 1, { opacity: 1 }, "frame"+t);
tl.to(img1, 1, { opacity: 0 }, "frame"+t);
Link to comment
Share on other sites

Thanks. Your sample is still a bit buggy on my side :) (tested FF 28 and Android 4.3)

 

Steps to reproduce:

1. Fast throw to the right and wait until it stops.

2. Try to start dragging slowly dragging to the left.

3. In about 1/3 times it jumps to a random image.

Link to comment
Share on other sites

Yep I see that too. Like I said the original demo didn't consider this stuff, and I added the throwProps stuff without much thought so there's probably a logic flaw in there somewhere. I'm not sure but it sounds like t.lastmultiplier could be a bit off so maybe the onThrowComplete could be causing some weirdness, or maybe removing the bounds that snapped x back to 0 has broken it? Whatever it is, I can't continue to be the only one modifying this to fit your needs; now it's your turn to either try and fix it or come up with a better solution. Good luck to you, and if you have a specific question about what you're trying, or some GSAP functionality you don't understand, I'm all ears.

  • Like 4
Link to comment
Share on other sites

  • 3 years later...
On 4/8/2014 at 11:59 AM, jamiejefferson said:

 


var images = $('.animatedimage').children(), // images in the sequence
    fps = 30,
    duration = 1 / fps;

var sequence = new TimelineMax({ repeat: -1 })
    .staggerTo(images, 0, { position: 'static', visibility: 'visible' }, duration, 0)
    .staggerTo(images.not(images.last()), 0, { position: 'absolute', visibility: 'hidden', immediateRender: false }, duration, duration)
    .set({}, {}, "+="+duration);

 

I know this post is rather old but, thanks for this little snippet, jamiejefferson! I used FFMPEG to convert an old MOV file to a png sequence and used your little snippet to recreate the animation from the MOV. As you probably know, MOVs have high-quality support for transparency but Apple no longer supports MOV files on Windows. There are a lot of great little MOVs out there in the wild that can be repurposed. I use a Mac but this kind of thing will allow those MOVs to be used on any platform. Here's a sample codepen. You might have to wait a several seconds for the images to load. 
 

See the Pen Xgrbvj?editors=0110 by swampthang (@swampthang) on CodePen

 

Link to comment
Share on other sites

I like the concept of transparent JPG,  but its more of a JS data faux transparent JPG, since its not an actual JPG/JPEG image. me personally would just convert it to a PNG-24 and skip the on the fly conversion/compression. But it is still pretty awesome :) 

  • Like 1
Link to comment
Share on other sites

Here's some of the theory behind transparent jpegs.

https://stackoverflow.com/a/9970137/2760155

http://jim.studt.net/jpeg-alpha/

 

Using JavaScript is just one way. Another way is to use an SVG mask. 

https://css-tricks.com/transparent-jpg-svg/

http://quasimondo.com/ZorroSVG/

 

The problem with an SVG mask is that it's an SVG, so animation performance may not be that great. Just scrolling a complex mask can kill your cpu. There's also a limit to the complexity of the mask. 

  • Like 1
Link to comment
Share on other sites

Yea, that transparent jpg thing is pretty crazy! I'm having to put together something that can convert MOVs into an image sequence and maintain transparency. Saving some file size it mainly important to me from a performance standpoint because my use of this is a desktop app in Electron. Do you think the transparent jpg's would allow GSAP to be more performant?

Link to comment
Share on other sites

21 minutes ago, swampthang said:

Yea, that transparent jpg thing is pretty crazy! I'm having to put together something that can convert MOVs into an image sequence and maintain transparency. Saving some file size it mainly important to me from a performance standpoint because my use of this is a desktop app in Electron. Do you think the transparent jpg's would allow GSAP to be more performant?

 

For your app using a transparent jpg won't be that useful. It only reduces the file size for downloading the image. Once you draw the image on a canvas, it's going to use just as much memory as a png.

  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...