Deprecate Keynote

Jake Ouellette
11 min readAug 31, 2015

--

We can make presentation writing fluid and seamless using layered software tools. Recently, I’ve discovered that combining a javascript presentation framework (e.g., reveal.js) with a templating engine (e.g., Jade, HAML), can allow for writing a presentations by hand that look like markdown but are as powerful as keynote.

For Developers, By Developers

I’m a software developer, and in 2014, I was preparing two presentations about software development, but for different audiences. One was geared towards developers who make tools used to build software while the other was targeted at Android developers who wanted to deepen their programming skills. They were vastly different audiences, but somehow the two talks had shared elements with some slides overlapping.

My brain, when I’m writing software for writing presentations about writing software used by software developers

One of these talks was about building software for use by software developers. Software development is often self-indulgent. We often try to automate our own work and reduce the amount of rote tasks we do from day-to-day.

Yet we give presentations that are largely constructed through a rote, manual process. Software developer presentations often have a pretty-typical structure:

  • an overview slide
  • some code examples
  • a cat gif
  • a conclusion.

We don’t use what-you-see-is-what-you-get (WYSIWYG) editors to make websites anymore, but we still use Keynote to make our presentations. Some of us use PowerPoint, mind you, not all presentation writers have the luxury of adding anvil transition animations.

I practiced one of my Keynote-based presentations with a colleague and he commented:

“by the way, the code examples weren’t formatted using a monospaced font.”

I was stupefied. Oh no: I didn’t bother to label my code examples correctly by using a different paragraph style, so I had to reformat and resize examples in over 200 slides. It took hours.

In retrospect:

  • I should have caught this problem earlier. At any stage of a presentation, I should be able to practice the incomplete talk and quickly get feedback. I’m a software engineer and I’m used to building minimum viable products. I often storyboard my talk in a text editor before I start making slides, but it’s hard to get quick feedback from something you can’t quickly show in a slide format.
Me, resizing everything
  • It should have taken less time to fix the problem. I wanted a consistent font size between sides, so I had to go to each code example and stretch the bounding box to fix the new monospace font.

#Hello world

This lesson inspired me to research a means to sketch out my talk and have it quickly be a facsimile of the final product. Markdown is a well-known, concise, language that’s great for sketching out ideas. Markdown is even the basis for the popular online slide presentation tools Deckset. Deckset’s Markdown-based talks are presentable directly from the text, MVP at its core.

Markdown’s simplicity is also a caveat, though; it has headers, bolding, hypertext links, but not a great deal beyond these basics. There are some common things that are in all of my software development talks that are not easy to express with markdown:

Appearing: It’s common that I have slide elements hidden that only come into view after other elements have been shown.

Fading: When making elements appear, I often like to hide previous elements to focus attention.

Disappearing: To really encourage focus, sometimes, I’ll go as far as to remove the previous element.

Highlighting: I use code examples throughout my talks. These examples often include segments being highlighted while the rest of the code is simultaneously faded out.

With an off-the-shelf tool, I wouldn’t have the freedom to invent any of these domain-specific requirements that make my presentations better for my audience.

Enter Reveal.JS

Reveal.js is a javascript framework for writing presentations. It has slide transitions, slide notes, and most notably, is written in HTML. I discovered it when researching markdown-based ways of writing talks. There are example presentations available online. With reveal.js, slides look simple:

<section>
<h2>Overview</h2>
<p>I’ll be talking about:</p>
<ul>
<li>Presentations</li>
<li>Cats</li>
</ul>
</section>

One of the reasons I accidentally discovered reveal.js is that it can render Markdown within slides:

<section data-markdown>
<script type=”text/template”>
## Overview
I’ll be talking about: * Presentations
* Cats
</script>
</section>

This Markdown feels extremely verbose because of the HTML script escape tags. It’s not nearly as elegant as Deckset. Although reveal.js provides me with text-based control over my talk, formatting the HTML tags wouldn’t provide me with the ease and readability I was looking for.

Jade, with envy

I had a moment of brilliance when reflecting upon the verbosity of javascript-based presentations: I was writing was a talk about layering cohesive, independent, software systems together to form a better whole. What better way to promote this ethos than to build a talk by applying these same principles?

