diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..61f1e4ed0c1981310b6c80b02f95ca647d4a3f5f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,114 @@
+# Database
+*.db
+
+# System
+.DS_Store
+
+# Editor Settings
+.hintrc
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.env.test
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+.parcel-cache
+
+# Next.js build output
+.next
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and *not* Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
diff --git a/src/main.js b/src/main.js
index 7f5b3201539f3e769c579e8ebf96dfe56af79b64..67120ff7526ff5b879532dab859656ae8cdcabe7 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,5 +1,202 @@
 import * as helpers from "./modules/helpers.js";
 
-function init() {}
+const navigation = {
+  label: "Menu",
+  path: "/menu",
+  command: "menu",
+  depth: 0,
+  submenu: {
+    call: {
+      label: "Call",
+      path: "/menu/call",
+      command: "call",
+      depth: 1,
+      submenu: {
+        emergency: {
+          label: "Emergency",
+          command: "emergency",
+          path: "/menu/call/emergency",
+          depth: 2,
+          message: "Calling Emergency",
+        },
+        contact1: {
+          label: "Flute Inc.",
+          command: "contact A",
+          path: "/menu/call/contact1",
+          depth: 2,
+          message: "Calling Flute Inc.",
+        },
+        contact2: {
+          label: "Brays AG",
+          command: "contact B",
+          path: "/menu/call/contact2",
+          depth: 2,
+          message: "Calling Brays AG",
+        },
+      },
+    },
+    check: {
+      label: "Check",
+      path: "/menu/check",
+      command: "check",
+      depth: 1,
+      submenu: {
+        daily: {
+          label: "Daily",
+          command: "daily",
+          path: "/menu/check/daily",
+          depth: 2,
+          message: "Displaying Daily Checklist",
+        },
+        weekly: {
+          label: "Weekly",
+          command: "weekly",
+          path: "/menu/check/weekly",
+          depth: 2,
+          message: "Displaying Weekly Checklist",
+        },
+        monthly: {
+          label: "Monthly",
+          command: "monthly",
+          path: "/menu/check/monthly",
+          depth: 2,
+          message: "Displaying Monthly Checklist",
+        },
+      },
+    },
+    apps: {
+      label: "Apps",
+      path: "/menu/apps",
+      command: "apps",
+      depth: 1,
+      submenu: {
+        record: {
+          label: "Record",
+          command: "record",
+          path: "/menu/apps/record",
+          depth: 2,
+          message: "Opening Recording App",
+        },
+        breakout: {
+          label: "Breakout",
+          command: "breakout",
+          path: "/menu/apps/breakout",
+          depth: 2,
+          message: "Opening Breakout App",
+        },
+        statistics: {
+          label: "Statistics",
+          command: "statistics",
+          path: "/menu/apps/statistics",
+          depth: 2,
+          message: "Opening Statistics App",
+        },
+      },
+    },
+  },
+};
+
+const backItem = {
+  label: "Back",
+  path: "../",
+  command: "back",
+};
+
+// init application
+function init() {
+  // build navigation
+  const appEl = document.getElementById("app");
+  const navigationEl = document.createElement("nav");
+  navigationEl.id = "navigation";
+  const listEl = document.createElement("ul");
+  navigationEl.appendChild(listEl);
+  appEl.replaceChildren(navigationEl);
+
+  resetNavigationEl();
+}
+
+function resetNavigationEl() {
+  const navigationEl = document.getElementById("navigation");
+  const listEl = navigationEl.querySelector("ul");
+  let itemEl = buildNavigationItemEl(navigation);
+  listEl.replaceChildren(itemEl);
+}
+
+// build navigation item
+function buildNavigationItemEl(item) {
+  const itemEl = document.createElement("li");
+  const linkEl = document.createElement("a");
+  linkEl.href = item.path;
+  linkEl.innerHTML = item.label;
+  linkEl.dataset.command = item.command;
+  itemEl.appendChild(linkEl);
+
+  linkEl.addEventListener("click", onMouseClick);
+
+  return itemEl;
+}
+
+// on menu item mouseclick
+function onMouseClick(event) {
+  event.preventDefault();
+  const path = event.target.getAttribute("href");
+  navigateTo(path);
+}
+
+// navigate to page
+function navigateTo(path) {
+  if (path === "/") resetNavigationEl();
+  else {
+    let navObj = helpers.findNestedObject(navigation, "path", path);
+
+    // is menu
+    if (navObj.hasOwnProperty("submenu")) updateNavigation(navObj);
+    else {
+      //is final page
+      let appEl = document.getElementById("app");
+      let messageEl = document.createElement("div");
+      messageEl.innerHTML = navObj.message;
+      appEl.replaceChildren(messageEl);
+
+      let exitEl = document.createElement("a");
+      exitEl.href = "/";
+      exitEl.innerHTML = "Exit";
+      appEl.appendChild(exitEl);
+    }
+  }
+}
+
+// update Navigation
+function updateNavigation(object) {
+  // update navigation
+  const listEl = document.createElement("ul");
+
+  // is navigation
+  for (let key in object.submenu) {
+    let itemEl = buildNavigationItemEl(object.submenu[key]);
+    listEl.appendChild(itemEl);
+  }
+
+  // add "back" button
+  let backItemEl;
+  if (object.depth === 0) {
+    backItemEl = buildNavigationItemEl({
+      label: "Close",
+      path: "/",
+      command: "close",
+    });
+  } else if (object.depth === 1) {
+    backItemEl = buildNavigationItemEl({
+      label: "Back",
+      path: "/menu",
+      command: "back",
+    });
+  }
+
+  listEl.appendChild(backItemEl);
+
+  const navigationEl = document.getElementById("navigation");
+  navigationEl.replaceChildren(listEl);
+}
 
 init();
