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

Feature for saving gif files #5118

Closed
1 of 17 tasks
stalgiag opened this issue Mar 23, 2021 · 23 comments · Fixed by #5709
Closed
1 of 17 tasks

Feature for saving gif files #5118

stalgiag opened this issue Mar 23, 2021 · 23 comments · Fixed by #5709

Comments

@stalgiag
Copy link
Contributor

New feature details:

I am getting this request quite a lot from my students. They want to be able to share their work on social media in animated form. I know that saveFrames exists but students have to already be relatively advanced to use that and it doesn't encode to gif.

Other options like using ccapture.js, require a number of advanced skills that students often don't have during their first experiences with coding.

Since GIF support was enabled we already have most of the work in place for this feature. saveGif already exists as a private method for saving animated p5.Image objects as GIFs. To enable this feature, we would have to add a separate public method (probably saveGif and the private one would be renamed) that stores frames over a certain number of frames and then turns them into an animated p5.Image object. This object could then be sent to the private method which could handle all of the encoding.

How would this new feature help increase access to p5.js?

It would enable students to share their work in animated form without needing advanced skills.

Most appropriate sub-area of p5.js?

  • Accessibility (Web Accessibility)
  • Build tools and processes
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Friendly error system
  • Image
  • IO (Input/Output)
  • Localization
  • Math
  • Unit Testing
  • Typography
  • Utilities
  • WebGL
  • Other (specify if possible)
@golanlevin
Copy link

golanlevin commented Mar 23, 2021

The p5.createloop library by @mrchantey currently provides straightforward GIF loop export functionality for p5.js. I have used it very successfully with my students (Art first-year undergrads with no prior programming experience); the only "advanced skill" needed is knowing how to add the include to the HTML.

It would be worth evaluating whether it should be incorporated wholesale, or, remain an external library and simply advertised better, for example on the https://p5js.org/libraries/ page.

@stalgiag
Copy link
Contributor Author

stalgiag commented Mar 23, 2021

Thanks @golanlevin ! Yes I saw createLoop in exploring and it seems really cool. I think there is still a bit of curtain pulling back here that could ideally be avoided for something this core to the use of p5. Depending on the education context revealing a secondary file with a markup language, adding additional libraries, and passing object literals as parameters can all feel pretty intimidating. I have had students ask to download gifs on their first or second day of class.

I believe that since we already have gif encoding functionality in the core library we should take advantage of this and have a simple saveGif() function that works with or without arguments.

@golanlevin
Copy link

Thanks @stalgiag, I completely understand. This especially makes sense for middle-schoolers. Uh, so let's think through some proposals then:

(1) saveGif(filename, nFrames);

This immediately starts recording the next nFrames frames, and when it's done, saves it out as a GIF. Puts the burden on the programmer of knowing whether they are actively writing to a GIF. Could cause problems if the programmer calls saveGif while another call to saveGif is actively running.

(2)
saveGif(START, filename); // starts recording
saveGif(STOP); // stops recording

(3)
beginRecord(GIF, filename);
endRecord();
// analogous to Processing PDF: https://processing.org/reference/libraries/pdf/index.html

(4)
// in setup:
GIFWriter myGiffer = createGIFWriter();
// in draw:
myGiffer.nextFrame();
// on (e.g.) keyPressed:
myGiffer.save(filename, fps, loopBool, nPaletteColors);
myGiffer.clear();

@stalgiag
Copy link
Contributor Author

Thanks for this!

Number 1 is what I was originally thinking. My thought was that the library could keep a flag true during recording and ignore additional calls (maybe use FES). I like that both parameters can be optional here with a default name and frame count. We could also enforce a maximum frame count to prevent memory problems. Anything over 500ish frames should likely be a screen recording. This has the benefit of being a single command that could be put in mousePressed but it also runs the risk of masking complexity too much.

I like 2 and 3. The start and stop formatting feels natural. My primary concern would be holding programmers responsible for not overflowing the memory.

I dig the flexibility and power of 4. Would it be overdoing it to combine 1 & 4? Webgl camera offers something like this with the ability to create a persistent camera with createCamera() for later use or call camera()to edit the sketch state immediately.

I'd love to hear thoughts from other people as well. I think this issue can stay open for a while as it warrants discussion. In the meantime, p5.createLoop is a great alternative and is heavily encouraged for people facing this challenge right now.

@golanlevin
Copy link

golanlevin commented Mar 23, 2021

I would also love to hear other voices in this.
I have just two other considerations:

  • I think it could be good to mimic Processing-style libraries if possible (e.g. PDF export), to encourage harmonies across toolkits.
  • I can imagine situations in which the user doesn't know (in advance) how many frames they want to record. For example, suppose I create a GIF from a gesture that I'm drawing -- the number of frames depends on how long I'm scribbling.

FWIW, The following would be a Processing (Java) style way of doing things:

var myGiffer; 
var bRecording = false; 
function setup(){
  myGiffer = createGIFWriter();
}

function draw(){
  circle(mouseX, mouseY, 50); 
  if (bRecording) myGiffer.nextFrame();
}

function mousePressed(){
  if (!bRecording){
    bRecording = true;
    myGiffer.clear();
    myGiffer.beginRecord(); 
  } else {
    bRecording = false;
    myGiffer.endRecord();
    myGiffer.save("output.gif", 30, TRUE, 256); // filename, fps, loop, npalette
  }
}

@stalgiag stalgiag changed the title saveGif() function for saving gif files Feature for saving gif files Mar 23, 2021
@mrchantey
Copy link

Great to see this discussion being had. In writing p5.createGIF, and then deprecating it in favour of p5.createLoop, I encountered a handful of discoveries:

  • When a user says "I want to create a GIF", what they usually mean is a looping GIF
  • This workflow is fundamentally different from that of saving images or frames
  • Users will generally have an idea of the duration in seconds rather than frame count
  • The createLoop library works with a single argument, createLoop(duration), which defaults to 3 seconds.
  • To create a meaningful looping animation, variables like loopProgress need to be exposed in the draw function.
  • This approach means that a user can write a frame-perfect GIF loop with the library only appearing twice in their sketch:
    //in setup
    createLoop()
    //in draw
    myObjectXPos = animLoop.progress
  • The encoder used should be asynchronous so the user can continue to enjoy their sketch, some of these operations can be expensive

@mrchantey
Copy link

Out of interest the library was created after following some of @shiffman's more loopy tutorials on coding train :)

For anybody interested in an implementation, these are a great starting point for observing the workflow and where it can be improved.

@golanlevin
Copy link

@mrchantey — thanks for making such a great, easy-to-use library. I had very good results using p5.createLoop with my students, Art-school first-years.

I totally get what you're saying about making looping GIFs being the goal for many people. The variables you exposed for this (0..1, 0....2pi) are super useful. Your looping noise also elegantly obscures some really complex, difficult-to-explain stuff under the hood -- nicely done.

I wasn't sure how to trigger p5.createLoop to start recording at any time other than in setup(). Admittedly I didn't work very hard to figure out an answer. But FWIW, this became a small issue for a student who wanted to record a GIF after the screen had already built up some imagery through user interaction. She ended up doing something else.

I don't think it's crazy to want a screen-recording tool, that produces animated GIFs, whose recording the p5 programmer can .start() and .stop() when they choose. I agree that this is a different workflow.

@mrchantey
Copy link

@golanlevin that is a very understandable use-case. Not crazy at all, and the implementation wouldnt be either. If you're interested, the encoding library works just like this. All that would be needed is to create a p5 wrapper for it.

@stalgiag
Copy link
Contributor Author

Thanks for the library @mrchantey ! I love the ability to create seamless loops.

p5 has an encoding library omggif. It is similar to gif.js, just smaller. We actually already encode gifs for people that are saving image assets that are already animated as seen in saveGif. We just need to decide on the design for making this available for recording the entire canvas.

@shiffman
Copy link
Member

Super excited to see this discussion! Would love to help in any way that I can. A totally different but related direction (a la the Processing "MovieMaker" tool) would be to build in a saveGIF button / export option into the web editor itself! This is probably a step 2 or longer term option (and has its downsides as well) but could be really wonderful for the short 2 hour intro to p5 weekend workshop context.

@GregStanton
Copy link
Collaborator

Hi everyone!

As a p5.js user and aspiring library contributor, I'm really excited to see this discussion.

My experience as a user

In case adding another perspective helps, I'll describe my experience learning to create my first Twitter GIF using p5.js. I learned p5.js on my own (with the help of The Coding Train videos by @shiffman), and despite my previous programming experience, it took a lot of effort to make the GIF.

