diff --git a/package.json b/package.json
index 0bb1ea3..d2b8f7d 100644
--- a/package.json
+++ b/package.json
@@ -11,6 +11,7 @@
     "check": "svelte-check --tsconfig ./tsconfig.json"
   },
   "dependencies": {
+    "@empathize/framework": "^1.3.5",
     "js-md5": "^0.7.3",
     "semver": "^7.3.5",
     "svelte-i18n": "^3.3.13",
@@ -18,12 +19,12 @@
   },
   "devDependencies": {
     "@neutralinojs/neu": "^9.1.1",
-    "@sveltejs/vite-plugin-svelte": "^1.0.0-next.35",
+    "@sveltejs/vite-plugin-svelte": "^1.0.0-next.36",
     "@tsconfig/svelte": "^3.0.0",
     "@types/js-md5": "^0.4.3",
     "neutralino-appimage-bundler": "^1.3.2",
     "sass": "^1.49.0",
-    "svelte": "^3.46.2",
+    "svelte": "^3.46.3",
     "svelte-check": "^2.3.0",
     "svelte-preprocess": "^4.10.2",
     "tslib": "^2.3.1",
diff --git a/src/components/Checkbox.svelte b/src/components/Checkbox.svelte
index cab820d..62ab6fe 100644
--- a/src/components/Checkbox.svelte
+++ b/src/components/Checkbox.svelte
@@ -1,6 +1,8 @@
 <script lang="ts">
     import { _ } from 'svelte-i18n';
 
+    import { Configs } from '../empathize';
+
     export let active: boolean = false;
     export let disabled: boolean = false;
 
@@ -12,8 +14,6 @@
 
     import Checkmark from '../assets/svgs/checkmark.svg';
 
-    import Configs from '../ts/Configs';
-
     Configs.get(prop).then((value) => active = value as boolean);
 
     function updateCheckbox()
diff --git a/src/components/DiscordSettings.svelte b/src/components/DiscordSettings.svelte
index 99b4c31..a4be027 100644
--- a/src/components/DiscordSettings.svelte
+++ b/src/components/DiscordSettings.svelte
@@ -1,7 +1,7 @@
 <script lang="ts">
     import { _ } from 'svelte-i18n';
 
-    import Configs from '../ts/Configs';
+    import { Configs } from '../empathize';
 
     export let visible: boolean = false;
 
diff --git a/src/components/DropdownCheckboxes.svelte b/src/components/DropdownCheckboxes.svelte
index a65e9d9..042fa74 100644
--- a/src/components/DropdownCheckboxes.svelte
+++ b/src/components/DropdownCheckboxes.svelte
@@ -1,7 +1,7 @@
 <script lang="ts">
     import { _ } from 'svelte-i18n';
 
-    import Configs from '../ts/Configs';
+    import { Configs } from '../empathize';
 
     export let prop: string = '';
     export let lang: string = '';
diff --git a/src/components/EnvironmentManager.svelte b/src/components/EnvironmentManager.svelte
index 2f400f7..baac135 100644
--- a/src/components/EnvironmentManager.svelte
+++ b/src/components/EnvironmentManager.svelte
@@ -1,19 +1,22 @@
 <script lang="ts">
     import { _ } from 'svelte-i18n';
 
-    import Configs from '../ts/Configs';
+    import { Configs } from '../empathize';
 
     import Button from './Button.svelte';
 
     let last_id = 0, variables = {}, selected;
 
     Configs.get('env').then((env) => {
-        for (const key of Object.keys(env as object))
+        if (env)
         {
-            variables[last_id++] = {
-                key: key,
-                value: env![key]
-            };
+            for (const key of Object.keys(env as object))
+            {
+                variables[last_id++] = {
+                    key: key,
+                    value: env![key]
+                };
+            }
         }
     });
 
@@ -29,26 +32,30 @@
 </script>
 
 <div>
-    <table class="table properties-table" style="margin-top: 16px">
-        <tr>
-            <th>{$_('settings.environment.items.table.name')}</th>
-            <th>{$_('settings.environment.items.table.value')}</th>
-        </tr>
-
-        {#each Object.keys(variables) as key}
-            <tr on:click={() => selected = key} class:selected={selected === key}>
-                <td>
-                    <span>{variables[key].key}</span>
-                    <input bind:value={variables[key].key} on:change={updateEnv} />
-                </td>
-        
-                <td>
-                    <span>{variables[key].value}</span>
-                    <input bind:value={variables[key].value} on:change={updateEnv} />
-                </td>
+    {#if Object.keys(variables).length > 0}
+        <table class="table properties-table" style="margin-top: 16px">
+            <tr>
+                <th>{$_('settings.environment.items.table.name')}</th>
+                <th>{$_('settings.environment.items.table.value')}</th>
             </tr>
-        {/each}
-    </table>
+
+            {#each Object.keys(variables) as key}
+                <tr on:click={() => selected = key} class:selected={selected === key}>
+                    <td>
+                        <span>{variables[key].key}</span>
+                        <input bind:value={variables[key].key} on:change={updateEnv} />
+                    </td>
+            
+                    <td>
+                        <span>{variables[key].value}</span>
+                        <input bind:value={variables[key].value} on:change={updateEnv} />
+                    </td>
+                </tr>
+            {/each}
+        </table>
+    {:else}
+        <p>There're no variables here</p>
+    {/if}
 
     <div style="margin-top: 16px">
         <Button lang="settings.environment.items.buttons.add" click={() => variables[last_id++] = { key: '', value: '' }} />
diff --git a/src/components/SelectionBox.svelte b/src/components/SelectionBox.svelte
index 4ea2e4c..a7a9a68 100644
--- a/src/components/SelectionBox.svelte
+++ b/src/components/SelectionBox.svelte
@@ -1,7 +1,7 @@
 <script lang="ts">
     import { _ } from 'svelte-i18n';
 
-    import Configs from '../ts/Configs';
+    import { Configs } from '../empathize';
 
     export let prop: string = '';
     export let lang: string = '';
diff --git a/src/defaultSettings.ts b/src/defaultSettings.ts
index 0d5fb73..ba9a0fa 100644
--- a/src/defaultSettings.ts
+++ b/src/defaultSettings.ts
@@ -1,6 +1,6 @@
-import Configs from './ts/Configs';
+import { Configs, promisify } from './empathize';
+
 import constants from './ts/Constants';
-import promisify from './ts/core/promisify';
 
 promisify(async () => {
     Configs.defaults({
diff --git a/src/empathize.ts b/src/empathize.ts
new file mode 100644
index 0000000..237b973
--- /dev/null
+++ b/src/empathize.ts
@@ -0,0 +1,55 @@
+import {
+    // Paths API
+    path, dir,
+
+    // Filesystem API
+    fs,
+
+    // Windows API
+    Windows,
+
+    // OS API
+    Process, Tray, IPC, Notification, Archive,
+
+    // Network API
+    fetch, Domain, Downloader,
+
+    // Async API
+    promisify,
+
+    // Meta classes
+    Cache, Configs, Debug
+} from '@empathize/framework';
+
+import YAML from 'yaml';
+
+import constants from './ts/Constants';
+
+Configs.file = constants.paths.config;
+Cache.file = constants.paths.cache;
+
+Configs.serialize = YAML.stringify;
+Configs.unserialize = YAML.parse;
+
+export {
+    // Paths API
+    path, dir,
+
+    // Filesystem API
+    fs,
+
+    // Windows API
+    Windows,
+
+    // OS API
+    Process, Tray, IPC, Notification, Archive,
+
+    // Network API
+    fetch, Domain, Downloader,
+
+    // Async API
+    promisify,
+
+    // Meta classes
+    Cache, Configs, Debug
+};
diff --git a/src/index.svelte b/src/index.svelte
index c037d1e..24d0006 100644
--- a/src/index.svelte
+++ b/src/index.svelte
@@ -6,18 +6,12 @@
     import { onMount } from 'svelte';
     import { _, locale } from 'svelte-i18n';
 
-    import Window from './ts/neutralino/Window';
-    import Process from './ts/neutralino/Process';
+    import { Windows, path, Archive, Debug, Downloader, IPC, Configs } from './empathize';
 
     import Launcher from './ts/Launcher';
     import constants from './ts/Constants';
     import Game from './ts/Game';
     import Background from './ts/launcher/Background';
-    import Archive from './ts/core/Archive';
-    import Debug from './ts/core/Debug';
-    import Downloader from './ts/core/Downloader';
-    import IPC from './ts/core/IPC';
-    import Configs from './ts/Configs';
 
     import Gear from './assets/images/gear.png';
     import GearActive from './assets/images/gear-active.png';
@@ -36,7 +30,7 @@
     const launcher = new Launcher(onMount);
 
     Neutralino.events.on('ready', () => {
-        Window.open('splash', {
+        Windows.open('splash', {
             title: 'Splash',
             width: 300,
             height: 400,
@@ -60,13 +54,13 @@
             await launcher.rpc.stop(true);
 
         // Remove .tmp files from the temp folder
-        await Neutralino.os.execCommand(`find "${Process.addSlashes(tempDir)}" -maxdepth 1 -type f -name "*.tmp" -delete`);
+        await Neutralino.os.execCommand(`find "${path.addSlashes(tempDir)}" -maxdepth 1 -type f -name "*.tmp" -delete`);
 
         // Remove old launcher's log files
         const purge_logs = await Configs.get('purge_logs.launcher') as string|null;
 
         if (purge_logs !== null && purge_logs[purge_logs.length - 1] == 'd')
-            await Neutralino.os.execCommand(`find "${Process.addSlashes(launcherDir)}/logs" -maxdepth 1 -mtime ${purge_logs.substring(0, purge_logs.length - 1)} -delete`);
+            await Neutralino.os.execCommand(`find "${path.addSlashes(launcherDir)}/logs" -maxdepth 1 -mtime ${purge_logs.substring(0, purge_logs.length - 1)} -delete`);
 
         // Save logs
         const log = Debug.get().join('\r\n');
@@ -103,7 +97,7 @@
          * Update launcher's title
          */
         Game.latest.then((game) => {
-            Window.current.setTitle(`${constants.placeholders.uppercase.full} Linux Launcher - ${game.version}`);
+            Windows.current.setTitle(`${constants.placeholders.uppercase.full} Linux Launcher - ${game.version}`);
         });
 
         /**
diff --git a/src/settings.svelte b/src/settings.svelte
index 6dd9a36..52a2c96 100644
--- a/src/settings.svelte
+++ b/src/settings.svelte
@@ -6,16 +6,11 @@
     import { onMount } from 'svelte';
     import { _, locale, locales } from 'svelte-i18n';
 
-    import Window from './ts/neutralino/Window';
-    import Process from './ts/neutralino/Process';
+    import { Windows, Configs, Debug, IPC, Process, path } from './empathize';
 
     import constants from './ts/Constants';
-    import Configs from './ts/Configs';
     import Launcher from './ts/Launcher';
     import FPSUnlock from './ts/FPSUnlock';
-    
-    import Debug from './ts/core/Debug';
-    import IPC from './ts/core/IPC';
     import Runners from './ts/core/Runners';
 
     import Button from './components/Button.svelte';
@@ -41,72 +36,6 @@
 
     launcherLocales = launcherLocales;
 
-    /**
-     * Game voice packs languages
-     */
-
-    const voiceLocales = {
-        'en-us': 'settings.general.items.lang.voice.items.en-us',
-        'ja-jp': 'settings.general.items.lang.voice.items.ja-jp',
-        'ko-kr': 'settings.general.items.lang.voice.items.ko-kr',
-        'zn-cn': 'settings.general.items.lang.voice.items.zn-cn'
-    };
-
-    /**
-     * Themes
-     */
-
-    const themes = {
-        'system': 'settings.general.items.theme.items.system',
-        'light': 'settings.general.items.theme.items.light',
-        'dark': 'settings.general.items.theme.items.dark'
-    };
-
-    /**
-     * HUD options
-     */
-
-    const huds = {
-        'none': 'settings.enhancements.items.hud.items.none',
-        'dxvk': 'settings.enhancements.items.hud.items.dxvk',
-        'mangohud': 'settings.enhancements.items.hud.items.mangohud'
-    };
-
-    /**
-     * Wine synchronizations
-     */
-
-    const winesyncs = {
-        'none': 'settings.enhancements.items.winesync.items.none',
-        'esync': 'settings.enhancements.items.winesync.items.esync',
-        'fsync': 'settings.enhancements.items.winesync.items.fsync'
-    };
-
-    /**
-     * Delete launcher logs options
-     */
-
-    const purgeLauncherLogs = {
-        '1d': 'settings.enhancements.items.purge_logs.launcher.items.1d',
-        '3d': 'settings.enhancements.items.purge_logs.launcher.items.3d',
-        '5d': 'settings.enhancements.items.purge_logs.launcher.items.5d',
-        '7d': 'settings.enhancements.items.purge_logs.launcher.items.7d',
-        '14d': 'settings.enhancements.items.purge_logs.launcher.items.14d',
-        'never': 'settings.enhancements.items.purge_logs.launcher.items.never'
-    };
-
-    /**
-     * Menu items
-     */
-    const menuItems = [
-        'general',
-        'enhancements',
-        'runners',
-        'dxvks',
-        'shaders',
-        'environment'
-    ];
-
     /**
      * Some components stuff
      */
@@ -203,8 +132,8 @@
 
     // Do some stuff when all the content will be loaded
     onMount(async () => {
-        await Window.current.show();
-        await Window.current.center(900, 600);
+        await Windows.current.show();
+        // FIXME: await Windows.current.center(900, 600);
 
         // This thing will fix window resizing
         // in several cases (wayland + gnome + custom theme)
@@ -214,7 +143,7 @@
 
             else
             {
-                Window.current.setSize({
+                Windows.current.setSize({
                     width: 900 + (900 - window.innerWidth),
                     height: 600 + (600 - window.innerHeight),
                     resizable: false
@@ -241,8 +170,13 @@
 {#if typeof $locale === 'string'}
     <main>
         <div class="menu">
-            {#each menuItems as item}
-                <div class="menu-item" on:click={changeItem} class:menu-item-active={selectedItem === item} data-anchor={item}>{ $_(`settings.${item}.title`) }</div>
+            {#each ['general', 'enhancements', 'runners', 'dxvks', 'shaders', 'environment'] as item}
+                <div
+                    class="menu-item"
+                    class:menu-item-active={selectedItem === item}
+                    data-anchor={item}
+                    on:click={changeItem}
+                >{$_(`settings.${item}.title`)}</div>
             {/each}
         </div>
 
@@ -269,14 +203,23 @@
                     tooltip="settings.general.items.lang.voice.tooltip"
                     prop="lang.voice"
                     selected={undefined}
-                    items={voiceLocales}
+                    items={{
+                        'en-us': 'settings.general.items.lang.voice.items.en-us',
+                        'ja-jp': 'settings.general.items.lang.voice.items.ja-jp',
+                        'ko-kr': 'settings.general.items.lang.voice.items.ko-kr',
+                        'zn-cn': 'settings.general.items.lang.voice.items.zn-cn'
+                    }}
                     selectionUpdated={() => voiceUpdateRequired = true}
                 />
 
                 <SelectionBox
                     lang="settings.general.items.theme.title"
                     prop="theme"
-                    items={themes}
+                    items={{
+                        'system': 'settings.general.items.theme.items.system',
+                        'light': 'settings.general.items.theme.items.light',
+                        'dark': 'settings.general.items.theme.items.dark'
+                    }}
                     valueChanged={switchTheme}
                 />
 
@@ -294,7 +237,7 @@
 
                         const runnersDir = await constants.paths.runnersDir;
                         
-                        Process.run(`"${Process.addSlashes(await constants.paths.launcherDir)}/winetricks.sh"`, {
+                        Process.run(`"${path.addSlashes(await constants.paths.launcherDir)}/winetricks.sh"`, {
                             env: {
                                 WINE: runner ? `${runnersDir}/${runner.name}/${runner.files.wine}` : 'wine',
                                 WINESERVER: runner ? `${runnersDir}/${runner.name}/${runner.files.wineserver}` : 'wineserver',
@@ -308,7 +251,7 @@
 
                         const runnerDir = runner ? `${await constants.paths.runnersDir}/${runner.name}` : '';
                         
-                        Process.run(runner ? `"${Process.addSlashes(`${runnerDir}/${runner.files.wine}`)}" "${Process.addSlashes(`${runnerDir}/${runner.files.winecfg}`)}"` : 'winecfg', {
+                        Process.run(runner ? `"${path.addSlashes(`${runnerDir}/${runner.files.wine}`)}" "${path.addSlashes(`${runnerDir}/${runner.files.winecfg}`)}"` : 'winecfg', {
                             env: {
                                 WINE: runner ? `${runnerDir}/${runner.files.wine}` : 'wine',
                                 WINESERVER: runner ? `${runnerDir}/${runner.files.wineserver}` : 'wineserver',
@@ -319,14 +262,14 @@
 
                     <!-- svelte-ignore missing-declaration -->
                     <Button lang="settings.general.items.buttons.launcher" click={async () => {
-                        Neutralino.os.execCommand(`xdg-open "${Process.addSlashes(await constants.paths.launcherDir)}"`, {
+                        Neutralino.os.execCommand(`xdg-open "${path.addSlashes(await constants.paths.launcherDir)}"`, {
                             background: true
                         });
                     }} />
 
                     <!-- svelte-ignore missing-declaration -->
                     <Button lang="settings.general.items.buttons.game" click={async () => {
-                        Neutralino.os.execCommand(`xdg-open "${Process.addSlashes(await constants.paths.gameDir)}"`, {
+                        Neutralino.os.execCommand(`xdg-open "${path.addSlashes(await constants.paths.gameDir)}"`, {
                             background: true
                         });
                     }} />
@@ -339,7 +282,11 @@
                 <SelectionBox
                     lang="settings.enhancements.items.hud.title"
                     prop="hud"
-                    items={huds}
+                    items={{
+                        'none': 'settings.enhancements.items.hud.items.none',
+                        'dxvk': 'settings.enhancements.items.hud.items.dxvk',
+                        'mangohud': 'settings.enhancements.items.hud.items.mangohud'
+                    }}
                 />
 
                 <SelectionBox
@@ -347,7 +294,11 @@
                     prop="winesync"
                     tooltip="settings.enhancements.items.winesync.tooltip"
                     tooltip_size="large"
-                    items={winesyncs}
+                    items={{
+                        'none': 'settings.enhancements.items.winesync.items.none',
+                        'esync': 'settings.enhancements.items.winesync.items.esync',
+                        'fsync': 'settings.enhancements.items.winesync.items.fsync'
+                    }}
                 />
 
                 <Checkbox
@@ -388,7 +339,14 @@
                     lang="settings.enhancements.items.purge_logs.launcher.title"
                     tooltip="settings.enhancements.items.purge_logs.launcher.tooltip"
                     prop="purge_logs.launcher"
-                    items={purgeLauncherLogs}
+                    items={{
+                        '1d': 'settings.enhancements.items.purge_logs.launcher.items.1d',
+                        '3d': 'settings.enhancements.items.purge_logs.launcher.items.3d',
+                        '5d': 'settings.enhancements.items.purge_logs.launcher.items.5d',
+                        '7d': 'settings.enhancements.items.purge_logs.launcher.items.7d',
+                        '14d': 'settings.enhancements.items.purge_logs.launcher.items.14d',
+                        'never': 'settings.enhancements.items.purge_logs.launcher.items.never'
+                    }}
                 />
             </div>
 
diff --git a/src/splash.svelte b/src/splash.svelte
index 5263a19..d292723 100644
--- a/src/splash.svelte
+++ b/src/splash.svelte
@@ -6,10 +6,7 @@
     import { onMount } from 'svelte';
     import { _, locale } from 'svelte-i18n';
 
-    import Configs from './ts/Configs';
-    import IPC from './ts/core/IPC';
-
-    import Window from './ts/neutralino/Window';
+    import { Configs, IPC, Windows } from './empathize';
 
     import Splash from './assets/gifs/running-qiqi.gif';
     import SplashSecret from './assets/gifs/loading-marie-please.gif';
@@ -19,8 +16,8 @@
     let phrase = Math.round(Math.random() * 8);
 
     onMount(() => {
-        Window.current.show();
-        Window.current.center(300, 400);
+        Windows.current.show();
+        // FIXME: Windows.current.center(300, 400);
     });
 
     const isLauncherLoaded = () => {
@@ -32,7 +29,7 @@
                 for (const record of launcherLoaded)
                     await record.pop();
 
-                Window.current.hide();
+                Windows.current.hide();
                 Neutralino.app.exit();
             }
 
diff --git a/src/ts/Configs.ts b/src/ts/Configs.ts
deleted file mode 100644
index 40d79e8..0000000
--- a/src/ts/Configs.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-import YAML from 'yaml';
-
-import constants from './Constants';
-
-declare const Neutralino;
-
-// Ok yea, null, object and boolean aren't scalars
-// but I don't care
-type scalar = null | string | number | boolean | object;
-
-export default class Configs
-{
-    /**
-     * Get config value
-     * 
-     * @param name config name, e.g. "lang.launcher"
-     * 
-     * @returns undefined if config doesn't exist. Otherwise - config value
-     */
-    public static get(name: string = ''): Promise<undefined|scalar|scalar[]>
-    {
-        return new Promise(async (resolve) => {
-            Neutralino.filesystem.readFile(await constants.paths.config).then((config) => {
-                config = YAML.parse(config);
-
-                if (name !== '')
-                {
-                    name.split('.').forEach((value) => {
-                        config = config[value];
-                    });
-                }
-
-                resolve(config);
-            }).catch(() => {
-                setTimeout(() => resolve(this.get(name)), 100);
-            });
-        });
-    }
-
-    /**
-     * Set config value
-     * 
-     * @param name config name, e.g. "lang.launcher"
-     * @param value config value, e.g. "en-us"
-     * 
-     * @returns Promise<void> indicates if the settings were updated
-     */
-    public static set(name: string, value: scalar|scalar[]|Promise<scalar|scalar[]>): Promise<void>
-    {
-        const getUpdatedArray = (path: string[], array: scalar|scalar[], value: scalar|scalar[]): scalar|scalar[] => {
-            array![path[0]] = path.length > 1 ?
-                getUpdatedArray(path.slice(1), array![path[0]] ?? {}, value) : value;
-
-            return array;
-        };
-
-        return new Promise(async (resolve) => {
-            value = await Promise.resolve(value);
-
-            Neutralino.filesystem.readFile(await constants.paths.config).then(async (config) => {
-                config = YAML.stringify(getUpdatedArray(name.split('.'), YAML.parse(config), value));
-
-                Neutralino.filesystem.writeFile(await constants.paths.config, config)
-                    .then(() => resolve());
-            }).catch(async () => {
-                let config = YAML.stringify(getUpdatedArray(name.split('.'), {}, value));
-
-                Neutralino.filesystem.writeFile(await constants.paths.config, config)
-                    .then(() => resolve());
-            });
-        });
-    }
-
-    /**
-     * Set default values
-     * 
-     * @param configs object of default values
-     * 
-     * @returns Promise<void> indicates if the default settings were applied
-     */
-    public static defaults(configs: object): Promise<void>
-    {
-        return new Promise(async (resolve) => {
-            const setDefaults = async (current: object) => {
-                const updateDefaults = (current: object, defaults: object) => {
-                    Object.keys(defaults).forEach((key) => {
-                        // If the field exists in defaults and doesn't exist in current
-                        if (current[key] === undefined)
-                            current[key] = defaults[key];
-
-                        // If both default and current are objects
-                        // and we also should check if they're not nulls
-                        // because JS thinks that [typeof null === 'object']
-                        else if (typeof current[key] == 'object' && typeof defaults[key] == 'object' && current[key] !== null && defaults[key] !== null)
-                            current[key] = updateDefaults(current[key], defaults![key]);
-                    });
-
-                    return current;
-                };
-
-                Neutralino.filesystem.writeFile(await constants.paths.config, YAML.stringify(updateDefaults(current, configs)))
-                    .then(() => resolve());
-            };
-
-            Neutralino.filesystem.readFile(await constants.paths.config)
-                .then((config) => setDefaults(YAML.parse(config)))
-                .catch(() => setDefaults({}));
-        });
-    }
-}
diff --git a/src/ts/Constants.ts b/src/ts/Constants.ts
index 8f0a4d8..74bc700 100644
--- a/src/ts/Constants.ts
+++ b/src/ts/Constants.ts
@@ -1,4 +1,4 @@
-import Configs from './Configs';
+import { Configs } from '../empathize';
 
 declare const Neutralino;
 declare const NL_CWD;
diff --git a/src/ts/FPSUnlock.ts b/src/ts/FPSUnlock.ts
index 7d7a1c5..ead6880 100644
--- a/src/ts/FPSUnlock.ts
+++ b/src/ts/FPSUnlock.ts
@@ -1,6 +1,6 @@
+import { Downloader, path } from '../empathize';
+
 import constants from './Constants';
-import Downloader from './core/Downloader';
-import Process from './neutralino/Process';
 
 declare const Neutralino;
 
@@ -35,7 +35,7 @@ export default class FPSUnlock
                     Downloader.download(constants.uri.fpsunlock.bat, fpsunlockBat).then((stream) => {
                         stream.finish(async () => {
                             // sed -i 's/start ..\/GI_FPSUnlocker\/unlockfps.exe \%\*/start ..\/fpsunlock\/unlockfps.exe \%\*/g' unlockfps.bat
-                            Neutralino.os.execCommand(`sed -i 's/start ..\\/GI_FPSUnlocker\\/unlockfps.exe \\%\\*/start ..\\/fpsunlock\\/unlockfps.exe \\%\\*/g' "${Process.addSlashes(fpsunlockBat)}"`)
+                            Neutralino.os.execCommand(`sed -i 's/start ..\\/GI_FPSUnlocker\\/unlockfps.exe \\%\\*/start ..\\/fpsunlock\\/unlockfps.exe \\%\\*/g' "${path.addSlashes(fpsunlockBat)}"`)
                                 .then(() => resolve());
                         });
                     });
diff --git a/src/ts/Game.ts b/src/ts/Game.ts
index c032754..0554cdb 100644
--- a/src/ts/Game.ts
+++ b/src/ts/Game.ts
@@ -5,14 +5,13 @@ import type {
     Diff
 } from './types/GameData';
 
+import type { Stream as DownloadingStream } from '@empathize/framework/dist/network/Downloader';
+
+import { fetch, Domain, promisify, Downloader, Cache, Debug } from '../empathize';
+import { DebugThread } from '@empathize/framework/dist/meta/Debug';
+
 import constants from './Constants';
-import fetch from './core/Fetch';
 import AbstractInstaller from './core/AbstractInstaller';
-import Domain from './core/Domain';
-import promisify from './core/promisify';
-import Debug, { DebugThread } from './core/Debug';
-import Downloader, { Stream as DownloadingStream } from './core/Downloader';
-import Cache from './core/Cache';
 
 declare const Neutralino;
 
diff --git a/src/ts/Launcher.ts b/src/ts/Launcher.ts
index 3e2df3b..953ad2e 100644
--- a/src/ts/Launcher.ts
+++ b/src/ts/Launcher.ts
@@ -1,13 +1,11 @@
 import { locale } from 'svelte-i18n';
 
-import Window from './neutralino/Window';
-import Process from './neutralino/Process';
-import Tray from './neutralino/Tray';
+import {
+    Windows, Process, Tray,
+    Configs, Debug, IPC
+} from '../empathize';
 
 import constants from './Constants';
-import Configs from './Configs';
-import Debug from './core/Debug';
-import IPC from './core/IPC';
 import DiscordRPC from './core/DiscordRPC';
 import Locales from './launcher/Locales';
 
@@ -56,7 +54,7 @@ export default class Launcher
             {
                 this.settingsMenu = undefined;
 
-                const window = await Window.open('settings', {
+                const window = await Windows.open('settings', {
                     title: 'Settings',
                     width: 900,
                     height: 600,
@@ -96,11 +94,11 @@ export default class Launcher
                             });
                         });
 
-                        Window.current.show();
-                        Window.current.center(1280, 700);
+                        Windows.current.show();
+                        // TODO: Windows.current.center(1280, 700);
                     })
 
-                    Window.current.hide();
+                    Windows.current.hide();
                 }
 
                 resolve(window.status);
diff --git a/src/ts/Patch.ts b/src/ts/Patch.ts
index 5fc4477..e781c76 100644
--- a/src/ts/Patch.ts
+++ b/src/ts/Patch.ts
@@ -2,14 +2,12 @@ import type { PatchInfo } from './types/Patch';
 
 import md5 from 'js-md5';
 
+import { fetch, promisify, Debug, Cache, path } from '../empathize';
+import { DebugThread } from '@empathize/framework/dist/meta/Debug';
+
 import constants from './Constants';
 import Game from './Game';
-import fetch from './core/Fetch';
 import AbstractInstaller from './core/AbstractInstaller';
-import promisify from './core/promisify';
-import Process from './neutralino/Process';
-import Debug, { DebugThread } from './core/Debug';
-import Cache from './core/Cache';
 
 declare const Neutralino;
 
@@ -50,37 +48,37 @@ class Stream extends AbstractInstaller
                     /**
                      * Remove test version restrictions from the main patch
                      */
-                    () => Neutralino.os.execCommand(`cd "${Process.addSlashes(patchDir)}" && sed -i '/^echo "If you would like to test this patch, modify this script and remove the line below this one."/,+5d' patch.sh`),
+                    () => Neutralino.os.execCommand(`cd "${path.addSlashes(patchDir)}" && sed -i '/^echo "If you would like to test this patch, modify this script and remove the line below this one."/,+5d' patch.sh`),
 
                     /**
                      * Remove /etc/hosts editing due to sudo permissions
                      */
-                    () => Neutralino.os.execCommand(`cd "${Process.addSlashes(patchDir)}" && sed -i '/^# ===========================================================/,+68d' patch.sh`),
+                    () => Neutralino.os.execCommand(`cd "${path.addSlashes(patchDir)}" && sed -i '/^# ===========================================================/,+68d' patch.sh`),
                     
                     /**
                      * Remove test version restrictions from the anti-login crash patch
                      */
-                    () => Neutralino.os.execCommand(`cd "${Process.addSlashes(patchDir)}" && sed -i '/^echo "       necessary afterwards (Friday?). If that's the case, comment the line below."/,+2d' patch_anti_logincrash.sh`),
+                    () => Neutralino.os.execCommand(`cd "${path.addSlashes(patchDir)}" && sed -i '/^echo "       necessary afterwards (Friday?). If that's the case, comment the line below."/,+2d' patch_anti_logincrash.sh`),
 
                     /**
                      * Make the main patch executable
                      */
-                    () => Neutralino.os.execCommand(`chmod +x "${Process.addSlashes(patchDir)}/patch.sh"`),
+                    () => Neutralino.os.execCommand(`chmod +x "${path.addSlashes(patchDir)}/patch.sh"`),
 
                     /**
                      * Make the anti-login crash patch executable
                      */
-                    () => Neutralino.os.execCommand(`chmod +x "${Process.addSlashes(patchDir)}/patch_anti_logincrash.sh"`),
+                    () => Neutralino.os.execCommand(`chmod +x "${path.addSlashes(patchDir)}/patch_anti_logincrash.sh"`),
 
                     /**
                      * Execute the main patch installation script
                      */
-                    () => Neutralino.os.execCommand(`cd "${Process.addSlashes(gameDir)}" && yes yes | bash "${Process.addSlashes(patchDir)}/patch.sh"`),
+                    () => Neutralino.os.execCommand(`cd "${path.addSlashes(gameDir)}" && yes yes | bash "${path.addSlashes(patchDir)}/patch.sh"`),
 
                     /**
                      * Execute the anti-login crash patch installation script
                      */
-                    () => Neutralino.os.execCommand(`cd "${Process.addSlashes(gameDir)}" && yes | bash "${Process.addSlashes(patchDir)}/patch_anti_logincrash.sh"`)
+                    () => Neutralino.os.execCommand(`cd "${path.addSlashes(gameDir)}" && yes | bash "${path.addSlashes(patchDir)}/patch_anti_logincrash.sh"`)
                 ]
             });
 
diff --git a/src/ts/Voice.ts b/src/ts/Voice.ts
index 00bd15e..8fca9c6 100644
--- a/src/ts/Voice.ts
+++ b/src/ts/Voice.ts
@@ -1,14 +1,14 @@
 import type { VoicePack } from './types/GameData';
 import type { VoiceLang, InstalledVoice } from './types/Voice';
 
+import type { Stream as DownloadingStream } from '@empathize/framework/dist/network/Downloader';
+
+import { Configs, Debug, Downloader, promisify, path } from '../empathize';
+import { DebugThread } from '@empathize/framework/dist/meta/Debug';
+
 import constants from './Constants';
 import Game from './Game';
 import AbstractInstaller from './core/AbstractInstaller';
-import Configs from './Configs';
-import Debug, { DebugThread } from './core/Debug';
-import Downloader, { Stream as DownloadingStream } from './core/Downloader';
-import Process from './neutralino/Process';
-import promisify from './core/promisify';
 
 declare const Neutralino;
 
@@ -170,15 +170,15 @@ export default class Voice
 
             const pipeline = promisify({
                 callbacks: [
-                    () => Neutralino.os.execCommand(`rm -rf "${Process.addSlashes(`${voiceDir}/${this.langs[lang]}`)}"`),
+                    () => Neutralino.os.execCommand(`rm -rf "${path.addSlashes(`${voiceDir}/${this.langs[lang]}`)}"`),
 
                     (): Promise<void> => new Promise(async (resolve) => {
-                        Neutralino.os.execCommand(`rm -f "${Process.addSlashes(`${await constants.paths.gameDir}/Audio_${this.langs[lang]}_pkg_version`)}"`)
+                        Neutralino.os.execCommand(`rm -f "${path.addSlashes(`${await constants.paths.gameDir}/Audio_${this.langs[lang]}_pkg_version`)}"`)
                             .then(() => resolve());
                     }),
 
                     (): Promise<void> => new Promise(async (resolve) => {
-                        Neutralino.os.execCommand(`sed -i '/${this.langs[lang]}/d' "${Process.addSlashes(`${await constants.paths.gameDataDir}/Persistent/audio_lang_14`)}"`)
+                        Neutralino.os.execCommand(`sed -i '/${this.langs[lang]}/d' "${path.addSlashes(`${await constants.paths.gameDataDir}/Persistent/audio_lang_14`)}"`)
                             .then(() => resolve());
                     })
                 ],
diff --git a/src/ts/core/AbstractInstaller.ts b/src/ts/core/AbstractInstaller.ts
index 001e059..7a82c6f 100644
--- a/src/ts/core/AbstractInstaller.ts
+++ b/src/ts/core/AbstractInstaller.ts
@@ -1,7 +1,9 @@
+import type { Stream as DownloadStream } from '@empathize/framework/dist/network/Downloader';
+
+import { Downloader, Archive } from '../../empathize';
+import { DebugThread } from '@empathize/framework/dist/meta/Debug';
+
 import constants from '../Constants';
-import Downloader, { Stream as DownloadStream } from './Downloader';
-import Archive from './Archive';
-import { DebugThread } from './Debug';
 
 declare const Neutralino;
 
@@ -68,7 +70,7 @@ export default abstract class Installer
                         if (shouldResolve)
                             debugThread.log(`Resolved unpack dir: ${unpackDir}`);
 
-                        Archive.unpack(archivePath, unpackDir).then((stream) => {
+                        Archive.extract(archivePath, unpackDir).then((stream) => {
                             stream.progressInterval = this.unpackProgressInterval;
         
                             stream.start(() => {
diff --git a/src/ts/core/Archive.ts b/src/ts/core/Archive.ts
deleted file mode 100644
index dbeeb2b..0000000
--- a/src/ts/core/Archive.ts
+++ /dev/null
@@ -1,364 +0,0 @@
-import type {
-    ArchiveType,
-    Size,
-    File,
-    ArchiveInfo
-} from '../types/Archive';
-
-import { DebugThread } from './Debug';
-import promisify from './promisify';
-import Process from '../neutralino/Process';
-
-declare const Neutralino;
-declare const NL_CWD;
-
-class Stream
-{
-    protected _id: number = -1;
-
-    /**
-     * ID of the archive unpacker process
-     */
-    public get id(): number
-    {
-        return this._id;
-    }
-
-    /**
-     * The interval in ms between progress event calls
-     */
-    public progressInterval: number = 500;
-
-    protected path: string;
-    protected unpackDir: string|null;
-    protected unpacked: number = 0;
-
-    protected archive?: ArchiveInfo;
-
-    protected onStart?: () => void;
-    protected onProgress?: (current: number, total: number, difference: number) => void;
-    protected onFinish?: () => void;
-    protected onError?: () => void;
-
-    protected started: boolean = false;
-    protected finished: boolean = false;
-    protected throwedError: boolean = false;
-
-    /**
-     * @param path path to archive
-     * @param unpackDir directory to extract the files to
-     */
-    public constructor(path: string, unpackDir: string|null = null)
-    {
-        this.path = path;
-        this.unpackDir = unpackDir;
-        this.started = true;
-
-        const debugThread = new DebugThread('Archive/Stream', {
-            message: {
-                'path': path,
-                'unpack dir': unpackDir
-            }
-        });
-
-        if (this.onStart)
-            this.onStart();
-
-        Archive.getInfo(path).then((info) => {
-            if (info === null)
-            {
-                this.throwedError = true;
-
-                if (this.onError)
-                    this.onError();
-            }
-
-            else
-            {
-                this.archive = info;
-
-                let command = {
-                    tar: `tar -xvf "${Process.addSlashes(path)}"${unpackDir ? ` -C "${Process.addSlashes(unpackDir)}"` : ''}`,
-                    zip: `unzip -o "${Process.addSlashes(path)}"${unpackDir ? ` -d "${Process.addSlashes(unpackDir)}"` : ''}`
-                }[this.archive.type!];
-
-                if (unpackDir)
-                    command = `mkdir -p "${Process.addSlashes(unpackDir)}" && ${command}`;
-
-                let remainedFiles = this.archive.files;
-                
-                const baseDir = unpackDir ?? NL_CWD;
-
-                Neutralino.os.execCommand(command, {
-                    background: true
-                }).then((result) => {
-                    this._id = result.pid;
-                });
-
-                debugThread.log(`Unpacking started with command: ${command}`);
-
-                const updateProgress = async () => {
-                    let difference: number = 0;
-                    let pool: any[] = [];
-
-                    remainedFiles.forEach((file) => {
-                        if (file.path != '#unpacked#')
-                        {
-                            pool.push((): Promise<void> => {
-                                return new Promise((resolve) => {
-                                    Neutralino.filesystem.getStats(`${baseDir}/${file.path}`)
-                                        .then(() => {
-                                            this.unpacked += file.size.uncompressed!;
-                                            difference += file.size.uncompressed!;
-
-                                            file.path = '#unpacked#';
-
-                                            resolve();
-                                        })
-                                        .catch(() => resolve())
-                                });
-                            });
-                        }
-                    });
-
-                    await promisify({
-                        callbacks: pool,
-                        callAtOnce: true,
-                        interval: 200
-                    });
-
-                    remainedFiles = remainedFiles.filter((file) => file.path != '#unpacked#');
-
-                    if (this.onProgress)
-                        this.onProgress(this.unpacked, this.archive!.size.uncompressed!, difference);
-
-                    if (this.unpacked >= this.archive!.size.uncompressed!)
-                    {
-                        this.finished = true;
-    
-                        debugThread.log('Unpacking finished');
-
-                        if (this.onFinish)
-                            this.onFinish();
-                    }
-    
-                    if (!this.finished)
-                        setTimeout(updateProgress, this.progressInterval);
-                };
-        
-                setTimeout(updateProgress, this.progressInterval);
-            }
-        });
-    }
-
-    /**
-     * Specify event that will be called when the extraction has started
-     * 
-     * @param callback
-     */
-    public start(callback: () => void)
-    {
-        this.onStart = callback;
-
-        if (this.started)
-            callback();
-    }
-
-    /**
-     * Specify event that will be called every [this.progressInterval] ms while extracting the archive
-     * 
-     * @param callback
-     */
-    public progress(callback: (current: number, total: number, difference: number) => void)
-    {
-        this.onProgress = callback;
-    }
-
-    /**
-     * Specify event that will be called after the archive has been extracted
-     * 
-     * @param callback
-     */
-    public finish(callback: () => void)
-    {
-        this.onFinish = callback;
-
-        if (this.finished)
-            callback();
-    }
-
-    /**
-     * Specify event that will be called if archive can't be extracted
-     * 
-     * @param callback
-     */
-    public error(callback: () => void)
-    {
-        this.onError = callback;
-
-        if (this.throwedError)
-            callback();
-    }
-
-    /**
-     * Close unpacking stream
-     */
-    public close(forced: boolean = false)
-    {
-        Neutralino.os.execCommand(`kill ${forced ? '-9' : '-15'} ${this._id}`);
-    }
-}
-
-export default class Archive
-{
-    protected static streams: Stream[] = [];
-
-    /**
-     * Get type of archive
-     * 
-     * @param path path to archive
-     * @returns supported archive type or null
-     */
-    public static getType(path: string): ArchiveType|null
-    {
-        if (path.substring(path.length - 4) == '.zip')
-            return 'zip';
-
-        else if (path.substring(path.length - 7, path.length - 2) == '.tar.')
-            return 'tar';
-
-        else return null;
-    }
-
-    /**
-     * Get archive info
-     * 
-     * @param path path to archive
-     * @returns null if the archive has unsupported type. Otherwise - archive info
-     */
-    public static getInfo(path: string): Promise<ArchiveInfo|null>
-    {
-        const debugThread = new DebugThread('Archive.getInfo', `Getting info about archive: ${path}`);
-
-        return new Promise(async (resolve) => {
-            let archive: ArchiveInfo = {
-                size: {
-                    compressed: null,
-                    uncompressed: null
-                },
-                type: this.getType(path),
-                files: []
-            };
-
-            switch (archive.type)
-            {
-                case 'tar':
-                    const tarOutput = await Neutralino.os.execCommand(`tar -tvf "${path}"`);
-
-                    for (const match of tarOutput.stdOut.matchAll(/^[dwxr\-]+ [\w/]+[ ]+(\d+) [0-9\-]+ [0-9\:]+ (.+)/gm))
-                    {
-                        let fileSize = parseInt(match[1]);
-
-                        archive.size.uncompressed! += fileSize;
-
-                        archive.files.push({
-                            path: match[2],
-                            size: {
-                                compressed: null,
-                                uncompressed: fileSize
-                            }
-                        });
-                    }
-
-                    debugThread.log({
-                        message: {
-                            'type': archive.type,
-                            'compressed size': archive.size.compressed,
-                            'uncompressed size': archive.size.uncompressed,
-                            'files amount': archive.files.length
-                        }
-                    });
-
-                    resolve(archive);
-
-                    break;
-
-                case 'zip':
-                    const zipOutput = await Neutralino.os.execCommand(`unzip -v "${path}"`);
-
-                    for (const match of zipOutput.stdOut.matchAll(/^(\d+)  [a-zA-Z\:]+[ ]+(\d+)[ ]+[0-9\-]+% [0-9\-]+ [0-9\:]+ [a-f0-9]{8}  (.+)/gm))
-                    {
-                        let uncompressedSize = parseInt(match[1]),
-                            compressedSize = parseInt(match[2]);
-
-                        archive.size.compressed!   += compressedSize;
-                        archive.size.uncompressed! += uncompressedSize;
-
-                        archive.files.push({
-                            path: match[3],
-                            size: {
-                                compressed: compressedSize,
-                                uncompressed: uncompressedSize
-                            }
-                        });
-                    }
-
-                    debugThread.log({
-                        message: {
-                            'type': archive.type,
-                            'compressed size': archive.size.compressed,
-                            'uncompressed size': archive.size.uncompressed,
-                            'files amount': archive.files.length
-                        }
-                    });
-
-                    resolve(archive);
-
-                    break;
-
-                default:
-                    debugThread.log(`Unsupported archive type: ${archive.type}`);
-
-                    resolve(null);
-
-                    break;
-            }
-        });
-    }
-
-    /**
-     * Extract Archive
-     * 
-     * @param path path to archive
-     * @param unpackDir directory to extract the files to
-     */
-    public static unpack(path: string, unpackDir: string|null = null): Promise<Stream>
-    {
-        return new Promise((resolve) => {
-            const stream = new Stream(path, unpackDir);
-
-            this.streams.push(stream);
-
-            resolve(stream);
-        });
-    }
-
-    /**
-     * Close every open archive extracting stream
-     */
-    public static closeStreams(forced: boolean = false)
-    {
-        this.streams.forEach((stream) => {
-            stream.close(forced);
-        });
-    }
-};
-
-export { Stream };
-
-export type {
-    ArchiveType,
-    File,
-    Size,
-    ArchiveInfo
-};
diff --git a/src/ts/core/Cache.ts b/src/ts/core/Cache.ts
deleted file mode 100644
index 42cb7d7..0000000
--- a/src/ts/core/Cache.ts
+++ /dev/null
@@ -1,128 +0,0 @@
-import constants from '../Constants';
-import Debug from './Debug';
-
-type Record = {
-    expired: boolean;
-    value: object|object[];
-};
-
-declare const Neutralino;
-
-export default class Cache
-{
-    // Locally stored cache to not to access
-    // cache.json file every time we want to find something
-    protected static cache: object|null = null;
-
-    /**
-     * Get cached value
-     * 
-     * @returns null if this value is not cached
-     */
-    public static get(name: string): Promise<Record|null>
-    {
-        return new Promise(async (resolve) => {
-            if (this.cache !== null && this.cache[name] !== undefined)
-            {
-                const expired = this.cache[name].ttl !== null ? Date.now() > this.cache[name].ttl * 1000 : false;
-
-                Debug.log({
-                    function: 'Cache.get',
-                    message: [
-                        `Resolved ${expired ? 'expired' : 'unexpired'} hot cache record`,
-                        `[name] ${name}`,
-                        `[value]: ${JSON.stringify(this.cache[name].value)}`
-                    ]
-                });
-
-                resolve({
-                    expired: expired,
-                    value: this.cache[name].value
-                });
-            }
-            
-            else Neutralino.filesystem.readFile(await constants.paths.cache)
-                .then((cache) => {
-                    this.cache = JSON.parse(cache);
-
-                    if (this.cache![name] === undefined)
-                        resolve(null);
-
-                    else
-                    {
-                        const output = {
-                            expired: this.cache![name].ttl !== null ? Date.now() > this.cache![name].ttl * 1000 : false,
-                            value: this.cache![name].value
-                        };
-
-                        Debug.log({
-                            function: 'Cache.get',
-                            message: [
-                                `Resolved ${output.expired ? 'expired' : 'unexpired'} cache`,
-                                `[name] ${name}`,
-                                `[value]: ${JSON.stringify(output.value)}`
-                            ]
-                        });
-
-                        resolve(output);
-                    }
-                })
-                .catch(() => resolve(null));
-        });
-    }
-
-    /**
-     * Cache value
-     * 
-     * @param name name of the value to cache
-     * @param value value to cache
-     * @param ttl number of seconds to cache
-     * 
-     * @returns promise that indicates when the value will be cached
-     */
-    public static set(name: string, value: object|object[], ttl: number|null = null): Promise<void>
-    {
-        return new Promise((resolve) => {
-            constants.paths.cache.then((cacheFile) => {
-                const writeCache = () => {
-                    Debug.log({
-                        function: 'Cache.set',
-                        message: [
-                            'Caching data:',
-                            `[ttl] ${ttl}`,
-                            `[value] ${JSON.stringify(value)}`
-                        ]
-                    });
-    
-                    this.cache![name] = {
-                        ttl: ttl !== null ? Math.round(Date.now() / 1000) + ttl : null,
-                        value: value
-                    };
-    
-                    Neutralino.filesystem.writeFile(cacheFile, JSON.stringify(this.cache))
-                        .then(() => resolve());
-                };
-                
-                if (this.cache === null)
-                {
-                    Neutralino.filesystem.readFile(cacheFile)
-                        .then((cacheRaw) => 
-                        {
-                            this.cache = JSON.parse(cacheRaw);
-
-                            writeCache();
-                        })
-                        .catch(() => {
-                            this.cache = {};
-
-                            writeCache();
-                        });
-                }
-
-                else writeCache();
-            });
-        });
-    }
-};
-
-export type { Record };
diff --git a/src/ts/core/DXVK.ts b/src/ts/core/DXVK.ts
index 4f76002..757dfcc 100644
--- a/src/ts/core/DXVK.ts
+++ b/src/ts/core/DXVK.ts
@@ -1,12 +1,11 @@
 import type { DXVK as TDXVK } from '../types/DXVK';
 
+import { Configs, Process, promisify, path } from '../../empathize';
+import { DebugThread } from '@empathize/framework/dist/meta/Debug';
+
 import constants from '../Constants';
-import Configs from '../Configs';
 import AbstractInstaller from './AbstractInstaller';
-import Process from '../neutralino/Process';
-import promisify from './promisify';
 import Runners from './Runners';
-import { DebugThread } from './Debug';
 
 declare const Neutralino;
 
@@ -143,7 +142,7 @@ export default class DXVK
             const version = typeof dxvk !== 'string' ?
                 dxvk.version : dxvk;
 
-            await Neutralino.os.execCommand(`rm -rf "${Process.addSlashes(await constants.paths.dxvksDir)}/dxvk-${version}"`);
+            await Neutralino.os.execCommand(`rm -rf "${path.addSlashes(await constants.paths.dxvksDir)}/dxvk-${version}"`);
 
             debugThread.log('Deletion completed');
 
diff --git a/src/ts/core/Debug.ts b/src/ts/core/Debug.ts
deleted file mode 100644
index 4747077..0000000
--- a/src/ts/core/Debug.ts
+++ /dev/null
@@ -1,133 +0,0 @@
-import type { DebugOptions, LogRecord } from '../types/Debug';
-
-class DebugThread
-{
-    protected thread: number;
-    protected funcName: string|null;
-
-    public constructor(funcName: string|null = null, options: DebugOptions|string|null = null)
-    {
-        // Generate some random thread id
-        this.thread = 1000 + Math.round(Math.random() * 8999);
-
-        this.funcName = funcName;
-
-        if (options !== null)
-            this.log(options);
-    }
-
-    public log(options: DebugOptions|string)
-    {
-        Debug.log({
-            thread: this.thread,
-            function: this.funcName ?? '',
-
-            ...(typeof options === 'string' ? { message: options } : options)
-        });
-    }
-}
-
-class Debug
-{
-    public static readonly startedAt = new Date;
-    
-    protected static logOutput: LogRecord[] = [];
-
-    protected static onLogHandler?: (record: LogRecord) => void;
-    
-    protected static formatTime(time: number): string
-    {
-        const prefixTime = (time: number): string => {
-            return time < 10 ? `0${time}` : time.toString();
-        };
-
-        const date = new Date(time);
-
-        return `${prefixTime(date.getHours())}:${prefixTime(date.getMinutes())}:${prefixTime(date.getSeconds())}.${date.getMilliseconds()}`;
-    }
-
-    public static log(options: DebugOptions|string)
-    {
-        const time = Date.now();
-
-        let output: LogRecord = {
-            time: time,
-            log: [
-                `[${this.formatTime(time)}]`
-            ]
-        };
-
-        if (typeof options === 'string')
-            output.log[0] += ` ${options}`;
-
-        else
-        {
-            // Add thread id
-            if (options.thread)
-                output.log[0] += `[thread: ${options.thread}]`;
-
-            // Add function name
-            if (options.function)
-                output.log[0] += `[${options.function}]`;
-
-            // Add log message if it is a single line
-            if (typeof options.message === 'string')
-                output.log[0] += ` ${options.message}`;
-
-            // message: [a, b, c, d]
-            else if (Array.isArray(options.message))
-                options.message.forEach((line) => {
-                    if (line !== '')
-                        output.log.push(` - ${line}`);
-                });
-
-            // message: { a: b, c: d }
-            else Object.keys(options.message).forEach((key) => {
-                output.log.push(` - [${key}] ${options.message[key]}`);
-            });
-        }
-
-        console.log(output.log.join('\r\n'));
-
-        this.logOutput.push(output);
-
-        if (this.onLogHandler)
-            this.onLogHandler(output);
-    }
-
-    public static merge(records: LogRecord[])
-    {
-        this.logOutput.unshift(...records);
-        this.logOutput.sort((a, b) => a.time - b.time);
-    }
-
-    public static getRecords(): LogRecord[]
-    {
-        return this.logOutput;
-    }
-
-    public static get(): string[]
-    {
-        let output: string[] = [];
-
-        this.logOutput.forEach((record) => {
-            record.log.forEach((line) => output.push(line));
-        });
-
-        return output;
-    }
-
-    public static handler(handler: (record: LogRecord) => void)
-    {
-        this.onLogHandler = handler;
-    }
-}
-
-export default Debug;
-
-export { DebugThread };
-
-export type {
-    DebugOptions,
-    LogRecord
-};
diff --git a/src/ts/core/DiscordRPC.ts b/src/ts/core/DiscordRPC.ts
index a5b1654..4c79996 100644
--- a/src/ts/core/DiscordRPC.ts
+++ b/src/ts/core/DiscordRPC.ts
@@ -1,6 +1,6 @@
 import type { Params } from '../types/DiscordRPC';
 
-import Process from '../neutralino/Process';
+import { Process, path } from '../../empathize';
 
 declare const NL_CWD;
 
@@ -19,10 +19,10 @@ export default class DiscordRPC
         ];
 
         if (params.details)
-            exec = [...exec, `-d "${Process.addSlashes(params.details)}"`];
+            exec = [...exec, `-d "${path.addSlashes(params.details)}"`];
 
         if (params.state)
-            exec = [...exec, `-s "${Process.addSlashes(params.state)}"`];
+            exec = [...exec, `-s "${path.addSlashes(params.state)}"`];
 
         if (params.icon)
         {
diff --git a/src/ts/core/Domain.ts b/src/ts/core/Domain.ts
deleted file mode 100644
index c25aee7..0000000
--- a/src/ts/core/Domain.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-import type { DomainInfo } from '../types/Domain';
-
-import Process from '../neutralino/Process';
-import { DebugThread } from './Debug';
-
-declare const Neutralino;
-
-export default class Domain
-{
-    public static getInfo(uri: string): Promise<DomainInfo>
-    {
-        const debugThread = new DebugThread('Domain.getInfo', `Getting info about uri: ${uri}`);
-
-        return new Promise(async (resolve) => {
-            const process = await Neutralino.os.execCommand(`ping -n -4 -w 1 -B "${Process.addSlashes(uri)}"`);
-            const output = process.stdOut || process.stdErr;
-
-            const resolveInfo = (info: DomainInfo) => {
-                debugThread.log({ message: info });
-
-                resolve(info);
-            };
-
-            if (output.includes('Name or service not known'))
-            {
-                resolveInfo({
-                    uri: uri,
-                    available: false
-                });
-            }
-
-            else
-            {
-                const regex = /PING (.*) \(([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\) .* ([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}) : [\d]+\([\d]+\)/gm.exec(output);
-
-                if (regex !== null)
-                {
-                    resolveInfo({
-                        uri: regex[1],
-                        remoteIp: regex[2],
-                        localIp: regex[3],
-                        available: regex[2] !== regex[3]
-                    });
-                }
-            }
-        });
-    }
-};
diff --git a/src/ts/core/Downloader.ts b/src/ts/core/Downloader.ts
deleted file mode 100644
index 4a4457b..0000000
--- a/src/ts/core/Downloader.ts
+++ /dev/null
@@ -1,230 +0,0 @@
-import Process from '../neutralino/Process';
-import { DebugThread } from './Debug';
-import fetch from './Fetch';
-
-declare const Neutralino;
-
-class Stream
-{
-    protected _id: number = -1;
-
-    /**
-     * ID of the curl process
-     */
-    public get id(): number
-    {
-        return this._id;
-    }
-
-    /**
-     * The interval in ms between progress event calls
-     */
-    public progressInterval: number = 200;
-
-    /**
-     * The interval in ms between checking was downloading resumed after pausing
-     */
-    public pauseInterval: number = 500;
-
-    protected uri: string;
-    protected output: string;
-    protected total: number;
-    protected previous: number = 0;
-
-    protected onStart?: () => void;
-    protected onProgress?: (current: number, total: number, difference: number) => void;
-    protected onFinish?: () => void;
-
-    protected started: boolean = false;
-    protected paused: boolean = true; // true because we call .resume() method at start
-    protected finished: boolean = false;
-
-    protected debugThread: DebugThread;
-
-    public constructor(uri: string, output: string, total: number)
-    {
-        this.uri = uri;
-        this.output = output;
-        this.total = total;
-        this.started = true;
-
-        this.debugThread = new DebugThread('Downloader/Stream', {
-            message: {
-                'uri': uri,
-                'output file': output,
-                'total size': total
-            }
-        });
-
-        if (this.onStart)
-            this.onStart();
-
-        this.resume();
-
-        const updateProgress = () => {
-            if (!this.paused)
-            {
-                Neutralino.filesystem.getStats(output).then((stats) => {
-                    if (this.onProgress)
-                        this.onProgress(stats.size, this.total, stats.size - this.previous);
-
-                    this.previous = stats.size;
-
-                    if (stats.size >= this.total)
-                    {
-                        this.finished = true;
-
-                        this.debugThread.log('Downloading finished');
-
-                        if (this.onFinish)
-                            this.onFinish();
-                    }
-
-                    if (!this.finished)
-                        setTimeout(updateProgress, this.progressInterval);
-                }).catch(() => {
-                    if (!this.finished)
-                        setTimeout(updateProgress, this.progressInterval);
-                });
-            }
-
-            else setTimeout(updateProgress, this.pauseInterval);
-        };
-
-        setTimeout(updateProgress, this.progressInterval);
-    }
-
-    /**
-     * Specify event that will be called when the download gets started
-     * 
-     * @param callback
-     */
-    public start(callback: () => void)
-    {
-        this.onStart = callback;
-
-        if (this.started)
-            callback();
-    }
-
-    /**
-     * Specify event that will be called every [this.progressInterval] ms while the file is downloading
-     * 
-     * @param callback
-     */
-    public progress(callback: (current: number, total: number, difference: number) => void)
-    {
-        this.onProgress = callback;
-    }
-
-    /**
-     * Specify event that will be called after the file is downloaded
-     * 
-     * @param callback
-     */
-    public finish(callback: () => void)
-    {
-        this.onFinish = callback;
-
-        if (this.finished)
-            callback();
-    }
-
-    /**
-     * Pause downloading
-     */
-    public pause()
-    {
-        if (!this.paused)
-        {
-            this.debugThread.log('Downloading paused');
-
-            this.close(true);
-
-            this.paused = true;
-        }
-    }
-
-    /**
-     * Resume downloading
-     */
-    public resume()
-    {
-        if (this.paused)
-        {
-            const command = `curl -s -L -N -C - -o "${Process.addSlashes(this.output)}" "${this.uri}"`;
-
-            this.debugThread.log(`Downloading started with command: ${command}`);
-
-            Neutralino.os.execCommand(command, {
-                background: true
-            }).then((result) => {
-                this._id = result.pid;
-            });
-
-            this.paused = false;
-        }
-    }
-
-    /**
-     * Close downloading stream
-     */
-    public close(forced: boolean = false)
-    {
-        Neutralino.os.execCommand(`kill ${forced ? '-9' : '-15'} ${this._id}`);
-    }
-}
-
-export default class Downloader
-{
-    protected static streams: Stream[] = [];
-
-    /**
-     * Download file
-     * 
-     * @param uri file's uri to download
-     * @param output relative or absolute path to the file to save it as
-     * 
-     * @returns downloading stream
-     */
-    public static async download(uri: string, output: string|null = null): Promise<Stream>
-    {
-        return new Promise(async (resolve) => {
-            fetch(uri).then((response) => {
-                const stream = new Stream(uri, output ?? this.fileFromUri(uri), response.length!);
-
-                this.streams.push(stream);
-
-                resolve(stream);
-            });
-        });
-    }
-
-    /**
-     * Close every open downloading stream
-     */
-    public static closeStreams(forced: boolean = false)
-    {
-        this.streams.forEach((stream) => {
-            stream.close(forced);
-        });
-    }
-
-    /**
-     * Get a file name from the URI
-     */
-    public static fileFromUri(uri: string): string
-    {
-        const file = uri.split('/').pop()!.split('#')[0].split('?')[0];
-
-        if (file === '')
-            return 'index.html';
-
-        else if (`https://${file}` != uri && `http://${file}` != uri)
-            return file;
-
-        else return 'index.html';
-    }
-};
-
-export { Stream };
diff --git a/src/ts/core/Fetch.ts b/src/ts/core/Fetch.ts
deleted file mode 100644
index c4115d7..0000000
--- a/src/ts/core/Fetch.ts
+++ /dev/null
@@ -1,79 +0,0 @@
-declare const Neutralino;
-
-class Response
-{
-    /**
-     * Requested url
-     */
-    public readonly url: string;
-
-    /**
-     * HTTP status code
-     */
-    public readonly status: number|null;
-
-    /**
-     * Content length
-     */
-    public readonly length: number|null;
-
-    /**
-     * Represents whether the response was successful (status in the range 200-299) or not
-     */
-    public readonly ok: boolean;
-
-    public constructor(url: string, status: number|null, length: number|null)
-    {
-        this.url = url;
-        this.status = status;
-        this.length = length;
-
-        // https://developer.mozilla.org/en-US/docs/Web/API/Response/ok
-        this.ok = status! >= 200 && status! <= 299;
-    }
-
-    /**
-     * Get request's body
-     * 
-     * @param delay maximal request delay in milliseconds
-     */
-    public body(delay: number|null = null): Promise<string>
-    {
-        return new Promise((resolve) => {
-            Neutralino.os.execCommand(`curl -s -L ${delay !== null ? `-m ${delay / 1000}` : ''} "${this.url}"`)
-                .then((output) => resolve(output.stdOut));
-        });
-    }
-}
-
-/**
- * Fetch data from the URL
- * 
- * @param delay maximal request delay in milliseconds
- */
-export default function fetch(url: string, delay: number|null = null): Promise<Response>
-{
-    return new Promise(async (resolve) => {
-        let header = await Neutralino.os.execCommand(`curl -s -I -L ${delay !== null ? `-m ${delay / 1000}` : ''} "${url}"`);
-
-        if (header.stdOut == '')
-            header = header.stdErr;
-
-        else header = header.stdOut;
-
-        header = header.split(/^HTTP\/[\d]+ /mi).pop();
-
-        let status: any = /^([\d]+)[\s]+$/m.exec(header);
-        let length: any = /^content-length: ([\d]+)/mi.exec(header);
-
-        if (status !== null)
-            status = parseInt(status[1]);
-
-        if (length !== null)
-            length = parseInt(length[1]);
-
-        resolve(new Response(url, status, length));
-    });
-};
-
-export { Response };
diff --git a/src/ts/core/Git.ts b/src/ts/core/Git.ts
index 6c9a59c..24b2cfe 100644
--- a/src/ts/core/Git.ts
+++ b/src/ts/core/Git.ts
@@ -1,4 +1,4 @@
-import Process from '../neutralino/Process';
+import { path } from '../../empathize';
 
 type Tag = {
     tag: string,
@@ -17,7 +17,7 @@ export default class Git
     public static getTags(repository: string): Promise<Tag[]>
     {
         return new Promise(async (resolve) => {
-            const output = await Neutralino.os.execCommand(`git ls-remote --tags "${Process.addSlashes(repository)}"`);
+            const output = await Neutralino.os.execCommand(`git ls-remote --tags "${path.addSlashes(repository)}"`);
 
             let tags: Tag[] = [];
 
diff --git a/src/ts/core/IPC.ts b/src/ts/core/IPC.ts
deleted file mode 100644
index 3173824..0000000
--- a/src/ts/core/IPC.ts
+++ /dev/null
@@ -1,101 +0,0 @@
-import constants from '../Constants';
-
-declare const Neutralino;
-
-class IPCRecord
-{
-    public readonly id: number;
-    public readonly time: number;
-    public readonly data: any;
-
-    public constructor(id: number, time: number, data: any)
-    {
-        this.id = id;
-        this.time = time;
-        this.data = data;
-    }
-
-    /**
-     * Remove the record from the storage
-     */
-    public pop(): IPCRecord
-    {
-        IPC.remove(this);
-
-        return this;
-    }
-
-    public get(): { id: number; time: number; data: any}
-    {
-        return {
-            id: this.id,
-            time: this.time,
-            data: this.data
-        };
-    }
-}
-
-export default class IPC
-{
-    /**
-     * Read records from the "shared inter-process storage"
-     */
-    public static read(): Promise<IPCRecord[]>
-    {
-        return new Promise(async (resolve) => {
-            Neutralino.filesystem.readFile(`${await constants.paths.launcherDir}/.ipc.json`)
-                .then((data) => resolve(JSON.parse(data).map((record) => new IPCRecord(record.id, record.time, record.data))))
-                .catch(() => resolve([]));
-        });
-    }
-
-    /**
-     * Write some data to the "shared inter-process storage"
-     */
-    public static write(data: any): Promise<void>
-    {
-        return new Promise(async (resolve) => {
-            const records = await this.read();
-
-            records.push({
-                id: Math.round(Math.random() * 100000),
-                time: Date.now(),
-                data: data
-            } as IPCRecord);
-
-            await Neutralino.filesystem.writeFile(`${await constants.paths.launcherDir}/.ipc.json`, JSON.stringify(records));
-
-            resolve();
-        });
-    }
-
-    /**
-     * Remove record from the "shared inter-process storage"
-     */
-    public static remove(record: IPCRecord): Promise<void>
-    {
-        return new Promise(async (resolve) => {
-            let records = await this.read();
-
-            records = records.filter((item) => item.id !== record.id || item.time !== record.time);
-
-            await Neutralino.filesystem.writeFile(`${await constants.paths.launcherDir}/.ipc.json`, JSON.stringify(records));
-
-            resolve();
-        });
-    }
-
-    /**
-     * Remove all the record from the "shared inter-process storage"
-     */
-    public static purge(): Promise<void>
-    {
-        return new Promise(async (resolve) => {
-            Neutralino.filesystem.removeFile(`${await constants.paths.launcherDir}/.ipc.json`)
-                .then(() => resolve())
-                .catch(() => resolve());
-        });
-    }
-};
-
-export { IPCRecord };
diff --git a/src/ts/core/Notifications.ts b/src/ts/core/Notifications.ts
deleted file mode 100644
index d979f8d..0000000
--- a/src/ts/core/Notifications.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import type { NotificationsOptions } from '../types/Notifications';
-
-import Process from '../neutralino/Process';
-
-declare const Neutralino;
-
-export default class Notifications
-{
-    /**
-     * Show notification
-     */
-    public static show(options: NotificationsOptions)
-    {
-        let command = `notify-send "${Process.addSlashes(options.title)}" "${Process.addSlashes(options.body)}"`;
-
-        // Specify notification icon
-        if (options.icon)
-            command += ` -i "${Process.addSlashes(options.icon)}"`;
-
-        // Specify notification duration
-        if (options.duration)
-            command += ` -d ${options.duration}`;
-
-        // Specify notification importance
-        if (options.importance)
-            command += ` -u ${options.importance}`;
-
-        Neutralino.os.execCommand(command, {
-            background: true
-        });
-    }
-};
diff --git a/src/ts/core/Prefix.ts b/src/ts/core/Prefix.ts
index edf2876..d480ac6 100644
--- a/src/ts/core/Prefix.ts
+++ b/src/ts/core/Prefix.ts
@@ -1,7 +1,7 @@
+import { Process, Downloader, Debug, path } from '../../empathize';
+import { DebugThread } from '@empathize/framework/dist/meta/Debug';
+
 import constants from '../Constants';
-import Process from '../neutralino/Process';
-import Debug, { DebugThread } from './Debug';
-import Downloader from './Downloader';
 import Runners from './Runners';
 
 declare const Neutralino;
@@ -52,7 +52,7 @@ export default class Prefix
                 .catch(() => {
                     Downloader.download(constants.uri.winetricks, winetricksPath).then((stream) => {
                         stream.finish(async () => {
-                            await Neutralino.os.execCommand(`chmod +x "${Process.addSlashes(winetricksPath)}"`);
+                            await Neutralino.os.execCommand(`chmod +x "${path.addSlashes(winetricksPath)}"`);
 
                             resolve(winetricksPath);
                         });
@@ -64,12 +64,12 @@ export default class Prefix
     /**
      * Create wine prefix using the current selected wine
      * 
-     * @param path folder to create prefix in
+     * @param folder folder to create prefix in
      * @param progress function that will be called with every creation step
      * 
      * @returns false if there's no selected wine version. Otherwise true
      */
-    public static create(path: string, progress?: (output: string, current: number, total: number) => void): Promise<boolean>
+    public static create(folder: string, progress?: (output: string, current: number, total: number) => void): Promise<boolean>
     {
         const debugThread = new DebugThread('Prefix.create', 'Creating wine prefix');
 
@@ -108,11 +108,11 @@ export default class Prefix
                     this.getWinetricks().then(async (winetricks) => {
                         let installationProgress = 0;
 
-                        const process = await Process.run(`"${Process.addSlashes(winetricks)}" corefonts usetakefocus=n`, {
+                        const process = await Process.run(`"${path.addSlashes(winetricks)}" corefonts usetakefocus=n`, {
                             env: {
                                 WINE: `${await constants.paths.runnersDir}/${runner.name}/${runner.files.wine}`,
                                 WINESERVER: `${await constants.paths.runnersDir}/${runner.name}/${runner.files.wineserver}`,
-                                WINEPREFIX: path
+                                WINEPREFIX: folder
                             }
                         });
 
diff --git a/src/ts/core/Runners.ts b/src/ts/core/Runners.ts
index 1a475d1..6a6ef63 100644
--- a/src/ts/core/Runners.ts
+++ b/src/ts/core/Runners.ts
@@ -3,11 +3,11 @@ import type {
     RunnerFamily
 } from '../types/Runners';
 
+import { Configs, Process, path } from '../../empathize';
+import { DebugThread } from '@empathize/framework/dist/meta/Debug';
+
 import constants from '../Constants';
-import Configs from '../Configs';
 import AbstractInstaller from './AbstractInstaller';
-import Process from '../neutralino/Process';
-import { DebugThread } from './Debug';
 
 declare const Neutralino;
 
@@ -149,7 +149,7 @@ class Runners
             const name = typeof runner !== 'string' ?
                 runner.name : runner;
 
-            Process.run(`rm -rf "${Process.addSlashes(await constants.paths.runnersDir + '/' + name)}"`)
+            Process.run(`rm -rf "${path.addSlashes(await constants.paths.runnersDir + '/' + name)}"`)
                 .then((process) => {
                     process.finish(() => {
                         debugThread.log('Runner deleted');
diff --git a/src/ts/core/promisify.ts b/src/ts/core/promisify.ts
deleted file mode 100644
index b60e499..0000000
--- a/src/ts/core/promisify.ts
+++ /dev/null
@@ -1,83 +0,0 @@
-type callback = () => any;
-
-type PromiseOptions = {
-    callbacks: callback[]|Promise<any>[];
-
-    /**
-     * If true, then all the callbacks will be called
-     * at the same time and promisify will be resolved
-     * when all of them have finished
-     * 
-     * Otherwise, callbacks will be called one after the other
-     * and promisify will be resolved with the last one
-     */
-    callAtOnce?: boolean;
-
-    /**
-     * [callAtOnce: true] updates interval in ms
-     * 
-     * @default 100
-     */
-    interval?: number;
-};
-
-/**
- * Make a promise from the provided function(s) and run it(them)
- */
-export default function promisify(callback: callback|Promise<any>|PromiseOptions): Promise<any>
-{
-    return new Promise(async (resolve) => {
-        // promisify(() => { ... })
-        if (typeof callback === 'function')
-            resolve(await Promise.resolve(callback()));
-
-        // promisify(new Promise(...))
-        else if (typeof callback['then'] === 'function')
-            resolve(await callback);
-        
-        // promisify({ callbacks: [ ... ] })
-        else
-        {
-            let outputs = {};
-
-            // @ts-expect-error
-            if (callback.callAtOnce)
-            {
-                // @ts-expect-error
-                let remained = callback.callbacks.length;
-
-                // @ts-expect-error
-                for (let i = 0; i < callback.callbacks.length; ++i) // @ts-expect-error
-                    promisify(callback.callbacks[i]).then((output) => {
-                        outputs[i] = output;
-
-                        --remained;
-                    });
-
-                const updater = () => {
-                    if (remained > 0) // @ts-expect-error
-                        setTimeout(updater, callback.interval ?? 100);
-
-                    else resolve(outputs);
-                };
-
-                // @ts-expect-error
-                setTimeout(updater, callback.interval ?? 100);
-            }
-
-            else
-            {
-                // @ts-expect-error
-                for (let i = 0; i < callback.callbacks.length; ++i) // @ts-expect-error
-                    outputs[i] = await promisify(callback.callbacks[i]);
-
-                resolve(outputs);
-            }
-        }
-    });
-};
-
-export type {
-    PromiseOptions,
-    callback
-};
diff --git a/src/ts/launcher/Background.ts b/src/ts/launcher/Background.ts
index 24eb7e9..1f2a0d1 100644
--- a/src/ts/launcher/Background.ts
+++ b/src/ts/launcher/Background.ts
@@ -1,5 +1,6 @@
+import { fetch } from '../../empathize';
+
 import constants from '../Constants';
-import fetch from '../core/Fetch';
 import Locales from './Locales';
 
 export default class Background
diff --git a/src/ts/launcher/Locales.ts b/src/ts/launcher/Locales.ts
index fd3b3c7..e1674ad 100644
--- a/src/ts/launcher/Locales.ts
+++ b/src/ts/launcher/Locales.ts
@@ -2,9 +2,9 @@ import { dictionary, locale } from 'svelte-i18n';
 
 import YAML from 'yaml';
 
+import { promisify, Configs } from '../../empathize';
+
 import constants from '../Constants';
-import promisify from '../core/promisify';
-import Configs from '../Configs';
 
 type AvailableLocales =
     | 'en-us'
diff --git a/src/ts/launcher/Shaders.ts b/src/ts/launcher/Shaders.ts
index ef070de..1cc2bfc 100644
--- a/src/ts/launcher/Shaders.ts
+++ b/src/ts/launcher/Shaders.ts
@@ -2,9 +2,9 @@ import YAML from 'yaml';
 
 import type { Shader } from '../types/Shaders';
 
-import Configs from '../Configs';
+import { Configs, promisify } from '../../empathize';
+
 import constants from '../Constants';
-import promisify from '../core/promisify';
 
 declare const Neutralino;
 
diff --git a/src/ts/launcher/State.ts b/src/ts/launcher/State.ts
index d8bfbb6..db83153 100644
--- a/src/ts/launcher/State.ts
+++ b/src/ts/launcher/State.ts
@@ -3,22 +3,20 @@ import { dictionary, locale } from 'svelte-i18n';
 
 import semver from 'semver';
 
-import type { LauncherState } from '../types/Launcher';
+import { Windows, Debug, IPC, Notification } from '../../empathize';
+import { DebugThread } from '@empathize/framework/dist/meta/Debug';
 
-import Window from '../neutralino/Window';
+import type { LauncherState } from '../types/Launcher';
 
 import Launcher from '../Launcher';
 import Game from '../Game';
 import Patch from '../Patch';
 import Voice from '../Voice';
 import Runners from '../core/Runners';
-import Debug, { DebugThread } from '../core/Debug';
 import DXVK from '../core/DXVK';
-import IPC from '../core/IPC';
 import Locales from './Locales';
 import Git from '../core/Git';
 import constants from '../Constants';
-import Notifications from '../core/Notifications';
 
 export default class State
 {
@@ -97,8 +95,8 @@ export default class State
         this.update().then(async () => {
             IPC.write('launcher-loaded');
 
-            await Window.current.show();
-            await Window.current.center(1280, 700);
+            await Windows.current.show();
+            // FIXME: await Windows.current.center(1280, 700);
 
             // Check for new versions of the launcher
             Git.getTags(constants.uri.launcher).then((tags) => {
@@ -110,7 +108,7 @@ export default class State
 
                         const locales = (currentDictionary[currentLocale ?? 'en-us'] ?? currentDictionary['en-us'])['launcher']!['update'] as object;
                         
-                        Notifications.show({
+                        Notification.show({
                             title: locales['title'].replace('{from}', Launcher.version).replace('{to}', tag.tag),
                             body:  locales['body'].replace('{repository}', constants.uri.launcher),
                             icon: `${constants.paths.appDir}/public/images/baal64-transparent.png`
@@ -128,7 +126,7 @@ export default class State
 
                 else
                 {
-                    Window.current.setSize({
+                    Windows.current.setSize({
                         width: 1280 + (1280 - window.innerWidth),
                         height: 700 + (700 - window.innerHeight),
                         resizable: false
@@ -400,7 +398,7 @@ export default class State
                                 {
                                     state = 'game-launch-available';
 
-                                    Notifications.show({
+                                    Notification.show({
                                         title: 'An Anime Game Launcher',
                                         body: 'All the patch repositories are not available. You\'ll be able to run the game, but launcher can\'t be sure is it patched properly',
                                         icon: `${constants.paths.appDir}/public/images/baal64-transparent.png`,
diff --git a/src/ts/launcher/states/ApplyPatch.ts b/src/ts/launcher/states/ApplyPatch.ts
index 8875d23..80f7d19 100644
--- a/src/ts/launcher/states/ApplyPatch.ts
+++ b/src/ts/launcher/states/ApplyPatch.ts
@@ -1,6 +1,7 @@
+import { Notification } from '../../../empathize';
+
 import Launcher from '../../Launcher';
 import Patch from '../../Patch';
-import Notifications from '../../core/Notifications';
 import constants from '../../Constants';
 
 export default (launcher: Launcher): Promise<void> => {
@@ -8,7 +9,7 @@ export default (launcher: Launcher): Promise<void> => {
         // Show an error notification if xdelta3 package is not installed
         if (!await Launcher.isPackageAvailable('xdelta3'))
         {
-            Notifications.show({
+            Notification.show({
                 title: 'An Anime Game Launcher',
                 body: 'You must download xdelta3 package to apply the patch',
                 icon: `${constants.paths.appDir}/public/images/baal64-transparent.png`,
@@ -76,7 +77,7 @@ export default (launcher: Launcher): Promise<void> => {
                             // If for some reasons patch wasn't applied successfully
                             if (!result)
                             {
-                                Notifications.show({
+                                Notification.show({
                                     title: 'An Anime Game Launcher',
                                     body: 'Patch wasn\'t applied successfully. Please, check your log file to find a reason of it, or ask someone in our discord server',
                                     icon: `${constants.paths.appDir}/public/images/baal64-transparent.png`
@@ -89,7 +90,7 @@ export default (launcher: Launcher): Promise<void> => {
                 });
             }
         }).catch(() => {
-            Notifications.show({
+            Notification.show({
                 title: 'An Anime Game Launcher',
                 body: 'All the patch repositories are not available. You\'ll be able to run the game, but launcher can\'t be sure is it patched properly',
                 icon: `${constants.paths.appDir}/public/images/baal64-transparent.png`,
diff --git a/src/ts/launcher/states/Install.ts b/src/ts/launcher/states/Install.ts
index 40b80db..b38bb6c 100644
--- a/src/ts/launcher/states/Install.ts
+++ b/src/ts/launcher/states/Install.ts
@@ -3,10 +3,11 @@ import { _ } from 'svelte-i18n';
 
 import type Launcher from '../../Launcher';
 
+import { Debug } from '../../../empathize';
+
 import Game from '../../Game';
 import Prefix from '../../core/Prefix';
 import constants from '../../Constants';
-import Debug from '../../core/Debug';
 
 declare const Neutralino;
 
diff --git a/src/ts/launcher/states/InstallVoice.ts b/src/ts/launcher/states/InstallVoice.ts
index 0d8182c..8e801e7 100644
--- a/src/ts/launcher/states/InstallVoice.ts
+++ b/src/ts/launcher/states/InstallVoice.ts
@@ -4,8 +4,9 @@ import { _ } from 'svelte-i18n';
 import type Launcher from '../../Launcher';
 import type { VoiceLang } from '../../types/Voice';
 
+import { promisify } from '../../../empathize';
+
 import Voice from '../../Voice';
-import promisify from '../../core/promisify';
 import Game from '../../Game';
 
 export default (launcher: Launcher): Promise<void> => {
diff --git a/src/ts/launcher/states/Launch.ts b/src/ts/launcher/states/Launch.ts
index e3c5f42..965e910 100644
--- a/src/ts/launcher/states/Launch.ts
+++ b/src/ts/launcher/states/Launch.ts
@@ -1,11 +1,8 @@
-import Process from '../../neutralino/Process';
-import Window from '../../neutralino/Window';
+import { Process, Windows, Configs, Notification, path } from '../../../empathize';
+import { DebugThread } from '@empathize/framework/dist/meta/Debug';
 
 import Launcher from '../../Launcher';
-import Configs from '../../Configs';
 import constants from '../../Constants';
-import { DebugThread } from '../../core/Debug';
-import Notifications from '../../core/Notifications';
 import Runners from '../../core/Runners';
 import Game from '../../Game';
 
@@ -20,7 +17,7 @@ export default (launcher: Launcher): Promise<void> => {
         // If telemetry servers are not disabled
         if (!telemetry)
         {
-            Notifications.show({
+            Notification.show({
                 title: 'An Anime Game Launcher',
                 body: 'Telemetry servers are not disabled',
                 icon: `${constants.paths.appDir}/public/images/baal64-transparent.png`,
@@ -33,7 +30,7 @@ export default (launcher: Launcher): Promise<void> => {
         // Otherwise run the game
         else
         {
-            Window.current.hide();
+            Windows.current.hide();
 
             launcher.updateDiscordRPC('in-game');
 
@@ -139,7 +136,7 @@ export default (launcher: Launcher): Promise<void> => {
                 else console.warn(`GPU ${LauncherLib.getConfig('gpu')} not found. Launching on the default GPU`);
             }*/
 
-            let command = `"${Process.addSlashes(wineExeutable)}" ${await Configs.get('fps_unlocker') ? 'unlockfps.bat' : 'launcher.bat'}`;
+            let command = `"${path.addSlashes(wineExeutable)}" ${await Configs.get('fps_unlocker') ? 'unlockfps.bat' : 'launcher.bat'}`;
 
             /**
              * Gamemode integration
@@ -208,8 +205,8 @@ export default (launcher: Launcher): Promise<void> => {
                     {
                         const stopTime = Date.now();
 
-                        Window.current.show();
-                        Window.current.center(1280, 700);
+                        Windows.current.show();
+                        // FIXME: Windows.current.center(1280, 700);
 
                         launcher.updateDiscordRPC('in-launcher');
                         launcher.tray.hide();
@@ -218,7 +215,7 @@ export default (launcher: Launcher): Promise<void> => {
                         Configs.get('purge_logs.game').then(async (purge_logs) => {
                             if (purge_logs)
                             {
-                                const gameDir = Process.addSlashes(await constants.paths.gameDir);
+                                const gameDir = path.addSlashes(await constants.paths.gameDir);
 
                                 // Delete .log files (e.g. "ZFGameBrowser_xxxx.log")
                                 Neutralino.os.execCommand(`find "${gameDir}" -maxdepth 1 -type f -name "*.log" -delete`);
diff --git a/src/ts/launcher/states/PredownloadVoice.ts b/src/ts/launcher/states/PredownloadVoice.ts
index 9aaa3c2..4c441f4 100644
--- a/src/ts/launcher/states/PredownloadVoice.ts
+++ b/src/ts/launcher/states/PredownloadVoice.ts
@@ -1,8 +1,9 @@
 import type Launcher from '../../Launcher';
 import type { VoiceLang } from '../../types/Voice';
 
+import { promisify } from '../../../empathize';
+
 import Voice from '../../Voice';
-import promisify from '../../core/promisify';
 
 export default (launcher: Launcher): Promise<void> => {
     return new Promise(async (resolve) => {
diff --git a/src/ts/neutralino/Process.ts b/src/ts/neutralino/Process.ts
deleted file mode 100644
index 1f827ec..0000000
--- a/src/ts/neutralino/Process.ts
+++ /dev/null
@@ -1,267 +0,0 @@
-import constants from '../Constants';
-import Debug, { DebugThread } from "../core/Debug";
-
-declare const Neutralino;
-declare const NL_CWD;
-
-type ProcessOptions = {
-    /**
-     * Environment variables
-     */
-    env?: object;
-
-    /**
-     * Current working directory for the running process
-     */
-    cwd?: string;
-
-    /**
-     * Interval between tries to find started process id
-     * 
-     * @default 50
-     */
-    childInterval?: number;
-};
-
-class Process
-{
-    /**
-     * Process ID
-     */
-    public readonly id: number;
-
-    /**
-     * Interval in ms between process status update
-     * 
-     * null if you don't want to update process status
-     * 
-     * @default 200
-     */
-    public runningInterval: number|null = 200;
-
-    /**
-     * Interval in ms between process output update
-     * 
-     * null if you don't want to update process output
-     * 
-     * @default 500
-     */
-    public outputInterval: number|null = 500;
-
-    protected outputFile: string|null;
-    protected outputOffset: number = 0;
-
-    protected _finished: boolean = false;
-
-    /**
-     * Whether the process was finished
-     */
-    public get finished(): boolean
-    {
-        return this._finished;
-    };
-
-    protected onOutput?: (output: string, process: Process) => void;
-    protected onFinish?: (process: Process) => void;
-
-    public constructor(pid: number, outputFile: string|null = null)
-    {
-        const debugThread = new DebugThread('Process/Stream', `Opened process ${pid} stream`);
-
-        this.id = pid;
-        this.outputFile = outputFile;
-
-        const updateStatus = () => {
-            this.running().then((running) => {
-                // The process is still running
-                if (running)
-                {
-                    if (this.runningInterval)
-                        setTimeout(updateStatus, this.runningInterval);
-                }
-
-                // Otherwise the process was stopped
-                else
-                {
-                    this._finished = true;
-
-                    debugThread.log('Process stopped');
-
-                    if (this.onFinish)
-                        this.onFinish(this);
-                }
-            });
-        };
-
-        if (this.runningInterval)
-            setTimeout(updateStatus, this.runningInterval);
-
-        if (this.outputFile)
-        {
-            const updateOutput = () => {
-                Neutralino.filesystem.readFile(this.outputFile)
-                    .then((output: string) => {
-                        if (this.onOutput)
-                            this.onOutput(output.substring(this.outputOffset), this);
-
-                        this.outputOffset = output.length;
-
-                        if (this._finished)
-                        {
-                            if (output !== '')
-                            {
-                                debugThread.log({
-                                    message: [
-                                        'Process output:',
-                                        ...output.split(/\r\n|\r|\n/)
-                                    ]
-                                });
-                            }
-
-                            Neutralino.filesystem.removeFile(this.outputFile);
-                        }
-
-                        else if (this.outputInterval)
-                            setTimeout(updateOutput, this.outputInterval);
-                    })
-                    .catch(() => {
-                        if (this.outputInterval && !this._finished)
-                            setTimeout(updateOutput, this.outputInterval);
-                    });
-            };
-
-            if (this.outputInterval)
-                setTimeout(updateOutput, this.outputInterval);
-        }
-    }
-
-    /**
-     * Specify callback to run when the process will be finished
-     */
-    public finish(callback: (process: Process) => void)
-    {
-        this.onFinish = callback;
-
-        if (this._finished)
-            callback(this);
-
-        // If user stopped process status auto-checking
-        // then we should check it manually when this method was called
-        else if (this.runningInterval === null)
-        {
-            this.running().then((running) => {
-                if (!running)
-                {
-                    this._finished = true;
-
-                    callback(this);
-                }
-            });
-        }
-    }
-
-    public output(callback: (output: string, process: Process) => void)
-    {
-        this.onOutput = callback;
-    }
-
-    /**
-     * Kill process
-     */
-    public kill(forced: boolean = false): Promise<void>
-    {
-        Neutralino.filesystem.removeFile(this.outputFile);
-
-        return Process.kill(this.id, forced);
-    }
-
-    /**
-     * Returns whether the process is running
-     * 
-     * This method doesn't call onFinish event
-     */
-    public running(): Promise<boolean>
-    {
-        return new Promise((resolve) => {
-            Neutralino.os.execCommand(`ps -p ${this.id} -S`).then((output) => {
-                resolve(output.stdOut.includes(this.id) && !output.stdOut.includes('Z   '));
-            });
-        });
-    }
-
-    /**
-     * Run shell command
-     */
-    public static run(command: string, options: ProcessOptions = {}): Promise<Process>
-    {
-        return new Promise(async (resolve) => {
-            const tmpFile = `${await constants.paths.tempDir}/${10000 + Math.round(Math.random() * 89999)}.tmp`;
-
-            // Set env variables
-            if (options.env)
-                for (const key of Object.keys(options.env))
-                    command = `${key}="${this.addSlashes(options.env![key].toString())}" ${command}`;
-
-            // Set output redirection to the temp file
-            command = `${command} > "${this.addSlashes(tmpFile)}" 2>&1`;
-
-            // Set current working directory
-            if (options.cwd)
-                command = `cd "${this.addSlashes(options.cwd)}" && ${command}`;
-
-            // And run the command
-            const process = await Neutralino.os.execCommand(command, {
-                background: true
-            });
-
-            const childFinder = async () => {
-                const childProcess = await Neutralino.os.execCommand(`pgrep -P ${process.pid}`);
-
-                // Child wasn't found
-                if (childProcess.stdOut == '')
-                    setTimeout(childFinder, options.childInterval ?? 50);
-
-                // Otherwise return its id
-                else
-                {
-                    const processId = parseInt(childProcess.stdOut.substring(0, childProcess.stdOut.length - 1));
-
-                    Debug.log({
-                        function: 'Process.run',
-                        message: {
-                            'running command': command,
-                            'cwd': options.cwd,
-                            'initial process id': process.pid,
-                            'real process id': processId,
-                            ...options.env
-                        }
-                    });
-        
-                    resolve(new Process(processId, tmpFile));
-                }
-            };
-
-            setTimeout(childFinder, options.childInterval ?? 50);
-        });
-    }
-
-    public static kill(id: number, forced: boolean = false): Promise<void>
-    {
-        return new Promise((resolve) => {
-            Neutralino.os.execCommand(`kill ${forced ? '-9' : '-15'} ${id}`).then(() => resolve());
-        });
-    }
-
-    /**
-     * Replace '\a\b' to '\\a\\b'
-     * And replace ''' to '\''
-     */
-    public static addSlashes(str: string): string
-    {
-        return str.replaceAll('\\', '\\\\').replaceAll('"', '\\"');
-    }
-}
-
-export type { ProcessOptions };
-
-export default Process;
diff --git a/src/ts/neutralino/Tray.ts b/src/ts/neutralino/Tray.ts
deleted file mode 100644
index c02b4d0..0000000
--- a/src/ts/neutralino/Tray.ts
+++ /dev/null
@@ -1,120 +0,0 @@
-declare const Neutralino;
-
-type Item = {
-    /**
-     * Item text
-     */
-    text: string;
-
-    /**
-     * Item id
-     */
-    id?: string;
-
-    /**
-     * Whether the item disabled or not
-     * 
-     * If yes, then it will be a string
-     */
-    disabled?: boolean;
-
-    /**
-     * Is this item a checkbox or not
-     */
-    checked?: boolean;
-
-    /**
-     * Event on click
-     * 
-     * If specified, then will generate random
-     * item id if it is not specified
-     */
-    click?: (item: Item) => void;
-};
-
-Neutralino.events.on('trayMenuItemClicked', (item) => {
-    for (const tray of Tray.trays)
-        for (const trayItem of tray.items)
-            if (trayItem.id === item.detail.id)
-            {
-                if (trayItem.click)
-                {
-                    trayItem.click({
-                        id: item.detail.id,
-                        text: item.detail.text,
-                        disabled: item.detail['isDisabled'],
-                        checked: item.detail['isChecked'],
-                        click: trayItem.click
-                    });
-                }
-
-                return;
-            }
-});
-
-export default class Tray
-{
-    public static trays: Tray[] = [];
-
-    public icon: string;
-
-    protected _items: Item[] = [];
-
-    public get items(): Item[]
-    {
-        return this._items.map((item) => {
-            return {
-                id: item.id,
-                text: item.text,
-                disabled: item['isDisabled'],
-                checked: item['isChecked'],
-                click: item.click
-            };
-        });
-    }
-
-    public set items(items: Item[])
-    {
-        this._items = items.map((item) => {
-            if (item.id === undefined && item.click !== undefined)
-                item.id = 'click:' + Math.random().toString().substring(2);
-            
-            return {
-                id: item.id,
-                text: item.text,
-                isDisabled: item.disabled,
-                isChecked: item.checked,
-                click: item.click
-            };
-        });
-    }
-
-    public constructor(icon: string, items: Item[] = [])
-    {
-        this.icon = icon;
-        this.items = items;
-
-        Tray.trays.push(this);
-    }
-
-    public update(items: Item[]|null = null): Promise<void>
-    {
-        if (items !== null)
-            this.items = items;
-        
-        return Neutralino.os.setTray({
-            icon: this.icon,
-            menuItems: this._items
-        });
-    }
-
-    public hide(): Promise<void>
-    {
-        return Neutralino.os.setTray({
-            icon: this.icon,
-            menuItems: []
-        });
-    }
-};
-
-export type { Item };
diff --git a/src/ts/neutralino/Window.ts b/src/ts/neutralino/Window.ts
deleted file mode 100644
index 440b650..0000000
--- a/src/ts/neutralino/Window.ts
+++ /dev/null
@@ -1,82 +0,0 @@
-type WindowSize = {
-    width?: number;
-    height?: number;
-    minWidth?: number;
-    minHeight?: number;
-    maxWidth?: number;
-    maxHeight?: number;
-    resizable?: boolean;
-};
-
-type WindowOptions = WindowSize & {
-    title?: string;
-    icon?: string;
-    fullScreen?: boolean;
-    alwaysOnTop?: boolean;
-    enableInspector?: boolean;
-    borderless?: boolean;
-    maximize?: boolean;
-    hidden?: boolean;
-    maximizable?: boolean;
-    exitProcessOnClose?: boolean;
-    processArgs?: string;
-};
-
-type WindowOpenResult = {
-    status: boolean;
-    data?: {
-        pid: number;
-        stdOut: string;
-        stdErr: string;
-        exitCode: number;
-    };
-};
-
-declare const Neutralino;
-
-class Window
-{
-    public static get current(): any
-    {
-        return {
-            ...Neutralino.window,
-
-            center(windowWidth: number, windowHeight: number)
-            {
-                Neutralino.window.move(Math.round((window.screen.width - windowWidth) / 2), Math.round((window.screen.height - windowHeight) / 2));
-            }
-        };
-    }
-
-    public static open(name: string, options: WindowOptions = {}): Promise<WindowOpenResult>
-    {
-        return new Promise(async (resolve) => {
-            const status = await Neutralino.window.create(`/${name}.html`, {
-                width: 600,
-                height: 400,
-                enableInspector: false,
-                exitProcessOnClose: true,
-
-                ...options,
-
-                // So basically you should display the window manually
-                // with Window.current.show() when your app will load
-                // all its content there
-                hidden: true
-            });
-
-            resolve({
-                status: status !== undefined,
-                data: status
-            });
-        });
-    }
-}
-
-export type {
-    WindowSize,
-    WindowOptions,
-    WindowOpenResult
-};
-
-export default Window;
diff --git a/src/ts/types/Archive.d.ts b/src/ts/types/Archive.d.ts
deleted file mode 100644
index 414f045..0000000
--- a/src/ts/types/Archive.d.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-type ArchiveType =
-    | 'tar'
-    | 'zip'
-    | null;
-
-type Size = {
-    compressed?: number | null;
-    uncompressed?: number | null;
-};
-
-type File = {
-    path: string;
-    size: Size;
-};
-
-type ArchiveInfo = {
-    size: Size;
-    type: ArchiveType;
-    files: File[];
-};
-
-export type {
-    ArchiveType,
-    Size,
-    File,
-    ArchiveInfo
-};
diff --git a/src/ts/types/Debug.d.ts b/src/ts/types/Debug.d.ts
deleted file mode 100644
index f8715bd..0000000
--- a/src/ts/types/Debug.d.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-type DebugOptions = {
-    /**
-     * Some random-generated thread id
-     */
-    thread?: number;
-
-    /**
-     * Some function name
-     */
-    function?: string;
-
-    /**
-     * Some log message
-     */
-    message: string|string[]|object;
-};
-
-type LogRecord = {
-    time: number;
-    log: string[];
-};
-
-export type { DebugOptions, LogRecord };
diff --git a/src/ts/types/Domain.d.ts b/src/ts/types/Domain.d.ts
deleted file mode 100644
index a9ef794..0000000
--- a/src/ts/types/Domain.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-type DomainInfo = {
-    uri: string;
-    remoteIp?: string;
-    localIp?: string;
-    available: boolean;
-};
-
-export type { DomainInfo };
diff --git a/src/ts/types/Notifications.d.ts b/src/ts/types/Notifications.d.ts
deleted file mode 100644
index b3e1e4c..0000000
--- a/src/ts/types/Notifications.d.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-type NotificationsOptions = {
-    title: string;
-    body: string;
-
-    /**
-     * Icon name or path
-     */
-    icon?: string;
-
-    /**
-     * Number of seconds this notification
-     * will be visible
-     */
-    duration?: number;
-
-    /**
-     * Importance of the notification
-     * 
-     * @default "normal"
-     */
-    importance?: 'low' | 'normal' | 'critical';
-};
-
-export type { NotificationsOptions };
diff --git a/tsconfig.json b/tsconfig.json
index 4b17e3a..292bfda 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -2,12 +2,12 @@
   "extends": "@tsconfig/svelte/tsconfig.json",
   "compilerOptions": {
     "target": "esnext",
-    "useDefineForClassFields": true,
     "module": "esnext",
     "strict": true,
     "noImplicitAny": false,
     "removeComments": true,
     "resolveJsonModule": true,
+    "useDefineForClassFields": true,
     /**
      * Typecheck JS in `.svelte` and `.js` files by default.
      * Disable checkJs if you'd like to use dynamic types in JS.