That’s when I realized the applicability of Jade. Jade is a templating language originally built to make writing node.js apps cleaner and easier to maintain. Jade compiles to HTML, but is whitespace important, akin to the Python language. Here’s what the Jade equivalent of the previous example looks like:

section
h2 overview
p I’ll be talking about:
ul
li Presentations
li Cats

With Jade, all of the verbosity is modeling real semantic elements: headers, paragraphs, and lists. Jade was acceptable for me; not just acceptable, it was extensible.

As an example of its extensibility, the example presentation for reveal.js has giant chunk of initialization code in its <HEAD> — code that wouldn’t change between my talks. I didn’t want to look at that code, I wanted a document that just had slides. This dream was realizable with Jade, because you could simply move all that code into a separate file, then import it with a single line into any talk:

extends ./layout.jade

This greatly simplified my talks. Now I had a single document, and all it had in it was slide content.

Adding Common Presentation Components

My original use case for reveal.js was building sufficiently expressive presentation slides. When I started out, I attempted to replicate common patterns I had in Keynote in this new framework.

Reveal.js out of the box can make it so HTML elements appear as you step between them. With HTML, all you’d need to do is add class=“fragment” to a tag. With Jade, it’s even easier. It looks like:

Appearing elements
ul
li.fragment mutable state
li.fragment inheritance
li.fragment classes
li.fragment identity

Fragments appear when you step into them, and once shown, are visible permanently. These fragments get extra HTML classes as their state transitions:

  • .current-fragment — Set when the fragment is the active frame of the slide
  • .visible — Set once the fragment has been the current-fragment, and all frames after that.

With these two classes, you can use CSS to create your own behaviors. For example, I was able to make material I covered fade out to keep the attention of my audience:

Fading out elements
.dimafter {
color: inherit;
text-shadow: inherit;
opacity: 1;
visibility: visible;
}
.fragment.visible:not(.current-fragment).dimafter {
color: inherit;
opacity: 0.1;
visibility: visible;
}

Once I added these tags, all I needed to do was mark list elements with them:

section
ul
li.fragment.dimafter "message passing"
li.fragment.dimafter "late binding"

Sometimes, I like to keep a single header, but swap out the content of a slide. The CSS required for this is similar to dimming text, except the element gets removed from the layout entirely.

.replaceafter {
color: inherit;
text-shadow: inherit;
opacity: 1;
visibility: visible;
position:relative;
display:block;
}
.fragment.visible:not(.current-fragment).replaceafter {
color: inherit;
opacity: 0;
visibility: hidden;
display: none;
}

These were just as easy to set up as the `dimafter` elements:

section
p High Cohesion
p.fragment.replaceafter Enables separation of concerns
p.fragment.replaceafter Minimizes changes to code

Code examples are straightforward to add to a talk. They can be incorporated by simply using a pre tag.

pre
| class example {
| public method {
| // Code here.
| }
| }

One thing I didn’t love about code examples out of the box is I couldn’t easily callout small segments of them easily. I decided I wanted something elegant, such as outlining a specific line to be highlighted. I was able to hack up something that looked like this:

pre.fragment.dimcode
| public example {
span.fragment.dimcode
br
| public method {
br
| // Code here.
| }
| }

Suddenly, my hacking started to reduce the readability of reveal.js. I wanted this to feel like Markdown, but with some unique components. I was able to solve this by creating mixins. Mixins are a Jade templating technique to simplify the creation of reusable blocks of HTML tags. The two mixins I created were:

Code examples — the segment of a slide containing code

mixin codeexample
pre.fragment.dimcode
block

Code blocks — highlighted sections of a code example with unique behaviors

mixin codeblock
span.fragment.dimcode
br
block
br

The pervious example was reformatted into:

+codeexample
| public example {
+codeblock
| public method {
| // Code here.
| }
| }

I found this to be much more readable, and with a lack of a better solution, stuck with it. The code-dimming behavior took a bit more CSS to animate nicely, but actually making the blocks fade in and out was a simple matter of making the code examples have the correct visibility based on whether or not it was the current fragment:

Code fading
.reveal .slides section .fragment.visible:not(.current-fragment).dimcode {
color: rgba(255,255, 255, 0.3);
visibility: visible;
}
.reveal .slides section .fragment.visible.current-fragment.dimcode {
color: rgba(255,255, 255, 1);
visibility: visible;
}

If your slide has a custom look-and-feel, it’s easy to build custom components that represent the layout:

I was able to build this by defining a Jade mixin that I named “imageslide” which represents this pattern. It’s easy to add content using this imageslide mixin:

+imageslide('resources/android_robot.png', '(...footer text...)')
h2 Android
ul
li Google
li Java
li Netrunner

The mixin itself was composed from basic HTML divs and styling:

mixin imageslide(image, footer)
section
div
div(style='float:left;')
img.noborder(src=image, height='300')
div
block
div(style='clear:both;')
em=footer

I’ve collected all of these examples into a Github repository that I’m affectionately calling reveal.jade, a thin composition layer that requires reveal.js as its base.

Mechanics of Giving the Talk

When giving a talk with keynote, I rely a lot on slide notes. I prefer that my presentations are lean: Mostly images, some text, but the text is often not directly read, but instead, explained.

Reveal.js supports slide notes trivially by adding an element called aside with a class=“notes”. In Jade, this is beautiful:

section
p Dynamic dispatch is sometimes called polymorphism
aside.notes.
Polymorphism is what
java devs are used
to hearing...

To start reveal.js you run grunt with the command: `grunt serve`. Normally, with reveal.js, when your index.html is updated, the page reloads. However, I’ve layered jade on top of it, so now I needed a way to watch files. There are a lot of great tools for this, fswatch, facebook watchman… The easiest thing for me to set up was a Gradle task that executes a small shell script. Since Gradle 2.6, it’s had file watching support.

What isn’t perfect?

For me, this was a completely novel way of writing a talk. I had a lot of fears going in that I wouldn’t be able to even complete a single talk on time. What I’ve found is although these methods are powerful, there are a couple of areas with opportunities for improvement:

  1. Presentation sharing — Exporting PDFs is a feature of reveal.js, but it exports all the fragments. I only want to export all fragments on slides where I’ve got disappearing elements. I haven’t had an opportunity to try decktape, though I’m curious if it has any features to help ease this pain.
  2. Greater than symbol in code examples — Jade has a weird behavior with the `<` and `>` symbols. Normally `|` means that the line of code gets rendered directly to html without being processed for HTML tags, however, < and > still get escaped during the conversion. This caused me to have to manually write all my `>` symbols as &gt;, which was a detriment to readability of the document.
  3. Drawing and animating shapes — One thing I did pretty often in keynote is animate sequences of events with arrows moving around boxes. This is one of the only places a WYSIWYG editor ends up making sense. I wish I could easily design an animation and then export it to a nicely laid out widget composed of html, canvas, and javascript. In the interim, I’ll likely build these in keynote and hack them in, either via exporting the gross keynote HTML and manually pulling in the one slide, or via some path that converts the keynote to quicktime and finally to a gif. Ugh.

Besides rough edges, another concern I have with stopping using keynote is the rate by which the web development community replaces javascript frameworks (and, by proxy, these presentation frameworks.) Decktape claims it can print slides from a number of different frameworks: CSSS, deck.js, flowtime.js, HTML Slidy, impress.js, remark.js, reveal.js, Shower, and Bespoke.js. Although I’ve heard good things about reveal.js, I haven’t had nearly the time to explore how well Jade would layer on top of other options. I wouldn’t be surprised if some of my CSS components are already defaults in other frameworks.

Conclusions

Recently I was challenged to give another two talks in succession that ended up sharing about a third of their content, and this was my first opportunity to apply these techniques I had been researching. Refactoring one of the talks to work for the other presentation was straightforward, simple, extensible. I look forward to giving more talks with these techniques.

Please feel free to give me feedback if there’s a better way I could be doing any of this, and definitely check out my GitHub repo for the examples above.

--

--