Advertisement
  1. Computer Skills

How to Create a Slideshow Presentation From Markdown Notes

Scroll to top
14 min read

Markdown text formatting has revolutionized note taking. It gives a way to format without cluttering up what is being written. Now comes the moment you need to make a presentation based on your notes. You need an effective and easy way to create your presentation from your notes. In this tutorial, I’ll show you how to create a HTML slide show from markdown notes.

Markdown to HTML

A rendering program is a program that takes the markdown and translates it to another format. The best renderer I have used is kramdown. Kramdown is a Ruby program that takes text in one format and translates it in to another. It defaults to markdown to HTML.

Since Ruby is pre-installed on all Macs, installing kramdown is easy. To install kramdown, open a Terminal and type:

sudo gem install kramdown

Once installed, the kramdown command is usable. As an example, put the following markdown in to a file called test.md:

1
# This is a header    - Bullet item	- Another bullet itemJust some text.

On the command line, type:

kramdown test.md > test.html

There will now be a test.html file with the this content:

1
<h1 id="this-is-a-header">This is a header</h1><ul>  <li>Bullet item</li>  <li>Another bullet item</li></ul><p>Just some text.</p>

The kramdown program only translates the markdown given to valid HTML. It doesn’t try to create a full page of properly formatted HTML with a header and body sections. This is important for creating a slide show from markdown. For each slide, the HTML for the given content will be generated and not anything extra. It is easy to wrap the slides inside the main HTML for the slide show page.

Basics for an HTML Slideshow

The slideshow page has a beginning HTML, the slides HTML, and the ending HTML. The beginning and ending sections get copied in, while the slides HTML gets generated by kramdown with some extra clean-up work.

Create a file called presbegin.html with this code:

1
<!DOCTYPE html><html><head>    <title>Slide Show</title></head><body>	<div id="container">		<div id='section0' class='section'>				<div class='slide'>

This is the beginning of the slide show. It’s not a complete HTML page. The body of the HTML has a three divs: container div, section0 div, and a slide div. The container div contains the entire slide show. 

Inside of the container is the section0 div and it’s slide div. The sections help format everything in each slide section, while the individual slide contains formatting for that slide.

The ending will be similar. Create a file called presend.html and place the following code:

1
</div><div></body></html>

Not much! It closes out the last slide’s divs and the body and html tags.

The only special formatting needed in the markdown notes is for any pictures and for detailing the end of each slide. Since markdown has an anchor type for pictures, that tag is used with one difference: instead of having a text description for the picture, that area will describe the classes to attach to the picture. Also, the markdown code for horizontal rules is used to separate slides. 

Therefore, the basic formula for creating the slide show is: copy the presbegin.html, generate HTML from the markdown, translate all <hr /> tags to </div></div><div id='section1' class='section'><div class='slide'></code>, fix all picture tags to use the subtext as classes, and copy the presend.html.

Create a new file called pres.rb and place this code:

1
#!/usr/bin/ruby## Set some variables.#require("FileUtils")$presDir = ""pressBaseDir = File.dirname(__FILE__)theme = ARGV[1]## Get the slide presentation parts loaded.#presBegin = `cat '#{pressBaseDir}/presbegin.html'`presEnd = `cat '#{pressBaseDir}/presend.html'`## Get the directory of the presentation.#$presDir = File.dirname(ARGV[0])## Convert the Markdown to HTML.#presTextHTML = `cat '#{ARGV[0]}' | kramdown`## Convert the horizontal rules to the divs we need.#$divCount = 1while presTextHTML.sub!(/\<hr \/\>/, "</div></div><div id='section#{$divCount}' class='section'><div class='slide'>") != nil do    $divCount = $divCount + 1end$divCount = $divCount -1## Make sure the last div gets closed.#presTextHTML += "</div>";## Fix all images to be on it's own after the slide div.#m = /\<p\>\<img src\=\"(.*)\" alt\=\"(.*)\" \/\>\<\/p\>/.match(presTextHTML)if m != nil	postMatch = ""	presTextHTML = ""	while m != nil		presTextHTML += m.pre_match		presTextHTML += "<img src='#{m[1]}' class='#{m[2]}' />"		postMatch = m.post_match		m = /\<p\>\<img src\=\"(.*)\" alt\=\"(.*)\" \/\>\<\/p\>/.match(m.post_match)	end	presTextHTML += postMatchendpresTextHTML += "<script> window.MaxSlideNum = #{$divCount}; </script>"## Write the HTML to an index.html file in that directory.#target = open("#{$presDir}/index.html", 'w')target.truncate(0)target.write(presBegin + presTextHTML + presEnd)target.close## Copy the CSS file to that directory and rename it to theme.css.#FileUtils.cp("#{pressBaseDir}/#{theme}.css",$presDir)File.rename("#{$presDir}/#{theme}.css","#{$presDir}/theme.css")

