Another New Old Project: Langton’s Ant

Click here to see Langton’s Ant in the Labs.

I probably could have posted this project before the 3D version, but the 3D version was already done in Javascript, and besides: 3D is just cool!

The above screenshot is taken at just over 10,000 iterations into the animation. Langton’s Ant will, if undisturbed, create a “highway” which will proceed off into infinity unless the world it is crawling wraps at the edges, as this one does.

If you have seen one Langton’s Ant animation you have probably seen them all, though in this one I added a heat map which shows the number of times the Ant has visited each cell. It will take a while to begin to see different colors, and everything will look blue for quite some time. The above screenshot of the heat map was taken at approximately 100,000 iterations.

As with all of my experiments, all of the code is contained in a single page for easy download and modification. I did not use any external libraries and I commented the Javascript for ease of reading and interpretation. Enjoy!

Another Resurrected Project: The Trigonometron

Click here to access the Trigonometron.

Much to my surprise, when browsing old(!) versions of this site using the Wayback Machine, I found the source code to the Trigonometron, one of the very first experiments I posted online, back at the beginning of 2002. This predates almost all of my Flash experiments, and indeed I ported this one to Flash a few years after I built the original in Dynamic HTML.

(Dynamic HTML, for you youngsters, it what we used to call it when you used Javascript to modify the HTML in a page without having to reload the page.)

Note that the version in the Laboratory section of this site is 99.99% unmodified from the original created almost twenty years ago. The only changes I made were to update the Javascript for positioning the elements so it works in modern browsers, and to change the balls from using a .gif image to using pure CSS for the graphics. Everything else is exactly as it was, including a check to see if the user is accessing the site with Netscape Navigator.

I may do a complete update to this project, as it was built for browsers running at 800×600 resolution following an early-2000s aesthetic, which means tiny, tiny text.

You can View Source of the Trigonometron to see what coding looked like in all its glory, back in 2001 and 2002.

A Blast From the Past: Langton’s Ant in 3D

Langton's Ants in 3D

This is an update to a post from March 2, 2012.

From 2002 to around 2012 I devoted most of my creative energy to programming. I created well over a hundred visual toys and simple games, and kept the momentum going until a series of life events sucked the mental and emotional energy from me. When I got my life back I turned my creative energies to writing fiction and poetry, and my decade-plus of experiments in mathematics, geometry, cellular automata and game design fell by the wayside.  Most of those experiments were in Flash and though I still have the source code rebuilding them in Javascript would be an extremely time-consuming project.

But some of those experiments were in Javascript, particularly after I saw the writing on the wall for Flash and Actiosncript. This is one of those experiments – a 3D version of the Langton’s Ant cellular automation, created using hand-rolled Javascript, with an assist from the Three.js 3D rendering library.

Click here to access the Langton’s Ants in 3D experiment. Once there, you can right-click on the animation and select “save image as…” to take a screenshot of the Ant trail.

The original post from March 2, 2012, with code breakdown and explanation is here.

Here are a couple more screenshots from later iterations of the algorithm:

Langton's Ants in 3D

Langton's Ants in 3D

Simple Backbone Marionette Example With AppRouter

This one took a little longer than the rest to put together, because I nearly broke my brain trying to figure out how routing worked. I found myriad code samples for setting up and using the router, but no one sample had everything I needed to put together a bare-bones app. Once i finally figured it out, the rest snapped together immediately. So without further ado – First, the Javascript file:

/* define the application */
var app = new Backbone.Marionette.Application();

/* add the main region to the application */
app.addRegions({
	appRegion: '#AppBase'
});

/* define the module we will be using to create this app */
app.module('RouteTest',function(module, App, Backbone, Marionette, $, _){
	"use strict";

	/* the layout for the main view */
	module.AppLayoutView = Marionette.LayoutView.extend({
		tagName: 'div',
		id: 'AppLayoutView',
		template: '#template-AppLayoutView',

		regions: {
			'contentRegion' : '#ContentRegion'
		},
		ui: {
			'navHome' : '#nav-home',
			'navInfo' : '#nav-info'
		},
		events: {
			'click #nav-home' : 'onNavHomeClicked',
			'click #nav-info' : 'onNavInfoClicked'
		},

		/* when the view initializes, call initRouter to */
		initialize: function() {
			this.initRouter();
		},

		/* once the DOM is ready, start the Backbone history manager.
			This will cause the application to synch up with the 
			current route of the browser, e.g. #home or #info.
			This must be called onRender instead of on initialize
			because it immediately tries to render the appropriate view
			into the contentRegion. Also: If you don't start the backbone
			history, the router won't work. */
		onRender: function() {
			if( ! Backbone.History.started) Backbone.history.start();
		},

		/* initialize the AppRouter, which synchs the application
			to the browser navigation */
		initRouter: function() {

			// cache reference to 'this' in the module scope
			var capturedThis = this;

			// assign route handlers to specific routes.
			// In this case, 'home' is triggered when the browser
			// visits index.html#home. Likewise index.html#info.
			// the empty set is for an address with no hash.
			var appRouteHandler = {
					'' : 'onHomeRoute',
				'home' : 'onHomeRoute',
				'info' : 'onInfoRoute'
			}

			// controller which contains the methods which
			// are used as route handlers. These are referenced
			// in the appRoutes object above.
			var appRouterController = {
				onHomeRoute: function() {
					capturedThis.onHomeNavigated();
				},
				onInfoRoute: function() {
					capturedThis.onInfoNavigated();
				}
			};

			// define an AppRouter constructor
			var router = Marionette.AppRouter.extend({});

			// create a new instance of the AppRouter
			// and assign the routes and controller
			var appRouter = new router({
				appRoutes: appRouteHandler, 
				controller: appRouterController
			});
		},

		/* called when the router sees that we have met the criteria
			to trigger the 'onHomeRoute' handler */
		onHomeNavigated: function() {

			// define and display an instance of the HomeLayoutView
			var homeLayoutView = new module.HomeLayoutView();
			this.contentRegion.show(homeLayoutView);

			// update the navigation
			this.$el.find('.navButton.active').removeClass('active');
			this.ui.navHome.addClass('active');
		},

		/* called when the router sees that we have met the criteria
			to trigger the 'onInfoRoute' handler */
		onInfoNavigated: function() {
			var infoLayoutView = new module.InfoLayoutView();
			this.contentRegion.show(infoLayoutView);
			this.$el.find('.navButton.active').removeClass('active');
			this.ui.navInfo.addClass('active');
		}
	});

	/* view definition for the 'Home' screen */
	module.HomeLayoutView = Marionette.LayoutView.extend({
		tagName: 'div',
		id: 'HomeLayoutView',
		className: 'contentLayout',
		template: '#template-HomeLayoutView'
	});

	/* view definition for the 'Info' screen */
	module.InfoLayoutView = Marionette.LayoutView.extend({
		tagName: 'div',
		id: 'InfoLayoutView',
		className: 'contentLayout',
		template: '#template-InfoLayoutView'
	});

	/* add initializer, which fires when the app starts */
	module.addInitializer(function(){
		var layout = new module.AppLayoutView();

		/* show the layout in the region we created at the top of this file */
		app.appRegion.show(layout);
	});
});

