My painful, futile quest for programmable slideshow animations
I wanted a slideshow software with programmable animations. I got suffering instead.
First of all, new TLA+ workshop! October 16th, details here. Use the discount code C0MPUT3RTHINGS
for $100 off.
But enough about business, I'm here to complain.
My painful, fruitless quest for programmable slideshow animations
I'm giving the Are We Engineers talk in Perth September and looking over the slides has reminded me of how much I hate slides. I started with PowerPoint but switched to Beamer in 2018 or so, which is a LaTeX package for making slide decks. Unlike PowerPoint, it's a text file, which is makes version control and synchronization a lot easier. But then I saw some really good slide decks and realized that if I wanted to give the best talk possible, I'd have to make really good slides. I don't have an eye for design and I tweak my talks too regularly to pay a designer to "bake" them.
So what does that leave? Animations! Good animations make things feel alive. I'm not talking about making text spin around but actually adding semantic value, like showing a diagram and smoothly zooming in to part of it. This is where beamer falls flat; since it only outputs pdf, the only "animations" are appearing and disappear.
I went back to PowerPoint for a bit and found you can do complex animations, but it's really hard. PowerPoint really doesn't want you adding more than one or two simple animations to a slide. Like if you want to make things a thing move from A to B, that's a "move arc". If you add two move arcs to an object there's no way to "anchor" the second one to start at the end of the first one. You can manually align them but then if you change the nature of the arc (say, it go left-right instead of up-down) it will reset the starting point of the arc. And also its duration and delay, for some reason. The whole animation system is filled with these kinds of footguns.
It seems like Microsoft is just hoping people forget about animations? There've been no new animations since 2016,1 There's nothing in the JavaScript API, and the animation section of the XML spec just tells you to read the ISO standard, which is 5000 pages long.
So to hell with GUIs. If we want to have programmable animations, we gotta go our own way.
What to do instead
I know some people run slides from their browser, so that's... html, I guess? That makes sense, there's a whole animation layer in CSS, so you'd just need a javascript slideshow package and you're good to go. I did some searching and found revealjs and impress.js. I decided to save that for later and focus on animations, because that's what's interesting to me.
Animating things in CSS seemed real finicky, but some blogger I forget (I think Cassie Evans?) mentioned the greensock library (gsap), which has a nicer imperative API for animations. It also works on SVGs. I like SVGs! They're easy to make, they scale well, and I can edit them in Inkscape. And most importantly, there's a whole bunch of sites with premade svgs (1 2 3), which is good because I can't draw.
Making an animation's SVG
Simple enough.
- Load a new project in inkscape, using a "slideshow" template
- Copy a bunch of svgs into a slide.
- Go through the XML and give IDs to things I want to animate. This could be entire SVGs or a part of an SVG, etc.2
- Lay down a bunch of animation guidelines, like targets to move to and paths to follow, and put them in a hidden layer.
- Save the SVG.
I have a bunch of tricks I do to make this editing phase easier, maybe that'll be a blogpost in time. In any case, it's not too hard to make an svg, and then I just need to load it into an HTML file, add a <source>
for gsap, and I'm good to go.
That's when I hit problem number 1.
Damn Browsers and their damn security measures
So there's two main ways to embed an svg into html: an <img>
tag and an <object>
tag. An image tag loads it in as an image, an object tag inserts the entire DOM tree as a subdocument.
Obviously, you can't modify an embedded image with javascript. But neither can you modify an embedded object. I think this is a security thing? Objects are external resources and you don't want it messing with your page or vice-versa. I think it's a dumb idea, because it's inconveniencing me personally by making my dumb use case slightly harder.
Good news is there's a third option. Bad news is it's embedding the whole svg inside the HTML file. And then manually updating it every time I have to tweak the svg.
Eff that. I'm doing this project to do less grind, not more. Time for a metafile. Step one, make an HTML page that's also valid XML.3 Step two, add a new tag:
<animation svg="path/to/svg"></animation>
Step three, write a python program that reads in the "XML" file and replaces the body of the tag with the svg content. Means I can't put a <
in my javascript but oh well it works. After that, I can put the animation logic in an HTML script tag and I've got animations!
Much later I'll discover that svgs can include scripts too and I could have just put the animation directly in the svg. This seems like it'd solve some problems, but it won't.
The high point
Once all of that's actually done, actually animating turns out to be a cinch. I got all the payoff I was hoping for: I can choreograph animations on several objects, I can reorder steps and timings without breaking everything, I can try several variations at the same time, all sorts of great stuff.
This is where it kinda sucks to be doing this as a newsletter. I can't embed an animated SVG; the best I can do is drop a gif and a link. So here's the link and here's the gif:
That's a seven step animation. If I change the starting coordinates of the machine in the svg, it'll still move to the correct spot in the animation. I'm especially satisfied with the saw motion, which would be hell to do in powerpoint.
Now all I have left is to learn a javascript slideshow library! How bad can it be?
Later bites me in the ass
I'm going to be talking about RevealJS here but the same problems I have apply to the other libraries I looked at. I haven't used it in anger and don't want to be too hard on it, and I'm sure it's a great tool for lots of people! Why it wasn't a good tool for me is apparent in how it describes itself:
A tool that enables anyone with a web browser to create fully-featured and beautiful presentations for free.
One thing I've learned is that "fully-featured and beautiful" means a very particular style. RevealJS is designed to make beautiful presentations that look like this:
If you want something very different from that, then RevealJS is the wrong tool for the job, in the same way that a toaster is the wrong tool to cook a steak.
RevealJS slides are a single, giant html file. Slides look like this:
<div class="reveal">
<div class="slides">
<section>
slide one
</section>
<section>
slide two
</section>
</div>
</div>
The bigger problem is that, as it's a single html page, all of the animation javascript is dumped in the global namespace. If I have a gsap.to('.foo', x)
somewhere, that affects all of .foo
elements in all svgs. I can't work on animations in isolation anymore, since they're all dumped in the global namespace.
Okay, but this is because I'm inlining all of the svgs, right? And now I know that I can put the javascript inside the svg file, can't I just include it as an <object>
? The problem here is that RevealJS loads in all of the objects at the very beginning, which means that all of the animations start immediately. By the time I get to the slide, the animation is already over. If I inline the svg I can reset it on the corresponding slide load, but then I have the global namespace problem.
This is only two yaks deep. I tried both approaches and ran into even more problems with each, which had their own workarounds, which lead to even more problems. And this was just to get animations working correctly. I had other issues with "regular" features! The size/layout/spacing of slide elements is dynamically computed from all the content, so adding a new subheading can make all of the other text on the page smaller. This makes things like consistent headers and footers really tough to manage.
At some point I decided the only way to get consistent layouts would be to make every slide an SVG, and then dynamically inject other svgs representing layout and footers into each "slide". So now I'm injecting svgs into other svgs into html and
This is insane
This is so much effort
How about I just put the CSS animation in a powerpoint slide?
So I look up how to do that:
"Record the screen and embed a video"
Goddamn it.
My current "process"
- Create the animation in SVG and CSS. That's still easy.
- Set up OBS to take a recording of my browser running the animation.
- Place the recording on its own Powerpoint slide, crop it, align it, and frame it.
This is awful, and it's made worse by multistep animations (where I want the steps to sync with what I say). For those, I need to record each step separately from the rest and put it on its own slide. AutoHotKey helps a bit here:
#SingleInstance Force
WinActivate "ahk_exe obs64.exe"
Send "{F14}" ; In OBS this is "start record"
WinActivate "ahk_exe firefox.exe"
Send "{F5}"
x := 0
while(PixelSearch(&Px, &Py, 15, 15, 30, 30, 0x0000D6, 3)) {
x++
Sleep 10
if(x > 500) {
break
}
}
WinActivate "ahk_exe obs64.exe"
Send "{F14}"
The animation svgs have a blue border which disappears after the animation "section" is over. As soon as AHK sees the blue pixel disappear it goes over to OBS and stops the recording. Then I move the starting point of the animation over (with gsap.seek) and rerun the script. Still a lot of manual effort to split all of the animations, but less than before.
...And in writing that I just realized I should be doing all the postprocessing in Da Vinci Resolve. I can just do one recording and split the video! Jesus I'm an idiot for not using DVR sooner.
Lessons Learned
I wanted to conclude this with "I got nowhere and achieved nothing", but I actually learned a lot about SVGs and animation, which will be useful blog posts. And I can now make better presentations, just with a lot more effort than I was hoping for.
Still haunted though. "Programmable slideshows with complex animations" shouldn't be this hard. I feel like a crazy person.
If you're reading this on the web, you can subscribe here. Updates are once a week. My main website is here.
My new book, Logic for Programmers, is now in early access! Get it here.