This Ruby code performs the actions as described. The program file has to be made executable with:

chmod a+x pres.rb

The program is used with the following command line:

pres.rb <name of markdown file> <theme name>

This code is assuming that the presentation is not in the same directory as the code. Therefore, wherever you have the code, make sure you add it to your path.

Formatting With CSS

With the bulk translation of the markdown file to HTML done, the next step is to format the slides. To create the styles needed, add this code to the header section of the presbegin.html file:

1
<style type="text/css">/* http://meyerweb.com/eric/tools/css/reset/   v2.0 | 20110126   License: none (public domain)*/html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {    margin: 0;	padding: 0;	border: 0;	font-size: 100%;	font: inherit;	vertical-align: baseline;}/* HTML5 display-role reset for older browsers */article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {	display: block;}body {	line-height: 1;}ol, ul {	list-style: none;}blockquote, q {	quotes: none;}blockquote:before, blockquote:after, q:before, q:after {	content: '';	content: none;}table {	border-collapse: collapse;	border-spacing: 0;}/******************************************************************************** * CSS for the Slide show. Changing these can effect the running of the slideshow. ********************************************************************************//* * These styles are for formatting the slides. */body {	width  : 	1200px;	height : 	640px;}.slide {	display         :    flex;	vertical-align  : 	middle;	text-align      : 	center;	flex-direction  : 	column;	align-self      : 	center;	align-items     : 	center;	align-content   : 	center;	justify-content : 	center;	position        : 	absolute;	top             : 	0px;	left            : 	0px;	height	       : 	640px;	width           : 	1200px;	z-index         : 	100;}img.background {	height         : 640px;	width          : 1200px;	position       : absolute;	top            : 0px;	left           : 0px;	z-index        : 1;}img.left {	order: -1;	margin-right: auto;}img.right {	order: 100;	margin-left: auto;}img.rounded {	border-radius: 10px;}.slide p, .slide h1, .slide h2, .slide h3, .slide h4, .slide h5, .slide h6, .slide span {	text-align     : center;	vertical-align : middle;	align-self     : center;	align-items    : center;	align-content  : center;	justify-content: center;	margin-bottom  : 10px;	z-index        : 100;}.section {	display          : 	none;	top              : 	0px;	left             : 	0px;}</style><link rel="stylesheet" type="text/css" href="theme.css">

The first part is a reset script using MeyerWeb Reset. Whenever working with HTML and CSS, a reset script should be used to put every browser on the same playing field. This is good design practice.

The second part are the styles needed to get the slides to take up the screen, the text to be centered, basic ordering and formatting for the pictures, and the basic setup for a background image. 

I have set the screen size to 1200x640 pixels which works great on my Macbook Air 11" screen. You can change it to whatever works best for you.

Now create a theme file. Make a file called Basic.css and place the following code:

1
/* * Will be the CSS file for the Basic Theme */body {    background-color: rgba(79, 150, 200, 0.4);}.slide {	color: rgb(221, 239, 252);	background-color: rgba(79, 150, 200, 0.4);}.slide h1, .slide h2, .slide h3, .slide h4, .slide h5, .slide h6, .slide p, .slide ol li, .slide ul li {	font-family: Times;}.background {	opacity        : 	.80;}.slide h1 {	font-size: 10em;}.slide h2 {	font-size: 8em;}.slide h3 {	font-size: 6em;}.slide h4 {	font-size: 4em;}.slide h5 {	font-size: 2em;}.slide h6 {	font-size: 1em;}.slide p {	font-size: 2em;}.slide ol {	list-style: decimal-leading-zero;	text-align: left;}.slide ol li {	font-size: 2em;}.slide ul {	list-style: disc;	text-align: left;}.slide ul li {	font-size: 2em;}

This is a basic theme that you can use to make your own themes. This theme file will be copied to the presentation directory and renamed to theme.css. That is the file loaded by the slide show.

To add extra styling to pictures, create a class tag in the theme’s css file. Add that class tag to the text for the picture. Therefore, a picture with the background tag would look like:

