Randomize slides in reveal.js

I have a reveal.js presentation with approximately 300 slides. The purpose of this presentation is to cycle slides in "kiosk mode" on a monitor behind a conference booth.

To create a "kiosk mode" I've got:

Reveal.initialize({
    controls: false,    // hide the control arrows
    progress: false,    // hide the progress bar
    history: false,     // don't add each slide to browser history
    loop: true,         // loop back to the beginning after last slide
    transition: fade,   // fade between slides
    autoSlide: 5000,    // advance automatically after 5000 ms
});

This works very well, but I'd like to randomize the slides. The slides are currently just a list of 300 <section> tags in the index document - they aren't being pulled from anywhere external. Currently random: true isn't a configuration option in reveal.js.

The display order of fragments can be controlled with data-fragment-index. Is it possible to do something like that with sections? Is there a way to trick reveal.js into randomizing my slides?

My preference would be to shuffle them each time around - that is, to show slides 1-300 in random order, and then shuffle them, and show 1-300 again in a different random order. I would also be happy with just jumping to a random slide for each transition, though.


While Reveal itself does not have this functionality built in, it does let you set up event hooks to do actions when all the slides are loaded, this means JQUERY TO THE RESCUE!

You can combine Reveal's "All slides are ready" event with simple javascript to reorder all the sections, here's a simple PoC:

First import jQuery, I did this by adding it directly above the import for js/reveal.min.js:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

Then, set up an event listener:

Reveal.addEventListener('ready', function(event) {
    // Declare a function to randomize a jQuery list of elements
    // see http://stackoverflow.com/a/11766418/472021 for details           
    $.fn.randomize = function(selector){
        (selector ? this.find(selector) : this).parent().each(function(){
            $(this).children(selector).sort(function(){
                return Math.random() - 0.5;
            }).detach().appendTo(this);
        });

        return this;
    };

    // call our new method on all sections inside of the main slides element.
    $(".slides > section").randomize();
});

I put this right after declaring my Reveal settings and dependencies, but I'm pretty sure you can put it anywhere.

What this does is waits for all javascript, css, etc to load, manually reorders the slides in the DOM, then lets Reveal start off doing its thing. You should be able to combine this with all your other reveal settings since it's not doing anything disruptive to reveal itself.

Regarding the "shuffling them each time around" portion, the easiest way to do this would be to use another event listener, slidechanged. You could use this listener to check if the last slide has just been transitioned to, after which the next time slidechanged is called you could simply refresh the page.

You can do this with something like:

var wasLastPageHit = false;
Reveal.addEventListener('slidechanged', function(event) {           
    if (wasLastPageHit) {
        window.location.reload();
    }       

    if($(event.currentSlide).is(":last-child")) {
        // The newly opened slide is the last one, set up a marker
        // so the next time this method is called we can refresh.
        wasLastPageHit = true;
    }
});

As of reveal.js 3.3.0 there is now a built in helper function for randomizing slide order.

If you want the slide order to be random from the start use the shuffle config option:

Reveal.initialize({ shuffle: true });

If you want to manually tell reveal.js when to shuffle there's an API method:

Reveal.shuffle();

To shuffle the presentation after each finished loop you'll need to monitor slide changes to detect when we circle back to the first slide.

Reveal.addEventListener( 'slidechanged', function( event ) {
    if( Reveal.isFirstSlide() ) {
        // Randomize the order again
        Reveal.shuffle();

        // Navigate to the first slide according to the new order
        Reveal.slide( 0, 0 );
    }
} );