/* when the DOM for this page is available, start the application */
$(document).ready(function() {
	app.start();
});

And here is the HTML file, including the templates.

<!doctype html>
<html>
	<head>
		<title>Backbone/Marionette Routing Example Using AppRouter</title>
		<style type="text/css">
			body {
				background: #ffffff;
			}
			#AppBase {
				width: 600px;
				margin: 10px auto;
				padding: 0;
			}
			#AppLayoutView {
				float: left;
				width: 598px;
				margin: 0;
				padding: 0;
				border: 1px solid #808080;
			}
			h1 {
				margin: 0;
				padding: 0;
				float: left;
				width: 100%;
				height: 30px;
				text-align: center;
				font: 24px/30px courier;
			}
			#Navigation {
				float: left;
				width: 100%;
				height: 30px;
				background: #ededed;
				text-align: center;
			}
			#Navigation a {
				font: 16px/30px courier, monospace;
				color: #000000;
				text-decoration: none;
			}
			#Navigation .navButton.active {
				color: #ff0000;
			}
			#ContentRegion {
				float: left;
				width: 100%;
			}
			.contentLayout {
				float:left;
				width: 100%;
				margin: 0;
				padding: 0;
				
			}
			#HomeLayoutView {
				background: #edffed;
			}
			#InfoLayoutView {
				background: #ededff;
			}
			.contentLayout h2 {
				margin: 0;
				padding: 0;
				text-align: center;
				border-bottom: 1px solid #808080;
				background: #ffffff;
			}
			.contentLayout p {
				padding: .5em 1em;
			}
		</style>
	</head>
	<body>
		<!-- Base element for app -->
		<div id="AppBase"></div>

		<!-- main layout template -->
		<script type="text/template" id="template-AppLayoutView">
			<h1>Backbone/Marionette Routing Example</h1>
			<div id="Navigation">
				<a id="nav-home" class="navButton" href="#home">Home</a> : : : 
				<a id="nav-info" class="navButton" href="#info">Information</a>
			</div>
			<div id="ContentRegion">HELLO!</div>
		</script>

		<!-- home screen template -->
		<script type="text/template" id="template-HomeLayoutView">
			<h2>Home</h2>
			<p>This is the home view</p>
		</script>

		<!-- info screen template -->
		<script type="text/template" id="template-InfoLayoutView">
			<h2>Information</h2>
			<p>This is a page of information</p>
		</script>

		<!-- libraries -->
		<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
		<script type="text/javascript" src="js/underscore.js"></script>
		<script type="text/javascript" src="js/backbone.js"></script>
		<script type="text/javascript" src="js/backbone.marionette.js"></script>

		<!-- app code -->
		<script type="text/javascript" src="js/script.js"></script>
	</body>
</html>

By the way, the missing piece which ended up costing me the better part of a day was the Backbone.history.start() call in the onRender method in the main Layout view.

More On Using Google Spreadsheets and Backbone/Marionette

Pulling data from a published Google Spreadsheet it actually quite simple. All you need is a spreadsheet which you have “published to web”; i.e. made visible (but not editable) to the public. Backbone models have no difficulty pulling the data in, but the structure is complex, and requires a little explanation.

First, here is what the spreadsheet looks like:

Name per square foot height
arugula 9 9
basil 4 9
beets 9 6
carrots 16 4
collard greens 2 16
cauliflower 1 18
tomatoes 1 36
broccoli 1 24
mustard greens 9 12
peppers 1 18
chard 4 12
kale 2 12
radish 36 8
brussels sprouts 1 24
okra 1 24
eggplant 1 24
celery 4 18

I am pulling in a representational JSON feed from Google Drive. The data (trimmed to the first two rows) looks something like this:

{
	"version": "1.0",
	"encoding": "UTF-8",
	"feed": {
		"xmlns": "http://www.w3.org/2005/Atom",
		"xmlns$openSearch": "http://a9.com/-/spec/opensearchrss/1.0/",
		"xmlns$gsx": "http://schemas.google.com/spreadsheets/2006/extended",
		"id": {
			"$t": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values"
		},
		"updated": {
			"$t": "2014-01-22T19:27:16.240Z"
		},
		"category": [
			{
				"scheme": "http://schemas.google.com/spreadsheets/2006",
				"term": "http://schemas.google.com/spreadsheets/2006#list"
			}
		],
		"title": {
			"type": "text",
			"$t": "Sheet1"
		},
		"link": [
			{
				"rel": "alternate",
				"type": "text/html",
				"href": "https://spreadsheets.google.com/pub?key={{DOCUMENT_KEY}}"
			},
			{
				"rel": "http://schemas.google.com/g/2005#feed",
				"type": "application/atom+xml",
				"href": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values"
			},
			{
				"rel": "self",
				"type": "application/atom+xml",
				"href": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values?alt=json-in-script"
			}
		],
		"author": [
			{
				"name": {
					"$t": "user.name"
				},
				"email": {
					"$t": "user.name@gmail.com"
				}
			}
		],
		"openSearch$totalResults": {
			"$t": "17"
		},
		"openSearch$startIndex": {
			"$t": "1"
		},
		"entry": [
			{
				"id": {
					"$t": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values/{{CELL_KEY}}"
				},
				"updated": {
					"$t": "2014-01-22T19:27:16.240Z"
				},
				"category": [
					{
						"scheme": "http://schemas.google.com/spreadsheets/2006",
						"term": "http://schemas.google.com/spreadsheets/2006#list"
					}
				],
				"title": {
					"type": "text",
					"$t": "arugula"
				},
				"content": {
					"type": "text",
					"$t": "persquarefoot: 9, height: 9"
				},
				"link": [
					{
						"rel": "self",
						"type": "application/atom+xml",
						"href": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values/{{CELL_KEY}}"
					}
				],
				"gsx$name": {
					"$t": "arugula"
				},
				"gsx$persquarefoot": {
					"$t": "9"
				},
				"gsx$height": {
					"$t": "9"
				}
			},
			{
				"id": {
					"$t": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values/{{CELL_KEY}}"
				},
				"updated": {
					"$t": "2014-01-22T19:27:16.240Z"
				},
				"category": [
					{
						"scheme": "http://schemas.google.com/spreadsheets/2006",
						"term": "http://schemas.google.com/spreadsheets/2006#list"
					}
				],
				"title": {
					"type": "text",
					"$t": "basil"
				},
				"content": {
					"type": "text",
					"$t": "persquarefoot: 4, height: 9"
				},
				"link": [
					{
						"rel": "self",
						"type": "application/atom+xml",
						"href": "https://spreadsheets.google.com/feeds/list/{{DOCUMENT_KEY}}/od6/public/values/{{CELL_KEY}}"
					}
				],
				"gsx$name": {
					"$t": "basil"
				},
				"gsx$persquarefoot": {
					"$t": "4"
				},
				"gsx$height": {
					"$t": "9"
				}
			}
		]
	}
}

