diff --git a/package.json b/package.json
index eb64199..0fab7db 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,8 @@
"homepage": "https://jmaio.github.io/mandelbrot-maps/",
"dependencies": {
"@material-ui/core": "^4.4.2",
+ "@material-ui/icons": "^4.9.1",
+ "@material-ui/lab": "^4.0.0-alpha.44",
"@mdi/js": "^4.4.95",
"complex.js": "^2.0.11",
"gl-matrix": "^3.1.0",
@@ -49,4 +51,4 @@
"jest-canvas-mock": "^2.2.0",
"jest-webgl-canvas-mock": "^0.2.3"
}
-}
\ No newline at end of file
+}
diff --git a/public/clientDetect.js b/public/clientDetect.js
new file mode 100644
index 0000000..8e079f0
--- /dev/null
+++ b/public/clientDetect.js
@@ -0,0 +1,216 @@
+/**
+ * JavaScript Client Detection
+ * (C) viazenetti GmbH (Christian Ludwig)
+ */
+(function (window) {
+ var unknown = '-';
+
+ // screen
+ var screenSize = '';
+ if (screen.width) {
+ width = (screen.width) ? screen.width : '';
+ height = (screen.height) ? screen.height : '';
+ screenSize += '' + width + " x " + height;
+ }
+
+ // browser
+ var nVer = navigator.appVersion;
+ var nAgt = navigator.userAgent;
+ var browser = navigator.appName;
+ var version = '' + parseFloat(navigator.appVersion);
+ var majorVersion = parseInt(navigator.appVersion, 10);
+ var nameOffset, verOffset, ix;
+
+ // Opera
+ if ((verOffset = nAgt.indexOf('Opera')) != -1) {
+ browser = 'Opera';
+ version = nAgt.substring(verOffset + 6);
+ if ((verOffset = nAgt.indexOf('Version')) != -1) {
+ version = nAgt.substring(verOffset + 8);
+ }
+ }
+ // Opera Next
+ if ((verOffset = nAgt.indexOf('OPR')) != -1) {
+ browser = 'Opera';
+ version = nAgt.substring(verOffset + 4);
+ }
+ // Edge
+ else if ((verOffset = nAgt.indexOf('Edge')) != -1) {
+ browser = 'Microsoft Edge';
+ version = nAgt.substring(verOffset + 5);
+ }
+ // MSIE
+ else if ((verOffset = nAgt.indexOf('MSIE')) != -1) {
+ browser = 'Microsoft Internet Explorer';
+ version = nAgt.substring(verOffset + 5);
+ }
+ // Chrome
+ else if ((verOffset = nAgt.indexOf('Chrome')) != -1) {
+ browser = 'Chrome';
+ version = nAgt.substring(verOffset + 7);
+ }
+ // Safari
+ else if ((verOffset = nAgt.indexOf('Safari')) != -1) {
+ browser = 'Safari';
+ version = nAgt.substring(verOffset + 7);
+ if ((verOffset = nAgt.indexOf('Version')) != -1) {
+ version = nAgt.substring(verOffset + 8);
+ }
+ }
+ // Firefox
+ else if ((verOffset = nAgt.indexOf('Firefox')) != -1) {
+ browser = 'Firefox';
+ version = nAgt.substring(verOffset + 8);
+ }
+ // MSIE 11+
+ else if (nAgt.indexOf('Trident/') != -1) {
+ browser = 'Microsoft Internet Explorer';
+ version = nAgt.substring(nAgt.indexOf('rv:') + 3);
+ }
+ // Other browsers
+ else if ((nameOffset = nAgt.lastIndexOf(' ') + 1) < (verOffset = nAgt.lastIndexOf('/'))) {
+ browser = nAgt.substring(nameOffset, verOffset);
+ version = nAgt.substring(verOffset + 1);
+ if (browser.toLowerCase() == browser.toUpperCase()) {
+ browser = navigator.appName;
+ }
+ }
+ // trim the version string
+ if ((ix = version.indexOf(';')) != -1) version = version.substring(0, ix);
+ if ((ix = version.indexOf(' ')) != -1) version = version.substring(0, ix);
+ if ((ix = version.indexOf(')')) != -1) version = version.substring(0, ix);
+
+ majorVersion = parseInt('' + version, 10);
+ if (isNaN(majorVersion)) {
+ version = '' + parseFloat(navigator.appVersion);
+ majorVersion = parseInt(navigator.appVersion, 10);
+ }
+
+ // mobile version
+ var mobile = /Mobile|mini|Fennec|Android|iP(ad|od|hone)/.test(nVer);
+
+ // cookie
+ var cookieEnabled = (navigator.cookieEnabled) ? true : false;
+
+ if (typeof navigator.cookieEnabled == 'undefined' && !cookieEnabled) {
+ document.cookie = 'testcookie';
+ cookieEnabled = (document.cookie.indexOf('testcookie') != -1) ? true : false;
+ }
+
+ // system
+ var os = unknown;
+ var clientStrings = [
+ {s:'Windows 10', r:/(Windows 10.0|Windows NT 10.0)/},
+ {s:'Windows 8.1', r:/(Windows 8.1|Windows NT 6.3)/},
+ {s:'Windows 8', r:/(Windows 8|Windows NT 6.2)/},
+ {s:'Windows 7', r:/(Windows 7|Windows NT 6.1)/},
+ {s:'Windows Vista', r:/Windows NT 6.0/},
+ {s:'Windows Server 2003', r:/Windows NT 5.2/},
+ {s:'Windows XP', r:/(Windows NT 5.1|Windows XP)/},
+ {s:'Windows 2000', r:/(Windows NT 5.0|Windows 2000)/},
+ {s:'Windows ME', r:/(Win 9x 4.90|Windows ME)/},
+ {s:'Windows 98', r:/(Windows 98|Win98)/},
+ {s:'Windows 95', r:/(Windows 95|Win95|Windows_95)/},
+ {s:'Windows NT 4.0', r:/(Windows NT 4.0|WinNT4.0|WinNT|Windows NT)/},
+ {s:'Windows CE', r:/Windows CE/},
+ {s:'Windows 3.11', r:/Win16/},
+ {s:'Android', r:/Android/},
+ {s:'Open BSD', r:/OpenBSD/},
+ {s:'Sun OS', r:/SunOS/},
+ {s:'Chrome OS', r:/CrOS/},
+ {s:'Linux', r:/(Linux|X11(?!.*CrOS))/},
+ {s:'iOS', r:/(iPhone|iPad|iPod)/},
+ {s:'Mac OS X', r:/Mac OS X/},
+ {s:'Mac OS', r:/(MacPPC|MacIntel|Mac_PowerPC|Macintosh)/},
+ {s:'QNX', r:/QNX/},
+ {s:'UNIX', r:/UNIX/},
+ {s:'BeOS', r:/BeOS/},
+ {s:'OS/2', r:/OS\/2/},
+ {s:'Search Bot', r:/(nuhk|Googlebot|Yammybot|Openbot|Slurp|MSNBot|Ask Jeeves\/Teoma|ia_archiver)/}
+ ];
+ for (var id in clientStrings) {
+ var cs = clientStrings[id];
+ if (cs.r.test(nAgt)) {
+ os = cs.s;
+ break;
+ }
+ }
+
+ var osVersion = unknown;
+
+ if (/Windows/.test(os)) {
+ osVersion = /Windows (.*)/.exec(os)[1];
+ os = 'Windows';
+ }
+
+ switch (os) {
+ case 'Mac OS X':
+ osVersion = /Mac OS X (10[\.\_\d]+)/.exec(nAgt)[1];
+ break;
+
+ case 'Android':
+ osVersion = /Android ([\.\_\d]+)/.exec(nAgt)[1];
+ break;
+
+ case 'iOS':
+ osVersion = /OS (\d+)_(\d+)_?(\d+)?/.exec(nVer);
+ osVersion = osVersion[1] + '.' + osVersion[2] + '.' + (osVersion[3] | 0);
+ break;
+
+ default:
+ break;
+ }
+
+ // user agent string manipulation to obtain device model
+ var system = nAgt.substring(nAgt.indexOf('(') + 1, nAgt.indexOf(')'));
+ var device = system.substring(system.lastIndexOf(';') + 1);
+
+ // use JavaScript to detect GPU used from within your browser - by cvan
+ // https://gist.github.com/cvan/042b2448fcecefafbb6a91469484cdf8
+ var canvas = document.createElement('canvas');
+ var gl;
+ var debugInfo;
+ var gpuVendor;
+ var renderer;
+
+ try {
+ gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
+ } catch (e) {}
+
+ if (gl) {
+ debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
+ gpuVendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
+ renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
+ }
+ // ----------------------------------------------------------------
+
+ window.jscd = {
+ browser: browser,
+ browserVersion: majorVersion,
+ browserRelease: version,
+ // vendor: navigator.vendor,
+ device: device,
+ os: os,
+ osVersion: osVersion,
+ mobile: mobile,
+ platform: navigator.platform,
+ screen: screenSize,
+ dpr: +window.devicePixelRatio.toFixed(3),
+ gpu: renderer,
+ gpuVendor: gpuVendor,
+ userAgent: navigator.userAgent,
+ // cookies: cookieEnabled,
+ // flashVersion: flashVersion
+ };
+}(this));
+
+// alert(
+// 'OS: ' + jscd.os +' '+ jscd.osVersion + '\n' +
+// 'Browser: ' + jscd.browser +' '+ jscd.browserMajorVersion +
+// ' (' + jscd.browserVersion + ')\n' +
+// 'Mobile: ' + jscd.mobile + '\n' +
+// 'Flash: ' + jscd.flashVersion + '\n' +
+// 'Cookies: ' + jscd.cookies + '\n' +
+// 'Screen Size: ' + jscd.screen + '\n\n' +
+// 'Full User Agent: ' + navigator.userAgent
+// );
diff --git a/public/favicon-192.png b/public/favicon-192.png
new file mode 100644
index 0000000..99cca91
Binary files /dev/null and b/public/favicon-192.png differ
diff --git a/public/favicon-256.png b/public/favicon-256.png
new file mode 100644
index 0000000..93fa277
Binary files /dev/null and b/public/favicon-256.png differ
diff --git a/public/favicon-512.png b/public/favicon-512.png
new file mode 100644
index 0000000..4379449
Binary files /dev/null and b/public/favicon-512.png differ
diff --git a/public/index.html b/public/index.html
index 4c825ec..9f0ec4f 100644
--- a/public/index.html
+++ b/public/index.html
@@ -11,15 +11,22 @@
gtag('config', 'UA-25811690-6');
+
-
+
+
-
+
+
+
+
+
+
+
-