Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prototype GIF library #2747

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft

Prototype GIF library #2747

wants to merge 1 commit into from

Conversation

kach
Copy link
Contributor

@kach kach commented Dec 17, 2020

As discussed here: https://forum.snap.berkeley.edu/t/snap-project-to-animated-gif/4895

(Don't worry! Not a "real" PR!) This is a proof-of-concept/discussion-starting Snap! library that uses gif.js to create GIF animations of whatever's happening on the stage.

Discussion topics:

  • Possibly the "wrong" block abstraction. Maybe a nicer abstraction would be a C-shaped block called "create GIF animation" which exports an "upvar" that's a command block called "snapshot." I'm not sure!
  • No way to control inter-frame delay time yet. I'm not sure whether it's better to infer inter-frame delay from the "wall clock" amount of time that has passed between calls to "snapshot," or whether it's better to allow students to specify a number of milliseconds, or whether it's better to just hardcode 20ms (as it is now).
  • GIF.js is MIT-licensed, I hope that is acceptable. I imagine you'd want to add an attribution somewhere, but I'm not sure where.

Bugs:

  • Does not work in "retina mode." I think I know why, but haven't investigated yet.
  • Race condition if you manage to call "snapshot" twice before the aux library loads (this is easily fixable: there's the "wait until done" solution from the bignums library loader, I just haven't implemented it yet).

@brianharvey
Copy link
Collaborator

Wow I didn't know there was a "work in progress" feature in git. Pretty sure I've never seen that before, although I've seen plenty of works in progress. :)

I don't think there's one correct abstraction, especially about timing. For your tree example, you want every MOVE to trigger a snapshot. Depending on the purpose, you might also want every TURN to trigger one. (No for a demo, yes for a lesson about recursion and fractals.) So I would be inclined to do your upvar thing (but what I really really want is an up-block feature, so the user wouldn't have to know about RUN), but also have two Boolean inputs for snap-on-move and snap-on-turn, maybe defaulting to on and off.

From sad experience: Stick ten or twenty copies of the first frame in front, and ten or twenty copies of the last frame at the end, especially the latter. Otherwise people get confused about the animation, especially if they haven't seen any such computational process before. Or, maybe even ten or twenty empty frames after the final one.

And yeah, you have to fix the retina bug, because Jens has already hidden that checkbox and keeps threatening to remove it altogether. The difficult decision is whether you should scale down by half in retina mode. If not, your gif will take up a gargantuan amount of screen space, but if so, you lose a little beautiful sharpness.

@brianharvey
Copy link
Collaborator

brianharvey commented Dec 17, 2020

What am I doing wrong?
Google Chrome001
The error happens after the drawing is finished.

@kach
Copy link
Contributor Author

kach commented Dec 17, 2020

Might be that race condition. Try sticking a "wait 1 sec" in your for loop for now. Also, you probably want the "snapshot" block to be inside the loop.

@brianharvey
Copy link
Collaborator

Never mind; the helper .js has to be in libraries; I tried just pulling gif.xml into my project. Duh.

@brianharvey
Copy link
Collaborator

I hate my life.
Google Chrome002
This is after I made a fork of Snap! because Jens yelled at me for making branches in the master, and then made a branch in my fork, and then couldn't find a way to pull this PR into it, so I downloaded the four files by hand (and had to rename LIBRARIES.txt to LIBRARIES), and then tried to load the library but when I click on "libraries..." in the File menu I got a MacOS open dialog, so I had to steer to the repo, and then still couldn't get a Snap! libraries dialog, but instead got another system file open dialog, so I just opened gif.xml in it. And then I drew the squiral and got this new error message when it got to the export GIF block.

@kach
Copy link
Contributor Author

kach commented Dec 17, 2020

You have to serve the files from a server! (For security reasons.) Even localhost will do.

@jmoenig
Copy link
Owner

jmoenig commented Dec 17, 2020

Very nice, thanks, @kach !

Instead of a whole mechanism spread out over 3 command blocks I think I'd much prefer one single block, either a reporter or - perhaps better here - a command that takes a list of costumes as input and produces an animated GIF from that. Additional parameters should probably be the frame rate and the dimensions of the output GIF and perhaps others, such as whether the GIF is looping, which kind and level of compression, color palette and reduction etc. etc. For starters we could leave out the more "advanced" parameters and only offer framerate and dimensions. That would also take care of retina issues.

But the main suggestion from me is to use Snap's lists of costumes for this, and not to implement a separate container mechanism. Does that make sense?

Oh, if you're going to go with my list-of-costumes suggestion you'd probably want to guard against costumes of different dimensions. But you'd have to do this anyway, even in your current architecture.

What do you think?

@brianharvey
Copy link
Collaborator

If it uses a list of costumes, it becomes a bit harder to make an animation like Kartik's tree. Either version can be written in terms of the other, of course, but the library should provide tools for both cases without the user having to deal with the boring parts.

As for all those "additional parameters" you want, who are you really and what did you do to Jens? You always yell at people who want a zillion parameters to, e.g., the WRITE block.

A reporter would be great if only we supported animated costumes, but since we don't, all we can do with the gif is export it. So it might as well be a command.

If you put a non-looping gif in a web page, does it just do the animation right away, before the user is even looking at it? Or would it run when clicked? I'm leaning toward saying it should always be looping.

I think a fixed frame rate is okay, maybe just a hair slower than Kartik's example. As for the dimensions, the really right thing is that when about to export, look for pixels that are transparent all the way down, including the background layer, and if there are some in every frame then it can reduce the dimensions to the bounding box of the largest image. But for the most part I think exporting the entire stage is fine.

@kach
Copy link
Contributor Author

kach commented Dec 17, 2020

Regarding "list of costumes" — yes! I agree. See my comments on Bernat's solution in the forum thread (I'm sorry to have "forked" the discussion across two sites!).

Regarding parameters — I would say the only parameter worth exposing is the delay time. The rest of the options all have sane defaults that are very rarely modified in practice. Here is a proposed modification to Bernat's block:

add snapshot of stage to [list] with delay (10) ms

The list created would be a list of (costume, delay-time) pairs which you can feed to the "export GIF" block. For extra credit, the "10" number input could have a dropdown that lets you select "real time" as an option. It would infer the delay based on the wall-clock time since the last snapshot was added.

Does this seem reasonable to you, Jens?

@DarDoro
Copy link
Contributor

DarDoro commented Dec 18, 2020

Why such artificial delay, 10ms?
Typically Snap! iterations are executed at 60FPS so snapshots taken this way have ~16ms delay.
I'm afraid, that for real use, the framerate will be limited to a few FPS only. Otherwise, the 60 s recording will have 3600 frames. And 3600 costumes...
I'm afraid that there will be a resource problem. I was looking for a GIF library with the capability to additive creation of output. Most libraries require frames available at once as a list of URI of external images or base64 of image data.
So, in memory will be, 3600 costumes, base64 data of every costume, and newly created GIF.

As for single frames delay, it can be encoded in costume name eq. "frame1_x20" for waiting 20 x dt. Or as a property of JS costume object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants