diff --git a/.gitignore b/.gitignore
index 1b5c03b..d9e8435 100644
--- a/.gitignore
+++ b/.gitignore
@@ -92,3 +92,7 @@ jspm_packages
# Optional REPL history
.node_repl_history
+
+# bundled javascript
+/build/*.js
+/build/*.js.map
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..18d652d
--- /dev/null
+++ b/index.html
@@ -0,0 +1,11 @@
+
+
+
+ Arbor
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..e7e601b
--- /dev/null
+++ b/package.json
@@ -0,0 +1,46 @@
+{
+ "name": "arbor-frontend",
+ "version": "1.0.0",
+ "description": "This is the frontend part of the Arbor application",
+ "main": "index.js",
+ "scripts": {
+ "start:dev": "webpack-dev-server",
+ "build": "webpack -p --define process.env.NODE_ENV='\"production\"' --progress --colors",
+ "build:watch": "webpack -w -d",
+ "test": "mocha --compilers js:babel-core/register --require ./test/test_helper.js test/**/*.js",
+ "test:watch": "npm run test -- --watch"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git@git.timshomepage.net:timw4mail/arbor-frontend.git"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "dependencies": {
+ "immutable": "^3.8.1",
+ "react": "^15.1.0",
+ "react-dom": "^15.1.0",
+ "react-redux": "^4.4.5",
+ "react-router": "^2.4.1",
+ "redux": "^3.5.2"
+ },
+ "devDependencies": {
+ "babel": "^6.5.2",
+ "babel-loader": "^6.2.4",
+ "babel-preset-es2015": "^6.9.0",
+ "babel-preset-react": "^6.5.0",
+ "chai": "^3.5.0",
+ "mocha": "^2.5.3",
+ "postcss": "^5.0.21",
+ "postcss-cssnext": "^2.6.0",
+ "webpack": "^1.13.1",
+ "webpack-dev-server": "^1.14.1"
+ },
+ "babel": {
+ "presets": [
+ "es2015",
+ "react"
+ ]
+ }
+}
diff --git a/src/action_creators.js b/src/action_creators.js
new file mode 100644
index 0000000..3356938
--- /dev/null
+++ b/src/action_creators.js
@@ -0,0 +1,7 @@
+export function setState(state) {
+
+}
+
+export function update(item) {
+
+}
\ No newline at end of file
diff --git a/src/app.js b/src/app.js
new file mode 100644
index 0000000..26a294d
--- /dev/null
+++ b/src/app.js
@@ -0,0 +1,19 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import {Router, Route, hashHistory} from 'react-router';
+import {createStore} from 'redux';
+import {Provider} from 'react-redux';
+
+import reducer from './reducer';
+import App from './components/App';
+
+const store = createStore(reducer);
+
+const routes = ;
+
+ReactDOM.render(
+
+ {routes}
+ ,
+ document.getElementById('app')
+);
\ No newline at end of file
diff --git a/src/components/App.js b/src/components/App.js
new file mode 100644
index 0000000..e47ea81
--- /dev/null
+++ b/src/components/App.js
@@ -0,0 +1,9 @@
+import React from 'react';
+
+class App extends React.Component {
+ render() {
+ return this.props.children
+ }
+}
+
+export default App;
\ No newline at end of file
diff --git a/src/constants.js b/src/constants.js
new file mode 100644
index 0000000..d7236c9
--- /dev/null
+++ b/src/constants.js
@@ -0,0 +1,6 @@
+/**
+ * 'Global' constants
+ */
+export const SET_STATE = 'SET_STATE';
+export const UPDATE = 'UPDATE';
+export const DELETE = 'DELETE';
\ No newline at end of file
diff --git a/src/reducer.js b/src/reducer.js
new file mode 100644
index 0000000..8623cb4
--- /dev/null
+++ b/src/reducer.js
@@ -0,0 +1,22 @@
+import {Map} from 'immutable';
+import * as CONST from './constants';
+
+const actionMap = {
+ [CONST.SET_STATE]: (state) => {
+
+ }
+};
+
+/**
+ * Reducer function mapping action objects to state transition functions
+ *
+ * @param {Map} state
+ * @param {Object} action
+ * @return {Map}
+ */
+export default function reducer(state=Map(), action) {
+ // Return default state if action is undefined
+ if ( ! Object.keys(actionMap).includes(action)) {
+ return state;
+ }
+}
\ No newline at end of file
diff --git a/test/test_helper.js b/test/test_helper.js
new file mode 100644
index 0000000..824d268
--- /dev/null
+++ b/test/test_helper.js
@@ -0,0 +1,21 @@
+/**
+ * Fakes a browser environment for testing react
+ */
+import jsdom from 'jsdom';
+import chai from 'chai';
+import chaiImmutable from 'chai-immutable';
+
+const doc = jsdom.jsdom('');
+const win = doc.defaultView;
+
+global.document = doc;
+global.window = win;
+
+// Hoist window properties to global
+Object.keys(window).forEach(key => {
+ if ( ! (key in global)) {
+ global[key] = window[key];
+ }
+});
+
+chai.use(chaiImmutable);
\ No newline at end of file
diff --git a/webpack.config.js b/webpack.config.js
new file mode 100644
index 0000000..b8630aa
--- /dev/null
+++ b/webpack.config.js
@@ -0,0 +1,39 @@
+const webpack = require('webpack');
+
+module.exports = {
+ cache: true,
+ debug: true,
+ devServer: {
+ contentBase: './build',
+ hot: true
+ },
+ devtool: 'sourcemaps',
+ entry: [
+ 'webpack/hot/only-dev-server',
+ './src/app.js',
+ ],
+ module: {
+ loaders: [{
+ test: /\.js$/,
+ exclude: /(node_modules)/,
+ loader: 'react-hot!babel-loader'
+ }, {
+ test: /\.css$/,
+ loader: 'style-loader!css-loader!postcss-loader'
+ }]
+ },
+ output: {
+ path: `${__dirname}/build`,
+ publicPath: '/',
+ filename: 'bundle.js'
+ },
+ plugins: [
+ new webpack.HotModuleReplacementPlugin()
+ ],
+ postcss: () => {
+
+ },
+ resolve: {
+ extensions: ['', '.js']
+ }
+};
\ No newline at end of file