Automated Reveal.js setup

This post outlines my efforts to bring in markdown focused workflow for creating presentations. The tool allows setting up automated workflow leveraging markdown and Reveal.js.

Reveal.js has teased me for many days to Leave powerpoint/impress and try it. I never gave it a serious thought, as my existing setup was working just fine. But as now i have started to use markdown a lot .I realised the need for clean plaintext version of data and capabilities to present it easily and quickly. So i started to read about reveal.js and how to use it.

General reading around reveal.js suggested that people were either writing HTML, directly copy pasting markdown or relying on external tools like pandoc.

So the general use case i observed is as following:

  1. Write slides in markdown.
  2. Convert slides from markdown to reveal.js format (using pandoc)
  3. Place converted index.html and git clone reveal.js in same folder.
  4. To present launch the html file in browser full screen.

Advantage of this approach:

  1. Markdown is neutral in nature if written properly
  2. No need of a server style hosting or running your own python simple server

Disadvantages:

  1. If even a word is changed the steps 1 and 2 needs to be repeated.
  2. Once those changes are done browser needs to be refreshed or reopened.

At this point i saw multiple set of repetitions, so wanted to optimise and automate this approach. This is the point where i identified that reveal.js also supports external markdown syntax (silly me for not reading the README carefully the first time). However it had one caveat, the markdown needs to be served via web server for browsers to pick it up.

This is what led to my current automated setup. In short this one screenshot should showcase how simple it becomes to run presentations using this.

Reveal.js Automation setup
Reveal.js Automation setup

So what i have as my current setup is

  1. A bash script called “present” (glue for all : the heart/brain)
  2. Folder where git clone of reveal.js is placed
  3. Customised index.html with placeholder text

So after doing this one time effort this is how my setup looks like.

  1. Write markdown in any arbitrary location.
  2. “present setup” (if md file name is anything other then presentation.md then specify it) : This still looks like how we do pandoc however the additional commands is where the beauty of the script lies in.
  3. “present” : This is one command which performs following operations
    1. Start a python simpleHTTP server
    2. Based on the predefined browser path, start a browser (chrome / chromium) with url of index file in it.
  4. present print” : This performs similar steps (start webserver and lauch browser) but it also appends “?print-pdf” in the url which informs reveal.js to present slides in printable format.
  5. “present clean” : This will clean all the additional resource i.e. index.html and reveal.js

This setup allows me to continue working on markdown file and all i need to do is change file in markdown save and go back to browser refresh page to get the output reflected.

Once presentation is done and you close the browser then it automatically kills the python server that was started. (and hence not leaving stale bits.)

The fourth command : “present print” was added to ensure we are able to quickly create distributable copies of the presentation.

So without further ado here is the script