It’s a lot of information, but it is fairly simply laid out. There is a lot of meta-data and author information. For the purposes of a simple display list, the only data we need is the ‘entries’ array. This is an array of Javascript objects, each of which represents a row in the spreadsheet. This assumes that the first row in the spreadsheet contains the titles for each column; e.g. ‘name’, ‘per square foot’, etc.

Note that within each of the entries in the array are three objects which correspond to the columns in the spreadsheet: gsx$name, gsx$persquarefoot, and gsx$height. These are simply the names of the columns, stripped of spaces and converted to all lower case. Each of these objects contains a single object with the key ‘$t’, which has a value equal to the content of the corresponding cell from the spreadsheet.

If you review the code from my previous post you can see that, once the data structure is known, it is quite simple to parse the JSON for the values you need.

Note also that this entry does not address the process of modifying a Google Spreadsheet from outside of the Google Drive context; that is a significantly more complex operation.

Backbone/Marionette App Pulling Data From Google Spreadsheet

Here is an example of a simple display application pulling data from a publicly available Google spreadsheet. It parses the data into a usable form and displays it in a sortable table using a Marionette.js Composite View.

The methods used, and pitfalls inherent, in pulliing a JSON feed from a Google spreadsheet warrant their own post, which will happen in the near future. In the meantime, here is the code for this app. First the Javascript:

/* define the application */
var app = new Backbone.Marionette.Application();

/* add the main region to the application */
app.addRegions({
	appRegion: '#AppBase'
});

/* define the module we will be using to create this app */
app.module('Garden',function(module, App, Backbone, Marionette, $, _){
	"use strict";

	/* the URL for the JSON feed from the Google Spreadsheep */
	module.spreadsheetKey = '0AtrrbpAB-ITbdFFXVklRbHZUVW5kX2F1UWVKVVBfOVE'; // a sample spreadsheet in google docs
	module.spreadsheetURL = 'https://spreadsheets.google.com/feeds/list/{{KEY}}/od6/public/values?alt=json-in-script&callback=?';

	/* model for an individual item */
	module.GardenModel = Backbone.Model.extend({
		/* the URL from which the data is pulled */
		url: module.spreadsheetURL.split('{{KEY}}').join(module.spreadsheetKey),

		/* take the data retrieved from the URL, go through it looking for only
			the data we actually need, and pull it out and format it. This is 
			necessary because the data returned by Google Spreadsheets
			is a cumbersome mess. */
		parse: function(data) {
			var parsedArray = [];

			/* use Underscore to iterate through each item in the feed,
				and pull out the necessary fields and put them in an
				array of anonymous objects which will be returned
				as the main model for this application */
			_.each(data.feed.entry,function(oItem) {
				parsedArray.push({
					name: oItem['gsx$name']['$t'],
					perSquareFoot: parseInt(oItem['gsx$persquarefoot']['$t']),
					height: parseFloat(oItem['gsx$height']['$t'])
				});
			});
			return ({dataset:parsedArray});
		}
	});

	module.PlantModel = Backbone.Model.extend({
		defaults: {
			name: '',
			perSquareFoot: 1,
			height: 1
		}
	});

	module.PlantCollection = Backbone.Collection.extend({
		model: module.PlantModel,

		/* initial field used to sort the models when the collection is displayed */
		comparator: 'name'
	});

	/* individual item view for each model in the collection */
	module.PlantItemView = Marionette.ItemView.extend({
		tagName: 'tr',
		template: '#row-template'
	});

	/* Composite View for displaying tabular data. Composite Views
		allow more complex HTML to be used when rendering a template */
	module.PlantCompositeView = Marionette.CompositeView.extend({
		tagName: 'table',
		itemView: module.PlantItemView,

		/* the element in the template which will serve as the container for the ItemViews */
		itemViewContainer: 'tbody',
		template: '#table-template',

		/* add mouse events */
		events: {
			'click th' : 'onHeaderClicked'
		},
		
		/* called when one of the table headers is clicked. 
			Pulls the value of the 'data-sort' attribute on the element
			and uses that as the sort argument in the collection */
		onHeaderClicked: function(event){
			this.collection.comparator = $(event.target).data('sort');
			this.collection.sort();
			this.render();
		}
	});

	/* main layout for the application */
	module.GardenLayoutView = Marionette.LayoutView.extend({
		tagName: 'div',
		id: 'AppContainer',
		template: '#layout-template',
		regions: {
			ListRegion: '#ListRegion'
		},

		/* called when the DOM for this view is available */
		onRender: function(){

			/* create a new collection based on the model fed into this view
				when it was created */
			var plantCollection = new module.PlantCollection(this.model.get('dataset'));

			/* create the new Composite View based on the collection*/
			var plantCompositeView = new module.PlantCompositeView({collection: plantCollection});

			/* display the composite view */
			this.ListRegion.show(plantCompositeView);
		}
	});

	/* add initializer, which fires when the app starts */
	module.addInitializer(function(){

		/* create a new instance of GardenModel */
		var baseModel = new module.GardenModel();

		/* create a local reference to 'this', which can be used in asynchronous callbacks */
		var capturedThis = this;

		/* load the data into the model */
		baseModel.fetch()
			.fail(function() {
				debugger;
			})
			.done(function() {
				/* on successfully loading the data, create a new instance of the main layout view,
					and feed the model into it. */
				var layout = new module.GardenLayoutView({model: baseModel});

				/* show the layout in the region we created at the top of this file */
				app.appRegion.show(layout);
			});
	});

});

/* when the DOM for this page is available, start the application */
$(document).ready(function() {app.start();});

And now the HTML and CSS

<!doctype html>
<html>
	<head>
		<title>Backbone/Marionette using data from Google Spreadsheet rendered in a Composite View</title>
		<style type="text/css">
			body {
				background: #ffffff;
			}
			#AppBase {
				width: 600px;
				margin: 10px auto 0 auto;
				padding: 0;
			}
			h1 {
				font: bold 16px/24px arial, sans-serif;
				text-align: center;
			}
			table {
				width: 600px;
				border-collapse: collapse;
			}
			th {
				font: 14px/18px courier;
				width: 200px;
				text-align: center;
				border: 1px solid #808080;
				background: #ededed;
				cursor: pointer;
			}
			th:hover {
				background: #cdcdcd;
				color: #990000;
			}
			td {
				font: 14px/18px courier;
				width: 200px;
				border: 1px solid #808080;
			}
			tfoot td {
				width: 600px;
				text-align: center;
			}
		</style>
	</head>
	<body>
		<!-- Base element for app -->
		<!--
			Dont use the BODY element as the base because when the app renders in the BODY
			it will wipe out the template files before the views can pick them up 
		-->
		<div id="AppBase"></div>

		<!-- TEMPLATES -->
		<!-- table row template -->
		<script type="text/template" id="row-template">
			<td><%- name %></td>
			<td><%- perSquareFoot %></td>
			<td><%- height %></td>
		</script>

		<!-- table body template for composite view -->
		<script type="text/template" id="table-template">
			<thead>
				<tr>
					<th data-sort="name">Name</th>
					<th data-sort="perSquareFoot">Per Square Foot</th>
					<th data-sort="height">Height</th>
				</tr>
			</thead>
			<tbody></tbody>
			<tfoot>
				<td colspan="3">Click column headers to sort table</td>
			</tfoot>
		</script>

		<!-- main layout template -->
		<script type="text/template" id="layout-template">
			<h1>Backbone/Marionette Application Which Retrieves Data From a Google Spreadsheet and Displays It In a Sortable Composite View</h1>
			<div id="ListRegion"></div>
		</script>

		<!-- libraries -->
		<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
		<script type="text/javascript" src="js/underscore.js"></script>
		<script type="text/javascript" src="js/backbone.js"></script>
		<script type="text/javascript" src="js/backbone.marionette.js"></script>

		<!-- app code -->
		<script type="text/javascript" src="js/script.js"></script>
	</body>
</html>

Here are links to the code libraries used in this app:

Backbone/Marionette App Using Models, Collections and LocalStorage

This is an example of a simple library application which uses Backbone.js Models and Collections, and Marionette.js ItemViews, CollectionViews, and Layouts. It also uses the Backbone.js LocalStorage plugin, for saving data to the browser’s local storage system.

Here is the Javascript file, called “script.js”:

/* define the application */
var app = new Backbone.Marionette.Application();

/* define the region into which the app will be rendered */
app.addRegions({
	libraryRegion: '#libraryApp' // element in the HTML file
});

/* define the module we will use for this app */
app.module('Library',function(module, App, Backbone, Marionette, $, _){

	/* define the model used for a Genre */
	module.GenreModel = Backbone.Model.extend({
		defaults: {
			title: ''
		}
	});

	/* define the collection used for Genres */
	module.GenreCollection = Backbone.Collection.extend({

		/* set the model used in this collection */
		model: module.GenreModel,

		/* define localStorage container for this collection */
		localStorage: new Backbone.LocalStorage("LibraryGenreCollection")
	});

	/* define the model used for an Author */
	module.AuthorModel = Backbone.Model.extend({
		defaults: {
			firstName: '',
			lastName: ''
		}
	});

	/* define the collection used for Authors */
	module.AuthorCollection = Backbone.Collection.extend({
		/* set the model used in this collection */
		model: module.AuthorModel,

		/* define the localStorage container for his collection */
		localStorage: new Backbone.LocalStorage("LibraryAuthorCollection")
	});

	/* define the model used for a Book */
	module.BookModel = Backbone.Model.extend({
		defaults: {
			id: null,
			title: '',
			authorFirst: '',
			authorLast: '',
			genre: ''
		}
	});

	/* define the collection used for Books */
	module.BookCollection = Backbone.Collection.extend({

		/* set the model used in this collection */
		model: module.BookModel,
		localStorage: new Backbone.LocalStorage("LibraryCollection")
	});

	/* the main layout used for this app */
	module.LibraryView = Marionette.LayoutView.extend({

		/* local variables used to store/access collections */
		bookCollection: null,
		authorCollection: null,
		genreCollection: null,

		/* HTML template used for this view */
		template: '#layout-template',

		/* define mouse events */
		events: {
			'click #btnSave' : 'onSaveClicked',
			'click #btnClear' : 'onClearClicked',
			'click #btnClearCache' : 'onClearCacheClicked',
			'change #selectGenreRegion select' : 'onGenreSelected',
			'change #selectAuthorRegion select' : 'onAuthorSelected'
		},

		/* UI shortcuts */
		ui: {
			inputTitle: '#txtTitle', // title input field
			inputAuthorFirst: '#txtAuthorFirst', // author first name input field
			inputAuthorLast: '#txtAuthorLast', // author last name input field
			inputGenre: '#txtGenre', // genre input field
			selectGenre: '#selectGenre', // genre select list
			selectAuthor: '#selectAuthor' // author select list
		},

		/* regions into which other views will be rendered */
		regions: {
			authorRegion: '#selectAuthorRegion', // dropdown list of authors
			genreRegion: '#selectGenreRegion', // dropdown list of genres
			outputRegion: '#outputRegion' // list of books
		},

		/* called on click of SAVE button */
		onSaveClicked: function() {
			this.addBook();
		},

		/* called on click of CLEAR FORM button */
		onClearClicked: function() {
			this.clearForm();
		},

		/* called on click of CLEAR CACHE button.
			this will empty the localstorage cache for this app */
		onClearCacheClicked: function() {
			window.localStorage.clear();
			this.render();
		},

		/* called when a genre is selected from the dropdown menu */
		onGenreSelected: function() {
			var selectedGenre = $('#selectGenre').val();
			
			/* if the selected genre value is blank, do nothing */
			if(selectedGenre === '') return;

			/* update the genre input element with the value pulled from the select element */
			this.ui.inputGenre.val(selectedGenre);
		},

		/* called when an author is selected from the dropdown menu */
		onAuthorSelected: function() {
			
			/* set the values of the first and last name */
			var authorFirst = $('#selectAuthor').val().split(', ')[1];
			var authorLast = $('#selectAuthor').val().split(', ')[0];

			/* if the value is blank, do nothing */
			if(authorFirst === '' && authorLast === '') return;

			/* update the appropriate input elements with the values pulled from the select element */
			this.ui.inputAuthorFirst.val(authorFirst);
			this.ui.inputAuthorLast.val(authorLast);
		},

		/* add a book to the collection */
		addBook: function() {

			/* get values from the form elements */
			var newTitle = this.ui.inputTitle.val(),
				newAuthorFirst = this.ui.inputAuthorFirst.val(),
				newAuthorLast = this.ui.inputAuthorLast.val(),
				newGenre = this.ui.inputGenre.val();

			/* add a new model to the book collection.
				Automatically adds and instance of the 
				module.BookModel type because that is the 
				model associated with the BookCollection */
			this.bookCollection.add({
				id: new Date().getTime(),
				title: newTitle,
				authorFirst: newAuthorFirst,
				authorLast: newAuthorLast,
				genre: newGenre
			});

			/* iterate through the collection and save each model. 
				necessary to do it this way because of how
				Backbone.localStorage works. */
			this.bookCollection.each(function(oBook) {
				oBook.save();
			});

			/* clear the form elements */
			this.clearForm();

			/* add the author to the list of authors */
			this.addAuthor(newAuthorFirst,newAuthorLast);

			/* add the genre to the list of genres */
			this.addGenre(newGenre);
		},

		/* add a genre to the list of genres */
		addGenre: function(sGenre) {

			/* set a state variable */
			var exists = false;

			/* iterate through the collection to see if the genre
				we are attempting to add already exists */
			this.genreCollection.each(function(oGenre) {
				if(oGenre.get('title') === sGenre) exists = true;
			});

			/* if the genre already exists, exit and do nothing */
			if(exists) return;

			/* add the new genre to the collection. Defaults to an
				instance of module.GenreModel, because that is what
				is associated with the module.GenreCollection */
			this.genreCollection.add({
				title: sGenre
			});

			/* iterate through the genres in the collection and save each one */
			this.genreCollection.each(function(oGenre) {
				oGenre.save();
			});
		},

		/* add an author to the list of authors */
		addAuthor: function(sAuthFirst, sAuthLast) {
			/* set a state variable */
			var exists = false;

			/* iterate through the collection to see if the author
				we are attempting to add already exists */
			this.authorCollection.each(function(oAuthor) {
				if(oAuthor.get('firstName') === sAuthFirst && oAuthor.get('lastName') === sAuthLast) exists = true;
			});

			/* if the author already exists, exit and do nothing */
			if(exists) return;

			/* add the new author to the collection. Defaults to an
				instance of module.AuthorModel, because that is what
				is associated with the module.AuthorCollection */
			this.authorCollection.add({
				firstName: sAuthFirst,
				lastName: sAuthLast
			});

			/* iterate through the authors in the collection and save each one */
			this.authorCollection.each(function(oAuthor) {
				oAuthor.save();
			});
		},

		/* clear all of the imput elements in the form */
		clearForm: function() {
			this.ui.inputTitle.val('');
			this.ui.inputAuthorFirst.val('');
			this.ui.inputAuthorLast.val('');
			this.ui.inputGenre.val('');
		},

		/* called when the DOM for this view is ready for manipulation */
		onRender: function(){
			/* save a local reference to the view, for use in
				model and collection callbacks */
			var capturedThis = this;

			/* create a new instance of the book collection */
			this.bookCollection = new module.BookCollection();

			/* load the book collection from local storage */
			this.bookCollection.fetch()
				.fail(function(){ /* something went wrong */
					console.log('failed to load book collection');
				})
				.done(function(){
					/* when loaded, create a new collectionview using it */
					var bookCollectionView = new module.BookCollectionView({collection: capturedThis.bookCollection});

					/* render the collectionview in the appropriate region */
					capturedThis.outputRegion.show(bookCollectionView);
				});
			
			/* create a new instance of the genre collection */
			this.genreCollection = new module.GenreCollection();

			/* load the collection of genres from local storage */
			this.genreCollection.fetch()
				.fail(function() { /* something went wrong */
					console.log('failed to load genre collection');
				})
				.done(function() { /* loaded successfully */

					/* if the genre collection is empty, add an initial element to use as a label */
					if(capturedThis.genreCollection.length === 0) {
						capturedThis.genreCollection.add({
							title: ''
						});
					}
					/* Create a new collectionview using the genreCollection */
					var genreCollectionView = new module.GenreCollectionView({collection: capturedThis.genreCollection});

					/* render the collectionview in the appropriate region */
					capturedThis.genreRegion.show(genreCollectionView);
				});

			/* create a new instance of the author collection */
			this.authorCollection = new module.AuthorCollection();

			/* load the collection of authors from local storage */
			this.authorCollection.fetch()
				.fail(function() { /* something went wrong */
					console.log('failed to load author collection');
				})
				.done(function() { /* loaded succesfully */

					/* if the genre collection is empty, add an initial element to use as a label */
					if(capturedThis.authorCollection.length === 0) {
						capturedThis.authorCollection.add({
							firstName: '',
							lastName: ''
						});
					}
					/* when the collection is loaded, create a new collectionview using it */
					var authorCollectionView = new module.AuthorCollectionView({collection: capturedThis.authorCollection});

					/* render the collectionview in the appropriate region */
					capturedThis.authorRegion.show(authorCollectionView);
				});
		}
	});
	
	/* item view for individual book */
	module.BookItemView = Marionette.ItemView.extend({
		tagName: 'li',
		template: '#book-template',
		events: {
			'click .delete' : 'onDeleteClicked'
		},

		/* when the delete button is clicked, destroy this model
			this removes the model from the parent collection */
		onDeleteClicked: function(){
			this.model.destroy();
		}
	});

	/* collection view for the list of books */
	module.BookCollectionView = Marionette.CollectionView.extend({
		tagName: 'ul',
		childView: module.BookItemView,
		id: 'bookList',

		/* listen for changes in the collection or the models therein */
		modelEvents: {
			'change' : 'onModelChanged'
		},

		/* when the collection or one of the models therein broadcasts a change event,
			re-render this view. In this example, this is called when a book is added
			or removed from the collection. */
		onModelChanged: function() {
			this.render();
		}
	});

	/* item view for an individual genre */
	module.GenreItemView = Marionette.ItemView.extend({
		template: '#genre-template',
		tagName: 'option',

		/* add attributes to this element. Setting a return value as is done
			here allows for attributes to be set 'on the fly'; in this instance
			each element created will have a unique value derived from
			the model associated with this view. */
		attributes: function(){
			return {
				value: this.model.get('title')
			}
		}
	});

	/* define the genre collection view */
	module.GenreCollectionView = Marionette.CollectionView.extend({
		tagName: 'select',
		childView: module.GenreItemView,
		id: 'selectGenre'
	});

	module.AuthorItemView = Marionette.ItemView.extend({
		template: '#author-template',
		tagName: 'option',

		/* add attributes to this element. Setting a return value as is done
			here allows for attributes to be set 'on the fly'; in this instance
			each element created will have a unique value derived from
			the lastName and firstName attributes of the model associated with this view. */
		attributes: function(){
			var authName = this.model.get('lastName') + ', ' + this.model.get('firstName');
			return {
				value: authName
			}
		}
	});

	/* define the author collection view */
	module.AuthorCollectionView = Marionette.CollectionView.extend({
		tagName: 'select',
		childView: module.AuthorItemView,
		id: 'selectAuthor'
	});

	/* add a method which will fire on the initialization
		of this application. In this case, render
		the main view in the region which was defined
		up at the top of this file. */
	module.addInitializer(function(){
		app.libraryRegion.show(new module.LibraryView());
	});

});

