The Wrap project provides a framework for creating and viewing presentations using web tools. Topics are
A Wrap presentation consists of a few static files, published on any web site, using any web server. An optional custom web server is provided:
This can be used for two purposes. First, it allows an author to develop a presentation on a local computer, before publishing somewhere else. This may be to test presentations before publishing, or to speed up development if the publishing process is slow.
Second, it provides a way of making a presentation totally self-contained. The server and a browser can be run on the same laptop, and the laptop can be taken to a venue, with no dependency on internet access. Only a data projector or similar is needed.
The server is written in JavaScript, and can be run using Node, which may need to be installed first.
Create a folder containing server.mjs
and a web page
index.html
, run the server with the command node
server
, and then view the page by visiting
http://localhost:8080/
with a browser.
Authors need to find a way to make sure web pages are valid, using an HTML-aware editor, or a framework, or a markdown language, or a template language, or a validity checker, for example. (A previous version of the server delivered pages as XHTML, for immediate feedback on errors. XHTML is now effectively obsolete, with browsers no longer updating it to match advances in web standards.)
If the server is run on Linux or macOS, URLs are case sensitive, whereas if it is run on Windows, URLs are case insensistive. That's because (as with almost all servers) URLS are treated as file paths and handed over to the platform's file system. So problems can arise if web pages are developed on one kind of platform and published on the other.
The viewer is the script:
A simple presentation consists of a folder containing wrap.mjs
,
and a web page index.html
with an inclusion like this:
<script type='module' src='wrap.mjs'></script>
The page index.html
is viewed in a browser, and the F11 key or
similar is used to make the browser go into full-screen mode. All scripts
associated with Wrap are modules, and their filenames have extension
.mjs
as a reminder that they must be included in pages using
<script type='module' ...
The viewer has been tested on recent Chrome and Firefox browsers. The relevant standards are followed, so that any up-to-date browser should work. No attempt has been made to support old or unusual browsers. If a presentation is made available to other people, either they can be told to use a suitable browser, or they can be given a PDF version of the presentation.
The simplest form of a one page presentation is:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Title</title> <script type='module' src='wrap.mjs'></script> </head> <body> <section> ... </section> </body> </html>
This can be used as a skeleton starting point for a new presentation by
copying it into a file index.html
. Here's a simple three-slide
example based on the skeleton:
view minimal example (or download)
Its slides are displayed in the default web-page style. They will look
more like normal presentation slides when style is added. A presentation is a
normal HTML5 web page, with each slide in the presentation being written
between <section>
and </section>
tags. The
viewer makes one of these visible at a time.
Wrap supports the idea of organising a presentation as a series of slides, in the traditional style. However, there is no desire to curb creativity by forcing the author into a mold. An unconventional presentation could consist of a single slide with a complex custom interactive behaviour.
The examples of HTML in this document have no indenting, and no blank lines except between slides. However, the most convenient layout for HTML is a matter of personal preference, perhaps depending on the features of the editor or other authoring tool being used.
Here is an example of the simple use of style to produce slides with large text and a coloured banner across the top:
view styled example (or download)
Style is added using the CSS style language. Style rules can be added to individual elements for one-off effects:
...<span style="color:red">danger</span>...
or they can be put into a style element in the head if they are to be used in multiple places in the presentation:
... <style> h2 { font-size: 200; } </style> ...
or they can be put in a separate style sheet, style.css
say, if
they apply to multiple presentations, and then a link can be added in the
head:
... <link href="style.css" rel="stylesheet" /> ...
A template can be defined to add identical elements to each slide. This example adds an image to every slide:
view template example (or download)
The template is:
<template> <img class="icon" src="wrap.png" /> </template>
The items in the template are copied and added to the end of each slide. Style is used to affect how template items look in the slides, using classes. Ids can't be used because they wouldn't be unique after copying. For example, this rule places the image on top of everything else, in the top left corner.
img.icon { position: absolute; top: 0; left: 0; }
An anonymous template is a default which applies to all slides. The
example shows that if the title slide is different from all the rest, it can
be handled by using different tags and style. The title slide in the example
uses h1
instead of h2
for the heading, with its own
style, and there is an id on the title slide so that a style rule can be used
to 'switch off' the icon image.
#title img { display: none; }
In more complex situations, multiple templates can be used. To define multiple templates, give them different ids:
<template id="normal"> ... </template> <template id="special"> ... </template>
Then to use a specific template for a slide rather then the default, add a class attribute:
<section class="normal"> ... </section> <section class="special"> ... </section>
If a slide contains an element of class here
, the current slide
number is inserted as its text:
<p class="here"></p>
A slide number element can be inserted from a template.
PageDown (or right arrow or down arrow or swipe left) takes you to the next slide, and PageUp (or left arrow or up arrow or swipe right) takes you to the previous slide. These should be familiar from PDF viewers and other presentation tools. Note, however, that the space bar, the enter key and the backspace key are not used for navigation, in case they are needed by a demo that involves typing text.
A clicker can be used to navigate, since it normally sends PageDown and PageUp signals. Explicit navigation links between slides can be added, either on every slide via a template, or individually using anchor tags, for example:
view navigation example (or download)
An individual HTML link in a slide to another web page works as normal, but a
link to another slide needs to be given the class jump
, so that its
behaviour can be adapted to do the right thing:
<section> ... <a class="jump" href="#info">see info</a> ... </section> ... <section id="info"> ... </section>
It is possible to use slide numbers, but using an id like this makes the link independent of slide insertions, deletions or reorderings.
If an element has class back
or next
, its
href
is filled in to form a link to the previous or next
slide. The jump
class is also needed:
<nav> <a class="jump back" href=""><</a> <span class="here"></span> <a class="jump next" href="">></a> </nav>
If desired, further links can be added which move to the previous or next segment of a presentation:
<nav> <a class="jump up" href=""><</a> <a class="jump back" href=""><</a> <span class="here"></span> <a class="jump next" href="">></a> <a class="jump down" href=""><</a> </nav>
Navigation links like this can be inserted from a template, to add them
uniformly to each slide. Segment boundaries are marked by slides with
data-up
or data-down
attributes linking them in
sequence. A less-than sign and greater-than sign are used as links, but they
have to be escaped as <
and >
to switch
off their special treatment in HTML. Backward links on the first slide, and
forward links on the last slide, are made invisible.
By holding down the PageDown or PageUp key, auto repeat can be used to get
quickly from one slide in a presentation to another. If the URL in the browser
is changed to add #3
on the end, say, then that causes a direct
jump to slide 3. This feature can also be used to create a link from elsewhere
to a presentation, starting at a specific slide. Clicking on the page number
adds the slide number to the URL to make it easy to copy or bookmark, and the
browser's back button removes it again.
The current slide number in a presentation is remembered so that, on return to the same URL, the presentation is started at the remembered slide. This uses local storage. (If you are worried about telling visitors about this and giving them the option to switch the feature off, as with cookies, the rules clearly say that you don't have to do that if the feature is just for the 'normal operation' of the site, rather than to track users or push adverts at them, for example.)
An aside is a slide that is not displayed in the main sequence, but can only be accessed by following an explicit link. Asides can be used for extra material that may or may not be displayed in an actual presentation according to circumstances. They can also be used for background information that appears in the printed or PDF form of a presentation, but not when presenting live. Here's an example:
view example of asides (or download)
An aside is exactly the same as a normal slide, except that it uses the
aside
tag instead of the section
tag. An aside is
named according to the most recent ordinary slide, e.g. asides following
slide 3
have names 3a
, 3b
, ...
Navigation with keys or with automatic navigation links bypasses the asides
(unless the current slide is already an aside) but explicitly added
jump
links can refer to them.
In the early days of HTML, the idea was that a page should say what to display, and it was up to the browser how to display it. This makes sense, and the idea is still current, because users have preferences such as how big the browser window is, and authors should respect that by not producing fixed-size pages, for example.
On the other hand, the idea has been, and still is, a great frustration to web authors in many circumstances, because they naturally want their pages to look the same, exactly as intended, in every browser and on every platform. As a result, there have been great advances in the standards, so that the exact pixel size and pixel position of almost every web feature can be controlled precisely.
Of course, the author of a presentation may not be interested in cross-browser or cross-platform issues, as long as the presentation works on the one computer used to present with. However, if a presentation has a long life, being used many times, or if the slides themselves are to be made available to other people, then these issues become important.
Perhaps the greatest exception to perfect pixel control is text. First of all, there isn't, and never has been, a single font that can be relied on to be installed on every major platform.
However, a good way round this, to produce slides that look similar on different systems, is to use web fonts. For example, suppose you decide to use the Tangerine font from Google Fonts. In the head of the presentation, you would add:
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Tangerine"> <style> .tang { font-family: 'Tangerine', serif; } </style>
The stylesheet from Google makes the font family Tangerine
available from the Google font site, and the style rule applies it to all
elements with class tang
in the presentation, with a fallback in
case the font isn't available or takes a long time to load.
A disadvantage of this is that the presentation may not be self-contained any
longer, needing network access to load the font. An alternative is to download
the desired font explicitly, say in TTF format as tangerine.ttf
,
and put it in the same folder as the presentation. Then put this in the head of
the presentation:
<style> @font-face { font-family:'Tangerine'; src:url('tangerine.ttf'); } .tang { font-family: 'Tangerine', serif; } </style>
Unfortunately, this isn't the end of the story. Even if you pick a web font, and even if you fix its font-size, and surprisingly even if the font is monospaced, the pixel measurement of the text differs between browsers, or between the same browser on different platforms, mostly because of different approaches taken to sub-pixel rendering.
So, it is best to go with the flow, and accept the fact that it is the browser which will ultimately decide where the line breaks come in a paragraph, for example.
Wrap has been used to good effect in the teaching of programming. An
extremely common requirement in that case is to be able to show a fragment of
program text in a slide. It is normal to use a pre
(preformatted
text) element for that:
<pre> console.log("Hello World!"); </pre>
The question naturally arises about what happens when the lines become too long to fit across the slide. It is not appropriate for the text to wrap, because program layout matters, especially in teaching. A better bet is to adjust the font size, so that the text fits. It is exceptionally time consuming and irritating to do that by hand, and in any case the width of the text is unpredictable, as explained above.
So Wrap provides automatic font resizing. For each pre
element,
Wrap dynamically checks whether the text overflows, and incrementally reduces
the font size until it fits. On the one hand, this is a crude technique, and
there may be a pause at the start while waiting for fonts to load and then
applying the process to the whole presentation. On the other hand, the technique
works no matter what browser or platform is used, no matter what style choices
are made which affect widths, and no matter what the display resolution is.
Sometimes, an author might want to reduce the font size of the text in a
pre
element, not because the text is too wide, but because it is
too long vertically. Wrap also checks for this, if the pre
element
is given an explicit height, e.g.
<pre style="height: 200px;">... ... </pre>
There is a potential problem with web fonts. If the initially visible slide
does not contain a particular web font, the browser may not load it. The
measurements used to resize the text would then be incorrectly based on the
fallback font. To avoid this, Wrap explicitly loads all the web fonts
mentioned in style @font-face
rules before resizing.
It is natural to want to add syntax highlighting to program text. Wrap is designed to take advantage of highlight.js. An example is:
view example of highlighting (or download)
In the head of a presentation, add (for example):
<link rel="stylesheet" href= "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/xcode.min.css" /> <script src= "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js" ></script> <script src= "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/languages/haskell.min.js" ></script>
This loads a chosen colour scheme (xcode in this case) and the highlight
script from a CDN (jsdelivr).
The most up-to-date version should be used, rather than the one shown, and
there are several CDN sites to choose from. Also, the highlight script may not
support all the languages which highlight.js
knows about, so a
language-specific script may need to be added, as illustrated here with
Haskell.
If the presentation needs to be self-contained, these files can be downloaded, put in the presentation folder, and included into the presentation with, e.g.
<link rel="stylesheet" href="xcode.min.css"/> <script src="highlight.min.js"></script> <script src="haskell.min.js"></script>
If Wrap detects that highlight.js
is present, then Wrap each
pre
element in the presentation is examined. A
data-lang
attribute on the pre
element is used to
decide what language the text is in. For example:
<pre data-lang="js"> console.log("Hello World!"); </pre>
In strict HTML, custom attributes, i.e. ones other than those specified for
the element in the standard, must have names which start with the
data-
prefix.
Often, all or most of the program fragments in a presentation have the same
language. If a data-lang
attribute is added to the body element,
that is treated by Wrap as a default for all the pre
elements in
the presentation. A particular pre
element can have a
data-lang="..."
attribute to override the default, or
data-lang=""
to prevent highlighting.
By default, the highlight.js
package highlights pre
elements with inner code
tags, and uses heuristic language
recognition and/or class attributes to determine the language. Wrap overrides
these defaults. It highlights any pre
element which has an
explicit or default language recognised by highlight.js
, and
determines the language using data-lang
instead of
class
, to avoid confusion with classes used for style purposes.
Often, when program text is shown in a pre
element, it is an
extract from a source file. A link can be made to the original source file
by adding a data-file
attribute like this:
<pre data-file="hello.mjs"> console.log("Hello World!"); </pre>
Wrap creates a link which is overlaid in the top right corner of the
pre
element.
There is a variation, using data-name
in place of
data-file
, where a filename or other label is attached to the
pre
element, but without making it into a link.
A presentation author wants to prepare material to fit exactly in a slide, and doesn't want to arrive at a venue only to discover that the local browser or platform or data projector causes the material not to fit, with ugly scroll bars being added, for example. Aside from the problems with text, there is also a potential problem with resolution.
In some ways, the old days of VGA projectors made things a little simpler, because the displayed resolution was always 1024x768 pixels. Now, with HDMI, the resolution of the projector or wall screen normally matches the resolution of the computer screen. But if the computer is not yours, it can be uncertain what the aspect ratio is going to be, let alone the resolution. Nothing beats a trial run at the intended venue to check whether everything is going to work.
If you know what resolution you are aiming for, either because you know the projector is VGA, or because you are taking your own laptop and you know the projector is HDMI, it is possible to check in advance. A useful technique is to install a window resizer extension in the browser on your development computer. This can be used to check the effect of a presentation on one or more specific screen resolutions.
The best approach seems to be to avoid having too much material on a slide, to avoid unnecessary absolute sizing or positioning, and to allow the browser to do what it likes.
When presenting using an extended desktop, either because there is no choice or because you want to look at notes on the main screen that are not to be displayed to the audience, some way of controlling what's on the extended desktop from the main screen is needed.
Wrap provides a feature where you can type ALT+w in a presentation. This creates an identical child window, or tab. If it is a tab, it can be dragged away to form a separate window.
All key presses except ALT combinations in the original window are duplicated and sent to the child window, so the two windows stay in step. The child can be dragged over onto the extended desktop, and the original window acts as a controller. The child can be made full screen with F11, while the original can be made small, allowing other windows to be viewed.
Typing ALT+O toggles overlays on or off. An overlay is an HTML element with
class overlay
. It is given a style display:none
and
then ALT+O switches between that and display:block
. Here is an
example where each slide is a full-sized image, and the overlays consist of
subtitle speaker notes.
view example of overlays (or download)
Animations can be written using JavaScript to do anything that is desired, though it can be a bit of a black art.
In a presentation, there are extra considerations beyond the normal use of JavaScript. There have to be ways to:
As a result, some conventions are set up for animations, so that they can be managed in a suitable way by Wrap. A simple example which reveals paragraphs in a slide one by one is illustrated by:
view example of animation
(or download)
view the reveal script
(or download)
An animation script must be a module with a default export. The export is a
function which takes a slide's section
element and returns a new
object representing an animation applied to that slide. The object can contain
any desired fields representing the current state of the animation, but must
provide methods start
, stop
, end
,
key
. These animation methods are:
start
is called when a slide is reached forwards from
a preceding slide. It sets the animation to its start point. It can also set
the animation going, if desired, rather than waiting for a key to be
pressed.end
is called when a slide is reached backwards, i.e.
from a following slide, to set the animation to its end point (if necessary,
by running through it at maximum speed).stop
is called when moving away from a slide, so that
the animation isn't running when the slide isn't being displayed.key
is called when a key is pressed. It is passed a
key code, and shift and control flags, as arguments. It returns
true
to indicate that the event was handled, and
false
otherwise.An animation is applied to a slide by adding a data-animate
attribute to specify the script file to be used:
<section data-animate="reveal.mjs">
Wrap dynamically imports the script, so there is no need to include it at the top of the presentation (though it does no harm). The dynamic import mechanism itself ensures that the script is only imported once, no many how many slides it is applied to.
The example reveal.mjs
animation is an event-driven one, where
changes only happen when the presenter presses a key. The animation recognises
the same keys as Wrap uses for navigation, so that the animation steps fit
seamlessly in to the presentation sequence, e.g. triggered by a clicker. The
presenter can go backwards through the animation as well as forwards, and the
animation is set to the end if the presenter navigates backwards to the
slide.
Animations can also be time-driven. An example is:
view example of timed animation
(or download)
view the countdown script
(or download)
The animation is a countdown from 10 to 0. The navigation keys are recognised by the animation. The PageUp key pauses a running animation, or goes back to the start if the animation is already paused, or skips to the previous slide (i.e. is ignored by the animation) if the animation is already at the start. The PageDown key restarts a paused animation, or skips to the end if the animation is already running, or skips to the next slide if the animation is already at the end.
For programmers, HTML's canvas
feature provides a lot of
scope. Here's an example:
view example of canvas animations
(or download)
view the draw script
(or download)
view the bounce script
(or download)
The example contains two animations. The first draws a diagram, using key presses to go through several stages (forwards or backwards). The canvas is placed over the slide. This is useful if you want to draw on top of other things on the slide, but is only likely to work if you know the screen resolution in advance: the example assumes 1024x768.
The second animation is a bouncing ball, illustrating that an image can be
drawn on a canvas, that the image can contain transparency, and that
requestAnimationFrame
can be used in place of
setInterval
for smooth animation at maximum speed. The canvas is
smaller, embedded in the slide, and centred, so that it is relatively
independent of resolution.
An animation can be defined to allow video or audio clips to be controlled using keys:
view video and audio example
(or download)
view the play script
(or download)
A single play
animation is provided which covers both video
and audio. PageDown starts a clip running, PageUp pauses it, and so on. A clip
is not auto-played, but is only started on pressing a key. (A browsers usually
prevents audio, or unmuted video, from playing unless the user starts them
during a user interaction. However, it may be possible to configure the
browser to allow auto-start.)
The style settings video, audio, img { display: block; }
are
needed if the media item is to fill the whole screen. Otherwise, they may be
treated as in-line items, and a few irritating pixels of "leading" may be
added which cause scroll bars to be added.
Printing and production of PDFs have only been tested using the Chrome browser, with a target of A4 paper size. Experimentation may be needed to get good results in other environments.
The first step is to add style rules to make adjustments. For example, to remove the navigation links, and to target portrait A4 printing with no gaps round the edge, try:
@media print { .back, .next, .up, .down { display: none; } } @page { size: 27cm 20.25cm; margin:0; padding:0; border: "none"; }
Next, press Alt+p to prepare for printing. This makes all the slides visible, and runs all the animations to the end. If there are problems with this, refreshing the presentation and pressing Alt+p again may be necessary.
Finally, use the print option in the browser. If the style adjustments are correct, no print options should need to be changed. To produce a PDF rather than printing to paper, change the printer target to Save as PDF.
Customising: The wrap.mjs
script can be freely
customised. However, there is no guarantee that later versions of
wrap.mjs
will be backwards compatible with the version you
customise, and there is no version numbering other than the repository commit
date. So, care is needed to merge customisations with updates.
Tickets: If presentations are hosted within an intranet which uses a single signon system, URLs may have tickets attached. These are annoying, particularly in browser history lists, because they are frequently out of date. Wrap has a demo feature which removes any ticket parameter attached to the presentation URL, and this can be adapted to other similar situations.
Mathematics: Browsers are required by HTML5 to support MathML as an embedded technology. However, authoring MathML text is fiddly, especially if it is not familiar to the author. MathJax provides an alternative, allowing LaTeX or AsciiMath to be used instead.
Illustrations: Several approaches to diagrams, sketches and other illustrations have been tried, with varying degrees of success. The problem is that the requirements, preferences and skills of authors differ widely. There doesn't at present seem to be an approach which is sufficiently general and robust to include in Wrap as an official feature. Some possibilities are mentioned here.
Static illustrations: If something static is all that is required, then any drawing or painting tool can be used, and an image exported for inclusion in a presentation. For example, UMLet, or UMLetino is a very useful and quick tool for simple diagrams consisting of boxes, ovals, arrows and labels. InkScape is a full-featured vector-based drawing tool. Krita is a full-featured pixel-based painting tool. Gimp is a full-featured image editing tool.
Animated illustrations: If you want to present a diagram which changes in discrete stages, you can of course produce a series of images from a drawing tool, and animate them by showing them one at a time. Alternatively, as shown in the animation section, a custom JavaScript animation can be written which draws onto a canvas. For more sophistication, an SVG diagram can be animated directly using JavaScript. But authoring SVG directly is not really practical, so a tool like InkScape would need to be used to create the initial SVG.
Hand-drawn illustrations: Sometimes, a hand-drawn sketch gives just the right impression of informality. If it only needs to be static, it can be prepared in advance as an image. To sketch live while presenting, the best approach seems to be to use your favourite mobile device with an accurate stylus, and see what software it has available for capturing and displaying sketches. This seems too hardware and skill dependent to make specific robust recommendations. An intermediate approach is to prepare a sketch in advance, capturing gestures and their timings, and animate it to produce a result which is "as live". There seem to be no simple, robust, open tools for this, though experience has been gained for some specific purposes with a custom canvas-based web page for recording sketches.
Recordings: There are various approaches to making a recording of a presentation. Perhaps the simplest is to record the audio of the presentation using a cheap USB microphone, then later use a tool like Audacity to tidy it up, and OBS Studio or similar to make a recording while running through the slides in time with the audio. (Note: it may be necessary to switch off Chrome's graphics acceleration option to get OBS and Chrome to work together.)
Prepared demos: For teaching programming, showing demos of editing, compiling and running programs is attractive. And this can be done particularly smoothly if it is within a presentation, rather than involving a clumsy and jarring switch of presentation environments. To show a program being edited, and then compiled and run in a text-based terminal, there are again both prepared and live approaches. For a prepared approach, all the text involved can easily be captured, and then its appearance on the screen animated to simulate the user typing or the tools producing output. The animation can be timed, or it can be controlled in segments (a character, word or line at a time) by key presses.
Live demos: For a live demo of using text-based tools, where the tools are driven from the presentation and the output from the tools is displayed in the presentation, a server-based approach is needed. A custom server can be set up, which the presentation communicates with, e.g. using web sockets. Some experience has been gained with doing this, but it seems very platform and skill dependent.
Interaction: If the presentation can be hosted somewhere where it has a publically accessible URL, then audience participation becomes possible. For example, a voting page can be set up, audience members can visit it on their mobiles or laptops, and the results gathered and displayed within the presentation. Again, this seems to be too environment specific to give much definite advice.