#!/bin/bash
echo "Present : Reveal.js Workflow Automation"
echo "Created by: Anant Shrivastava"
RJSVER="3.0.0"
CW=`pwd`
BASE="$HOME/Work/Presentations/presentation_resources/reveal/"
BASE_HTML=$BASE"/html"
HEADLESS=0
if [ $# -gt 0 ]
then
	if [ $1 == "headless" ]
	then
		HEADLESS=1
		shift
	fi
fi
if [ $HEADLESS == 1 ]
then
	echo "Headless mode selected ignoring browser check"
else
	if [[ "$OSTYPE" == "darwin"* ]]
	then
		if [ -f "$HOME/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" ]
	    then
	        BROWSER="$HOME/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
	    elif [ -f "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" ]
	    then
	        BROWSER="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"    
	    elif [ -f "$HOME/Applications/Chromium.app/Contents/MacOS/Chromium" ]
		then
			BROWSER="$HOME/Applications/Chromium.app/Contents/MacOS/Chromium"
		elif [ -f "/Applications/Chromium.app/Contents/MacOS/Chromium" ]
		then
			BROWSER="/Applications/Chromium.app/Contents/MacOS/Chromium"
		else
			echo "Chromium / Chrome browser was not found to be installed"
			echo "Please install it to use this script properly" 
			BROWSER="/Applications/Chromium.app/Contents/MacOS/Chromium"
		fi
	else
		if [ -f "/usr/bin/google-chrome" ]
	    then
	        BROWSER="/usr/bin/google-chrome"
	    elif [ -f "/usr/bin/chromium-browser" ]
		then
			BROWSER="/usr/bin/chromium-browser"
		else
			echo "Chromium/Chrome browser was not found to be installed"
			echo "Please install it to use this script properly" 
			BROWSER="/usr/bin/chromium-browser"
		fi
	fi
fi
BROWSER="$BROWSER"
BROWSER_PROFILE="$HOME/.profiles_chromium/presentor"
RESOURCES="$HOME/Work/Presentations/presentation_resources/resources/"
MARKDOWN_MODULES="$HOME/Work/Presentations/presentation_resources/markdown_modules/"
BASE_URL="https://github.com/anantshri/present/"
DEF_NAME="presentation.md"
if [ $# -eq 0 ]
then
	if [ $HEADLESS == 0 ]
	then
		python2 -m SimpleHTTPServer 9099 &
		pid=$!
		$BROWSER --app="http://localhost:9099/" --disable-gpu  --user-data-dir="$BROWSER_PROFILE"
		kill -KILL $pid
	else
		python2 -m SimpleHTTPServer 9099
	fi
elif [ $# -gt 0 ]
then
	if [ $1 == "init" -o $1 == "update" ]
	then
		echo "checking if base is upto date or not"
		echo "if base is not present we will create directories at $BASE"
		if [ -d $BASE/reveal.js ]
		then
			echo "Folder already exist"
			echo "Reveal.js is fixed to specific version $RJSVER"
			echo "More update features are not yet implemented"
			#cd $BASE/reveal.js
			#git pull
		else
			mkdir -p $BASE
			mkdir -p $MARKDOWN_MODULES
			mkdir -p $RESOURCES
			mkdir -p $BROWSER_PROFILE
			cd $BASE
			echo "git cloning the reveal.js repository"
			git clone --branch $RJSVER https://github.com/hakimel/reveal.js/
			mkdir $BASE_HTML
			#wget https://raw.githubusercontent.com/anantshri/present_revealjs_workflow_automation/master/index.html -O $BASE_HTML/index.html
			curl "https://raw.githubusercontent.com/anantshri/present_revealjs_workflow_automation/master/index.html" -o $BASE_HTML/index.html
			#wget https://raw.githubusercontent.com/anantshri/present_revealjs_workflow_automation/master/index_top.html -O $BASE_HTML/index_top.html
			curl "https://raw.githubusercontent.com/anantshri/present_revealjs_workflow_automation/master/index_top.html" -o $BASE_HTML/index_top.html
			#wget https://raw.githubusercontent.com/anantshri/present_revealjs_workflow_automation/master/index_bottom.html -O $BASE_HTML/index_bottom.html
			curl "https://raw.githubusercontent.com/anantshri/present_revealjs_workflow_automation/master/index_bottom.html" -o $BASE_HTML/index_bottom.html
			#wget https://raw.githubusercontent.com/anantshri/present_revealjs_workflow_automation/master/powerpoint_style.css -O $BASE_HTML/powerpoint_style.css
			curl "https://raw.githubusercontent.com/anantshri/present_revealjs_workflow_automation/master/powerpoint_style.css" -o $BASE_HTML/powerpoint_style.css
			echo "A sample html file is placed please change accordingly" 
			#echo "Please place a templatized html file"
			#echo "Sample template is available at $BASE_URL/blob/master/index.html"
			pwd
		fi
	elif [ $1 == "require" ]
	then
		echo "setup via requirement files"
		if [  -f $2 ]
		then
			inp=""
			style=""
			#echo "testing this section"
			ln -s $MARKDOWN_MODULES ./markdown
			template1='<section data-markdown="'
			template2='" data-separator="\n---\n" data-separator-vertical="\n--\n" data-separator-notes="^Notes:"></section>'
			while read p;
			do
			#echo $MARKDOWN_MODULES$p
			if [ -f $p ]
			then
				inp="$inp $template1$p$template2"
			elif [ -f $MARKDOWN_MODULES$p ]
			then
				inp="$inp $template1"markdown/"$p$template2"
				#echo $inp
			else
				echo "$MARKDOWN_MODULES$p and / or $p file not found : ignoring"
			fi
			done<$2
			# if style.css diff powerpoint_style.css is same then don't append.
			#if [ `diff $BASE_HTML/powerpoint_style.css ./style.css` ]
			#then
			#	echo "powerpoint_style already uptodate"
			#else
			#	echo "Adding powerpoint_style code in custom style.css"
			cat $BASE_HTML/powerpoint_style.css >> ./style.css
			#fi
			if [ -f style.css ]
			then
				style="<link rel='stylesheet' href='style.css'/>"
			fi
			#custom style
			cat $BASE_HTML/index_top.html > ./index.html
			echo $style >> ./index.html
			echo "</head><body><div class='reveal'><div class='slides'>" >> ./index.html
			ln -s $BASE/reveal.js/ ./reveal.js
			#mkdir reveal.js
			#cp -r $BASE/reveal.js/ ./reveal.js/
			echo $inp >> ./index.html
			cat $BASE_HTML/index_bottom.html >> ./index.html
			ln -s $RESOURCES ./resources

		else
			echo "Please specify existing requirement file"
		fi
	elif [ $1 == "setup" ]
	then
		if [ $# -gt 1 -a -f $2 ]
		then
			echo "setup for specific slide md file"
			echo "File Name is "  $2
			DEF_NAME=$2
		else
			echo "Invalid file name specified $2"
			exit
		fi
		echo "Setting up presentation for this folder"
		echo 
		#mkdir reveal.js
		#cp -r $BASE/reveal.js/ ./reveal.js/
		ln -s $BASE/reveal.js/ ./reveal.js
		#sed "s/#markdownfilename#/$DEF_NAME/g" $BASE_HTML/index.html > ./index.html
		style=""
		template1='<section data-markdown="'
		template2='" data-separator="\n---\n" data-separator-vertical="\n--\n" data-separator-notes="^Notes:"></section>'
		cat $BASE_HTML/powerpoint_style.css >> ./style.css
		if [ -f style.css ]
		then
			style="<link rel='stylesheet' href='style.css'/>"
		fi
		#custom style
		cat $BASE_HTML/index_top.html > ./index.html
		echo $style >> ./index.html
		echo "</head><body><div class='reveal'><div class='slides'>" >> ./index.html
		echo $template1"$2"$template2 >> ./index.html
		cat $BASE_HTML/index_bottom.html >> ./index.html
		ln -s $RESOURCES ./resources
	elif [ $1 == "clean" ]
	then
		echo "Lets clear everything then"
		if [ -d "resources" ]
		then
			rm  resources
		fi
		if [ -d "markdown" ]
		then
			rm markdown
		fi
		if [ -d "reveal.js" ]
		then
			rm reveal.js
		fi
		if [ -f "index.html" ]
		then
			rm  index.html
		fi
		if [ `diff $BASE_HTML/powerpoint_style.css ./style.css` ]
		then
			echo "Leaving style.css as is coz of custom code"
		else
			echo "removing style as it has no custom code added"
			rm style.css
		fi
	elif [ $1 == "print" ]
	then
		if [ -f "index.html" ]
		then
			if [ $HEADLESS == 0 ]
			then
				python2 -m SimpleHTTPServer 9099 &
				pid1=$!
				$BROWSER --app="http://localhost:9099/index.html?print-pdf" --disable-gpu  --user-data-dir="$BROWSER_PROFILE"
				kill -KILL $pid1
			else
				python2 -m SimpleHTTPServer 9099 				
			fi
		else
			echo "Index file not found please run present setup first"
		fi
	else
		echo "Un-identified argument"
		echo "setup : setup reveal.js environment"
		echo "setup slide_name.md"
		echo "clean : clear out all files"
	fi
fi
echo "Thanks for using present service"

The project is available at github

I have uploaded the whole script over at github so that it can be used by others and can be overall improved. Feel free to fork it ,hack it and customise it to your satisfaction. (If you think the setup might help others feel free to share it across)

Do you like what you read, What to share it

6 Replies to “Automated Reveal.js setup”

    1. regular server doesn’t impacts the plugins, so far all used plugins: slide notes, presenter support etc. have all worked fine.
      As for grunt, its just not yet in my personal workflow. been using bash and comfortable in customising stuff in it is why i wrote this.

      1. I suppose i misunderstood the question about using grunt serve. why grunt serve doesn’t make sense is coz we are not using the stock index.html rather the index.html is kept one level up and reveal.js folder is just used as dependencies. hence running grunt serve without modification will not serve the purpose and i prefer not to temper with external dependencies as little as possible.

  1. Using Mac Yosemite
    Cloned reveal.js to /User/Harshad/Dev.reveal.js
    Cloned present to /User/Harshad/Dev/present_workflow

    Using Chrome as browser so added the following line at line no 32
    BROWSER=”/Applications/Google Chrome.app/Contents/MacOS/Google Chrome”

    Base variable –
    BASE=”$HOME/Dev/present_workflow”

    Then when I run the default present_intro.md from your repo I get the following error


    ./present setup present_intro.md
    Present : Reveal.js Workflow Automation
    Created by: Anant Shrivastava
    setup for specific slide md file
    File Name is present_intro.md
    Setting up presentation for this folder

    ln: ./reveal.js: File exists
    ln: ./resources: File exists
    Thanks for using present service

    Also when I try to run it

    ./present
    Present : Reveal.js Workflow Automation
    Created by: Anant Shrivastava
    ./present: line 45: /Applications/Google: No such file or directory
    Thanks for using present service

    I am interested in this project and would like to extend it.

    1. P.S. – Tried both the combinations for Google Chrome

      BROWSER="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
      BROWSER="/Applications/Google Chrome.app/Contents/MacOS/Google\ Chrome"

      Also installed Chromium browser. Was able to run the presentation ./present but ended up getting a blank Chromium window.

Leave a Reply

Your email address will not be published. Required fields are marked *