The tech behind my Rust docs presentation

Yesterday I gave a presentation to the San Fransisco Bay Area Rust meetup, A broad vision for the Rust docs stack.

I gave this presentation from my home in Melbourne, Australia to the audience in the San Fransisco Bay Area; yet the slides that I used were running on a machine there and I controlled them from my own laptop.

I wanted to use the full WebRTC fanciness for the presentation (data for sync, plus video and audio), but the associated risk was a little too high, so I didn’t try it. (I’m behind NAT, so I’m not sure if it would have worked given the current lack of TURN support in WebRTC implementations—​it would depend on the network configuration at the other end.) We ended up going with the boring low‐tech approach of using Skype for the audio and video.

(I have a laptop without a camera; I borrowed a laptop with a camera for the presentation, but logged in as a guest on that machine I was unable to install the proper video conferencing software that Mozilla use; hence Skype.)

The format: SVG

First of all, the basic technology: I tried various HTML5 slide deck things (most notably, deck.js, reveal.js, impress.js and the Google I/O 2012 slides template) but wasn’t really happy with any of them; I could have worked with what was there, extending them with CSS and so forth, but I didn’t have a great deal of time, so I decided to go with an unconventional tool that I’m already familiar with, Inkscape paired with JessyInk (an extension bundled with Inkscape).

The end result is an SVG presentation in which I get as complete control of the drawing area as one would with PowerPoint and which runs nice and smoothly in decent browsers. By choice, I didn’t use any advanced features of JessyInk (no zooming Ć  la Prezi, no transitions, no effects).

Fonts

I normally use Ubuntu and Ubuntu Mono and I also wanted a nice serif—​I settled on Cardo (regularly a favourite of mine).

Of course, as I’m deploying the presentation on other people’s machines, the fonts need to be embedded in some way. (Or else convert all the text to paths, which isn’t good for accessibility or file size.)

Fortunately, there’s no need to mess about with SVG fonts; you can use the same technology as you would in HTML, web fonts; but you just can’t use a <link> element (it’s not valid SVG); you’ll need to use a different technique. I went for the quick‐and‐easy approach of using @import inside a <style> element. Just be careful to escape any ampersands as &amp;.

You can do this from inside Inkscape with the XML editor, or you can just pull out your favourite text editor and add it into a <defs> element.

<style
   type="text/css"
   id="style11865">
  @import url(https://fonts.googleapis.com/css?family=Cardo:400,400italic,700|Ubuntu:400,500,400italic,500italic|Ubuntu+Mono:400,700,400italic,700italic&amp;subset=latin,latin-ext);
</style>

I believe that writing <?xml-stylesheet href="https://..." type="text/css"?> would also work, but it wasn’t the first thing that occurred to me.

Remote control

At first I wanted (as a loyal Mozilla fan—​and also because it’s pretty cool) to use TogetherJS, but it’s been designed for working in HTML, and I didn’t have time to adapt it to SVG (at the least, it’d need changing away from using document.head as the place to inject scripts and also for any HTML stuff to be done as foreign objects), so I decided to just write the stuff myself. I didn’t want the bother of setting up a WebSocket server myself (it takes time that I really didn’t have spare, and rust-http certainly isn’t in any state to do WebSocket), so I went with a hosted solution, PubNub.

The simplest place to hook communications in was the keyboard event handlers, so I assessed JessyInk’s and replaced them with things that just publish a message to all subscribers and have the reception method perform the actual local change. This worked a treat. (I reckoned it’d take 20 minutes, so I allocated myself an hour, 3Ɨ generally being a decent estimation inflation coefficient. It took 20 minutes to be all working, though I probably spent another ten minutes playing with it.)

No, this is not at all perfect; if someone comes in after the start, or if you click (I could have disabled this—​it’s a first‐class feature to do so—​but didn’t bother) or use slide inventory mode and move the mouse to a different slide, they’ll be out of sync; the Home or End keys can fix this up. Controlling the actual location would be a much more solid approach.

I also observed that the slide inventory mode, supposedly activated by the i key, now required pressing that key twice to activate or deactivate; I didn’t investigate why this is at all.

I didn’t hook up the mouse, so even if I’d wanted to I couldn’t have used JessyInk’s fancy live drawing tools.

I had cause to try it briefly on a Mac in Safari; it didn’t work well. I’m not sure whose fault that is. But it worked fine on Firefox, which is all I needed.

This is the actual code contained in the SVG:


<script
   xlink:href="https://cdn.pubnub.com/pubnub.min.js"
   id="script697" />
<script
   id="script699">
      if (document.location.search == &quot;?sync&quot;) {
          var pubnub = PUBNUB.init({
              publish_key: 'pub-c-ae886adc-785e-4677-9669-38dcf8b777f9',
              subscribe_key: 'sub-c-c7e137e0-676a-11e3-8ebb-02ee2ddab7fe'
          });

          var _jessyInkKeyDown = keydown;
          function keydown(e) {
              if (!e) e = window.event;
              var code = e.keyCode || e.charCode;
              pubnub.publish({'channel': 'keydown', 'message': code});
              //return _jessyInkKeyDown(e);
          }
          document.onkeydown = keydown;
          var _jessyInkKeyPress = keypress;
          function keypress(e) {
              if (!e) e = window.event;
              var code = e.keyCode || e.charCode;
              pubnub.publish({'channel': 'keypress', 'message': code});
              //return _jessyInkKeyPress(e);
          }
          // Deliberately not doing mouse events: they're added complexity I don't need today

          pubnub.subscribe({
              channel: 'keydown',
              message: function(m) { _jessyInkKeyDown({'keyCode': m}); }
          });

          pubnub.subscribe({
              channel: 'keypress',
              message: function(m) { _jessyInkKeyPress({'keyCode': m}); }
          });
      }
  </script>

Yes, that’s all that was needed to make my slides sync a quarter of the way round the world. (Approximately 92.47° of longitude.) Note that I made it so that you had to add ?sync onto the end of the URL to activate syncing, so that I could be lazy and publish exactly what I had used, without needing to change it.