diff --git a/Framework/README.md b/Framework/README.md
index 2a0d46ed9..14df3366d 100644
--- a/Framework/README.md
+++ b/Framework/README.md
@@ -61,7 +61,7 @@ npm install --save @aliceo2/web-ui
### Getting started
* [Step-by-step tutorial: Time server using Ajax and WebSockets](./docs/tutorial/time-server.md)
-* [Advanced frontend demo](https://aliceo2group.github.io/WebUi/Framework/docs/demo/frontend.html)
+* [Advanced frontend demo](./docs/demo/README.md)
### Backend guide
* [REST API](./docs/guide/http-server.md) - Serves custom REST API, supports TLS
diff --git a/Framework/docs/demo/README.md b/Framework/docs/demo/README.md
new file mode 100644
index 000000000..dca9fcb5e
--- /dev/null
+++ b/Framework/docs/demo/README.md
@@ -0,0 +1,51 @@
+# WebUi Demos
+
+This folder contains example demos showcasing the WebUi framework.
+
+> Mithril is the JavaScript frontend framework that WebUi builds on. It provides the virtual DOM engine and rendering API `m()` that all WebUi components depend on. The WebUi framework's [renderer.js](../../Frontend/js/src/renderer.js#L26) explicitly imports Mithril via an absolute path. Without Mithril loaded globally, none of the demos can render.
+
+There are two ways to run the demos:
+1. [Full server approach](#1-full-server-approach-recommended) _(recommended)_ – run a backend that serves Mithril and all demos with clean routes.
+2. [Manual workaround](#2-manual-workaround-quick--dirty) _(quick & dirty)_ – serve Mithril with a static server.
+
+## 1. Full server approach (recommended)
+
+See the [project README](./project/README.md) for setup instructions.
+
+This uses a proper backend that serves Mithril and all demos with clean routes. In the HTTP server's [constructor](./project/index.js#L27) a [`specifyRoutes`](https://github.com/AliceO2Group/WebUi/blob/dev/Framework/Backend/http/server.js#L172) logic is invoked to wire up all required routes.
+
+## 2. Manual workaround (quick & dirty)
+
+Serve docs statically and manually provide Mithril.
+
+Copy Mithril to the expected `mithril/mithril.min.js` path:
+
+```bash
+cd WebUi/Framework
+npm ci
+mkdir -p mithril
+cp node_modules/mithril/mithril.min.js mithril/mithril.min.js
+```
+
+If you don't want to install everything, you can also create the file manually.
+```bash
+cd WebUi/Framework
+mkdir mithril
+touch mithril/mithril.min.js
+```
+Then copy the contents of the `mithril/mithril.min.js` file in there (available for example in the [unpkg.com](https://unpkg.com/mithril@2.3.7/mithril.min.js)).
+
+This is more error-prone than the local copy from `node_modules`.
+
+### Serve the Framework directory
+
+```bash
+python3 -m http.server 8080
+```
+
+Navigate through available demos:
+- [chart](http://localhost:8080/docs/demo/chart.html)
+- [frontend](http://localhost:8080/docs/demo/frontend.html)
+- [notification](http://localhost:8080/docs/demo/notification.html)
+- [template-1](http://localhost:8080/docs/demo/template-1.html)
+- [template-2](http://localhost:8080/docs/demo/template-2.html).
diff --git a/Framework/docs/demo/frontend.html b/Framework/docs/demo/frontend.html
index b0d0b9a91..e2e90c52b 100644
--- a/Framework/docs/demo/frontend.html
+++ b/Framework/docs/demo/frontend.html
@@ -136,6 +136,6 @@
// Mount will listen to model changes and draw inside body the view
mount(document.body, view, model, debug);
-// Expose model to interract with it the browser's console
+// Expose model to interact with it the browser's console
window.model = model;
diff --git a/Framework/docs/demo/project/README.md b/Framework/docs/demo/project/README.md
new file mode 100644
index 000000000..721bff668
--- /dev/null
+++ b/Framework/docs/demo/project/README.md
@@ -0,0 +1,35 @@
+# Full server approach
+
+For the setup, we're basically going to repeat the steps from the tutorial.
+
+### 1. Fetch project template
+
+```bash
+mkdir project
+git clone https://github.com/AliceO2Group/WebUi.git
+cp -R WebUi/Framework/docs/demo/project/* ./project
+cd project
+```
+
+### 2. Add the framework to dependency list
+
+```bash
+npm init
+npm install --save @aliceo2/web-ui
+```
+
+### 3. Launch the application
+
+Start the server
+```bash
+node index.js
+```
+
+Then, open your browser and navigate to [http://localhost:8080](http://localhost:8080). This is the main demo page.
+
+Navigate through available demos:
+- [chart](http://localhost:8080/chart)
+- [frontend](http://localhost:8080/frontend/)
+- [notification](http://localhost:8080/notification/)
+- [template-1](http://localhost:8080/template-1/)
+- [template-2](http://localhost:8080/template-2/).
diff --git a/Framework/docs/demo/project/config.js b/Framework/docs/demo/project/config.js
new file mode 100644
index 000000000..0be99471a
--- /dev/null
+++ b/Framework/docs/demo/project/config.js
@@ -0,0 +1,30 @@
+/**
+ * @license
+ * Copyright 2019-2020 CERN and copyright holders of ALICE O2.
+ * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
+ * All rights not expressly granted are reserved.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License v3 (GPL Version 3), copied verbatim in the file "COPYING".
+ *
+ * In applying this license CERN does not waive the privileges and immunities
+ * granted to it by virtue of its status as an Intergovernmental Organization
+ * or submit itself to any jurisdiction.
+ */
+
+/*
+ * This is quick start configuration
+ * See the Backend documentation for more details
+ *
+ */
+module.exports = {
+ jwt: {
+ secret: 'supersecret',
+ expiration: '10m',
+ },
+ http: {
+ port: 8080,
+ hostname: 'localhost',
+ tls: false,
+ },
+};
diff --git a/Framework/docs/demo/project/index.js b/Framework/docs/demo/project/index.js
new file mode 100644
index 000000000..4804f44b8
--- /dev/null
+++ b/Framework/docs/demo/project/index.js
@@ -0,0 +1,35 @@
+/**
+ * @license
+ * Copyright 2019-2020 CERN and copyright holders of ALICE O2.
+ * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
+ * All rights not expressly granted are reserved.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License v3 (GPL Version 3), copied verbatim in the file "COPYING".
+ *
+ * In applying this license CERN does not waive the privileges and immunities
+ * granted to it by virtue of its status as an Intergovernmental Organization
+ * or submit itself to any jurisdiction.
+ */
+
+// Import the backend classes
+const { HttpServer } = require('@aliceo2/web-ui');
+
+// Define configuration for JWT tokens and HTTP server
+const config = require('./config.js');
+
+/*
+ * HTTP server
+ * -----------
+ *
+ * Instantiate the HTTP server
+ */
+const httpServer = new HttpServer(config.http, config.jwt);
+
+// Server static content in public directory
+httpServer.addStaticPath('./public');
+httpServer.addStaticPath('./public/chart', '/chart');
+httpServer.addStaticPath('./public/frontend', '/frontend');
+httpServer.addStaticPath('./public/notification', '/notification');
+httpServer.addStaticPath('./public/template-1', '/template-1');
+httpServer.addStaticPath('./public/template-2', '/template-2');
diff --git a/Framework/docs/demo/project/public/chart/index.html b/Framework/docs/demo/project/public/chart/index.html
new file mode 100644
index 000000000..3c08b224b
--- /dev/null
+++ b/Framework/docs/demo/project/public/chart/index.html
@@ -0,0 +1,10 @@
+
+
Chart Demo
+
+
+
+Loading...
+
+
+
+
diff --git a/Framework/docs/demo/project/public/chart/main.js b/Framework/docs/demo/project/public/chart/main.js
new file mode 100644
index 000000000..bb73459b8
--- /dev/null
+++ b/Framework/docs/demo/project/public/chart/main.js
@@ -0,0 +1,78 @@
+/**
+ * @license
+ * Copyright 2019-2020 CERN and copyright holders of ALICE O2.
+ * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
+ * All rights not expressly granted are reserved.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License v3 (GPL Version 3), copied verbatim in the file "COPYING".
+ *
+ * In applying this license CERN does not waive the privileges and immunities
+ * granted to it by virtue of its status as an Intergovernmental Organization
+ * or submit itself to any jurisdiction.
+ */
+
+import {mount, h, Observable, chartTimeSeries} from '/js/src/index.js';
+
+// Example of chart integration with template engine
+const view = (model) => [
+ h('div.m4', [
+ chartTimeSeries({
+ series: model.series1,
+ title: 'Sinus',
+ colorPrimary: 'red',
+ width: '800',
+ }),
+ ]),
+ h('div.m4', [
+ chartTimeSeries({
+ series: model.series1,
+ title: 'Sinus',
+ colorPrimary: 'red',
+ width: '800',
+ timeWindow: 100,
+ }),
+ ]),
+ h('div.m4', [
+ chartTimeSeries({
+ series: model.series2,
+ title: 'Random',
+ colorPrimary: 'blue',
+ width: '800',
+ }),
+ ]),
+ h('div.m4', [
+ chartTimeSeries({
+ series: model.series3,
+ title: 'Sinus rounded',
+ colorPrimary: 'green',
+ width: '800',
+ }),
+ ]),
+];
+
+// Create some basic model
+const model = new Observable();
+model.series1 = [];
+model.series2 = [];
+model.series3 = [];
+model.notify();
+
+// Add points at 30 FPS but keep only first 800 points for memory leak
+let i = 0;
+setInterval(() => {
+ i++;
+ model.series1.push({value: Math.cos(i / 10), timestamp: Date.now()});
+ model.series2.push({value: Math.random() * 10, timestamp: Date.now()});
+ model.series3.push({value: Math.round(Math.cos(i / 10)), timestamp: Date.now()});
+
+ model.series1.splice(0, model.series1.length - 800);
+ model.series2.splice(0, model.series2.length - 800);
+ model.series3.splice(0, model.series3.length - 800);
+
+ model.notify();
+}, 33);
+
+mount(document.body, view, model, true);
+
+window.model = model;
diff --git a/Framework/docs/demo/project/public/frontend/index.html b/Framework/docs/demo/project/public/frontend/index.html
new file mode 100644
index 000000000..ae7087bda
--- /dev/null
+++ b/Framework/docs/demo/project/public/frontend/index.html
@@ -0,0 +1,10 @@
+
+Advanced Frontend Demo
+
+
+
+Loading...
+
+
+
+
diff --git a/Framework/docs/demo/project/public/frontend/main.js b/Framework/docs/demo/project/public/frontend/main.js
new file mode 100644
index 000000000..59eb9abd2
--- /dev/null
+++ b/Framework/docs/demo/project/public/frontend/main.js
@@ -0,0 +1,146 @@
+/**
+ * @license
+ * Copyright 2019-2020 CERN and copyright holders of ALICE O2.
+ * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
+ * All rights not expressly granted are reserved.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License v3 (GPL Version 3), copied verbatim in the file "COPYING".
+ *
+ * In applying this license CERN does not waive the privileges and immunities
+ * granted to it by virtue of its status as an Intergovernmental Organization
+ * or submit itself to any jurisdiction.
+ */
+
+// Import Framework tools
+import {mount, h, Observable, iconDashboard, iconGridTwoUp, iconGridThreeUp, iconGridFourUp, iconCog} from '/js/src/index.js';
+
+// This is our model, each time it is modified, it calls notify() and view is updated thanks to controller mount().
+class Model extends Observable {
+ constructor() {
+ super();
+ this.form = {name: '', online: false};
+ this.filter = '';
+ this.list = [
+ {name: 'TCP', online: true},
+ {name: 'MUON', online: true},
+ {name: 'TOF', online: false},
+ {name: 'EMCAL', online: true},
+ {name: 'PHOS', online: false},
+ ];
+ }
+
+ setName(name) {
+ this.form.name = name;
+ this.notify();
+ }
+
+ setStatus(online) {
+ this.form.online = online;
+ this.notify();
+ }
+
+ setFilter(filter) {
+ this.filter = filter;
+ this.notify();
+ }
+
+ add() {
+ this.list.push(this.form);
+ this.form = {name: '', online: false};
+ this.notify();
+ }
+}
+
+// View uses a vnode tree, CSS classes and some handlers to change model
+const view = (model) => h('.flex-column absolute-fill', [
+ header(model),
+ h('.flex-grow flex-row', [
+ h('.sidebar', [
+ h('.sidebar-content relative', [
+ sidebar(model)
+ ])
+ ]),
+ h('.flex-grow.relative', [
+ content(model)
+ ])
+ ]),
+]);
+
+const header = (model) => h('.bg-white flex-row p2 shadow-level2 level2', [
+ h('.flex-grow text-left', [
+ h('button.btn', iconCog()), ' ',
+ h('span.f4 gray', 'Demo App')
+ ]),
+ h('.w-50 text-center', [
+ h('h4', 'Status')
+ ]),
+ h('.flex-grow text-right', [
+ h('input.form-control.form-inline', {placeholder: 'Search', oninput: (e) => model.setFilter(e.target.value)}), ' ',
+ ]),
+]);
+
+const content = (model) => [
+ h('.scroll-y.absolute-fill.bg-white', [
+ h('p.p2.measure', 'This is an example of frontend use of WebUi Framework. You can add some elements to the table below and filter with search input.'),
+
+ h('.measure.m2.bg-gray-lighter.p3.br4.text-no-select', [
+ h('.form-group', [
+ h('label', {for: 'input-name'}, 'Name'),
+ h('input.form-control', {id: 'input-name', oninput: (e) => model.setName(e.target.value), value: model.form.name}, 'Name'),
+ ]),
+ h('.form-check.mv2', [
+ h('input.form-check-input', {id: 'input-status', onclick: (e) => model.setStatus(e.target.checked), checked: model.form.online, type: 'checkbox'}),
+ h('label.form-check-label', {for: 'input-status'}, 'Status online'),
+ ]),
+ h('button.btn btn-primary', {onclick: () => model.add()}, 'Add new detector'),
+ ]),
+
+ h('div.m2', [
+ h('table.table', [
+ h('thead', [
+ h('tr', [
+ h('th', 'Name'),
+ h('th', 'Online'),
+ ]),
+ ]),
+ listFiltered(model).map(item => h('tr', [
+ h('td', item.name),
+ h('td', {className: item.online ? '' : 'danger'}, item.online ? 'ON' : 'OFF')
+ ]))
+ ])
+ ]),
+
+ ])
+];
+
+const listFiltered = (model) => model.list.filter(item => item.name.toLocaleLowerCase().includes(model.filter.toLocaleLowerCase()));
+
+const sidebar = (model) => h('.absolute-fill scroll-y', [
+ h('.menu-title', 'Dashboard'),
+ h('a.menu-item', [
+ iconDashboard(), ' Status'
+ ]),
+
+ h('.menu-title', 'Listing'),
+ h('a.menu-item', [
+ iconGridTwoUp(), ' Environments'
+ ]),
+ h('a.menu-item', [
+ iconGridThreeUp(), ' Roles'
+ ]),
+ h('a.menu-item', [
+ iconGridFourUp(),
+ ' ',
+ '...'
+ ]),
+]);
+
+// Start application
+const model = new Model();
+const debug = true; // shows when redraw is done with timing, must always be < 33ms (30 FPS)
+// Mount will listen to model changes and draw inside body the view
+mount(document.body, view, model, debug);
+
+// Expose model to interact with it the browser's console
+window.model = model;
diff --git a/Framework/docs/demo/project/public/index.html b/Framework/docs/demo/project/public/index.html
new file mode 100644
index 000000000..6fc91475e
--- /dev/null
+++ b/Framework/docs/demo/project/public/index.html
@@ -0,0 +1,13 @@
+
+Demo
+
+
+
+Loading...
+
+
+
+
+
+
+
diff --git a/Framework/docs/demo/project/public/index.js b/Framework/docs/demo/project/public/index.js
new file mode 100644
index 000000000..bd5fe377f
--- /dev/null
+++ b/Framework/docs/demo/project/public/index.js
@@ -0,0 +1,54 @@
+/**
+ * @license
+ * Copyright 2019-2020 CERN and copyright holders of ALICE O2.
+ * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
+ * All rights not expressly granted are reserved.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License v3 (GPL Version 3), copied verbatim in the file "COPYING".
+ *
+ * In applying this license CERN does not waive the privileges and immunities
+ * granted to it by virtue of its status as an Intergovernmental Organization
+ * or submit itself to any jurisdiction.
+ */
+
+import { h, mount, Observable } from '/js/src/index.js';
+
+const DEMOS = [
+ { name: 'frontend', label: 'Frontend' },
+ { name: 'chart', label: 'Chart' },
+ { name: 'notification', label: 'Notification' },
+ { name: 'template-1', label: 'Template-1' },
+ { name: 'template-2', label: 'Template-2' },
+];
+
+class Model extends Observable {
+ constructor() {
+ super();
+ this.demos = DEMOS;
+ }
+ }
+
+function view (model) {
+ return h('.absolute-fill.flex-column.items-center.justify-center',
+ h('.bg-gray-lighter.br3.p4', [
+ h('h1', 'WebUi Demos'),
+ h('ul.list-unstyled',
+ model.demos.map(d =>
+ h('li.mb-2',
+ h('a', {
+ href: `/${d.name}${location.search}`,
+ class: 'link-primary'
+ }, d.label || d.name)
+ )
+ )
+ ),
+ ])
+ );
+}
+
+// Start application
+const model = new Model();
+const debug = true;
+mount(document.body, view, model, debug);
+window.model = model;
diff --git a/Framework/docs/demo/project/public/notification/index.html b/Framework/docs/demo/project/public/notification/index.html
new file mode 100644
index 000000000..f9dd60b29
--- /dev/null
+++ b/Framework/docs/demo/project/public/notification/index.html
@@ -0,0 +1,10 @@
+
+Demo
+
+
+
+Loading...
+
+
+
+
diff --git a/Framework/docs/demo/project/public/notification/main.js b/Framework/docs/demo/project/public/notification/main.js
new file mode 100644
index 000000000..470481817
--- /dev/null
+++ b/Framework/docs/demo/project/public/notification/main.js
@@ -0,0 +1,31 @@
+/**
+ * @license
+ * Copyright 2019-2020 CERN and copyright holders of ALICE O2.
+ * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
+ * All rights not expressly granted are reserved.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License v3 (GPL Version 3), copied verbatim in the file "COPYING".
+ *
+ * In applying this license CERN does not waive the privileges and immunities
+ * granted to it by virtue of its status as an Intergovernmental Organization
+ * or submit itself to any jurisdiction.
+ */
+
+import {mount, h, Notification, notification} from '/js/src/index.js';
+
+const view = (model) => [
+ notification(model),
+ h('div.m4', [
+ h('button', {onclick: () => model.show('An admin has taken lock form you.', 'primary')}, 'Show primary'),
+ h('button', {onclick: () => model.show('Environment has been created.', 'success')}, 'Show success'),
+ h('button', {onclick: () => model.show('Unable to create, please check inputs and retry.', 'warning')}, 'Show warning'),
+ h('button', {onclick: () => model.show('Server connection has been lost.', 'danger')}, 'Show danger'),
+ ]),
+];
+
+// Create some basic model
+const model = new Notification();
+
+mount(document.body, view, model, true);
+window.model = model;
diff --git a/Framework/docs/demo/project/public/session.js b/Framework/docs/demo/project/public/session.js
new file mode 100644
index 000000000..5ed992296
--- /dev/null
+++ b/Framework/docs/demo/project/public/session.js
@@ -0,0 +1,17 @@
+/**
+ * @license
+ * Copyright 2019-2020 CERN and copyright holders of ALICE O2.
+ * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
+ * All rights not expressly granted are reserved.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License v3 (GPL Version 3), copied verbatim in the file "COPYING".
+ *
+ * In applying this license CERN does not waive the privileges and immunities
+ * granted to it by virtue of its status as an Intergovernmental Organization
+ * or submit itself to any jurisdiction.
+*/
+
+import sessionService from '/js/src/sessionService.js';
+sessionService.loadAndHideParameters();
+window.sessionService = sessionService;
diff --git a/Framework/docs/demo/project/public/template-1/index.html b/Framework/docs/demo/project/public/template-1/index.html
new file mode 100644
index 000000000..a079da3df
--- /dev/null
+++ b/Framework/docs/demo/project/public/template-1/index.html
@@ -0,0 +1,10 @@
+
+Template-1 Demo
+
+
+
+Loading...
+
+
+
+
diff --git a/Framework/docs/demo/project/public/template-1/main.js b/Framework/docs/demo/project/public/template-1/main.js
new file mode 100644
index 000000000..e05af03fe
--- /dev/null
+++ b/Framework/docs/demo/project/public/template-1/main.js
@@ -0,0 +1,22 @@
+/**
+ * @license
+ * Copyright 2019-2020 CERN and copyright holders of ALICE O2.
+ * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
+ * All rights not expressly granted are reserved.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License v3 (GPL Version 3), copied verbatim in the file "COPYING".
+ *
+ * In applying this license CERN does not waive the privileges and immunities
+ * granted to it by virtue of its status as an Intergovernmental Organization
+ * or submit itself to any jurisdiction.
+ */
+
+// Import Framework tools
+import {mount, h, Observable} from '/js/src/index.js';
+
+const model = new Observable();
+const view = (model) => h('h1.title', `hello ${model.name}`);
+mount(document.body, view, model);
+model.name = 'Alice';
+model.notify();
diff --git a/Framework/docs/demo/project/public/template-2/index.html b/Framework/docs/demo/project/public/template-2/index.html
new file mode 100644
index 000000000..3c08b224b
--- /dev/null
+++ b/Framework/docs/demo/project/public/template-2/index.html
@@ -0,0 +1,10 @@
+
+Chart Demo
+
+
+
+Loading...
+
+
+
+
diff --git a/Framework/docs/demo/project/public/template-2/main.js b/Framework/docs/demo/project/public/template-2/main.js
new file mode 100644
index 000000000..b9915178e
--- /dev/null
+++ b/Framework/docs/demo/project/public/template-2/main.js
@@ -0,0 +1,60 @@
+/**
+ * @license
+ * Copyright 2019-2020 CERN and copyright holders of ALICE O2.
+ * See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
+ * All rights not expressly granted are reserved.
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License v3 (GPL Version 3), copied verbatim in the file "COPYING".
+ *
+ * In applying this license CERN does not waive the privileges and immunities
+ * granted to it by virtue of its status as an Intergovernmental Organization
+ * or submit itself to any jurisdiction.
+ */
+
+import {mount, h, Observable} from '/js/src/index.js';
+
+// This is our model, each time it is modified, it calls notify() and view is updated thanks to controller mount().
+class Model extends Observable {
+ constructor() {
+ super();
+ this.count = 0;
+ }
+
+ increment() {
+ this.count++;
+ this.notify();
+ }
+
+ decrement() {
+ this.count--;
+ this.notify();
+ }
+}
+
+// View uses a vnode tree, CSS classes and some handlers to change model
+function view(model) {
+ return h('.absolute-fill.flex-column.items-center.justify-center',
+ h('.bg-gray-lighter.br3.p4', [
+ h('h1', 'Hello World'),
+ h('ul', [
+ // Template string is used to concatenate wording and values of the model
+ h('li', `Counter: ${model.count}`),
+ ]),
+ h('div', [
+ // Lambda functions are used to bind to click events and ask model to change current state
+ h('button.btn', {onclick: e => model.increment()}, '++'), ' ',
+ h('button.btn', {onclick: e => model.decrement()}, '--'), ' ',
+ ])
+ ])
+ );
+}
+
+// Start application
+const model = new Model();
+const debug = true; // shows when redraw is done with timing, must always be < 33ms (30 FPS)
+// Mount will listen to model changes and draw inside body the view
+mount(document.body, view, model, debug);
+
+// Expose model to interact with it the browser's console
+window.model = model;
diff --git a/Framework/docs/demo/template-2.html b/Framework/docs/demo/template-2.html
index c71bd74fb..187ddb068 100644
--- a/Framework/docs/demo/template-2.html
+++ b/Framework/docs/demo/template-2.html
@@ -46,6 +46,6 @@
// Mount will listen to model changes and draw inside body the view
mount(document.body, view, model, debug);
-// Expose model to interract with it the browser's console
+// Expose model to interact with it the browser's console
window.model = model;
diff --git a/Framework/docs/tutorial/public/index.html b/Framework/docs/tutorial/public/index.html
index d8508d2c1..12b637ace 100644
--- a/Framework/docs/tutorial/public/index.html
+++ b/Framework/docs/tutorial/public/index.html
@@ -21,6 +21,6 @@
const debug = true; // shows when redraw is done
mount(document.body, view, model, debug);
-// Expose model to interract with it the browser's console
+// Expose model to interact with it the browser's console
window.model = model;