diff --git a/index.html b/index.html
index 37947e8..a82ff4c 100644
--- a/index.html
+++ b/index.html
@@ -5,6 +5,20 @@
Image to SVG Converter
+
+
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..13501f1
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,41 @@
+{
+ "name": "Vectra",
+ "short_name": "Vectra",
+ "description": "MakeVector Go BRRRR",
+ "icons": [
+ {
+ "sizes": "48x48",
+ "src": "maskable_icon_x48.png",
+ "type": "image/png"
+ },
+ {
+ "sizes": "72x72",
+ "src": "maskable_icon_x72.png",
+ "type": "image/png"
+ },
+ {
+ "sizes": "96x96",
+ "src": "maskable_icon_x96.png",
+ "type": "image/png"
+ },
+ {
+ "sizes": "128x128",
+ "src": "maskable_icon_x128.png",
+ "type": "image/png"
+ },
+ {
+ "sizes": "192x192",
+ "src": "maskable_icon_x192.png",
+ "type": "image/png"
+ },
+ {
+ "sizes": "384x384",
+ "src": "maskable_icon_x384.png",
+ "type": "image/png"
+ }
+],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#FFFFFF",
+ "background_color": "#000000"
+}
\ No newline at end of file
diff --git a/maskable_icon_x128.png b/maskable_icon_x128.png
new file mode 100644
index 0000000..19eb84b
Binary files /dev/null and b/maskable_icon_x128.png differ
diff --git a/maskable_icon_x192.png b/maskable_icon_x192.png
new file mode 100644
index 0000000..19eb84b
Binary files /dev/null and b/maskable_icon_x192.png differ
diff --git a/maskable_icon_x384.png b/maskable_icon_x384.png
new file mode 100644
index 0000000..19eb84b
Binary files /dev/null and b/maskable_icon_x384.png differ
diff --git a/maskable_icon_x48.png b/maskable_icon_x48.png
new file mode 100644
index 0000000..19eb84b
Binary files /dev/null and b/maskable_icon_x48.png differ
diff --git a/maskable_icon_x512.png b/maskable_icon_x512.png
new file mode 100644
index 0000000..19eb84b
Binary files /dev/null and b/maskable_icon_x512.png differ
diff --git a/maskable_icon_x72.png b/maskable_icon_x72.png
new file mode 100644
index 0000000..19eb84b
Binary files /dev/null and b/maskable_icon_x72.png differ
diff --git a/maskable_icon_x96.png b/maskable_icon_x96.png
new file mode 100644
index 0000000..19eb84b
Binary files /dev/null and b/maskable_icon_x96.png differ
diff --git a/serviceworker.js b/serviceworker.js
new file mode 100644
index 0000000..e707262
--- /dev/null
+++ b/serviceworker.js
@@ -0,0 +1,61 @@
+const CACHE_NAME = "vectra-offline-v1";
+const APP_FILES = ["./", "./index.html", "./styles.css", "./script.js",
+ "https://cdn.jsdelivr.net/npm/imagetracerjs@1.2.6/imagetracer_v1.2.6.min.js"
+];
+
+self.addEventListener("install", event => {
+ event.waitUntil(
+ caches.open(CACHE_NAME)
+ .then(cache => cache.addAll(APP_FILES))
+ .then(() => self.skipWaiting())
+ );
+});
+
+self.addEventListener("activate", event => {
+ event.waitUntil(
+ caches.keys()
+ .then(cacheNames => Promise.all(
+ cacheNames
+ .filter(cacheName =>
+ cacheName.startsWith("vectra-offline-") && cacheName !== CACHE_NAME
+ )
+ .map(cacheName => caches.delete(cacheName))
+ ))
+ .then(() => self.clients.claim())
+ );
+});
+
+self.addEventListener("fetch", event => {
+ const request = event.request;
+ const requestUrl = new URL(request.url);
+
+ if (request.method !== "GET" || requestUrl.origin !== self.location.origin) {
+ return;
+ }
+
+ event.respondWith((async () => {
+ try {
+ const response = await fetch(request);
+ if (response.ok && response.type === "basic") {
+ const cache = await caches.open(CACHE_NAME);
+ await cache.put(request, response.clone());
+ }
+ return response;
+ } catch (error) {
+ const cachedResponse = await caches.match(request);
+ if (cachedResponse) {
+ return cachedResponse;
+ }
+
+ if (request.mode === "navigate") {
+ const appShell = new URL("./index.html", self.registration.scope);
+ const fallback = await caches.match(appShell.href);
+ if (fallback) {
+ return fallback;
+ }
+ }
+
+ throw error;
+ }
+ })());
+});
\ No newline at end of file