/* once the DOM is ready, start the application */
$(document).ready(function() {app.start();});

Here is the HTML file:

<!doctype html>
<html>
	<head>
		<title>Library App Created in Backbone/Marionette Using LocalStorage</title>
		<link rel="stylesheet" href="style.css"/>
	</head>
	<body>
		<!-- Base element for app -->
		<!--
			Don't use the BODY element as the base element, because when the app renders in the BODY
			it will wipe out the template files before the views can pick them up.
		-->
		
		<div id="libraryApp"></div>

		<!-- TEMPLATES -->
		<!-- main layout template -->
		<script type="text/template" id="layout-template">
			<h1>Library App Using LocalStorage</h1>
			<div id="inputRegion">
				<div><label>Title</label><input id="txtTitle" type="text"/></div>
				<div class="author-row">
					<label>Author (last, first)</label><input id="txtAuthorLast" type="text"/><input id="txtAuthorFirst" type="text"/>
					<div id="selectAuthorRegion" class="selectContainer"></div>
				</div>
				<div>
					<label>Genre</label><input id="txtGenre" type="text"/>
					<div id="selectGenreRegion" class="selectContainer"></div>
				</div>
				<p class="buttons">
					<button id="btnSave">Save</button>
					<button id="btnClear">Clear</button>
					<button id="btnClearCache">Clear LocalStorage</button>
				</p>
			</div>
			<div id="outputRegion"></div>
		</script>

		<!-- book line item template -->
		<script type="text/template" id="book-template">
			<span>Title: <%- title %></span>
			<span>Author: <%- authorLast %>, <%- authorFirst %><br/></span>
			<span>Genre: <%- genre %><br/></span>
			<button class="delete">X</button>
		</script>

		<!-- genre option template -->
		<script type="text/template" id="genre-template">
		<%- title %>
		</script>

		<!-- author option template -->
		<script type="text/template" id="author-template">
		<%- lastName %>, <%- firstName %>
		</script>

		<!-- libraries -->
		<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
		<script type="text/javascript" src="js/underscore.js"></script>
		<script type="text/javascript" src="js/backbone.js"></script>
		<script type="text/javascript" src="js/backbone.localStorage.js"></script>
		<script type="text/javascript" src="js/backbone.marionette.js"></script>

		<!-- app code -->
		<script type="text/javascript" src="js/script.js"></script>
	</body>
</html>

And here is the style sheet:

#libraryApp {
	width: 600px;
	margin: 0 auto;
}
h1 {
	float:left;
	text-align: center;
	width: 600px;
	margin: 0 auto 10px auto;
	border-bottom: 1px solid #cdcdcd;
}
#inputRegion,#outputRegion {
	float: left;
	width: 100%;
	margin: 0 0 10px 0;
}
#inputRegion > div {
	float: left;
	clear: both;
}
#inputRegion label {
	float: left;
	width: 120px;
}
#inputRegion input {
	float: left;
	width: 200px;
}
#inputRegion .author-row input {
	width: 98px;
}
#inputRegion .selectContainer {
	float: left;
}
#inputRegion select {
	float: left;
	margin-left: 20px;
	width: 200px;
}
.buttons {
	float: left;
	clear: both;
}
#outputRegion ul{
	list-style: none;
	margin: 0;
	padding: 0;
	float: left;
	width: 100%;
	border-top: 1px solid #ccc;
}
#outputRegion li {
	position: relative;
	float: left;
	width: 100%;
	height: 60px;
	border-bottom: 1px solid #ccc;
}
#outputRegion li span {
	float: left;
	width: 80%;
}
#outputRegion li button {
	position: absolute;
	right: 0;
	top: 5px;
}

These are the code libraries used in this demo:

 

Simple Marionette.js Model, Collection and CollectionView Example

This is a simple example of using Backbone.js models and collections, and the Marionette.js ItemView and CollectionView. Here is the Javascript:

/* create a new instance of the Marionette app */
var app = new Backbone.Marionette.Application();

/* add the initial region which will contain the app */
app.addRegions({
	/* reference to container element in the HTML file */
	appRegion: '#AppBase'
});

