diff --git a/README.md b/README.md
index 94e3b3f3..f5c9ec84 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,15 @@
 # shapez.io
 
 
-
 
 This is the source code for shapez.io, an open source base building game inspired by Factorio.
-
 Your goal is to produce shapes by cutting, rotating, merging and painting parts of shapes.
 
-## Playing
-
-You can already play it [here](https://shapez.io).
+-   [Trello Board & Roadmap](https://trello.com/b/ISQncpJP/shapezio)
+-   [Free web version](https://shapez.io)
+-   [itch.io Page](https://tobspr.itch.io/shapezio)
+-   [Steam Page](https://steam.shapez.io)
+-   [Official Discord](https://discord.com/invite/HN7EVzV) <- _Highly recommended to join!_
 
 ## Building
 
@@ -46,3 +46,5 @@ This project is based on ES5. Some ES2015 features are used but most of them are
 For most assets I use Adobe Photoshop, you can find them in `assets/`.
 
 You will need a Texture Packer license in order to regenerate the atlas. If you don't have one but want to contribute assets, let me know and I might compile it for you. I'm currently switching to an open source solution but I can't give an estimate when thats done.
+
+
diff --git a/gulp/.itch.toml b/gulp/.itch.toml
new file mode 100644
index 00000000..2556ac9c
--- /dev/null
+++ b/gulp/.itch.toml
@@ -0,0 +1,9 @@
+[[actions]]
+name = "play"
+path = "shapezio.exe"
+platform = "windows"
+
+[[actions]]
+name = "play"
+path = "play.sh"
+platform = "linux"
diff --git a/gulp/standalone.js b/gulp/standalone.js
index 34001e07..6c5995bd 100644
--- a/gulp/standalone.js
+++ b/gulp/standalone.js
@@ -121,6 +121,8 @@ function gulptasksStandalone($, gulp, buildFolder) {
      * @param {boolean=} isRelease
      */
     function packageStandalone(platform, arch, cb, isRelease = false) {
+        const tomlFile = fs.readFileSync(path.join(__dirname, ".itch.toml"));
+
         packager({
             dir: tempDestBuildDir,
             appCopyright: "Tobias Springer",
@@ -150,17 +152,25 @@ function gulptasksStandalone($, gulp, buildFolder) {
                         fs.readFileSync(path.join(__dirname, "..", "LICENSE"))
                     );
 
-                    const playablePath = appPath + "_playable";
-                    fse.copySync(appPath, playablePath);
-                    fs.writeFileSync(path.join(playablePath, "steam_appid.txt"), "1134480");
-                    fs.writeFileSync(
-                        path.join(playablePath, "play.bat"),
-                        "start shapezio --dev --disable-direct-composition --in-process-gpu\r\n"
-                    );
-                    fs.writeFileSync(
-                        path.join(playablePath, "play_local.bat"),
-                        "start shapezio --local --dev --disable-direct-composition --in-process-gpu\r\n"
-                    );
+                    fs.writeFileSync(path.join(appPath, ".itch.toml"), tomlFile);
+
+                    if (platform === "linux" || platform === "darwin") {
+                        fs.writeFileSync(path.join(appPath, "play.sh"), "#!/usr/bin/env bash\n./shapezio\n");
+                        fs.chmodSync(path.join(appPath, "play.sh"), 0o775);
+                    } else if (platform === "win32") {
+                        // Optional: Create a playable copy. Shouldn't be required
+                        // const playablePath = appPath + "_playable";
+                        // fse.copySync(appPath, playablePath);
+                        // fs.writeFileSync(path.join(playablePath, "steam_appid.txt"), "1134480");
+                        // fs.writeFileSync(
+                        //     path.join(playablePath, "play.bat"),
+                        //     "start shapezio --dev --disable-direct-composition --in-process-gpu\r\n"
+                        // );
+                        // fs.writeFileSync(
+                        //     path.join(playablePath, "play_local.bat"),
+                        //     "start shapezio --local --dev --disable-direct-composition --in-process-gpu\r\n"
+                        // );
+                    }
                 });
 
                 cb();
@@ -182,10 +192,10 @@ function gulptasksStandalone($, gulp, buildFolder) {
         "standalone.package.prod",
         $.sequence("standalone.prepare", [
             "standalone.package.prod.win64",
-            // "standalone.package.prod.linux64",
+            "standalone.package.prod.linux64",
+            "standalone.package.prod.darwin64",
             // "standalone.package.prod.win32",
             // "standalone.package.prod.linux32",
-            // "standalone.package.prod.darwin64"
         ])
     );
 }
diff --git a/package.json b/package.json
index 64bc8ac1..8774e693 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,8 @@
         "tslint": "cd src/js && tsc",
         "lint": "npx eslint src/js",
         "prettier-all": "prettier --write src/**/*.* && prettier --write gulp/**/*.*",
-        "publishOnItch": "butler push tmp_standalone_files/shapez.io-standalone-win32-x64 tobspr/shapezio:windows --userversion-file version",
+        "publishOnItchWindows": "butler push tmp_standalone_files/shapez.io-standalone-win32-x64 tobspr/shapezio:windows --userversion-file version",
+        "publishOnItchLinux": "butler push tmp_standalone_files/shapez.io-standalone-linux-x64 tobspr/shapezio:linux-experimental --userversion-file version",
         "publishOnSteam": "cd gulp/steampipe && ./upload.bat",
         "publishStandalone": "yarn publishOnItch && yarn publishOnSteam",
         "publishWeb": "cd gulp && yarn main.deploy.prod",
diff --git a/src/css/ingame_hud/buildings_toolbar.scss b/src/css/ingame_hud/buildings_toolbar.scss
index 740e1f58..13da9f99 100644
--- a/src/css/ingame_hud/buildings_toolbar.scss
+++ b/src/css/ingame_hud/buildings_toolbar.scss
@@ -11,7 +11,11 @@
     border-bottom-width: 0;
     transition: transform 0.12s ease-in-out;
 
-    background: rgba(mix(#ddd, $colorBlueBright, 80%), 0.69);
+    background: rgba(mix(#ddd, $colorBlueBright, 90%), 0.75);
+
+    @include DarkThemeOverride {
+        background: #222428;
+    }
 
     &:not(.visible) {
         transform: translateX(-50%) translateY(#{D(100px)});
diff --git a/src/css/ingame_hud/keybindings_overlay.scss b/src/css/ingame_hud/keybindings_overlay.scss
index 1737e7b1..5a238f81 100644
--- a/src/css/ingame_hud/keybindings_overlay.scss
+++ b/src/css/ingame_hud/keybindings_overlay.scss
@@ -6,8 +6,12 @@
     display: flex;
     flex-direction: column;
     align-items: flex-start;
-    color: #fff;
-    text-shadow: #{D(1px)} #{D(1px)} 0 rgba(0, 10, 20, 0.1);
+    color: #333438;
+    // text-shadow: #{D(1px)} #{D(1px)} 0 rgba(0, 10, 20, 0.1);
+
+    @include DarkThemeOverride {
+        color: #fff;
+    }
 
     > .binding {
         display: inline-grid;
@@ -42,10 +46,13 @@
         }
 
         label {
-            color: $accentColorDark;
+            color: #333438;
             @include SuperSmallText;
             text-transform: uppercase;
-            color: #fff;
+            // color: #fff;
+            @include DarkThemeOverride {
+                color: #fff;
+            }
 
             @include S(margin-left, 5px);
         }
diff --git a/src/css/ingame_hud/pinned_shapes.scss b/src/css/ingame_hud/pinned_shapes.scss
index afedd6a5..1c944e35 100644
--- a/src/css/ingame_hud/pinned_shapes.scss
+++ b/src/css/ingame_hud/pinned_shapes.scss
@@ -16,8 +16,8 @@
         grid-template-columns: auto 1fr;
         grid-template-rows: 1fr 1fr;
         @include S(margin-bottom, 4px);
-        color: #fff;
-        text-shadow: #{D(1px)} #{D(1px)} 0 rgba(0, 10, 20, 0.2);
+        color: #333438;
+        // text-shadow: #{D(1px)} #{D(1px)} 0 rgba(0, 10, 20, 0.2);
 
         &.unpinable {
             > canvas {
@@ -59,7 +59,7 @@
 
         > .goalLabel {
             @include S(font-size, 7px);
-            opacity: 0.5;
+            opacity: 0.9;
             align-self: start;
             justify-self: start;
             font-weight: normal;
@@ -81,7 +81,6 @@
                     display: inline-block;
                     @include S(width, 8px);
                     @include S(height, 8px);
-                    opacity: 0.8;
                     @include S(top, 4px);
                     @include S(left, -7px);
                     background: uiResource("icons/current_goal_marker.png") center center / contain no-repeat;
diff --git a/src/css/ingame_hud/waypoints.scss b/src/css/ingame_hud/waypoints.scss
index fbb430fd..6517bbcf 100644
--- a/src/css/ingame_hud/waypoints.scss
+++ b/src/css/ingame_hud/waypoints.scss
@@ -38,13 +38,13 @@
         @include SuperSmallText;
         pointer-events: all;
         cursor: pointer;
-        color: #000;
+        color: #333438;
         @include S(padding-left, 11px);
         display: grid;
         grid-template-columns: 1fr auto;
         align-items: center;
         background: uiResource("icons/waypoint.png") left 50% / #{D(8px)} no-repeat;
-        opacity: 0.5;
+        opacity: 0.7;
         @include S(margin-bottom, 1px);
         font-weight: bold;
         &:hover {
diff --git a/src/css/states/preload.scss b/src/css/states/preload.scss
index 68a268e1..9bd23358 100644
--- a/src/css/states/preload.scss
+++ b/src/css/states/preload.scss
@@ -36,6 +36,9 @@
                 @include S(padding, 1px, 2px);
                 @include S(margin-right, 3px);
             }
+            a {
+                color: $colorBlueBright;
+            }
         }
     }
 
diff --git a/src/html/index.html b/src/html/index.html
index b1d89377..243455ea 100644
--- a/src/html/index.html
+++ b/src/html/index.html
@@ -40,6 +40,9 @@
         
         
         
+
+        
+        
     
 
     
diff --git a/src/js/changelog.js b/src/js/changelog.js
index 4d8844c8..0559801f 100644
--- a/src/js/changelog.js
+++ b/src/js/changelog.js
@@ -1,11 +1,25 @@
 export const CHANGELOG = [
     {
-        version: "1.1.2",
-        date: "unreleased",
+        version: "1.1.3",
+        date: "01.06.2020",
         entries: [
+            "Added setting to configure zoom / mouse wheel / touchpad sensitivity",
+            "Fix belts being too slow when copied via blueprint (by Dimava)",
+            "Allow binding mouse buttons to actions (by Dimava)",
+            "Increase readability of certain HUD elements",
+        ],
+    },
+    {
+        version: "1.1.2",
+        date: "30.05.2020",
+        entries: [
+            "The official trailer is now ready! Check it out here!",
+            "The steam page is now live!",
+            "Experimental linux builds are now available! Please give me feedback on them in the discord",
             "Allow hovering pinned shapes to enlarge them",
+            "Allow deselecting blueprints with right click and 'Q'",
             "Move default key for deleting from 'X' to 'DEL'",
-            "Show confirmation when deleting > 100 buildings",
+            "Show confirmation when deleting more than 100 buildings",
             "Reintroduce 'SPACE' keybinding to center on map",
             "Improved keybinding hints",
             "Fixed some keybindings showing as 'undefined'",
diff --git a/src/js/core/click_detector.js b/src/js/core/click_detector.js
index 557c1f28..1e332aa2 100644
--- a/src/js/core/click_detector.js
+++ b/src/js/core/click_detector.js
@@ -311,7 +311,7 @@ export class ClickDetector {
         const position = /** @type {typeof ClickDetector} */ (this.constructor).extractPointerPosition(event);
 
         if (event instanceof MouseEvent) {
-            const isRightClick = event.which == 3;
+            const isRightClick = event.button === 2;
             if (isRightClick) {
                 // Ignore right clicks
                 this.rightClick.dispatch(position, event);
@@ -384,7 +384,7 @@ export class ClickDetector {
         }
 
         if (event instanceof MouseEvent) {
-            const isRightClick = event.which == 3;
+            const isRightClick = event.button === 2;
             if (isRightClick) {
                 return;
             }
diff --git a/src/js/core/config.js b/src/js/core/config.js
index 5b802de3..c84dee3a 100644
--- a/src/js/core/config.js
+++ b/src/js/core/config.js
@@ -83,7 +83,7 @@ export const globalConfig = {
 
     debug: {
         /* dev:start */
-        fastGameEnter: true,
+        // fastGameEnter: true,
         // noArtificialDelays: true,
         // disableSavegameWrite: true,
         // showEntityBounds: true,
diff --git a/src/js/core/input_distributor.js b/src/js/core/input_distributor.js
index 4bd476b4..03ad8e0c 100644
--- a/src/js/core/input_distributor.js
+++ b/src/js/core/input_distributor.js
@@ -141,8 +141,13 @@ export class InputDistributor {
     bindToEvents() {
         window.addEventListener("popstate", this.handleBackButton.bind(this), false);
         document.addEventListener("backbutton", this.handleBackButton.bind(this), false);
-        window.addEventListener("keydown", this.handleKeydown.bind(this));
-        window.addEventListener("keyup", this.handleKeyup.bind(this));
+
+        window.addEventListener("keydown", this.handleKeyMouseDown.bind(this));
+        window.addEventListener("keyup", this.handleKeyMouseUp.bind(this));
+
+        window.addEventListener("mousedown", this.handleKeyMouseDown.bind(this));
+        window.addEventListener("mouseup", this.handleKeyMouseUp.bind(this));
+
         window.addEventListener("blur", this.handleBlur.bind(this));
     }
 
@@ -182,25 +187,28 @@ export class InputDistributor {
     }
 
     /**
-     * @param {KeyboardEvent} event
+     * @param {KeyboardEvent | MouseEvent} event
      */
-    handleKeydown(event) {
+    handleKeyMouseDown(event) {
+        const keyCode = event instanceof MouseEvent ? event.button + 1 : event.keyCode;
         if (
-            event.keyCode === 9 || // TAB
-            event.keyCode === 16 || // SHIFT
-            event.keyCode === 17 || // CTRL
-            event.keyCode === 18 || // ALT
-            (event.keyCode >= 112 && event.keyCode < 122) // F1 - F10
+            keyCode === 4 || // MB4
+            keyCode === 5 || // MB5
+            keyCode === 9 || // TAB
+            keyCode === 16 || // SHIFT
+            keyCode === 17 || // CTRL
+            keyCode === 18 || // ALT
+            (keyCode >= 112 && keyCode < 122) // F1 - F10
         ) {
             event.preventDefault();
         }
 
-        const isInitial = !this.keysDown.has(event.keyCode);
-        this.keysDown.add(event.keyCode);
+        const isInitial = !this.keysDown.has(keyCode);
+        this.keysDown.add(keyCode);
 
         if (
             this.forwardToReceiver("keydown", {
-                keyCode: event.keyCode,
+                keyCode: keyCode,
                 shift: event.shiftKey,
                 alt: event.altKey,
                 initial: isInitial,
@@ -210,8 +218,7 @@ export class InputDistributor {
             return;
         }
 
-        const code = event.keyCode;
-        if (code === 27) {
+        if (keyCode === 27) {
             // Escape key
             event.preventDefault();
             event.stopPropagation();
@@ -220,13 +227,14 @@ export class InputDistributor {
     }
 
     /**
-     * @param {KeyboardEvent} event
+     * @param {KeyboardEvent | MouseEvent} event
      */
-    handleKeyup(event) {
-        this.keysDown.delete(event.keyCode);
+    handleKeyMouseUp(event) {
+        const keyCode = event instanceof MouseEvent ? event.button + 1 : event.keyCode;
+        this.keysDown.delete(keyCode);
 
         this.forwardToReceiver("keyup", {
-            keyCode: event.keyCode,
+            keyCode: keyCode,
             shift: event.shiftKey,
             alt: event.altKey,
         });
diff --git a/src/js/core/utils.js b/src/js/core/utils.js
index f756a651..e50b71c8 100644
--- a/src/js/core/utils.js
+++ b/src/js/core/utils.js
@@ -24,9 +24,7 @@ export const BOTTOM = new Vector(0, 1);
 export const LEFT = new Vector(-1, 0);
 export const ALL_DIRECTIONS = [TOP, RIGHT, BOTTOM, LEFT];
 
-export const thousand = 1000;
-export const million = 1000 * 1000;
-export const billion = 1000 * 1000 * 1000;
+const bigNumberSuffixTranslationKeys = ["thousands", "millions", "billions", "trillions"];
 
 /**
  * Returns the build id
@@ -435,21 +433,20 @@ export function formatBigNumber(num, divider = ".") {
 
     if (num < 1000) {
         return sign + "" + num;
+    } else {
+        let leadingDigits = num;
+        let suffix = "";
+        for (let suffixIndex = 0; suffixIndex < bigNumberSuffixTranslationKeys.length; ++suffixIndex) {
+            leadingDigits = leadingDigits / 1000;
+            suffix = T.global.suffix[bigNumberSuffixTranslationKeys[suffixIndex]];
+            if (leadingDigits < 1000) {
+                break;
+            }
+        }
+        const leadingDigitsRounded = round1Digit(leadingDigits);
+        const leadingDigitsNoTrailingDecimal = leadingDigitsRounded.toString().replace(".0", "");
+        return sign + leadingDigitsNoTrailingDecimal + suffix;
     }
-    if (num > 10000) {
-        return Math_floor(num / 1000.0) + "k";
-    }
-
-    let rest = num;
-    let out = "";
-
-    while (rest >= 1000) {
-        out = (rest % 1000).toString().padStart(3, "0") + (out !== "" ? divider : "") + out;
-        rest = Math_floor(rest / 1000);
-    }
-
-    out = rest + divider + out;
-    return sign + out;
 }
 
 /**
@@ -731,14 +728,14 @@ export function checkTimerExpired(now, lastTick, tickRate) {
     Client A computes the timer and checks T > lastTick + interval. He computes
 
     30 >= 29.90 + 0.1   <=> 30 >= 30.0000  <=> True  <=> Tick performed
-    
+
     However, this is what it looks on client B:
-    
+
     33 >= 32.90 + 0.1   <=> 33 >= 32.999999999999998 <=> False <=> No tick performed!
-    
+
     This means that Client B will only tick at the *next* frame, which means it from now is out
     of sync by one tick, which means the game will resync further or later and be not able to recover,
-    since it will run into the same issue over and over. 
+    since it will run into the same issue over and over.
     */
 
     // The next tick, in our example it would be 30.0000 / 32.99999999998. In order to fix it, we quantize
diff --git a/src/js/game/camera.js b/src/js/game/camera.js
index 96bf5cd0..1a389cad 100644
--- a/src/js/game/camera.js
+++ b/src/js/game/camera.js
@@ -440,11 +440,11 @@ export class Camera extends BasicSerializableObject {
         }
 
         this.touchPostMoveVelocity = new Vector(0, 0);
-        if (event.which === 1) {
+        if (event.button === 0) {
             this.combinedSingleTouchStartHandler(event.clientX, event.clientY);
-        } else if (event.which === 2) {
+        } else if (event.button === 1) {
             this.downPreHandler.dispatch(new Vector(event.clientX, event.clientY), enumMouseButton.middle);
-        } else if (event.which === 3) {
+        } else if (event.button === 2) {
             this.downPreHandler.dispatch(new Vector(event.clientX, event.clientY), enumMouseButton.right);
         }
         return false;
@@ -464,7 +464,7 @@ export class Camera extends BasicSerializableObject {
             return;
         }
 
-        if (event.which === 1) {
+        if (event.button === 0) {
             this.combinedSingleTouchMoveHandler(event.clientX, event.clientY);
         }
 
@@ -503,7 +503,7 @@ export class Camera extends BasicSerializableObject {
             // event.stopPropagation();
         }
 
-        const delta = Math.sign(event.deltaY) * -0.15;
+        const delta = Math.sign(event.deltaY) * -0.15 * this.root.app.settings.getScrollWheelSensitivity();
         assert(Number.isFinite(delta), "Got invalid delta in mouse wheel event: " + event.deltaY);
         assert(Number.isFinite(this.zoomLevel), "Got invalid zoom level *before* wheel: " + this.zoomLevel);
         this.zoomLevel *= 1 + delta;
diff --git a/src/js/game/components/item_ejector.js b/src/js/game/components/item_ejector.js
index d5881a7d..5a40870b 100644
--- a/src/js/game/components/item_ejector.js
+++ b/src/js/game/components/item_ejector.js
@@ -44,7 +44,7 @@ export class ItemEjectorComponent extends Component {
 
         return new ItemEjectorComponent({
             slots: slotsCopy,
-            instantEject: false,
+            instantEject: this.instantEject,
         });
     }
 
diff --git a/src/js/game/hud/hud.js b/src/js/game/hud/hud.js
index b2472a68..e1f1dbbf 100644
--- a/src/js/game/hud/hud.js
+++ b/src/js/game/hud/hud.js
@@ -48,8 +48,8 @@ export class GameHUD {
         this.parts = {
             processingOverlay: new HUDProcessingOverlay(this.root),
             buildingsToolbar: new HUDBuildingsToolbar(this.root),
-            buildingPlacer: new HUDBuildingPlacer(this.root),
             blueprintPlacer: new HUDBlueprintPlacer(this.root),
+            buildingPlacer: new HUDBuildingPlacer(this.root),
             unlockNotification: new HUDUnlockNotification(this.root),
             gameMenu: new HUDGameMenu(this.root),
             massSelector: new HUDMassSelector(this.root),
diff --git a/src/js/game/hud/parts/blueprint_placer.js b/src/js/game/hud/parts/blueprint_placer.js
index b3b91a66..173d1809 100644
--- a/src/js/game/hud/parts/blueprint_placer.js
+++ b/src/js/game/hud/parts/blueprint_placer.js
@@ -1,4 +1,4 @@
-import { DrawParameters } from "../../../core/draw_parameters";
+//www.youtube.com/watch?v=KyorY1uIqiQimport { DrawParameters } from "../../../core/draw_parameters";
 import { STOP_PROPAGATION } from "../../../core/signal";
 import { TrackedState } from "../../../core/tracked_state";
 import { Vector } from "../../../core/vector";
@@ -36,6 +36,9 @@ export class HUDBlueprintPlacer extends BaseHUDPart {
             .getBinding(KEYMAPPINGS.placement.abortBuildingPlacement)
             .add(this.abortPlacement, this);
         keyActionMapper.getBinding(KEYMAPPINGS.placement.rotateWhilePlacing).add(this.rotateBlueprint, this);
+        keyActionMapper
+            .getBinding(KEYMAPPINGS.placement.abortBuildingPlacement)
+            .add(this.abortPlacement, this);
 
         this.root.camera.downPreHandler.add(this.onMouseDown, this);
         this.root.camera.movePreHandler.add(this.onMouseMove, this);
diff --git a/src/js/game/key_action_mapper.js b/src/js/game/key_action_mapper.js
index 2ffbb03c..9de75731 100644
--- a/src/js/game/key_action_mapper.js
+++ b/src/js/game/key_action_mapper.js
@@ -89,6 +89,16 @@ for (const categoryId in KEYMAPPINGS) {
  */
 export function getStringForKeyCode(code) {
     switch (code) {
+        case 1:
+            return "LMB";
+        case 2:
+            return "MMB";
+        case 3:
+            return "RMB";
+        case 4:
+            return "MB4";
+        case 5:
+            return "MB5";
         case 8:
             return "⌫";
         case 9:
diff --git a/src/js/platform/browser/google_analytics.js b/src/js/platform/browser/google_analytics.js
index 55de95cc..3c54fbbd 100644
--- a/src/js/platform/browser/google_analytics.js
+++ b/src/js/platform/browser/google_analytics.js
@@ -66,11 +66,6 @@ export class GoogleAnalyticsImpl extends AnalyticsInterface {
     }
 
     trackUiClick(elementName) {
-        // Only track a fraction of clicks to not annoy google analytics
-        if (Math_random() < 0.9) {
-            return;
-        }
-
         const stateKey = this.app.stateMgr.getCurrentState().key;
         const fullSelector = stateKey + ">" + elementName;
 
diff --git a/src/js/profile/application_settings.js b/src/js/profile/application_settings.js
index aa5048ff..37576466 100644
--- a/src/js/profile/application_settings.js
+++ b/src/js/profile/application_settings.js
@@ -8,6 +8,7 @@ import { createLogger } from "../core/logging";
 import { ExplainedResult } from "../core/explained_result";
 import { THEMES, THEME, applyGameTheme } from "../game/theme";
 import { IS_DEMO } from "../core/config";
+import { T } from "../translations";
 
 const logger = createLogger("application_settings");
 
@@ -18,27 +19,45 @@ export const uiScales = [
     {
         id: "super_small",
         size: 0.6,
-        label: "Super small",
     },
     {
         id: "small",
         size: 0.8,
-        label: "Small",
     },
     {
         id: "regular",
         size: 1,
-        label: "Regular",
     },
     {
         id: "large",
         size: 1.2,
-        label: "Large",
     },
     {
         id: "huge",
         size: 1.4,
-        label: "Huge",
+    },
+];
+
+export const scrollWheelSensitivities = [
+    {
+        id: "super_slow",
+        scale: 0.25,
+    },
+    {
+        id: "slow",
+        scale: 0.5,
+    },
+    {
+        id: "regular",
+        scale: 1,
+    },
+    {
+        id: "fast",
+        scale: 2,
+    },
+    {
+        id: "super_fast",
+        scale: 4,
     },
 ];
 
@@ -47,7 +66,7 @@ export const allApplicationSettings = [
     new EnumSetting("uiScale", {
         options: uiScales.sort((a, b) => a.size - b.size),
         valueGetter: scale => scale.id,
-        textGetter: scale => scale.label,
+        textGetter: scale => T.settings.labels.uiScale.scales[scale.id],
         category: categoryApp,
         restartRequired: false,
         changeCb:
@@ -56,6 +75,7 @@ export const allApplicationSettings = [
              */
             (app, id) => app.updateAfterUiScaleChanged(),
     }),
+
     new BoolSetting(
         "fullscreen",
         categoryApp,
@@ -86,6 +106,18 @@ export const allApplicationSettings = [
          */
         (app, value) => app.sound.setMusicMuted(value)
     ),
+    new EnumSetting("scrollWheelSensitivity", {
+        options: scrollWheelSensitivities.sort((a, b) => a.scale - b.scale),
+        valueGetter: scale => scale.id,
+        textGetter: scale => T.settings.labels.scrollWheelSensitivity.sensitivity[scale.id],
+        category: categoryApp,
+        restartRequired: false,
+        changeCb:
+            /**
+             * @param {Application} app
+             */
+            (app, id) => app.updateAfterUiScaleChanged(),
+    }),
 
     // GAME
     new EnumSetting("theme", {
@@ -133,6 +165,7 @@ class SettingsStorage {
         this.musicMuted = false;
         this.theme = "light";
         this.refreshRate = "60";
+        this.scrollWheelSensitivity = "regular";
 
         this.alwaysMultiplace = false;
         this.abortPlacementOnDeletion = true;
@@ -209,6 +242,17 @@ export class ApplicationSettings extends ReadWriteProxy {
         return 1;
     }
 
+    getScrollWheelSensitivity() {
+        const id = this.getAllSettings().scrollWheelSensitivity;
+        for (let i = 0; i < scrollWheelSensitivities.length; ++i) {
+            if (scrollWheelSensitivities[i].id === id) {
+                return scrollWheelSensitivities[i].scale;
+            }
+        }
+        logger.error("Unknown scroll wheel sensitivity id:", id);
+        return 1;
+    }
+
     getIsFullScreen() {
         return this.getAllSettings().fullscreen;
     }
@@ -295,7 +339,7 @@ export class ApplicationSettings extends ReadWriteProxy {
     }
 
     getCurrentVersion() {
-        return 8;
+        return 9;
     }
 
     /** @param {{settings: SettingsStorage, version: number}} data */
@@ -318,10 +362,15 @@ export class ApplicationSettings extends ReadWriteProxy {
         }
 
         if (data.version < 8) {
-            data.settings.abortPlacementOnDeletion = true;
+            data.settings.scrollWheelSensitivity = "regular";
             data.version = 8;
         }
 
+        if (data.version < 9) {
+            data.settings.abortPlacementOnDeletion = true;
+            data.version = 9;
+        }
+
         return ExplainedResult.good();
     }
 }
diff --git a/src/js/savegame/savegame.js b/src/js/savegame/savegame.js
index a78200f9..7d59a056 100644
--- a/src/js/savegame/savegame.js
+++ b/src/js/savegame/savegame.js
@@ -10,8 +10,9 @@ import { BaseSavegameInterface } from "./savegame_interface";
 import { createLogger } from "../core/logging";
 import { globalConfig } from "../core/config";
 import { SavegameInterface_V1000 } from "./schemas/1000";
-import { getSavegameInterface } from "./savegame_interface_registry";
+import { getSavegameInterface, savegameInterfaces } from "./savegame_interface_registry";
 import { SavegameInterface_V1001 } from "./schemas/1001";
+import { SavegameInterface_V1002 } from "./schemas/1002";
 
 const logger = createLogger("savegame");
 
@@ -30,6 +31,11 @@ export class Savegame extends ReadWriteProxy {
 
         /** @type {import("./savegame_typedefs").SavegameData} */
         this.currentData = this.getDefaultData();
+
+        assert(
+            savegameInterfaces[Savegame.getCurrentVersion()],
+            "Savegame interface not defined: " + Savegame.getCurrentVersion()
+        );
     }
 
     //////// RW Proxy Impl //////////
@@ -38,14 +44,14 @@ export class Savegame extends ReadWriteProxy {
      * @returns {number}
      */
     static getCurrentVersion() {
-        return 1001;
+        return 1002;
     }
 
     /**
      * @returns {typeof BaseSavegameInterface}
      */
     static getReaderClass() {
-        return SavegameInterface_V1001;
+        return savegameInterfaces[Savegame.getCurrentVersion()];
     }
 
     /**
@@ -82,6 +88,11 @@ export class Savegame extends ReadWriteProxy {
             data.version = 1001;
         }
 
+        if (data.version === 1001) {
+            SavegameInterface_V1002.migrate1001to1002(data);
+            data.version = 1002;
+        }
+
         return ExplainedResult.good();
     }
 
diff --git a/src/js/savegame/savegame_interface_registry.js b/src/js/savegame/savegame_interface_registry.js
index 2560b23e..7c6db250 100644
--- a/src/js/savegame/savegame_interface_registry.js
+++ b/src/js/savegame/savegame_interface_registry.js
@@ -2,11 +2,13 @@ import { BaseSavegameInterface } from "./savegame_interface";
 import { SavegameInterface_V1000 } from "./schemas/1000";
 import { createLogger } from "../core/logging";
 import { SavegameInterface_V1001 } from "./schemas/1001";
+import { SavegameInterface_V1002 } from "./schemas/1002";
 
 /** @type {Object.} */
-const interfaces = {
+export const savegameInterfaces = {
     1000: SavegameInterface_V1000,
     1001: SavegameInterface_V1001,
+    1002: SavegameInterface_V1002,
 };
 
 const logger = createLogger("savegame_interface_registry");
@@ -27,7 +29,7 @@ export function getSavegameInterface(savegame) {
         return null;
     }
 
-    const interfaceClass = interfaces[version];
+    const interfaceClass = savegameInterfaces[version];
     if (!interfaceClass) {
         logger.warn("Version", version, "has no implemented interface!");
         return null;
diff --git a/src/js/savegame/schemas/1002.js b/src/js/savegame/schemas/1002.js
new file mode 100644
index 00000000..92dadfc1
--- /dev/null
+++ b/src/js/savegame/schemas/1002.js
@@ -0,0 +1,37 @@
+import { createLogger } from "../../core/logging.js";
+import { T } from "../../translations.js";
+import { SavegameInterface_V1001 } from "./1001.js";
+
+const schema = require("./1002.json");
+const logger = createLogger("savegame_interface/1002");
+
+export class SavegameInterface_V1002 extends SavegameInterface_V1001 {
+    getVersion() {
+        return 1002;
+    }
+
+    getSchemaUncached() {
+        return schema;
+    }
+
+    /**
+     * @param {import("../savegame_typedefs.js").SavegameData} data
+     */
+    static migrate1001to1002(data) {
+        logger.log("Migrating 1001 to 1002");
+        const dump = data.dump;
+        if (!dump) {
+            return true;
+        }
+
+        const entities = dump.entities;
+        for (let i = 0; i < entities.length; ++i) {
+            const entity = entities[i];
+            const beltComp = entity.components.Belt;
+            const ejectorComp = entity.components.ItemEjector;
+            if (beltComp && ejectorComp) {
+                ejectorComp.instantEject = true;
+            }
+        }
+    }
+}
diff --git a/src/js/savegame/schemas/1002.json b/src/js/savegame/schemas/1002.json
new file mode 100644
index 00000000..6682f615
--- /dev/null
+++ b/src/js/savegame/schemas/1002.json
@@ -0,0 +1,5 @@
+{
+    "type": "object",
+    "required": [],
+    "additionalProperties": true
+}
diff --git a/src/js/states/keybindings.js b/src/js/states/keybindings.js
index 0f7fcf9e..bc2b4a18 100644
--- a/src/js/states/keybindings.js
+++ b/src/js/states/keybindings.js
@@ -105,6 +105,10 @@ export class KeybindingsState extends TextualGameState {
                 event.preventDefault();
             }
 
+            if (event.target && event.target.tagName === "BUTTON" && keyCode === 1) {
+                return;
+            }
+
             if (
                 // Enter
                 keyCode === 13 ||
@@ -122,8 +126,8 @@ export class KeybindingsState extends TextualGameState {
         });
 
         dialog.inputReciever.backButton.add(() => {});
-
         this.dialogs.internalShowDialog(dialog);
+
         this.app.sound.playUiSound(SOUNDS.dialogOk);
     }
 
diff --git a/translations/base-en.yaml b/translations/base-en.yaml
index c2a39348..7602b64e 100644
--- a/translations/base-en.yaml
+++ b/translations/base-en.yaml
@@ -26,6 +26,13 @@ global:
     # How big numbers are rendered, e.g. "10,000"
     thousandsDivider: ","
 
+    # The suffix for large numbers, e.g. 1.3k, 400.2M, etc.
+    suffix:
+        thousands: k
+        millions: M
+        billions: B
+        trillions: T
+
     # Shown for infinitely big numbers
     infinite: inf
 
@@ -127,7 +134,7 @@ dialogs:
 
     editKeybinding:
         title: Change Keybinding
-        desc: Press the key you want to assign, or escape to cancel.
+        desc: Press the key or mouse button you want to assign, or escape to cancel.
 
     resetKeybindingsConfirmation:
         title: Reset keybindings
@@ -511,6 +518,23 @@ settings:
             title: Interface scale
             description: >-
                 Changes the size of the user interface. The interface will still scale based on your device resolution, but this setting controls the amount of scale.
+            scales:
+                super_small: Super small
+                small: Small
+                regular: Regular
+                large: Large
+                huge: Huge
+
+        scrollWheelSensitivity:
+            title: Zoom sensitivity
+            description: >-
+                Changes how sensitive the zoom is (Either mouse wheel or trackpad).
+            sensitivity:
+                super_slow: Super slow
+                slow: Slow
+                regular: Regular
+                fast: Fast
+                super_fast: Super fast
 
         fullscreen:
             title: Fullscreen
diff --git a/version b/version
index 8428158d..9c1218c2 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-1.1.2
\ No newline at end of file
+1.1.3
\ No newline at end of file