Since my sketch involved a computationally expensive simulation, real-time rendering wasn't smooth, which ruled out a screen recording tool like Apowersoft Online Screen Recorder.

The p5.js reference pointed me to ccapture.js. Eventually I found a video on YouTube that broke down how to use ccapture.js. Due to the randomness in the duration of my sketch, I had to include logic around the start and stop calls. For some reason, it didn't work.

After that, I found p5.createLoop. Thank you @mrchantey for making this! I did manage to get it working, with a hack: I guessed an upper bound on the duration. The result is a looping GIF that either gets cut short or has a delay before restarting. (Here's the sketch in question. Please note that it is currently set to download the GIF automatically.) If you run the sketch, you will see a warning, but I believe that could be fixed by a recent update to p5.createLoop.

My takeaway

I was thrilled to make the GIFs, but the process felt complicated and unreliable.

In addition to understanding how to include a library in a sketch, along with the other issues @stalgiag mentioned, there is always a problem of having to decide which library is best, and even potentially having to try out multiple libraries.

For a feature as essential as GIF creation, eliminating any steps in this process would be incredibly helpful. A flexible, well-documented solution that's built directly into p5.js would make a big difference. A simple GIF solution is especially crucial since easy GIF creation will allow creative coders to make their creations visible on social media, and that will help build the p5.js community by spreading awareness!

Including a "Save GIF" button in the web editor, as @shiffman proposed, would be amazing. Perhaps the button could cover the most common use case(s), and there could be a more flexible solution that can be implemented in the code.

My thoughts on the more flexible options

For the more flexible option, I like beginRecord() / endRecord() and createGIFWriter(), as proposed by @golanlevin. I like createGIFWriter() the most.

Why I like beginRecord(GIF, filename) / endRecord():

  • It's more flexible than saveGIF(filename, nFrames) and supports a use case I've already encountered.
  • It's easy to use and will be familiar to users of beginShape() / endShape(). In contrast, saveGIF(START, filename) / saveGIF(STOP) conflicts with usage of the existing saveFrames() function. Since saveFrames() doesn't have start and stop functionality, users will have trouble remembering the usage pattern, unless saveFrames() is re-engineered.
  • It's more flexible than saveGIF(START, filename) / saveGIF(STOP) since it parameterizes the file type; however, another approach could be to create multiple functions like beginGIF(filename) and beginPDF(filename), in the same way that there are createDiv() and createP() for specific HTML elements.

Why I prefer createGIFWriter():

  • It supports the greatest number of use cases, which seems very important; otherwise, it will sometimes be necessary to turn to an external library to get the job done, and then we are back where we started in those cases.
  • While this is the most complicated option, it could be made to more or less mirror existing p5.js functions such as createGraphics() and createWriter(), which would make it easier to learn.

A two-pronged solution?

Ease of use is really important, but so is flexibility, so a two-pronged approach seems reasonable, similar to what @stalgiag proposed.

  1. Perhaps there could be a beginner-friendly, time-saving option for common use cases.
    a. I especially like the idea of a Save GIF button that's built into the web editor for common use cases. A visible button would increase awareness that GIF creation is possible; coders learning on their own won't have to guess that GIF functionality exists or look it up. It would also make GIF creation as simple as possible.
    b. If the button is untenable for some reason, another option would be to make a simple function saveGIF(filename, duration, [framerate]) that would be an analogue to saveFrames(). A duration parameter (rather than a frame count) would likely be simpler for beginners, and it would also be more consistent with saveFrames() parameters.
  2. For maximal flexibility, the createGIFWriter() function could be developed as well.

@two-ticks
Copy link
Contributor

two-ticks commented Mar 27, 2021

saveGif feature can also be very useful for STEM communities on twitter and instagram. The saveGIF button / export option into the web editor would be great for exporting animations and sharing them easily. By manipulating text and KaTeX elements user can also animate text and equations which can be a great for remote teaching. I tried recording KaTeX equations through ccapture.js but was not able to record. It would be great if saveGif can solve this problem.

@DivyamAhuja
Copy link
Contributor

@stalgiag @shiffman Will this feature will be good as a GSoC project? (maybe it can be extended into real Movie maker as @shiffman said if support for p5.sound and mp4 can be added. am not sure about this tho)

@stalgiag
Copy link
Contributor Author

Hi @DivyamAhuja my sense is that this will not be enough work to constitute an entire GSoC project. This will be more of a matter of adding a few public functions that expose things that the library already does. The biggest challenge here is design but the work there will likely happen in the form of this ongoing community discussion.

It is possible that this could be part of a larger GSoC project but I don't expect that the work for this particular feature (even if we do both saveGif() and p5.GifWriter) will amount to more than 1 of the 15 hour weeks in GSoC.

The Movie Maker option could be the correct scope for GSoC but this would likely require further discussion to decide if the feature is appropriate.

This is all to say that this could be a part of a GSoC proposal but shouldn't be the entirety of one unless the community comes together and decides strongly in favor of multi-export tool in the online editor.

@DivyamAhuja
Copy link
Contributor

DivyamAhuja commented Mar 30, 2021

@stalgiag That's what I was thinking, but I don't think I got any idea of integrating this feature in any other project other than batch of bug fixes XD

@jesi-rgb
Copy link
Member

jesi-rgb commented Mar 30, 2022

Hi there everyone!

I got here through the project list that Processing has published for GSoC 2022.

As far as I can see, the discussion states that this is indeed a wanted feature (presented as high priority), but that it may not fulfil a complete GSoC project, though it is published as a potential project.

I am writing to ask what is the state of this discussion, since I see the last comment was exactly a year ago. I am a GSoC aspiring contributor and feel like I can tackle this topic, but wanted to know the team's opinion on it!

Thanks a lot for your time beforehand!

@stalgiag
Copy link
Contributor Author

Hi @jesi-rgb thanks for this question! GSoC is structured a little bit differently this year. Applicants choose between two different project scopes when applying: 175 hours (medium) and 350 hours (large). I can imagine a 175 hour or medium-sized project that proposes implementing p5.GifWriter, adding all of the utility functions necessary to work with it, writing tests, and writing examples. This work could be supplemented with related bug fixes and optimizations.

@jesi-rgb
Copy link
Member

@stalgiag nice to hear!

I would be very glad to implement this feature, since I myself am a particular user that's struggled with this particular topic. Publishing the beautiful animation you've just created to the web should be just as easy as a download button.

May I ask who could be the potential mentor to contact and ask feedback to?

Thanks much! 🙏🏻

@stalgiag
Copy link
Contributor Author

stalgiag commented Mar 30, 2022

I am not sure who is mentoring this year but when you are ready you can make a post on the Summer of Code category on the Discourse (where these discussions take place) and tag me. I would be happy to give feedback on your proposal.

@tapioca24
Copy link

tapioca24 commented Apr 7, 2022

Hi everyone!

I am so excited to see this discussion.
I started using p5.js and realized there was no easy way to record my sketches. Here are my thoughts on this subject

As @GregStanton said, both ease of use and flexibility are important.

For ease of use, I think a GUI like the recording button is a great option. Adding code for recording to a sketch is difficult for a beginner. Also, it would be nice not to have to add any code to the sketch, since the creative code and the code for recording should be separated.

As for flexibility, there are many factors.
First, I believe many video formats need to be supported. We are discussing gif here, but there are other options such as mp4 or webm. Having different solutions for each format would be confusing to users. An all-in-one solution is better.
Second, we need support for use cases where we want to programmatically control recording. This is useful, for example, for period-specific recording, as in p5.createloop.

And based on the above ideas, I have developed p5.capture, a library for easy recording of p5.js animations.
/~https://github.com/tapioca24/p5.capture

The differences from p5.createloop are as follows

  • Does not specialize in gif loop animations (webm, mp4, etc. are also supported)
  • Provides GUI for intuitive recording
  • Requires only one line for import

It is truly designed for beginners to easily record their work and share it quickly. In addition, an API is provided for flexibility.

Does this help?

@jesi-rgb
Copy link
Member

Hello, everyone! I am very excited to tell you that I am now a GSoC contributor for the processing foundation! My project aims to solve the very problem stated here in this conversation, so hopefully we'll be able to create an easy and fast method to download gif files directly.

Thanks a lot for your time and I am super excited to get to know you all! Have a great summer!

@Qianqianye
Copy link
Contributor

Congrats @jesi-rgb! I look forward to seeing what you will create during GSoC.

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

Successfully merging a pull request may close this issue.

10 participants