/* define a module to keep the code modular */
app.module('App',function(module, App, Backbone, Marionette, $, _){
	
	/* definition for book model, with default example of data structure */
	module.BookModel = Backbone.Model.extend({
		defaults: {
			title: '',
			authorFirst: '',
			authorLast: ''
		}
	});

	/* definition for book collection */
	module.BookCollection = Backbone.Collection.extend({
		
		/* set model type used for this collection */
		model: module.BookModel,

		/* comparator determines how collection is sorted */
		comparator: 'authorLast'
	});

	/* definition for individual item view */
	module.BookItemView = Marionette.ItemView.extend({
		tagName: 'li',

		/* set the template used to display this view */
		template: '#itemView-template',

		/* used to show the order in which these method are called */
		initialize: function(){ console.log('BookItemView: initialize >>> ' + this.model.get('title')) },
		onRender: function(){ console.log('BookItemView: onRender >>> ' + this.model.get('title')) },
		onShow: function(){ console.log('BookItemView: onShow >>> ' + this.model.get('title')) }
	});

	/* definition for collection view */
	module.BookCollectionView = Marionette.CollectionView.extend({
		tagName: 'ul',

		/* explicitly set the childview (formerly 'itemView') used to display the models in this collection */
		childView: module.BookItemView,

		initialize: function(){ console.log('BookCollectionView: initialize') },
		onRender: function(){ console.log('BookCollectionView: onRender') },
		onShow: function(){ console.log('BookCollectionView: onShow') }
	});

	/* define a view; in this case a 'LayoutView' (formerly 'Layout') */
	module.AppLayoutView = Marionette.LayoutView.extend({
		
		/* the auto-generated element which contains this view */
		tagName: 'div',

		/* id attribute for the auto-generated container element */
		id: 'AppContainer',

		/* reference to the template which will be rendered for this view */
		template: '#layout-template',

		/* define the regions within this layout, into which we will load additional views */
		regions: {
			'RegionOne' : '#regionOne'
		},

		/* called when the view initializes, before it displays */
		initialize: function() {
			console.log('main layout: initialize');
		},

		/* called when view renders in the DOM. This is a good place to 
			add nested views, because the views need existing DOM elements
			into which to be rendered. */
		onRender: function() {
			console.log('main layout: onRender');
			
			/* create an array of books using anonymouse objects;
				the objects have the same structure as in the 'defaults'
				attribute of the module.BookModel definition */
			var bookArray = [];
			bookArray.push({title: 'Wolf',authorLast: 'Harrison', authorFirst: 'Jim'});
			bookArray.push({title: 'The Theory and Practice of Rivers', authorLast: 'Snyder', authorFirst: 'Gary'});
			bookArray.push({title: 'Weather Central',authorLast: 'Kooser', authorFirst: 'Ted'});
			bookArray.push({title: 'Losing Season',authorLast: 'Ridl', authorFirst: 'Jack'});
			bookArray.push({title: 'Mornings Like This',authorLast: 'Dillard', authorFirst: 'Annie'});

			/* create a collection using the array of anonymous objects */
			var bookCollection = new module.BookCollection(bookArray);

			/* create new instance of the collection view using the bookCollection */
			var bookCollectionView = new module.BookCollectionView({collection: bookCollection});

			/* display the collection view in region 1 */
			this.RegionOne.show(bookCollectionView);
		},

		/* called when the view displays in the UI */
		onShow: function() {
			console.log('main layout: onShow');
		}
	});

	/* Tell the module what to do when it is done loading */
	module.addInitializer(function(){
		/* create a new instance of the layout from the module */
		var layout = new module.AppLayoutView();

		/* display the layout in the region defined at the top of this file */
		app.appRegion.show(layout);
	});
});

/* once the DOM initializes, start the app */
$(document).ready(function() {app.start();});

And here is the HTML, including the templates used by the Marionette views.

<!doctype html>
<html>
	<head>
		<title>Backbone/Marionette basic setup with nested views</title>
		<style type="text/css">
		body {
			background: #ffffff;
		}
		#AppBase {
			width: 400px;
			margin: 10px auto;
			padding: 0;
			outline: 1px solid #808080;
		}
		#AppContainer {
			width: 400px;
			margin: 0;
			padding: 0;
		}
		h1 {
			width:100%;
			margin: 0;
			padding: 0;
			text-align: center;
			border-bottom: 1px solid #808080;
		}
		ul {
			margin: 1em 0 0 0;
			padding:0;
			list-style-type: none;
			width: 400px;
		}
		li {
			margin-bottom: .5em;
			padding: 0 0 .5em 1em;
			border-bottom: 1px solid #dedede;
		}
		</style>
	</head>
	<body>
		<!-- Base element for app -->
		<!--
			Dont use the BODY element as the base because when the app renders in the BODY
			it will wipe out the template files before the views can pick them up 
		-->
		<div id="AppBase"></div>

		<!-- TEMPLATES -->
		<!-- main layout template -->
		<script type="text/template" id="layout-template">
			<h1>Main Template</h1>
			<div id="regionOne"></div>
		</script>

		<!-- bookItemView template -->
		<!-- This used the Underscore templating system, which is built into Marionette.js -->
		<script type="text/template" id="itemView-template">
			<span><b>Title</b>: <%- title %></span><br/>
			<span><b>Author</b>: <%- authorLast %>, <%- authorFirst %></span>
		</script>

		<!-- libraries -->
		<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
		<script type="text/javascript" src="js/underscore.js"></script>
		<script type="text/javascript" src="js/backbone.js"></script>
		<script type="text/javascript" src="js/backbone.marionette.js"></script>

		<!-- app code -->
		<script type="text/javascript" src="js/script.js"></script>
	</body>
</html>

Here are links to the code libraries used to create this example:

Simple Backbone/Marionette Example With Nested Views

Here is the Javascript file:

/* create a new instance of the Marionette app */
var app = new Backbone.Marionette.Application();

/* add the initial region which will contain the app */
app.addRegions({
	/* reference to container element in the HTML file */
	appRegion: '#AppBase'
});