1
![background](image-01.jpg)

Add the Javascript

For fastest loading of a web page, the JavaScripts should be at the bottom of the page. Therefore, in the presend.html, add this code just before the closing body tag:

1
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script><script src="http://cdn.craig.is/js/mousetrap/mousetrap.min.js?9d308"></script><script>    //	// This is the JavaScript for the slide show.	//	var slideNum = 0;	var duration = 800;	function nextSlide() {		//		// Fade out the current slide.		//		jQuery("#section"+slideNum).fadeOut(duration, function() {			//			// Increment the slide number.			//			slideNum++;			//			// Check to see if we are at a boundary condition.			//			if(slideNum > (window.MaxSlideNum))				slideNum = window.MaxSlideNum;			//			// Fade in the next slide.			//			jQuery("#section"+slideNum).fadeIn(duration);		});	}	function prevSlide() {		//		// Fade out the current slide.		//		jQuery("#section"+slideNum).fadeOut(duration,function() {			//			// decrement the slide number.			//			slideNum--;			//			// Check to see if we are at a boundary condition.			//			if(slideNum < 0)				slideNum = 0;			//			// Fade in the next slide.			//			jQuery("#section"+slideNum).fadeIn(duration);		});	}	function beginSlide() {		//		// Fade out the current slide.		//		jQuery("#section"+slideNum).fadeOut(duration, function() {			//			// Set the slide to the first slide.			//			slideNum = 0;			//			// Fade in the next slide.			//			jQuery("#section"+slideNum).fadeIn(duration);		});	}	$( document ).ready( function(){		//		// first hide all the slides.		//		jQuery(".section").hide();		//		// Make the first slide viewable.		//		jQuery("#section0").show();		//		// Setup the key bindings for transitioning the slides.		//		Mousetrap.bind('right', function(e) {			nextSlide();		});		Mousetrap.bind('left', function(e) {			prevSlide();		});		Mousetrap.bind('b', function(e) {			beginSlide();		});	});</script>

This code loads in Mousetrap to control the slide show and jQuery to perform the transitions. Two global variables are used to control the slide show: slideNum and duration. The slideNum is the number for the current slide, and duration defines the speed of the change. The lower the duration, the faster the slides change.

Three functions are defined next: nextSlide(), prevSlide(), and beginSlide(). These functions allow the user to go to the next slide, previous slide, and back to the first slide respectively.

After the functions, I used a hook to the jQuery ready function that processes code after everything is loaded into the browser. Once everything is loaded, all slides are hidden and just the first slide made visible. Then the left arrow key is bound to the prevSlide() function, the right arrow key is bound to the nextSlide() function, and the b key is bound to the beginSlide() function.

In the code, you will notice the window.MaxSlideNum global variable. The ruby code for creating the slides sets this variable inside the HTML generated for the slide presentation. It tells the controlling functions how many slides are in this presentation.

Other Ways to Use the Script

While using the command line program is doable, it is not convenient. The tutorial, Writing Dropzone 3 Actions, shows how to create a Dropzone 3 action. Follow that tutorial to make a new Dropzone 3 action with the following code:

1
# Dropzone Action Info# Name: MD to HTML Presentation Converter# Description: Takes a markdown file and converts it to an HTML/CSS presentation in the files directory. It assumes you have kramdown installed locally. To install, go to a commandline and type "sudo gem install kramdown".# Handles: Files# Creator: Richard Guay# URL: http://customct.com# Events: Clicked, Dragged# KeyModifiers: Command, Option, Control, Shift# SkipConfig: No# RunsSandboxed: Yes# Version: 1.0# MinDropzoneVersion: 3.0## Function:     dragged## Description: This function is called with Dropzone has files dropped on this action.# 					It then processed each given file as a markdown presentation.#def dragged	#	# Set some variables.	#	$presDir = ""	pressBaseDir = File.expand_path(".")	presNum = $items.count	theme = defined?( ENV['theme'] ) ? ENV['theme'] : "Basic"	#	# Tell Dropzone we are starting.	#	$dz.begin("Converting #{presNum} Presentations...")	$dz.determinate(true)	#	# Get the slide presentation parts loaded.	#	presBegin = `cat '#{pressBaseDir}/presbegin.html'`	presEnd = `cat '#{pressBaseDir}/presend.html'`	#	# Index over all of the given presentations.	#	for index in 0 ... presNum		#		# Get the directory of the presentation.		#		$presDir = File.dirname($items[index])		#		# Convert the Markdown to HTML.		#		presTextHTML = `cat '#{$items[index]}' | kramdown`		#		# Convert the horizontal rules to the divs we need.		#		$divCount = 1		while presTextHTML.sub!(/\<hr \/\>/, "</div></div><div id='section#{$divCount}' class='section'><div class='slide'>") != nil do			$divCount = $divCount + 1		end		$divCount = $divCount -1		#		# Make sure the last div gets closed.		#		presTextHTML += "</div>";		#		# Fix all images to be on it's own after the slide div.		#		m = /\<p\>\<img src\=\"(.*)\" alt\=\"(.*)\" \/\>\<\/p\>/.match(presTextHTML)		if m != nil			postMatch = ""			presTextHTML = ""			while m != nil				presTextHTML += m.pre_match				presTextHTML += "<img src='#{m[1]}' class='#{m[2]}' />"				postMatch = m.post_match				m = /\<p\>\<img src\=\"(.*)\" alt\=\"(.*)\" \/\>\<\/p\>/.match(m.post_match)			end			presTextHTML += postMatch		end		presTextHTML += "<script> window.MaxSlideNum = #{$divCount}; </script>"		#		# Write the HTML to an index.html file in that directory.		#		target = open("#{$presDir}/index.html", 'w')		target.truncate(0)		target.write(presBegin + presTextHTML + presEnd)		target.close		#		# Copy the CSS file to that directory and rename it to theme.css.		#		FileUtils.cp("#{pressBaseDir}/#{theme}.css",$presDir)		File.rename("#{$presDir}/#{theme}.css","#{$presDir}/theme.css")	   #	   # Tell Dropzone what percentage is done.	   #	   $dz.percent((((index + 1)*100)/presNum).to_i)	end	#	# Tell Dropzone that we are done.	#	$dz.finish("All Presentations Made.")	# You should always call $dz.url or $dz.text last in your script. The below $dz.text line places text on the clipboard.	# If you don't want to place anything on the clipboard you should still call $dz.url(false)	$dz.url("file://#{$presDir}/index.html")enddef clicked	#	# Allow the user to select a theme.	#	theme = "Basic"	#	# Show a list of themes.	#	qstr = "standard-dropdown --title \"Compress Files: Graphic Format\" --text \"What Theme?\" --items "	themlist = []	i = 0	Dir.glob("*.css") { |filename|		filename = File.basename(filename,".css")		qstr += "\"#{filename}\" "		themlist[i] = filename		i += 1	}	button2, index =$dz.cocoa_dialog(qstr).split("\n")	index = index.to_i	theme = themlist[index]	#	# Set the selected theme.	#	$dz.save_value("theme", theme)	#	# Tell the user what they selected.	#	$dz.finish("You selected '#{theme}' for your theme.")	$dz.url(false)end

Once created, load the action in to Dropzone 3. When a markdown file is dropped on the zone, it will create the presentation in the same directory.

Dropzone 3 ActionDropzone 3 ActionDropzone 3 Action
Dropzone 3 Action

Since Dropzone 3 is great for dropping many items on to it, you can great many presentations at one time. Just collect the files in the Drop Bar. Then move them to the dropzone for converting. Clicking the action will allow you to pick which theme to use. The completed Dropzone 3 action is included in the download.

Markdown to Presentation Alfred WorkflowMarkdown to Presentation Alfred WorkflowMarkdown to Presentation Alfred Workflow
Markdown to Presentation Alfred Workflow

This can also be made into an Alfred Workflow. The completed workflow is included in the download. The mds:theme command allows you to select the theme to use. The mds:showtheme will show the name of the currently set them in a notification. You can use the Alfred Browser to view a markdown file. When you hit right arrow on the file, you can select the Markdown to Slides command to create the presentation.

Deckset Does It All

If you find this program useful, you might want to check out Deckset.

Deckset Markdown to PresentationDeckset Markdown to PresentationDeckset Markdown to Presentation
Deckset Markdown to Presentation

Deckset takes a markdown file and converts it to a slide show. It has more functionality than presented in this tutorial. It also has many great themes to use.

Conclusion

With time always being on a premium, it is great to make use of notes as the basis for a presentation. Now that you have the tools in your hands, go and make some great presentations. This code is very basic and there is plenty of room for improvements. If you have changes or new themes for this code, please pass them on.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Computer Skills tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.