Manim – Python library for creating mathematical animations
manim.community
manim.community
Edit: sorry for being a joke but I saw "Python library math animation" and I immediately thought of 3B1B but I really had no idea this was it!
From the the READE:
"Note, there are two versions of manim. This repository began as a personal project by the author of 3Blue1Brown for the purpose of animating those videos, with video-specific code available here. In 2020 a group of developers forked it into what is now the community edition, with a goal of being more stable, better tested, quicker to respond to community contributions, and all around friendlier to get started with. See this page for more details."
https://github.com/two-ticks/p5.teach.js
https://medium.com/processing-foundation/p5-teach-teaching-m...
Making this comment less like a plug, and more like spam…
I for one am happy this got posted here. I used manim in the past, but its setup is really cumbersome (at least it was back then when I tried).
A JavaScript alternative is therefore much welcome. I will definitely have a look P5 Teach.
The syntax looks a lot easier than LaTeX for static images, but the animations also look really quick to generate with minimal boilerplate.
https://news.ycombinator.com/item?id=28245277 (community version)
https://news.ycombinator.com/item?id=19716019 (3Blue1Brown's version)
“Julia Animations and Visualizations”
In the first code snippet, I don't understand how Background(1:200, ground) is picked up. It looks to me like a statement disconnected from the others. I also don't understand how calling background("black") and sethue("white") in function ground affects anything. Are those some dynamic scope shenanigans? Or do those just modify some global variables? Generally, a lot of parts of the code don't seem connected in any way, I don't see how the data flows through code. Could someone familiar with Julia ELI5?
Co-creator of Javis.jl here! As adgjlsfhk1 said, there is an implicit global scope here! This comes from a historic artifact from Cairo (which is what Javis is using deep within its tooling stack) which utilizes this sort of approach.
Here is an ELI5 that may help about the flow of a Javis animation: imagine Javis as a magical artist sitting at a table. The artist is a bit peculiar as they can draw anything you want but will not draw anything until you finish telling them everything you want to see. When you create a `Video` object, the artist grabs an empty notebook and opens it up. If you create a `Background` object, basically you are telling the artist that you want the background of each page in the notebook to be, in this case, black for pages 1 - 200. As you keep telling the artist what you want, the artist listens to how you want it ordered, how objects should appear and animate, etc. Finally, when you tell the artist to `render` this animation, Javis springs to work and flips through all the different pages, drawing backgrounds, objects, etc. to match what you asked. Then, when Javis is all done, the artist gives you the notebook that when you open it up, it will magically flip through all the pages (i.e. at a given frame rate) showing you your requested animation.
I know this ELI5 doesn't really get into the internals, but at a high level, that is what is happening with the start of the `Video` object. Happy to give more details if desired. We are trying to move to a v1.0.0 release very soon and in v2.0.0 we want to experiment with different syntax - perhaps a more implicit syntax similar to manim and Processing. Out of curiosity, for you, do you find it necessary to know more about Javis's approach to use Javis or was this more of a question that you had? Reason why I ask is perhaps we could add a "How Javis Works" section to the documentation if that could help more folks.
Thanks!
The reason I asked is because when I saw Background(1:200, ground), I did not know what made Javis use this background. To me it looked like creating an object and immediately discarding it. Global state explains it, but by default I'd assume that I can e.g. create two animations simultaneously (not necessarily meaning parallelism or concurrency, just multiple animation objects coexisting in memory at the same time, with code applying modifications to one in line N and to the other in line M e.g.) In that case I don't know how Javis would distinguish which background should be applied to which animation, as the code doesn't explicitly show any connection between the video variable and the Background(1:200, ground). From your explanation I assume you can only create one animation at a time. It makes sense. It makes it similar to creating plots in gnuplot. Keep in mind that I don't program in Julia (I'm considering learning it though), so I may still be totally off the mark in my understanding.
When I learn a library, tracing how data flows through example programs is the guide I use. When I don't see the explicit connection facilitating this flow of data, the library feels a bit less predictable to me and I need to rely more on copy-pasting ready-made examples to get something working through trial-and-error instead of relying on an accurate mental model of what happens. I know that such explicitness can feel verbose sometimes, but there are methods of escaping the verbosity without losing explicitness. Two examples: iterator pipelines in Rust/streams in Java, builder pattern in any language with method call syntax. In the first example, usually the pipeline starts with the name of the source of data and is followed by transformations connected by dots, e.g.:
let names = vec!["Jane", "Jill", "Jack", "John"];
let total_bytes = names
.iter()
.map(|name: &&str| name.len())
.fold(0, |acc, len| acc + len );
The important thing here is that the dots signal that all those operations are applied to the result of the previous operations in pipeline (yet you don't need to name all the intermediate results). It's both terse and explicit.Builder pattern is similar: you have an object with methods which modify this object and return self/this, so that you don't need to repeat the name of the object being created in every line setting something in this object. E.g. I have this code in one of my Rust project using the clap library to parse CLI arguments:
let app = App::new(pkg_name)
.bin_name(bin_name)
.version(version.as_str())
.about("Compares directories file by file")
.arg(Arg::with_name("brief")
.short("q")
.long("brief")
.help("Report only when directories differ")
.display_order(1))
.arg(Arg::with_name("null")
.short("0")
.long("null")
.help("Print raw NUL-separated paths")
.display_order(2))
.arg(Arg::with_name("color")
.long("color")
.value_name("when")
.help("Print output in color")
.takes_value(true)
.possible_values(&["never", "always", "auto"])
.default_value("auto")
.display_order(3))
.arg(Arg::with_name("progress")
.long("progress")
.value_name("when")
.help("Print progress reports")
.takes_value(true)
.possible_values(&["never", "always", "auto"])
.default_value("auto")
.display_order(4))
.arg(Arg::with_name("block-size")
.short("b")
.long("block-size")
.value_name("block-size")
.help("Read files in blocks of <block-size> bytes")
.takes_value(true)
.validator(is_valid_block_size)
.display_order(5))
.help_message("Print help information and exit")
.version_message("Print version information and exit")
.arg(Arg::with_name("old")
.value_name("old")
.required_unless_one(&["help", "version"])
.hidden(true)
.index(1))
.arg(Arg::with_name("new")
.value_name("new")
.required_unless_one(&["help", "version"])
.hidden(true)
.index(2));
I think the builder pattern could be a good fit for Javis. But that's just a complete outsider's opinion who doesn't even program in Julia, so don't take that too seriously. I think the API being a bit more like gnuplot is just fine for Javis' apparent purpose.To answer your question more directly, yes, I do think that knowing a bit about internals helps me understand how I should be using it.
Cheers