BIT-101
Bill Gates touched my MacBook Pro
This is a project I am really happy about. I don’t know if anyone else will ever use it and that’s fine. It scratches a major itch for me and that’s great. I really love crafting my own development tooling so I have an environment that works just like I want it to. In this case, there were no tools that I could find to do what I wanted to do, so I made one. And it works!
I create animations. In code. Generally I write the code for a single frame of an animation. This has a percentage
variable passed to it that ranges from 0.0 to 1.0, depending which frame is being rendered. All the animation is based on that single variable and allows me to create perfectly looping animations.
I render each frame out as a .png
file in a frames
folder, then run ffmpeg on those frames to output either an animated gif, or more recently, an mp4 video. A single animation can have several hundred frames, and if the code is complex, can take a few minutes to render.
I don’t want to wait all that time to see what the animation is going to look like. Maybe it’s all wrong and I’ll be able to see that within a few frames, cancel, fix things and re-render.
Everything I do is on the command line. I code in neovim, in a terminal, compile my code with the Go toolchain, run ffmpeg to create the animation, which then launches a gif or video viewing program to play the result. So there’s no IDE with automatic previews of what’s going on. But I do have that folder of .png
s sitting there.
Early on, if I wanted a preview, I’d open up a new pane in tmux and navigate to the frames
folder, then open the first file there in an image viewer. Eventually I got smart and made a vim mapping, ,p
that will auto-launch the image viewer with the first frame. From there I could use the left and right arrows to scroll through each frame and see how things were coming along.
This worked great for a while, but it requires holding down the arrow key. And sometimes not enough is rendered, so it’s jumping from the last frame to the first, which is jarring, and I’ll just wait for a while, then go back to holding the key again, until enough frames were rendered to give a good representation of the animation.
Not awful, but I had this idea of an application custom build for my use case. So I made it.
isv
is an image sequence viewer. So you have a sequence of image files that will be eventually compiled into a standalone animation. This lets you play that animation back before it is compiled. It is NOT at all optimized for large images and is not intended to be a general purpose image viewer. But it’s great at playing back image sequences of frames up to a few hundred kb each. This is fine for me because even if I’m doing a higher resolution project, I’ll usually start by rendering it in low res at first to work out all the details, and only switch over to the final version when everything is worked out.
isv
is meant to be run from the command line, even though it opens up a gui window. So it’s not going to work in a terminal only vm or while sshing into a remote machine. You can either open it up in the directory where your frames are, by typing isv
there, or giving it a path to where those frames are: isv path/to/frames
. It will automatically load and display the first image (png
, jpg
or jpeg
) it finds. You can then use it just like I described using any other image viewer - scrolling back and forth through frames using the left and right arrow keys. When it hits the last frame it will loop around to the first, and vice-versa if going backwards. Other minor features include hitting f
to go to the first frame and l
to go to the last. So far though, that’s no better than what I had.
But hit p
and the frames start auto-playing through just like a video player, auto-looping when it gets to the end. Hit p
again, or space, and they stop. Same thing with r
- it will play the frames in reverse. And even better, b
will play in “bounce” mode. The animation will play forward to the last frame, then bounce back and play in reverse to the first frame, over and over. This is really good in the early stages of a render where there are fewer frames. Rather than that jarring jump back to frame one, it bounces forward and back smoothly and is a much better experience. As you get a few seconds into the animation, you may decide to switch it back to regular play mode.
By default, isv
attempts to play the frames back at 30 fps. Really just a bit slower than that, since all it really does is put a 33 ms delay in between each frame and doesn’t account for any other overhead. But this is just a preview, so I decided not to overcomplicate it. Using the up and down arrow keys you can increase the speed to 60 fps (aspirational - you very well may never achieve that) or unlimited (no delay), and decrease the speed to 10 fps, 5 fps and 1 fps, in case you want to inspect the details of your animation in slow motion.
The status bar will report the current play mode and attempted fps.
When isv
launches, it reads the directory and makes a list of the supported image files there. This is what it starts playing through. But if you’re actively rendering the frames of your animation, you will want to update that list from time to time.
Hit w
and it will start refreshing the image list every four seconds. Hit it again to stop watching. Of course this is not really watching, in the sense of an event-driven system where it knows when the directory contents are changed. It’s just reading the directory again. I may eventually do real file system watching, but it may be overcomplicating things, as it seems to work pretty well as it is.
If you want to refresh the list more often, hit the <
key (technically ,
since you don’t need to shift). Or to refresh less often, >
(or .
). These will set the update interval in one-second intervals from 1-10.
The watch state and timing data is also displayed in the status bar.
By design, I didn’t want to assume anything when you start isv
, so it doesn’t auto-play or auto-watch by default. But you can do any of that with command line flags.
-p
will have isv
auto-play when it starts. Likewise -r
and -b
will play in reverse or bounce mode upon startup.
-w n
will start watching the directory for changes every n
seconds. i.e. -w 2
will refresh the list every 2 seconds.
You can combine these like isv -p -w 2
or even isv -pw 2
.
In my vim mapping to preview the currently rendering animation I set it up as isv -bw 2 &
so it starts in bounce mode and refreshes every 2 seconds. The final &
has it run as a background thread so it doesn’t block my vim output.
isv -h
will of course show the full help file, which includes the command line flags as well as the keyboard shortcuts available while playing.
isv
was built with fyne (https://fyne.io/) which is a cross platform gui framework for Go. I found it super simple to get started with and really easy to figure out just about everything I needed to. The only real hard part was the “cross platform” part. Normally cross-compiling Go code is a piece of cake. But since fyne links to external C libraries for native ui elements, it needs access to a C compiler such as gcc or clang even to compile on your current OS. Compiling for a different OS is even more complex. They also have a tool called fyne-cross (https://github.com/fyne-io/fyne-cross) which helps, but can get pretty complex in itself. I was able to compile Linux on Linux and Windows on Linux. But I had to compile the MacOS version on a Mac. Even still Apple now quarantines unsigned apps on their new arm64 systems and you can only fix it on the command line, not in the control panel like you used to. (Instructions in the readme in the repo listed below.) So if you want to install a pre-compiled binary on your M1, you’ll have to jump through some hoops. Sorry, but I’m not paying Apple so that you can install my app on your computer.
Of course, this is all open source. You can check out the code and try to build it for yourself, try to install it through the go install
mechanism, which is pretty sweet, or just grab a binary release:
At this point, I’m pretty much done with development on isv
. I’ll be using it daily in my animation creation and fixing any bugs that might crop up or adding any new features that spring to my mind. But for now it does just what I want.
Comments? Best way to shout at me is on Mastodon