diff --git a/UI/README.md b/UI/README.md
new file mode 100644
index 0000000..62f0e1b
--- /dev/null
+++ b/UI/README.md
@@ -0,0 +1,4 @@
+## Svelte Plash Server - UI
+
+This is the main UI for the Plash Server done in Svelte. You can follow the project on my tutorials site: [Custom Computer Tools](http://www.customct.com/#/tutorials/plashserver/series).
+
diff --git a/UI/index.html b/UI/index.html
new file mode 100644
index 0000000..19c0df8
--- /dev/null
+++ b/UI/index.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+ Svelte app
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UI/package.json b/UI/package.json
new file mode 100644
index 0000000..29cb194
--- /dev/null
+++ b/UI/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "svelte-app",
+ "version": "1.0.0",
+ "scripts": {
+ "build": "rollup -c",
+ "dev": "rollup -c -w",
+ "start": "sirv public"
+ },
+ "devDependencies": {
+ "@rollup/plugin-commonjs": "^11.0.0",
+ "@rollup/plugin-node-resolve": "^6.0.0",
+ "rollup": "^1.20.0",
+ "rollup-plugin-livereload": "^1.0.0",
+ "rollup-plugin-svelte": "^5.0.3",
+ "rollup-plugin-terser": "^5.1.2",
+ "svelte": "^3.0.0"
+ },
+ "dependencies": {
+ "sirv-cli": "^0.4.4"
+ }
+}
diff --git a/UI/public/favicon.png b/UI/public/favicon.png
new file mode 100644
index 0000000..7e6f5eb
Binary files /dev/null and b/UI/public/favicon.png differ
diff --git a/UI/public/global.css b/UI/public/global.css
new file mode 100644
index 0000000..ec905f5
--- /dev/null
+++ b/UI/public/global.css
@@ -0,0 +1,66 @@
+html, body {
+ position: relative;
+ width: 100%;
+ height: 100%;
+}
+
+body {
+ color: #333;
+ margin: 0;
+ padding: 8px;
+ box-sizing: border-box;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
+}
+
+a {
+ color: rgb(0,100,200);
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+a:visited {
+ color: rgb(0,80,160);
+}
+
+label {
+ display: block;
+}
+
+input, button, select, textarea {
+ font-family: inherit;
+ font-size: inherit;
+ padding: 0.4em;
+ margin: 0 0 0.5em 0;
+ box-sizing: border-box;
+ border: 1px solid #ccc;
+ border-radius: 2px;
+}
+
+input:disabled {
+ color: #ccc;
+}
+
+input[type="range"] {
+ height: 0;
+}
+
+button {
+ color: #333;
+ background-color: #f4f4f4;
+ outline: none;
+}
+
+button:disabled {
+ color: #999;
+}
+
+button:not(:disabled):active {
+ background-color: #ddd;
+}
+
+button:focus {
+ border-color: #666;
+}
diff --git a/UI/public/index.html b/UI/public/index.html
new file mode 100644
index 0000000..19c0df8
--- /dev/null
+++ b/UI/public/index.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+ Svelte app
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UI/rollup.config.js b/UI/rollup.config.js
new file mode 100644
index 0000000..eae4c0b
--- /dev/null
+++ b/UI/rollup.config.js
@@ -0,0 +1,71 @@
+import svelte from 'rollup-plugin-svelte';
+import resolve from '@rollup/plugin-node-resolve';
+import commonjs from '@rollup/plugin-commonjs';
+import livereload from 'rollup-plugin-livereload';
+import { terser } from 'rollup-plugin-terser';
+
+const production = !process.env.ROLLUP_WATCH;
+
+export default {
+ input: 'src/main.js',
+ output: {
+ sourcemap: true,
+ format: 'iife',
+ name: 'app',
+ file: 'public/build/bundle.js'
+ },
+ plugins: [
+ svelte({
+ // enable run-time checks when not in production
+ dev: !production,
+ // we'll extract any component CSS out into
+ // a separate file — better for performance
+ css: css => {
+ css.write('public/build/bundle.css');
+ }
+ }),
+
+ // If you have external dependencies installed from
+ // npm, you'll most likely need these plugins. In
+ // some cases you'll need additional configuration —
+ // consult the documentation for details:
+ // https://github.com/rollup/plugins/tree/master/packages/commonjs
+ resolve({
+ browser: true,
+ dedupe: importee => importee === 'svelte' || importee.startsWith('svelte/')
+ }),
+ commonjs(),
+
+ // In dev mode, call `npm run start` once
+ // the bundle has been generated
+ !production && serve(),
+
+ // Watch the `public` directory and refresh the
+ // browser on changes when not in production
+ !production && livereload('public'),
+
+ // If we're building for production (npm run build
+ // instead of npm run dev), minify
+ production && terser()
+ ],
+ watch: {
+ clearScreen: false
+ }
+};
+
+function serve() {
+ let started = false;
+
+ return {
+ writeBundle() {
+ if (!started) {
+ started = true;
+
+ require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
+ stdio: ['ignore', 'inherit', 'inherit'],
+ shell: true
+ });
+ }
+ }
+ };
+}
diff --git a/UI/src/UI.svelte b/UI/src/UI.svelte
new file mode 100644
index 0000000..13ef8b0
--- /dev/null
+++ b/UI/src/UI.svelte
@@ -0,0 +1,65 @@
+
+
+
+
+
+ {#each widgets as widget}
+
+ {/each}
+
+
+
+
+
+
diff --git a/UI/src/components/CircleMeter.svelte b/UI/src/components/CircleMeter.svelte
new file mode 100644
index 0000000..d9159d9
--- /dev/null
+++ b/UI/src/components/CircleMeter.svelte
@@ -0,0 +1,78 @@
+
+
+
+
+
diff --git a/UI/src/components/CircleTime.svelte b/UI/src/components/CircleTime.svelte
new file mode 100644
index 0000000..70d6f3d
--- /dev/null
+++ b/UI/src/components/CircleTime.svelte
@@ -0,0 +1,78 @@
+