/* define a module to keep the code modular */
app.module('App',function(module, App, Backbone, Marionette, $, _){
	
	module.RegionOneLayoutView = Marionette.LayoutView.extend({
		
		/* specify element type of auto-generated container element */
		tagName: 'div',

		/* add ID attribute to the generated element */
		id: 'regionOneLayoutView',

		/* add class name to the generated element */
		template: '#layout-region-one',

		/* HTML template for this view */
		className: 'subLayout',
		initialize: function(){console.log('Region 1 Layout: initialize');},
		onRender: function(){console.log('Region 1 Layout: onRender');},
		onShow: function(){console.log('Region 1 Layout: onShow');}
	});

	module.RegionTwoLayoutView = Marionette.Layout.extend({
		
		/* specify element type of auto-generated container element */
		tagName: 'div',

		/* add ID attribute to the generated element */
		id: 'regionTwoLayoutView',

		/* add class name to the generated element */
		className: 'subLayout',

		/* HTML template for this view */
		template: '#layout-region-two',

		/* define UI events and assign event handlers */
		events: {
			'click .button1' : 'onButtonOneClicked',
			'click .button2' : 'onButtonTwoClicked',
			'click .button3' : 'onButtonThreeClicked'
		},

		/* click handlers for buttons */
		onButtonOneClicked: function(mouseEvent) {
			console.log('button one clicked');
		},
		onButtonTwoClicked: function(mouseEvent) {
			console.log('button two clicked');
		},
		onButtonThreeClicked: function(mouseEvent) {
			console.log('button three clicked');
		},
		initialize: function(){console.log('Region 2 Layout: initialize');},
		onRender: function(){console.log('Region 2 Layout: onRender');},
		onShow: function(){console.log('Region 2 Layout: onShow');}
	});

	/* define a view; in this case a 'Layout' */
	module.AppLayoutView = Marionette.Layout.extend({
		
		/* the auto-generated element which contains this view */
		tagName: 'div',

		/* id attribute for the auto-generated container element */
		id: 'AppContainer',

		/* reference to the template which will be rendered for this view */
		template: '#layout-template',

		/* define the regions within this layout, into which we will load additional views */
		regions: {
			'RegionOne' : '#regionOne',
			'RegionTwo' : '#regionTwo'
		},

		/* called when the view initializes, before it displays */
		initialize: function() {
			console.log('main layout: initialize');
		},

		/* called when view renders in the DOM. This is a good place to 
			add nested views, because the views need existing DOM elements
			into which to be rendered. */
		onRender: function() {
			console.log('main layout: onRender');
			/* create new instance of the region 1 layout view, and display it in Region1  */
			var regionOneLayoutView = new module.RegionOneLayoutView();
			this.RegionOne.show(regionOneLayoutView);

			/* create new instance of the region 2 layout view, and display it in Region2  */
			var regionTwoLayoutView = new module.RegionTwoLayoutView();
			this.RegionTwo.show(regionTwoLayoutView);
		},

		/* called when the view displays in the UI */
		onShow: function() {
			console.log('main layout: onShow');
		}
	});

	/* Tell the module what to do when it is done loading */
	module.addInitializer(function(){
		/* create a new instance of the layout from the module */
		var layout = new module.AppLayoutView();

		/* display the layout in the region defined at the top of this file */
		app.appRegion.show(layout);
	});
});

/* once the DOM initializes, start the app */
$(document).ready(function() {app.start();});

And here is the HTML document:

<!doctype html>
<html>
	<head>
		<title>Backbone/Marionette basic setup with nested views</title>
		<style type="text/css">
			body {
				background: #ffffff;
			}
			#AppBase {
				width: 100%;
				max-width: 960px;
				height: 480px;
				margin: 10px auto;
				padding: 0;
				float: left;
				outline: 1px solid #808080;
			}

			#AppContainer {
				margin: 0;
				padding: 0;
			}

			h1 {
				float:left;
				width:100%;
				margin:0;
				padding:0;
				text-align: center;
				height:100%;
			}
			.subLayout {
				float:left;
				width: 50%;
				height:200px;
				outline:1px solid #808080;
			}
			h2 {
				width:100%;
				text-align:center;
			}
			button {
				width: 75px;
				line-height:30px;
				text-align: center;
			}
		</style>
	</head>
	<body>
		<!-- Base element for app -->
		<!--
			Dont use the BODY element as the base because when the app renders in the BODY
			it will wipe out the template files before the views can pick them up 
		-->
		<div id="AppBase"></div>

		<!-- TEMPLATES -->
		<!-- main layout template -->
		<script type="text/template" id="layout-template">
			<h1>Main Template</h1>
			<div id="regionOne"></div>
			<div id="regionTwo"></div>
		</script>

		<!-- region 1 layout -->
		<script type="text/template" id="layout-region-one">
			<h2>Region 1 content</h2>
		</script>

		<!-- region 2 layout -->
		<script type="text/template" id="layout-region-two">
			<h2>Region 2 content</h2>
			<p>
				<button class="button1">One</button>
				<button class="button2">Two</button>
				<button class="button3">Three</button>
			</p>
		</script>
		<!-- libraries -->
		<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
		<script type="text/javascript" src="js/underscore.js"></script>
		<script type="text/javascript" src="js/backbone.js"></script>
		<script type="text/javascript" src="js/backbone.marionette.js"></script>

		<!-- app code -->
		<script type="text/javascript" src="js/script.js"></script>
	</body>
</html>

Links to necessary code libraries:

Barebones Backbone/Marionette File

I am posting this for two reasons: First, so that I have an easy place to go when I want to start a new Backbone/Marionette application and I don’t want to search around for a bare-bones template; and second, because when I started working with Backbone/Marionette I wish I could have found something like this; the equivalent of ‘Hello World’. Code follows, with comments therein.

/* create a new instance of the Marionette app */
var app = new Backbone.Marionette.Application();

/* add the initial region which will contain the app */
app.addRegions({
	/* reference to container element in the HTML file */
	appRegion: '#AppBase'
});

/* define a module to keep the code modular */
app.module('App',function(module, App, Backbone, Marionette, $, _){
	
	/* define a view; in this case a 'Layout' */
	module.GardenLayoutView = Marionette.LayoutView.extend({
		
		/* the auto-generated element which contains this view */
		tagName: 'div',

		/* id attribute for the auto-generated container element */
		id: 'AppContainer',

		/* reference to the template which will be rendered for this view */
		template: '#layout-template',

		/* called when the view initializes, before it displays */
		initialize: function() {
			console.log('initialize');
		},

		/* called when view renders in the DOM */
		onRender: function() {
			console.log('onRender');
		},

		/* called when the view displays in the UI */
		onShow: function() {
			console.log('onShow');
		}
	});

	/* Tell the module what to do when it is done loading */
	module.addInitializer(function(){
		/* create a new instance of the layout from the module */
		var layout = new module.GardenLayoutView();

		/* display the layout in the region defined at the top of this file */
		app.appRegion.show(layout);
	});
});


$(document).ready(function() {app.start();});

And here is the base HTML file, including references to all of the libraries which are required for creating a Backbone/Marionette application.

<!doctype html>
<html>
	<head>
		<title>Backbone/Marionette bare-bones setup</title>
		<link rel="stylesheet" href="style.css"/>
	</head>
	<body>
		<!-- Base element for app -->
		<!--
			Dont use the BODY element as the base because when the app renders in the BODY
			it will wipe out the template files before the views can pick them up 
		-->
		<div id="AppBase"></div>

		<!-- TEMPLATES -->
		<!-- main layout template -->
		<script type="text/template" id="layout-template">
			<h1>This is a rendered template</h1>
		</script>

		<!-- libraries -->
		<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
		<script type="text/javascript" src="js/underscore.js"></script>
		<script type="text/javascript" src="js/backbone.js"></script>
		<script type="text/javascript" src="js/backbone.marionette.js"></script>

		<!-- app code -->
		<script type="text/javascript" src="js/script.js"></script>
	</body>
</html>

The libraries which load in before the code for the script can be found here:

Each link also has information necessary for learning and implementing the libraries.