diff --git a/src/modules/helpers.js b/src/modules/helpers.js
index 376653a2674d667d69adf3be84084e11f2443604..eed7762d1e040a5667a54825a318ae876f62740c 100644
--- a/src/modules/helpers.js
+++ b/src/modules/helpers.js
@@ -1,3 +1,28 @@
+// map value range
 export function map(num, in_min, in_max, out_min, out_max) {
   return ((num - in_min) * (out_max - out_min)) / (in_max - in_min) + out_min;
 }
+
+// find nested object with key value pair
+// https://stackoverflow.com/questions/45336281/javascript-find-by-value-deep-in-a-nested-object-array
+export function findNestedObject(obj, key, value) {
+  // Base case
+  if (obj[key] === value) {
+    return obj;
+  } else {
+    var keys = Object.keys(obj); // add this line to iterate over the keys
+
+    for (var i = 0, len = keys.length; i < len; i++) {
+      var k = keys[i]; // use this key for iteration, instead of index "i"
+
+      // add "obj[k] &&" to ignore null values
+      if (obj[k] && typeof obj[k] == "object") {
+        var found = findNestedObject(obj[k], key, value);
+        if (found) {
+          // If the object was found in the recursive call, bubble it up.
+          return found;
+        }
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/styles/main.css b/src/styles/main.css
index 7222b3eafcc970da2aab4bf4b8d99595c08a6b2a..8f77ff8ed8d761b9182bd5553d57a3c8eb5d9026 100644
--- a/src/styles/main.css
+++ b/src/styles/main.css
@@ -1,11 +1,19 @@
 @import "config.css";
 #app {
+  color: var(--color-white);
+  background: black;
+  height: 100vh;
+  font: 300 5vw/1.2em Roboto, sans-serif;
   display: grid;
   grid-template-columns: 1fr;
   grid-template-rows: 1fr;
   grid-template-areas: "main";
-  height: 100vh;
-  background: black;
+  justify-items: center;
+  align-items: center;
+}
+a {
+  color: inherit;
+  text-decoration: none;
 }
 #log {
   position: absolute;
diff --git a/src/styles/main.less b/src/styles/main.less
index ec7065416073a7b90b5a1c1b4511b13c60fa61e2..9aaeb2f799c04c1416b372fffb95a9259bcf1fca 100644
--- a/src/styles/main.less
+++ b/src/styles/main.less
@@ -1,12 +1,21 @@
 @import "config.css";
 
 #app {
+  color: var(--color-white);
+  background: black;
+  height: 100vh;
+  font: 300 5vw/1.2em Roboto, sans-serif;
   display: grid;
   grid-template-columns: 1fr;
   grid-template-rows: 1fr;
   grid-template-areas: "main";
-  height: 100vh;
-  background: black;
+  justify-items: center;
+  align-items: center;
+}
+
+a {
+  color: inherit;
+  text-decoration: none;
 }
 
 #log {