diff --git a/Cargo.lock b/Cargo.lock
index 323b04845d..177191b539 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -162,6 +162,11 @@ name = "block"
 version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "byteorder"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "byteorder"
 version = "1.3.1"
@@ -296,7 +301,7 @@ name = "conrod_derive"
 version = "0.63.0"
 source = "git+https://gitlab.com/veloren/conrod.git#93f02e61838b475ff190b3563a0f41f8981cc228"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -511,7 +516,7 @@ name = "derivative"
 version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -614,7 +619,7 @@ name = "euclid_macros"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -633,7 +638,7 @@ name = "failure_derive"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1034,7 +1039,7 @@ dependencies = [
  "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "tiff 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1170,6 +1175,15 @@ dependencies = [
  "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "lz4-compress"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "lzw"
 version = "0.10.0"
@@ -1341,10 +1355,10 @@ dependencies = [
 
 [[package]]
 name = "num-derive"
-version = "0.2.4"
+version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -1591,7 +1605,7 @@ dependencies = [
 
 [[package]]
 name = "png"
-version = "0.14.0"
+version = "0.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1600,6 +1614,14 @@ dependencies = [
  "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "portpicker"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
 [[package]]
 name = "pretty_env_logger"
 version = "0.3.0"
@@ -1612,7 +1634,7 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "0.4.27"
+version = "0.4.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1628,7 +1650,7 @@ name = "quote"
 version = "0.6.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
 [[package]]
@@ -1969,7 +1991,7 @@ name = "serde_derive"
 version = "1.0.90"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -2018,7 +2040,7 @@ name = "shred-derive"
 version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -2127,7 +2149,7 @@ name = "syn"
 version = "0.15.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -2137,7 +2159,7 @@ name = "synstructure"
 version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)",
  "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2195,7 +2217,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
@@ -2288,6 +2310,7 @@ dependencies = [
  "image 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lz4-compress 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
  "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2345,6 +2368,7 @@ dependencies = [
  "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
  "msgbox 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "portpicker 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
  "simplelog 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2426,7 +2450,7 @@ name = "wayland-scanner"
 version = "0.21.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
- "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
  "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -2576,6 +2600,7 @@ dependencies = [
 "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
 "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
 "checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
+"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
 "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
 "checksum c_vec 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6237ac5a4b1e81c213c24c6437964c61e646df910a914b4ab1487b46df20bd13"
 "checksum cairo-rs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0180a8b65dc13e78479c6a47c4d5f094d64dc34465a9433c6daef9ae2fbfb3ee"
@@ -2684,6 +2709,7 @@ dependencies = [
 "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
 "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
 "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
+"checksum lz4-compress 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f966533a922a9bba9e95e594c1fdb3b9bf5fdcdb11e37e51ad84cd76e468b91"
 "checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
 "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
 "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
@@ -2703,7 +2729,7 @@ dependencies = [
 "checksum num 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf4825417e1e1406b3782a8ce92f4d53f26ec055e3622e1881ca8e9f5f9e08db"
 "checksum num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "57450397855d951f1a41305e54851b1a7b8f5d2e349543a02a2effe25459f718"
 "checksum num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "107b9be86cd2481930688277b675b0114578227f034674726605b8a482d8baf8"
-"checksum num-derive 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d9fe8fcafd1b86a37ce8a1cfa15ae504817e0c8c2e7ad42767371461ac1d316d"
+"checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2"
 "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
 "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
 "checksum num-rational 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e"
@@ -2732,9 +2758,10 @@ dependencies = [
 "checksum pistoncore-input 0.24.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c612ce242c7bac8e96426a0ca34275fd980af440f0cca7c6c0e840ef8a4052f"
 "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
 "checksum png 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f0b0cabbbd20c2d7f06dbf015e06aad59b6ca3d9ed14848783e98af9aaf19925"
-"checksum png 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9adebf7fb91ccf5eac9da1a8e00e83cb8ae882c3e8d8e4ad59da73cb8c82a2c9"
+"checksum png 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "63daf481fdd0defa2d1d2be15c674fbfa1b0fd71882c303a91f9a79b3252c359"
+"checksum portpicker 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b497d05c16fe00939445c00a4fe2fa4f3d3dfc9c0401a3ab5c577afda2debb9"
 "checksum pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8b3f4e0475def7d9c2e5de8e5a1306949849761e107b360d03e98eafaffd61"
-"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
+"checksum proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)" = "ba92c84f814b3f9a44c5cfca7d2ad77fa10710867d2bbb1b3d175ab5f47daa12"
 "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
 "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
 "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c"
diff --git a/assets/voxygen/font/LICENSE.txt b/assets/voxygen/font/LICENSE.txt
deleted file mode 100644
index d645695673..0000000000
--- a/assets/voxygen/font/LICENSE.txt
+++ /dev/null
@@ -1,202 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-   you may not use this file except in compliance with the License.
-   You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-   Unless required by applicable law or agreed to in writing, software
-   distributed under the License is distributed on an "AS IS" BASIS,
-   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-   See the License for the specific language governing permissions and
-   limitations under the License.
diff --git a/assets/voxygen/font/OFL.txt b/assets/voxygen/font/OFL.txt
index 03e726db14..ab509e62ed 100644
--- a/assets/voxygen/font/OFL.txt
+++ b/assets/voxygen/font/OFL.txt
@@ -19,7 +19,7 @@ with others.
 
 The OFL allows the licensed fonts to be used, studied, modified and
 redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded, 
+fonts, including any derivative works, can be bundled, embedded,
 redistributed and/or sold with any software provided that any reserved
 names are not used by derivative works. The fonts and derivatives,
 however, cannot be released under any other type of license. The
diff --git a/assets/voxygen/voxel/belt.vox b/assets/voxygen/voxel/belt.vox
index 41b283b6ea..c3f6db572d 100644
--- a/assets/voxygen/voxel/belt.vox
+++ b/assets/voxygen/voxel/belt.vox
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:c2e5445d2f4338b00ad1a69fafab99c5ad13edc26de817cc1b6ce3c615a44635
+oid sha256:9a321c80f87a239ce9a4de743a889b31ebb57831acfcb6fc77928c9b26700df2
 size 1544
diff --git a/assets/voxygen/voxel/chest.vox b/assets/voxygen/voxel/chest.vox
index 86794fabaf..9af67e7cbc 100644
--- a/assets/voxygen/voxel/chest.vox
+++ b/assets/voxygen/voxel/chest.vox
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:9c7c93fd3a28611bc93ba532d39fbbec594c21ab2f91a9925e11f15bb13a5371
-size 45499
+oid sha256:200cdedef555fa03b7761e0a3a4209de76851f007b6b137bd77925a49051e560
+size 2392
diff --git a/assets/voxygen/voxel/foot.vox b/assets/voxygen/voxel/foot.vox
index e2478167a1..c2e2dce585 100644
--- a/assets/voxygen/voxel/foot.vox
+++ b/assets/voxygen/voxel/foot.vox
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:0e9e0a34b70a5d4a1bddb306dfac354a95f3ce924f74484ebec4c8599c9caf70
+oid sha256:dcf8aa1a237dba07f8e078a71612d7ab44412a12950964a1d92856eaf5f2db62
 size 44523
diff --git a/assets/voxygen/voxel/head.vox b/assets/voxygen/voxel/head.vox
index 04e2fe94a3..0ebfea4bf0 100644
--- a/assets/voxygen/voxel/head.vox
+++ b/assets/voxygen/voxel/head.vox
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:479fcf40c20598bf284dca6fab690a351abc5a9b47d841f604667799f5c76c31
-size 48059
+oid sha256:57c31358507b87f7c88e18a54466f97e4f2603427dcd4892e14bfa38a4fa3dda
+size 4608
diff --git a/assets/voxygen/voxel/pants.vox b/assets/voxygen/voxel/pants.vox
index eb492cc6c8..0913ab44b5 100644
--- a/assets/voxygen/voxel/pants.vox
+++ b/assets/voxygen/voxel/pants.vox
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:365dbba45692d85df10dd9fb0d89b318f6f63bb3f713767ae0f75b63110164fe
-size 44891
+oid sha256:d73f412dc1f75af7cb0fcd7a46d02c464d1bcde6fc6143827c3bfec4276f61ad
+size 1784
diff --git a/assets/voxygen/voxel/sword.vox b/assets/voxygen/voxel/sword.vox
index b203a5e297..3cc01d1cbc 100644
--- a/assets/voxygen/voxel/sword.vox
+++ b/assets/voxygen/voxel/sword.vox
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:2eab472ba789f881e5abe85f5a5bf55a2bb178fdcbebbb735453621f16a63b55
+oid sha256:e458a391915d1381c5c8f995da96310e521a441d0e14e67bcacad423ffc68857
 size 1568
diff --git a/client/Cargo.lock b/client/Cargo.lock
new file mode 100644
index 0000000000..9a47c24bc9
--- /dev/null
+++ b/client/Cargo.lock
@@ -0,0 +1,586 @@
+[[package]]
+name = "arrayvec"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "atom"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "bitflags"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "byteorder"
+version = "1.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cfg-if"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "cloudabi"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-deque 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-channel"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "derivative"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "either"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "fnv"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "fuchsia-zircon"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "fuchsia-zircon-sys"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "hibitset"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "atom 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "libc"
+version = "0.2.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "lock_api"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "log"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "mopa"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "nodrop"
+version = "0.1.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "nonzero_signed"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "num_cpus"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "owning_ref"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "owning_ref"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "0.4.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "0.6.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "rayon"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)",
+ "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "scopeguard"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "shred"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mopa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "shred-derive"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "shrev"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "smallvec"
+version = "0.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "specs"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "hibitset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mopa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nonzero_signed 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "shred 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "shred-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "shrev 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "tuple_utils 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "syn"
+version = "0.15.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "tuple_utils"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-xid"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unreachable"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "veloren-client"
+version = "0.1.0"
+dependencies = [
+ "specs 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "void"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[metadata]
+"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
+"checksum atom 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3c86699c3f02778ec07158376991c8f783dd1f2f95c579ffaf0738dc984b2fe2"
+"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
+"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
+"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
+"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
+"checksum crossbeam 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d7408247b1b87f480890f28b670c5f8d9a8a4274833433fe74dc0dfd46d33650"
+"checksum crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7b85741761b7f160bc5e7e0c14986ef685b7f8bf9b7ad081c60c604bb4649827"
+"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
+"checksum crossbeam-deque 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7792c4a9b5a4222f654e3728a3dd945aacc24d2c3a1a096ed265d80e4929cb9a"
+"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150"
+"checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9"
+"checksum crossbeam-epoch 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2449aaa4ec7ef96e5fb24db16024b935df718e9ae1cec0a1e68feeca2efca7b8"
+"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
+"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015"
+"checksum crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41ee4864f4797060e52044376f7d107429ce1fb43460021b126424b7180ee21a"
+"checksum derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6073e9676dbebdddeabaeb63e3b7cefd23c86f5c41d381ee1237cc77b1079898"
+"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0"
+"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
+"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
+"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
+"checksum fxhash 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+"checksum hibitset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a795da5d89ae959c6765f92de69d0f1642134a80f0898f0ab231f7d67ffc5749"
+"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
+"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74"
+"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
+"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
+"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
+"checksum mopa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a785740271256c230f57462d3b83e52f998433a7062fc18f96d5999474a9f915"
+"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
+"checksum nonzero_signed 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d9813c459ba38abf9c40eecc8d59738eb7ebcfc45a857030967372dcb83e18de"
+"checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238"
+"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
+"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
+"checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac"
+"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
+"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa"
+"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c"
+"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
+"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
+"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
+"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
+"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372"
+"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
+"checksum rayon 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "373814f27745b2686b350dd261bfd24576a6fb0e2c5919b3a2b6005f820b0473"
+"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356"
+"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
+"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+"checksum shred 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c75ec29e8d2959ad96a1087fe4cadb926c6fc17cbae9812314fa8efe720aa2a"
+"checksum shred-derive 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fcf34e5e5302d3024aba7afc291f6d1ca7573ed035d3c0796976ba3f10691a1"
+"checksum shrev 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ec60ed6f60a4b3cdc2ceacf57215db3408fbd8990f66a38686a31558cd9da482"
+"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db"
+"checksum specs 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06df46b79dafa300305d7bddb756557d44385e5f8b311fa640bbfa2c748a358"
+"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
+"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc"
+"checksum tuple_utils 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbfecd7bb8f0a3e96b3b31c46af2677a55a588767c0091f484601424fcb20e7e"
+"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
+"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
+"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
+"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
+"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/client/src/input.rs b/client/src/input.rs
index c30a12bbb9..840ee46525 100644
--- a/client/src/input.rs
+++ b/client/src/input.rs
@@ -1,14 +1,21 @@
 use vek::*;
 
+pub enum InputEvent {
+    Jump,
+}
+
 pub struct Input {
-    // TODO: Use this type to manage client input
     pub move_dir: Vec2<f32>,
+    pub jumping: bool,
+    pub events: Vec<InputEvent>,
 }
 
 impl Default for Input {
     fn default() -> Self {
         Input {
             move_dir: Vec2::zero(),
+            jumping: false,
+            events: Vec::new(),
         }
     }
 }
diff --git a/client/src/lib.rs b/client/src/lib.rs
index 305cf38823..b3de584492 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -4,7 +4,10 @@ pub mod error;
 pub mod input;
 
 // Reexports
-pub use crate::{error::Error, input::Input};
+pub use crate::{
+    error::Error,
+    input::{Input, InputEvent},
+};
 pub use specs::join::Join;
 pub use specs::Entity as EcsEntity;
 
@@ -152,6 +155,7 @@ impl Client {
             self.entity,
             comp::Control {
                 move_dir: input.move_dir,
+                jumping: input.jumping,
             },
         );
 
@@ -195,7 +199,11 @@ impl Client {
             // Remove chunks that are too far from the player
             let mut chunks_to_remove = Vec::new();
             self.state.terrain().iter().for_each(|(key, _)| {
-                if (chunk_pos - key).map(|e| e.abs()).reduce_max() > 3 {
+                if (Vec2::from(chunk_pos) - Vec2::from(key))
+                    .map(|e: i32| e.abs())
+                    .reduce_max()
+                    > 6
+                {
                     chunks_to_remove.push(key);
                 }
             });
@@ -204,8 +212,8 @@ impl Client {
             }
 
             // Request chunks from the server
-            for i in chunk_pos.x - 1..chunk_pos.x + 2 {
-                for j in chunk_pos.y - 1..chunk_pos.y + 2 {
+            for i in chunk_pos.x - 3..chunk_pos.x + 4 {
+                for j in chunk_pos.y - 3..chunk_pos.y + 4 {
                     for k in 0..2 {
                         let key = Vec3::new(i, j, k);
                         if self.state.terrain().get_key(key).is_none()
diff --git a/common/Cargo.toml b/common/Cargo.toml
index 7cbb23e2d8..750eaa4975 100644
--- a/common/Cargo.toml
+++ b/common/Cargo.toml
@@ -16,8 +16,9 @@ mio = "0.6"
 mio-extras = "2.0"
 serde = "1.0"
 serde_derive = "1.0"
-bincode = "1.0"
+bincode = "1.1"
 log = "0.4"
 rand = "0.5"
 rayon = "1.0"
 lazy_static = "1.3"
+lz4-compress = "0.1"
diff --git a/common/src/comp/agent.rs b/common/src/comp/agent.rs
index 4617e78f3c..1c299b8ba3 100644
--- a/common/src/comp/agent.rs
+++ b/common/src/comp/agent.rs
@@ -13,12 +13,14 @@ impl Component for Agent {
 #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
 pub struct Control {
     pub move_dir: Vec2<f32>,
+    pub jumping: bool,
 }
 
 impl Default for Control {
     fn default() -> Self {
         Self {
             move_dir: Vec2::zero(),
+            jumping: false,
         }
     }
 }
diff --git a/common/src/comp/character.rs b/common/src/comp/character.rs
index 3ea3f58b64..d164b6d74b 100644
--- a/common/src/comp/character.rs
+++ b/common/src/comp/character.rs
@@ -113,12 +113,14 @@ impl Character {
 pub struct AnimationHistory {
     pub last: Option<Animation>,
     pub current: Animation,
+    pub time: f64,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
 pub enum Animation {
     Idle,
     Run,
+    Jump,
 }
 
 impl Component for Character {
diff --git a/common/src/net/post2.rs b/common/src/net/post2.rs
index fe1a0c5254..ea466ac8bb 100644
--- a/common/src/net/post2.rs
+++ b/common/src/net/post2.rs
@@ -193,10 +193,18 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
                     match send_rx.try_recv() {
                         Ok(send_msg) => {
                             // Serialize message
-                            let mut msg_bytes = bincode::serialize(&send_msg).unwrap();
+                            let msg_bytes = bincode::serialize(&send_msg).unwrap();
+                            let mut msg_bytes = lz4_compress::compress(&msg_bytes);
+
+                            /*
+                            if msg_bytes.len() > 512 {
+                                println!("MSG SIZE: {}", msg_bytes.len());
+                            }
+                            */
 
                             // Assemble into packet
                             let mut packet_bytes = msg_bytes.len().to_le_bytes().as_ref().to_vec();
+                            packet_bytes.push(msg_bytes.iter().fold(0, |a, x| a ^ *x));
                             packet_bytes.append(&mut msg_bytes);
 
                             // Split packet into chunks
@@ -256,20 +264,37 @@ impl<S: PostMsg, R: PostMsg> PostBox<S, R> {
 
                 // Try turning bytes into messages
                 for _ in 0..100 {
-                    match incoming_buf.get(0..8) {
+                    match incoming_buf.get(0..9) {
                         Some(len_bytes) => {
-                            let len = usize::from_le_bytes(<[u8; 8]>::try_from(len_bytes).unwrap()); // Can't fail
+                            let len = usize::from_le_bytes(
+                                <[u8; 8]>::try_from(&len_bytes[0..8]).unwrap(),
+                            ); // Can't fail
 
                             if len > MAX_MSG_SIZE {
                                 recv_tx.send(Err(Error::InvalidMessage)).unwrap();
                                 break 'work;
-                            } else if incoming_buf.len() >= len + 8 {
-                                match bincode::deserialize(&incoming_buf[8..len + 8]) {
+                            } else if incoming_buf.len() >= len + 9 {
+                                let checksum_found =
+                                    incoming_buf[9..len + 9].iter().fold(0, |a, x| a ^ *x);
+                                let checksum_expected = len_bytes[8];
+
+                                assert_eq!(
+                                    checksum_found, checksum_expected,
+                                    "Message checksum failed!"
+                                );
+
+                                let msg_bytes =
+                                    lz4_compress::decompress(&incoming_buf[9..len + 9]).unwrap();
+
+                                match bincode::deserialize(&msg_bytes) {
                                     Ok(msg) => recv_tx.send(Ok(msg)).unwrap(),
-                                    Err(err) => recv_tx.send(Err(err.into())).unwrap(),
+                                    Err(err) => {
+                                        println!("BINCODE ERROR: {:?}", err);
+                                        recv_tx.send(Err(err.into())).unwrap()
+                                    }
                                 }
 
-                                incoming_buf = incoming_buf.split_off(len + 8);
+                                incoming_buf = incoming_buf.split_off(len + 9);
                             } else {
                                 break;
                             }
diff --git a/common/src/state.rs b/common/src/state.rs
index 447c9117e4..82b28adfcf 100644
--- a/common/src/state.rs
+++ b/common/src/state.rs
@@ -30,7 +30,13 @@ struct Time(f64);
 
 /// A resource used to store the time since the last tick
 #[derive(Default)]
-pub struct DeltaTime(pub f64);
+pub struct DeltaTime(pub f32);
+
+/// At what point should we stop speeding up physics to compensate for lag? If we speed physics up
+/// too fast, we'd skip important physics events like collisions. This constant determines what
+/// the upper limit is. If delta time exceeds this value, the game's physics will begin to produce
+/// time lag. Ideally, we'd avoid such a situation.
+const MAX_DELTA_TIME: f32 = 0.2;
 
 pub struct Changes {
     pub new_chunks: HashSet<Vec3<i32>>,
@@ -198,9 +204,11 @@ impl State {
         self.ecs.write_resource::<TimeOfDay>().0 += dt.as_secs_f64() * DAY_CYCLE_FACTOR;
         self.ecs.write_resource::<Time>().0 += dt.as_secs_f64();
 
-        // Run systems to update the world
-        self.ecs.write_resource::<DeltaTime>().0 = dt.as_secs_f64();
+        // Update delta time
+        // Above a delta time of MAX_DELTA_TIME, start lagging to avoid skipping important physics events
+        self.ecs.write_resource::<DeltaTime>().0 = dt.as_secs_f32().min(MAX_DELTA_TIME);
 
+        // Run systems to update the world
         // Create and run dispatcher for ecs systems
         let mut dispatch_builder = DispatcherBuilder::new().with_pool(self.thread_pool.clone());
         sys::add_local_systems(&mut dispatch_builder);
diff --git a/common/src/sys/control.rs b/common/src/sys/control.rs
index 805336b939..0b3667322e 100644
--- a/common/src/sys/control.rs
+++ b/common/src/sys/control.rs
@@ -1,11 +1,16 @@
 // Library
-use specs::{Entities, Join, Read, ReadStorage, System, WriteStorage};
+use specs::{Entities, Join, Read, ReadExpect, ReadStorage, System, WriteStorage};
 use vek::*;
 
 // Crate
-use crate::comp::{
-    phys::{Dir, Pos, Vel},
-    Animation, AnimationHistory, Control,
+use crate::{
+    comp::{
+        phys::{Dir, Pos, Vel},
+        Animation, AnimationHistory, Control,
+    },
+    state::DeltaTime,
+    terrain::TerrainMap,
+    vol::{ReadVol, Vox},
 };
 
 // Basic ECS AI agent system
@@ -13,35 +18,70 @@ pub struct Sys;
 
 impl<'a> System<'a> for Sys {
     type SystemData = (
+        ReadExpect<'a, TerrainMap>,
+        Read<'a, DeltaTime>,
         Entities<'a>,
+        ReadStorage<'a, Pos>,
         WriteStorage<'a, Vel>,
         WriteStorage<'a, Dir>,
         WriteStorage<'a, AnimationHistory>,
         ReadStorage<'a, Control>,
     );
 
-    fn run(&mut self, (entities, mut vels, mut dirs, mut anims, controls): Self::SystemData) {
-        for (entity, mut vel, mut dir, control) in
-            (&entities, &mut vels, &mut dirs, &controls).join()
+    fn run(
+        &mut self,
+        (terrain, dt, entities, pos, mut vels, mut dirs, mut anims, controls): Self::SystemData,
+    ) {
+        for (entity, pos, mut vel, mut dir, control) in
+            (&entities, &pos, &mut vels, &mut dirs, &controls).join()
         {
-            // TODO: Don't hard-code this
-            // Apply physics to the player: acceleration and non-linear decceleration
-            vel.0 += control.move_dir * 2.0 - vel.0.map(|e| e * e.abs() + e) * 0.03;
+            let on_ground = terrain
+                .get((pos.0 - Vec3::unit_z() * 0.1).map(|e| e.floor() as i32))
+                .map(|vox| !vox.is_empty())
+                .unwrap_or(false)
+                && vel.0.z <= 0.0;
 
-            let animation = if control.move_dir.magnitude() > 0.01 {
-                dir.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
-                Animation::Run
+            if on_ground {
+                // TODO: Don't hard-code this
+                // Apply physics to the player: acceleration and non-linear decceleration
+                vel.0 += control.move_dir * 4.0 - vel.0.map(|e| e * vel.0.magnitude() + e) * 0.05;
+
+                if control.jumping {
+                    vel.0.z += 16.0;
+                }
             } else {
-                Animation::Idle
+                // TODO: Don't hard-code this
+                // Apply physics to the player: acceleration and non-linear decceleration
+                vel.0 += control.move_dir * 0.2 - vel.0.map(|e| e * e.abs() + e) * 0.002;
+            }
+
+            let animation = if on_ground {
+                if control.move_dir.magnitude() > 0.01 {
+                    dir.0 = vel.0.normalized() * Vec3::new(1.0, 1.0, 0.0);
+                    Animation::Run
+                } else {
+                    Animation::Idle
+                }
+            } else {
+                Animation::Jump
             };
 
-            let last_animation = anims.get_mut(entity).map(|h| h.current);
+            let last_history = anims.get_mut(entity).cloned();
+
+            let time = if let Some((true, time)) =
+                last_history.map(|last| (last.current == animation, last.time))
+            {
+                time + dt.0 as f64
+            } else {
+                0.0
+            };
 
             anims.insert(
                 entity,
                 AnimationHistory {
-                    last: last_animation,
+                    last: last_history.map(|last| last.current),
                     current: animation,
+                    time,
                 },
             );
         }
diff --git a/common/src/sys/phys.rs b/common/src/sys/phys.rs
index 32ba34b896..0de3578576 100644
--- a/common/src/sys/phys.rs
+++ b/common/src/sys/phys.rs
@@ -10,7 +10,7 @@ use vek::*;
 // Basic ECS physics system
 pub struct Sys;
 
-const GRAVITY: f32 = 9.81 * 2.0;
+const GRAVITY: f32 = 9.81 * 4.0;
 
 impl<'a> System<'a> for Sys {
     type SystemData = (
@@ -23,10 +23,10 @@ impl<'a> System<'a> for Sys {
     fn run(&mut self, (terrain, dt, mut positions, mut velocities): Self::SystemData) {
         for (pos, vel) in (&mut positions, &mut velocities).join() {
             // Gravity
-            vel.0.z -= GRAVITY * dt.0 as f32;
+            vel.0.z = (vel.0.z - GRAVITY * dt.0).max(-50.0);
 
             // Movement
-            pos.0 += vel.0 * dt.0 as f32;
+            pos.0 += vel.0 * dt.0;
 
             // Basic collision with terrain
             let mut i = 0;
@@ -34,9 +34,9 @@ impl<'a> System<'a> for Sys {
                 .get(pos.0.map(|e| e.floor() as i32))
                 .map(|vox| !vox.is_empty())
                 .unwrap_or(false)
-                && i < 80
+                && i < 100
             {
-                pos.0.z += 0.005;
+                pos.0.z += 0.0025;
                 vel.0.z = 0.0;
                 i += 1;
             }
diff --git a/server/src/lib.rs b/server/src/lib.rs
index f25d62c468..830337bc60 100644
--- a/server/src/lib.rs
+++ b/server/src/lib.rs
@@ -51,9 +51,15 @@ pub struct Server {
 }
 
 impl Server {
-    /// Create a new `Server`.
+    /// Create a new `Server` bound to the default socket.
     #[allow(dead_code)]
     pub fn new() -> Result<Self, Error> {
+        Self::bind(SocketAddr::from(([0; 4], 59003)))
+    }
+
+    /// Create a new server bound to the given socket
+    #[allow(dead_code)]
+    pub fn bind<A: Into<SocketAddr>>(addrs: A) -> Result<Self, Error> {
         let (chunk_tx, chunk_rx) = mpsc::channel();
 
         let mut state = State::new();
@@ -63,7 +69,7 @@ impl Server {
             state,
             world: World::new(),
 
-            postoffice: PostOffice::bind(SocketAddr::from(([0; 4], 59003)))?,
+            postoffice: PostOffice::bind(addrs.into())?,
             clients: Clients::empty(),
 
             thread_pool: threadpool::Builder::new()
@@ -137,6 +143,7 @@ impl Server {
             comp::AnimationHistory {
                 last: None,
                 current: Animation::Idle,
+                time: 0.0,
             },
         );
 
@@ -181,7 +188,7 @@ impl Server {
 
         // Fetch any generated `TerrainChunk`s and insert them into the terrain
         // Also, send the chunk data to anybody that is close by
-        for (key, chunk) in self.chunk_rx.try_iter() {
+        if let Ok((key, chunk)) = self.chunk_rx.try_recv() {
             // Send the chunk to all nearby players
             for (entity, player, pos) in (
                 &self.state.ecs().entities(),
@@ -191,9 +198,11 @@ impl Server {
                 .join()
             {
                 let chunk_pos = self.state.terrain().pos_key(pos.0.map(|e| e as i32));
-                let dist = (chunk_pos - key).map(|e| e.abs()).reduce_max();
+                let dist = (Vec2::from(chunk_pos) - Vec2::from(key))
+                    .map(|e: i32| e.abs())
+                    .reduce_max();
 
-                if dist < 4 {
+                if dist < 5 {
                     self.clients.notify(
                         entity,
                         ServerMsg::TerrainChunkUpdate {
@@ -225,7 +234,7 @@ impl Server {
                 min_dist = min_dist.min(dist);
             }
 
-            if min_dist > 3 {
+            if min_dist > 5 {
                 chunks_to_remove.push(key);
             }
         });
diff --git a/voxygen/Cargo.toml b/voxygen/Cargo.toml
index 8a7f84fe3d..e470bc23c7 100644
--- a/voxygen/Cargo.toml
+++ b/voxygen/Cargo.toml
@@ -46,3 +46,4 @@ fnv = "1.0"
 simplelog = "0.5"
 msgbox = "0.1"
 directories = "1.0"
+portpicker = "0.1"
diff --git a/voxygen/shaders/figure.frag b/voxygen/shaders/figure.frag
index bf6889d61c..6bc12dafb3 100644
--- a/voxygen/shaders/figure.frag
+++ b/voxygen/shaders/figure.frag
@@ -19,6 +19,7 @@ uniform u_globals {
 	vec4 view_distance;
 	vec4 time_of_day;
 	vec4 tick;
+	vec4 screen_res;
 };
 
 struct BoneData {
diff --git a/voxygen/shaders/figure.vert b/voxygen/shaders/figure.vert
index 7880d7876c..2c7c87d508 100644
--- a/voxygen/shaders/figure.vert
+++ b/voxygen/shaders/figure.vert
@@ -19,6 +19,7 @@ uniform u_globals {
 	vec4 view_distance;
 	vec4 time_of_day;
 	vec4 tick;
+	vec4 screen_res;
 };
 
 struct BoneData {
diff --git a/voxygen/shaders/postprocess.frag b/voxygen/shaders/postprocess.frag
index d3adcf5169..2731e84abc 100644
--- a/voxygen/shaders/postprocess.frag
+++ b/voxygen/shaders/postprocess.frag
@@ -18,13 +18,154 @@ uniform u_globals {
 	vec4 view_distance;
 	vec4 time_of_day;
 	vec4 tick;
+	vec4 screen_res;
 };
 
 out vec4 tgt_color;
 
-void main() {
-	// Uncomment to invert colors
-	//tgt_color = vec4(vec3(1.0, 1.0, 1.0) - texture2D(src_color, (f_pos + 1.0) / 2.0).xyz, 1.0);
-	tgt_color = texture2D(src_color, (f_pos + 1.0) / 2.0);
-	
+/**
+Basic FXAA implementation based on the code on geeks3d.com with the
+modification that the texture2DLod stuff was removed since it's
+unsupported by WebGL.
+
+--
+
+From:
+https://github.com/mitsuhiko/webgl-meincraft
+
+Copyright (c) 2011 by Armin Ronacher.
+
+Some rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * The names of the contributors may not be used to endorse or
+      promote products derived from this software without specific
+      prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FXAA_REDUCE_MIN
+    #define FXAA_REDUCE_MIN   (1.0/ 128.0)
+#endif
+#ifndef FXAA_REDUCE_MUL
+    #define FXAA_REDUCE_MUL   (1.0 / 8.0)
+#endif
+#ifndef FXAA_SPAN_MAX
+    #define FXAA_SPAN_MAX     8.0
+#endif
+
+//optimized version for mobile, where dependent
+//texture reads can be a bottleneck
+vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution,
+            vec2 v_rgbNW, vec2 v_rgbNE,
+            vec2 v_rgbSW, vec2 v_rgbSE,
+            vec2 v_rgbM) {
+    vec4 color;
+    mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y);
+    vec3 rgbNW = texture2D(tex, v_rgbNW).xyz;
+    vec3 rgbNE = texture2D(tex, v_rgbNE).xyz;
+    vec3 rgbSW = texture2D(tex, v_rgbSW).xyz;
+    vec3 rgbSE = texture2D(tex, v_rgbSE).xyz;
+    vec4 texColor = texture2D(tex, v_rgbM);
+    vec3 rgbM  = texColor.xyz;
+    vec3 luma = vec3(0.299, 0.587, 0.114);
+    float lumaNW = dot(rgbNW, luma);
+    float lumaNE = dot(rgbNE, luma);
+    float lumaSW = dot(rgbSW, luma);
+    float lumaSE = dot(rgbSE, luma);
+    float lumaM  = dot(rgbM,  luma);
+    float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
+    float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
+
+    mediump vec2 dir;
+    dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
+    dir.y =  ((lumaNW + lumaSW) - (lumaNE + lumaSE));
+
+    float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *
+                          (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);
+
+    float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
+    dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
+              max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
+              dir * rcpDirMin)) * inverseVP;
+
+    vec3 rgbA = 0.5 * (
+        texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz +
+        texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);
+    vec3 rgbB = rgbA * 0.5 + 0.25 * (
+        texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz +
+        texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz);
+
+    float lumaB = dot(rgbB, luma);
+    if ((lumaB < lumaMin) || (lumaB > lumaMax))
+        color = vec4(rgbA, texColor.a);
+    else
+        color = vec4(rgbB, texColor.a);
+    return color;
+}
+
+
+void texcoords(vec2 fragCoord, vec2 resolution,
+			out vec2 v_rgbNW, out vec2 v_rgbNE,
+			out vec2 v_rgbSW, out vec2 v_rgbSE,
+			out vec2 v_rgbM) {
+	vec2 inverseVP = 1.0 / resolution.xy;
+	v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP;
+	v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP;
+	v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP;
+	v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP;
+	v_rgbM = vec2(fragCoord * inverseVP);
+}
+
+
+vec4 fxaa_apply(sampler2D tex, vec2 fragCoord, vec2 resolution) {
+	mediump vec2 v_rgbNW;
+	mediump vec2 v_rgbNE;
+	mediump vec2 v_rgbSW;
+	mediump vec2 v_rgbSE;
+	mediump vec2 v_rgbM;
+
+	//compute the texture coords
+	texcoords(fragCoord, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);
+
+	//compute FXAA
+	return fxaa(tex, fragCoord, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);
+}
+
+void main() {
+	vec2 uv = (f_pos + 1.0) * 0.5;
+
+	/*
+	float px_size = 8.0;
+	vec2 px_count = screen_res.xy / px_size;
+	vec2 uv2 = floor(uv * px_count) / px_count;
+	*/
+
+	vec4 color = fxaa_apply(src_color, uv * screen_res.xy, screen_res.xy);
+
+	tgt_color = 1.0 - 1.0 / (color + 1.0);
+
+	//tgt_color = ceil(tgt_color * 10.0) / 10.0;
 }
diff --git a/voxygen/shaders/postprocess.vert b/voxygen/shaders/postprocess.vert
index 91cde43fb7..7d3c4774f0 100644
--- a/voxygen/shaders/postprocess.vert
+++ b/voxygen/shaders/postprocess.vert
@@ -16,6 +16,7 @@ uniform u_globals {
 	vec4 view_distance;
 	vec4 time_of_day;
 	vec4 tick;
+	vec4 screen_res;
 };
 
 out vec2 f_pos;
diff --git a/voxygen/shaders/skybox.frag b/voxygen/shaders/skybox.frag
index caa51fe4d9..b4ed5511a1 100644
--- a/voxygen/shaders/skybox.frag
+++ b/voxygen/shaders/skybox.frag
@@ -16,6 +16,7 @@ uniform u_globals {
 	vec4 view_distance;
 	vec4 time_of_day;
 	vec4 tick;
+	vec4 screen_res;
 };
 
 out vec4 tgt_color;
@@ -29,16 +30,16 @@ vec3 get_sky_color(vec3 dir, float time_of_day) {
 	const vec3 SKY_BOTTOM = vec3(0.0, 0.05, 0.2);
 
 	const vec3 SUN_HALO_COLOR  = vec3(1.0, 0.8, 0.5);
-	const vec3 SUN_SURF_COLOR  = vec3(1.0, 0.8, 0.5);
+	const vec3 SUN_SURF_COLOR  = vec3(1.0, 0.8, 0.0) * 100.0;
 
 	float sun_angle_rad = time_of_day * TIME_FACTOR;
 	vec3 sun_dir = vec3(sin(sun_angle_rad), 0.0, cos(sun_angle_rad));
 
 	vec3 sun_halo = pow(max(dot(dir, sun_dir), 0.0), 8.0) * SUN_HALO_COLOR;
-	vec3 sun_surf = min(pow(max(dot(dir, sun_dir), 0.0) + 0.01, 16.0), 1.0) * SUN_SURF_COLOR;
+	vec3 sun_surf = pow(max(dot(dir, sun_dir), 0.0), 1000.0) * SUN_SURF_COLOR;
 	vec3 sun_light = sun_halo + sun_surf;
 
-	return mix(SKY_BOTTOM, SKY_TOP, (dir.z + 1.0) / 2.0) + sun_light * 0.5;
+	return mix(SKY_BOTTOM, SKY_TOP, (dir.z + 1.0) / 2.0) + sun_light;
 }
 
 void main() {
diff --git a/voxygen/shaders/skybox.vert b/voxygen/shaders/skybox.vert
index 165e747ae9..825bbe7e88 100644
--- a/voxygen/shaders/skybox.vert
+++ b/voxygen/shaders/skybox.vert
@@ -16,6 +16,7 @@ uniform u_globals {
 	vec4 view_distance;
 	vec4 time_of_day;
 	vec4 tick;
+	vec4 screen_res;
 };
 
 out vec3 f_pos;
diff --git a/voxygen/shaders/terrain.frag b/voxygen/shaders/terrain.frag
index 1b718c3633..45ed1a4ce9 100644
--- a/voxygen/shaders/terrain.frag
+++ b/voxygen/shaders/terrain.frag
@@ -18,6 +18,7 @@ uniform u_globals {
 	vec4 view_distance;
 	vec4 time_of_day;
 	vec4 tick;
+	vec4 screen_res;
 };
 
 out vec4 tgt_color;
diff --git a/voxygen/shaders/terrain.vert b/voxygen/shaders/terrain.vert
index e195a1c464..89a386587c 100644
--- a/voxygen/shaders/terrain.vert
+++ b/voxygen/shaders/terrain.vert
@@ -18,6 +18,7 @@ uniform u_globals {
 	vec4 view_distance;
 	vec4 time_of_day;
 	vec4 tick;
+	vec4 screen_res;
 };
 
 out vec3 f_pos;
diff --git a/voxygen/src/anim/character/idle.rs b/voxygen/src/anim/character/idle.rs
index 901a0b9af4..bb76bd62de 100644
--- a/voxygen/src/anim/character/idle.rs
+++ b/voxygen/src/anim/character/idle.rs
@@ -1,5 +1,5 @@
 // Standard
-use std::f32::consts::PI;
+use std::{f32::consts::PI, ops::Mul};
 
 // Library
 use vek::*;
@@ -13,71 +13,79 @@ impl Animation for IdleAnimation {
     type Skeleton = CharacterSkeleton;
     type Dependency = f64;
 
-    fn update_skeleton(skeleton: &Self::Skeleton, time: f64) -> Self::Skeleton {
+    fn update_skeleton(
+        skeleton: &Self::Skeleton,
+        global_time: f64,
+        anim_time: f64,
+    ) -> Self::Skeleton {
         let mut next = (*skeleton).clone();
 
-        let wave = (time as f32 * 12.0).sin();
-        let wavecos = (time as f32 * 12.0).cos();
-        let wave_slow = (time as f32 * 6.0 + PI).sin();
-        let wavecos_slow = (time as f32 * 6.0 + PI).cos();
-        let waveultra_slow = (time as f32 * 1.0 + PI).sin();
-        let waveultracos_slow = (time as f32 * 1.0 + PI).cos();
+        let wave = (anim_time as f32 * 12.0).sin();
+        let wavecos = (anim_time as f32 * 12.0).cos();
+        let wave_slow = (anim_time as f32 * 6.0 + PI).sin();
+        let wavecos_slow = (anim_time as f32 * 6.0 + PI).cos();
+        let waveultra_slow = (anim_time as f32 * 1.0 + PI).sin();
+        let waveultracos_slow = (anim_time as f32 * 1.0 + PI).cos();
         let wave_dip = (wave_slow.abs() - 0.5).abs();
 
-        next.head.offset = Vec3::new(5.5, 0.0, 12.0 + waveultra_slow * 0.4);
-        next.head.ori = Quaternion::rotation_y(waveultra_slow * 0.05);
+        let head_look = Vec2::new(
+            (global_time as f32 / 5.0).floor().mul(7331.0).sin() * 0.5,
+            (global_time as f32 / 5.0).floor().mul(1337.0).sin() * 0.25,
+        );
+        next.head.offset = Vec3::new(5.5, 2.0, 11.5 + waveultra_slow * 0.4);
+        next.head.ori = Quaternion::rotation_z(head_look.x) * Quaternion::rotation_x(head_look.y);
         next.head.scale = Vec3::one();
 
-        next.chest.offset = Vec3::new(2.5, 0.0, 8.0 + waveultra_slow * 0.4);
-        next.chest.ori = Quaternion::rotation_y(0.0);
+        next.chest.offset = Vec3::new(5.5, 0.0, 7.5 + waveultra_slow * 0.4);
+        next.chest.ori = Quaternion::rotation_x(0.0);
         next.chest.scale = Vec3::one();
 
-        next.belt.offset = Vec3::new(2.5, 0.0, 6.0 + waveultra_slow * 0.4);
-        next.belt.ori = Quaternion::rotation_y(0.0);
+        next.belt.offset = Vec3::new(5.5, 0.0, 5.5 + waveultra_slow * 0.4);
+        next.belt.ori = Quaternion::rotation_x(0.0);
         next.belt.scale = Vec3::one();
 
-        next.shorts.offset = Vec3::new(2.5, 0.0, 3.0 + waveultra_slow * 0.4);
-        next.shorts.ori = Quaternion::rotation_y(0.0);
+        next.shorts.offset = Vec3::new(5.5, 0.0, 2.5 + waveultra_slow * 0.4);
+        next.shorts.ori = Quaternion::rotation_x(0.0);
         next.shorts.scale = Vec3::one();
 
         next.l_hand.offset = Vec3::new(
-            2.0 + waveultracos_slow * 0.3,
-            7.5,
-            12.5 + waveultra_slow * 1.1,
+            -7.5,
+            -2.0 + waveultracos_slow * 0.3,
+            12.0 + waveultra_slow * 1.1,
         );
-        next.l_hand.ori = Quaternion::rotation_y(0.0 + waveultra_slow * 0.06);
+        next.l_hand.ori = Quaternion::rotation_x(0.0 + waveultra_slow * 0.06);
         next.l_hand.scale = Vec3::one();
 
         next.r_hand.offset = Vec3::new(
-            2.0 + waveultracos_slow * 0.3,
-            -7.5,
-            12.5 + waveultra_slow * 1.1,
+            7.5,
+            -2.0 + waveultracos_slow * 0.3,
+            12.0 + waveultra_slow * 1.1,
         );
-        next.r_hand.ori = Quaternion::rotation_y(0.0 + waveultra_slow * 0.06);
+        next.r_hand.ori = Quaternion::rotation_x(0.0 + waveultra_slow * 0.06);
         next.r_hand.scale = Vec3::one();
 
-        next.l_foot.offset = Vec3::new(5.0, 3.4, 8.0);
-        next.l_foot.ori = Quaternion::rotation_y(0.04 + waveultra_slow * 0.04);
+        next.l_foot.offset = Vec3::new(-3.4, 0.0, 8.0);
+        next.l_foot.ori = Quaternion::identity();
         next.l_foot.scale = Vec3::one();
 
-        next.r_foot.offset = Vec3::new(5.0, -3.4, 8.0);
-        next.r_foot.ori = Quaternion::rotation_y(0.04 + waveultra_slow * 0.04);
+        next.r_foot.offset = Vec3::new(3.4, 0.0, 8.0);
+        next.r_foot.ori = Quaternion::identity();
         next.r_foot.scale = Vec3::one();
 
-        next.weapon.offset = Vec3::new(-4.5, 14.0, 13.0);
-        next.weapon.ori = Quaternion::rotation_x(2.5);
+        next.weapon.offset = Vec3::new(-5.0, -6.0, 18.5);
+        next.weapon.ori = Quaternion::rotation_y(2.5);
         next.weapon.scale = Vec3::one();
 
-        next.torso.offset = Vec3::new(-0.5, 0.0, 0.0);
-        next.torso.ori = Quaternion::rotation_y(0.0);
+        next.torso.offset = Vec3::new(-0.5, -0.2, 0.1);
+        next.torso.ori = Quaternion::rotation_x(0.0);
         next.torso.scale = Vec3::one() / 11.0;
 
         next.l_shoulder.offset = Vec3::new(2.9, 6.0, 18.0);
-        next.l_shoulder.ori = Quaternion::rotation_y(0.0);
+        next.l_shoulder.ori = Quaternion::rotation_x(0.0);
         next.l_shoulder.scale = Vec3::one();
 
         next.r_shoulder.offset = Vec3::new(2.9, -6.0, 18.0);
-        next.r_shoulder.ori = Quaternion::rotation_y(0.0);
+        next.r_shoulder.ori = Quaternion::rotation_x(0.0);
         next.r_shoulder.scale = Vec3::one();
 
         next
diff --git a/voxygen/src/anim/character/jump.rs b/voxygen/src/anim/character/jump.rs
new file mode 100644
index 0000000000..b966bce36e
--- /dev/null
+++ b/voxygen/src/anim/character/jump.rs
@@ -0,0 +1,84 @@
+// Standard
+use std::f32::consts::PI;
+
+// Library
+use vek::*;
+
+// Local
+use super::{super::Animation, CharacterSkeleton, SCALE};
+//
+
+pub struct JumpAnimation;
+
+impl Animation for JumpAnimation {
+    type Skeleton = CharacterSkeleton;
+    type Dependency = f64;
+
+    fn update_skeleton(
+        skeleton: &Self::Skeleton,
+        global_time: f64,
+        anim_time: f64,
+    ) -> Self::Skeleton {
+        let mut next = (*skeleton).clone();
+        let wave = (anim_time as f32 * 14.0).sin();
+        let arcwave = (1.0f32.ln_1p() - 1.0).abs();
+        let wavetest = (wave.cbrt());
+        let fuzzwave = (anim_time as f32 * 12.0).sin();
+        let wavecos = (anim_time as f32 * 14.0).cos();
+        let wave_slow = (anim_time as f32 * 5.0 + PI).min(PI / 2.0).sin();
+        let wave_slowtest = (anim_time as f32).min(PI / 2.0).sin();
+        let wavecos_slow = (anim_time as f32 * 8.0 + PI).cos();
+        let wave_dip = (wave_slow.abs() - 0.5).abs();
+        let mult = wave_slow / (wave_slow.abs());
+
+        next.head.offset = Vec3::new(5.5, 2.0, 12.0);
+        next.head.ori = Quaternion::rotation_x(0.15);
+        next.head.scale = Vec3::one();
+
+        next.chest.offset = Vec3::new(5.5, 0.0, 8.0);
+        next.chest.ori = Quaternion::rotation_z(0.0);
+        next.chest.scale = Vec3::one();
+
+        next.belt.offset = Vec3::new(5.5, 0.0, 6.0);
+        next.belt.ori = Quaternion::rotation_z(0.0);
+        next.belt.scale = Vec3::one();
+
+        next.shorts.offset = Vec3::new(5.5, 0.0, 3.0);
+        next.shorts.ori = Quaternion::rotation_z(0.0);
+        next.shorts.scale = Vec3::one();
+
+        next.l_hand.offset = Vec3::new(-7.5, -2.0, 12.0);
+        next.l_hand.ori = Quaternion::rotation_x(0.8);
+        next.l_hand.scale = Vec3::one();
+
+        next.r_hand.offset = Vec3::new(7.5, -2.0, 12.0);
+        next.r_hand.ori = Quaternion::rotation_x(-0.8);
+        next.r_hand.scale = Vec3::one();
+
+        next.l_foot.offset = Vec3::new(-3.4, 1.0, 6.0);
+        next.l_foot.ori = Quaternion::rotation_x(wave_slow * -1.2);
+        next.l_foot.scale = Vec3::one();
+
+        next.r_foot.offset = Vec3::new(3.4, -1.0, 6.0);
+        next.r_foot.ori = Quaternion::rotation_x(wave_slow * 1.2);
+        next.r_foot.scale = Vec3::one();
+
+        next.weapon.offset = Vec3::new(-5.0, -6.0, 19.0);
+        next.weapon.ori = Quaternion::rotation_y(2.5);
+        next.weapon.scale = Vec3::one();
+
+        next.torso.offset = Vec3::new(-0.5, 0.0, 0.2);
+        next.torso.ori = Quaternion::rotation_x(0.0);
+        next.torso.scale = Vec3::one() / 11.0;
+
+        next.l_shoulder.offset = Vec3::new(3.0, 6.0, 18.0);
+        next.l_shoulder.ori = Quaternion::rotation_y(0.0);
+        next.l_shoulder.scale = Vec3::one();
+
+        next.r_shoulder.offset = Vec3::new(3.0, -6.0, 18.0);
+        next.r_shoulder.ori = Quaternion::rotation_y(0.0);
+        next.r_shoulder.scale = Vec3::one();
+
+        next
+    }
+}
diff --git a/voxygen/src/anim/character/mod.rs b/voxygen/src/anim/character/mod.rs
index c0f15f1da3..8671f5ca10 100644
--- a/voxygen/src/anim/character/mod.rs
+++ b/voxygen/src/anim/character/mod.rs
@@ -1,10 +1,11 @@
 pub mod idle;
+pub mod jump;
 pub mod run;
 
 // Reexports
 pub use self::idle::IdleAnimation;
+pub use self::jump::JumpAnimation;
 pub use self::run::RunAnimation;
-
 // Crate
 use crate::render::FigureBoneData;
 
diff --git a/voxygen/src/anim/character/run.rs b/voxygen/src/anim/character/run.rs
index 39269d40c8..e6f2f6a8c0 100644
--- a/voxygen/src/anim/character/run.rs
+++ b/voxygen/src/anim/character/run.rs
@@ -11,57 +11,61 @@ pub struct RunAnimation;
 
 impl Animation for RunAnimation {
     type Skeleton = CharacterSkeleton;
-    type Dependency = f64;
+    type Dependency = (f32, f64);
 
-    fn update_skeleton(skeleton: &Self::Skeleton, time: f64) -> Self::Skeleton {
+    fn update_skeleton(
+        skeleton: &Self::Skeleton,
+        (velocity, global_time): Self::Dependency,
+        anim_time: f64,
+    ) -> Self::Skeleton {
         let mut next = (*skeleton).clone();
 
-        let wave = (time as f32 * 14.0).sin();
+        let wave = (anim_time as f32 * 14.0).sin();
         let wavetest = (wave.cbrt());
-        let fuzzwave = (time as f32 * 12.0).sin();
-        let wavecos = (time as f32 * 14.0).cos();
-        let wave_slow = (time as f32 * 7.0 + PI).sin();
-        let wavecos_slow = (time as f32 * 8.0 + PI).cos();
+        let fuzzwave = (anim_time as f32 * 12.0).sin();
+        let wavecos = (anim_time as f32 * 14.0).cos();
+        let wave_slow = (anim_time as f32 * 7.0 + PI).sin();
+        let wavecos_slow = (anim_time as f32 * 8.0 + PI).cos();
         let wave_dip = (wave_slow.abs() - 0.5).abs();
 
-        next.head.offset = Vec3::new(6.0, 0.0, 12.0 + wavecos * 1.3);
-        next.head.ori = Quaternion::rotation_y(-0.15);
+        next.head.offset = Vec3::new(5.5, 2.0, 12.0 + wavecos * 1.3);
+        next.head.ori = Quaternion::rotation_x(0.15);
         next.head.scale = Vec3::one();
 
-        next.chest.offset = Vec3::new(2.5, 0.0, 8.0 + wavecos * 1.1);
+        next.chest.offset = Vec3::new(5.5, 0.0, 8.0 + wavecos * 1.1);
         next.chest.ori = Quaternion::rotation_z(wave * 0.1);
         next.chest.scale = Vec3::one();
 
-        next.belt.offset = Vec3::new(2.5, 0.0, 6.0 + wavecos * 1.1);
+        next.belt.offset = Vec3::new(5.5, 0.0, 6.0 + wavecos * 1.1);
         next.belt.ori = Quaternion::rotation_z(wave * 0.25);
         next.belt.scale = Vec3::one();
 
-        next.shorts.offset = Vec3::new(2.5, 0.0, 3.0 + wavecos * 1.1);
+        next.shorts.offset = Vec3::new(5.5, 0.0, 3.0 + wavecos * 1.1);
         next.shorts.ori = Quaternion::rotation_z(wave * 0.6);
         next.shorts.scale = Vec3::one();
 
-        next.l_hand.offset = Vec3::new(2.0 - wavecos * 2.5, 7.5, 12.0 + wave * 1.5);
-        next.l_hand.ori = Quaternion::rotation_y(wavecos * 0.9);
+        next.l_hand.offset = Vec3::new(-7.5, -2.0 + wavecos * 2.5, 12.0 - wave * 1.5);
+        next.l_hand.ori = Quaternion::rotation_x(wavecos * 0.9);
         next.l_hand.scale = Vec3::one();
 
-        next.r_hand.offset = Vec3::new(2.0 + wavecos * 2.5, -7.5, 12.0 - wave * 1.5);
-        next.r_hand.ori = Quaternion::rotation_y(wavecos * -0.9);
+        next.r_hand.offset = Vec3::new(7.5, -2.0 - wavecos * 2.5, 12.0 + wave * 1.5);
+        next.r_hand.ori = Quaternion::rotation_x(wavecos * -0.9);
         next.r_hand.scale = Vec3::one();
 
-        next.l_foot.offset = Vec3::new(3.5 + wave * 1.0, 3.4, 6.0);
-        next.l_foot.ori = Quaternion::rotation_y(-0.0 - wave * 1.5);
+        next.l_foot.offset = Vec3::new(-3.4, 0.0 + wave * 1.0, 6.0);
+        next.l_foot.ori = Quaternion::rotation_x(-0.0 - wave * 1.5);
         next.l_foot.scale = Vec3::one();
 
-        next.r_foot.offset = Vec3::new(3.5 - wave * 1.0, -3.4, 6.0);
-        next.r_foot.ori = Quaternion::rotation_y(-0.0 + wave * 1.5);
+        next.r_foot.offset = Vec3::new(3.4, 0.0 - wave * 1.0, 6.0);
+        next.r_foot.ori = Quaternion::rotation_x(-0.0 + wave * 1.5);
         next.r_foot.scale = Vec3::one();
 
-        next.weapon.offset = Vec3::new(-5.0, 14.0, 13.0);
-        next.weapon.ori = Quaternion::rotation_x(2.5);
+        next.weapon.offset = Vec3::new(-5.0, -6.0, 19.0);
+        next.weapon.ori = Quaternion::rotation_y(2.5);
         next.weapon.scale = Vec3::one();
 
-        next.torso.offset = Vec3::new(-0.5, 0.0, 0.0);
-        next.torso.ori = Quaternion::rotation_y(0.25 + wavecos * 0.1);
+        next.torso.offset = Vec3::new(-0.5, -0.2, 0.2);
+        next.torso.ori = Quaternion::rotation_x(-velocity * 0.05 - wavecos * 0.1);
         next.torso.scale = Vec3::one() / 11.0;
 
         next.l_shoulder.offset = Vec3::new(3.0, 6.0, 18.0);
diff --git a/voxygen/src/anim/mod.rs b/voxygen/src/anim/mod.rs
index 47cee92280..38452e6c65 100644
--- a/voxygen/src/anim/mod.rs
+++ b/voxygen/src/anim/mod.rs
@@ -50,5 +50,9 @@ pub trait Animation {
     type Dependency;
 
     /// Returns a new skeleton that is generated by the animation
-    fn update_skeleton(skeleton: &Self::Skeleton, dependency: Self::Dependency) -> Self::Skeleton;
+    fn update_skeleton(
+        skeleton: &Self::Skeleton,
+        dependency: Self::Dependency,
+        anim_time: f64,
+    ) -> Self::Skeleton;
 }
diff --git a/voxygen/src/key_state.rs b/voxygen/src/key_state.rs
index c25bb4dd7b..22e666f0ba 100644
--- a/voxygen/src/key_state.rs
+++ b/voxygen/src/key_state.rs
@@ -20,13 +20,15 @@ impl KeyState {
     }
 
     pub fn dir_vec(&self) -> Vec2<f32> {
-        Vec2::<f32>::new(
+        let dir = Vec2::<f32>::new(
             if self.right { 1.0 } else { 0.0 } + if self.left { -1.0 } else { 0.0 },
             if self.up { 1.0 } else { 0.0 } + if self.down { -1.0 } else { 0.0 },
-        )
-    }
+        );
 
-    pub fn jump(&self) -> bool {
-        self.jump
+        if dir.magnitude_squared() == 0.0 {
+            dir
+        } else {
+            dir.normalized()
+        }
     }
 }
diff --git a/voxygen/src/menu/main/client_init.rs b/voxygen/src/menu/main/client_init.rs
index 732b849179..2781bd9662 100644
--- a/voxygen/src/menu/main/client_init.rs
+++ b/voxygen/src/menu/main/client_init.rs
@@ -1,8 +1,10 @@
 use client::{error::Error as ClientError, Client};
 use common::comp;
 use std::{
+    net::ToSocketAddrs,
     sync::mpsc::{channel, Receiver, TryRecvError},
     thread::{self, JoinHandle},
+    time::Duration,
 };
 
 #[derive(Debug)]
@@ -13,6 +15,7 @@ pub enum Error {
     NoAddress,
     // Parsing/host name resolution successful but could not connect
     ConnectionFailed(ClientError),
+    ClientCrashed,
 }
 
 // Used to asynchronusly parse the server address, resolve host names, and create the client (which involves establishing a connection to the server)
@@ -20,14 +23,21 @@ pub struct ClientInit {
     rx: Receiver<Result<Client, Error>>,
 }
 impl ClientInit {
-    pub fn new(connection_args: (String, u16, bool), client_args: (comp::Player, u64)) -> Self {
+    pub fn new(
+        connection_args: (String, u16, bool),
+        client_args: (comp::Player, u64),
+        wait: bool,
+    ) -> Self {
         let (server_address, default_port, prefer_ipv6) = connection_args;
         let (player, view_distance) = client_args;
 
         let (tx, rx) = channel();
 
         let handle = Some(thread::spawn(move || {
-            use std::net::ToSocketAddrs;
+            // Sleep the thread to wait for the single-player server to start up
+            if wait {
+                thread::sleep(Duration::from_millis(500));
+            }
             // Parses ip address or resolves hostname
             // Note: if you use an ipv6 address the number after the last colon will be used as the port unless you use [] around the address
             match server_address
@@ -80,7 +90,7 @@ impl ClientInit {
         match self.rx.try_recv() {
             Ok(result) => Some(result),
             Err(TryRecvError::Empty) => None,
-            Err(TryRecvError::Disconnected) => panic!("Thread panicked or already finished"),
+            Err(TryRecvError::Disconnected) => Some(Err(Error::ClientCrashed)),
         }
     }
 }
diff --git a/voxygen/src/menu/main/mod.rs b/voxygen/src/menu/main/mod.rs
index 78b431b9a8..f87fd6128b 100644
--- a/voxygen/src/menu/main/mod.rs
+++ b/voxygen/src/menu/main/mod.rs
@@ -78,6 +78,7 @@ impl PlayState for MainMenuState {
                         match err {
                             InitError::BadAddress(_) | InitError::NoAddress => "Server not found",
                             InitError::ConnectionFailed(_) => "Connection failed",
+                            InitError::ClientCrashed => "Client crashed",
                         }
                         .to_string(),
                     );
@@ -102,6 +103,7 @@ impl PlayState for MainMenuState {
                         client_init = client_init.or(Some(ClientInit::new(
                             (server_address, DEFAULT_PORT, false),
                             (comp::Player::new(username.clone()), 300),
+                            false,
                         )));
                     }
                     MainMenuEvent::StartSingleplayer => {
diff --git a/voxygen/src/menu/main/start_singleplayer.rs b/voxygen/src/menu/main/start_singleplayer.rs
index a8c83457dc..3e6e449540 100644
--- a/voxygen/src/menu/main/start_singleplayer.rs
+++ b/voxygen/src/menu/main/start_singleplayer.rs
@@ -4,17 +4,20 @@ use crate::{
     PlayState, PlayStateResult,
 };
 use common::comp;
+use log::warn;
+use std::net::SocketAddr;
 
 pub struct StartSingleplayerState {
     singleplayer: Singleplayer,
+    sock: SocketAddr,
 }
 
 impl StartSingleplayerState {
     /// Create a new `MainMenuState`
     pub fn new() -> Self {
-        Self {
-            singleplayer: Singleplayer::new(),
-        }
+        let (singleplayer, sock) = Singleplayer::new();
+
+        Self { singleplayer, sock }
     }
 }
 
@@ -23,19 +26,23 @@ impl PlayState for StartSingleplayerState {
         match direction {
             Direction::Forwards => {
                 let username = "singleplayer".to_owned();
-                let server_address = "localhost".to_owned();
+                let server_address = self.sock.ip().to_string();
 
                 let client_init = ClientInit::new(
-                    (server_address.clone(), DEFAULT_PORT, false),
+                    (server_address.clone(), self.sock.port(), false),
                     (comp::Player::new(username.clone()), 300),
+                    true,
                 );
 
                 // Client creation
                 let client = loop {
                     match client_init.poll() {
                         Some(Ok(client)) => break client,
-                        // Should always work
-                        Some(Err(err)) => unreachable!(),
+                        // An error occured!
+                        Some(Err(err)) => {
+                            warn!("Failed to start singleplayer server: {:?}", err);
+                            return PlayStateResult::Pop;
+                        }
                         _ => {}
                     }
                 };
diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs
index d11de34885..511bdd2fc5 100644
--- a/voxygen/src/render/mod.rs
+++ b/voxygen/src/render/mod.rs
@@ -23,7 +23,7 @@ pub use self::{
         },
         Globals,
     },
-    renderer::{Renderer, TgtColorFmt, TgtDepthFmt},
+    renderer::{Renderer, TgtColorFmt, TgtDepthFmt, WinColorFmt, WinDepthFmt},
     texture::Texture,
 };
 
diff --git a/voxygen/src/render/pipelines/mod.rs b/voxygen/src/render/pipelines/mod.rs
index c425c2d5eb..f58b520ee4 100644
--- a/voxygen/src/render/pipelines/mod.rs
+++ b/voxygen/src/render/pipelines/mod.rs
@@ -27,6 +27,7 @@ gfx_defines! {
         view_distance: [f32; 4] = "view_distance",
         time_of_day: [f32; 4] = "time_of_day", // TODO: Make this f64
         tick: [f32; 4] = "tick",
+        screen_res: [f32; 4] = "screen_res",
     }
 }
 
@@ -41,6 +42,7 @@ impl Globals {
             view_distance: [0.0; 4],
             time_of_day: [0.0; 4],
             tick: [0.0; 4],
+            screen_res: [800.0, 500.0, 0.0, 0.0],
         }
     }
 
@@ -53,6 +55,7 @@ impl Globals {
         view_distance: f32,
         time_of_day: f64,
         tick: f64,
+        screen_res: Vec2<u16>,
     ) -> Self {
         Self {
             view_mat: arr_to_mat(view_mat.into_col_array()),
@@ -62,6 +65,7 @@ impl Globals {
             view_distance: [view_distance; 4],
             time_of_day: [time_of_day as f32; 4],
             tick: [tick as f32; 4],
+            screen_res: Vec4::from(screen_res.map(|e| e as f32)).into_array(),
         }
     }
 }
diff --git a/voxygen/src/render/pipelines/postprocess.rs b/voxygen/src/render/pipelines/postprocess.rs
index feca548759..34cebebaf8 100644
--- a/voxygen/src/render/pipelines/postprocess.rs
+++ b/voxygen/src/render/pipelines/postprocess.rs
@@ -12,7 +12,7 @@ use gfx::{
 
 // Local
 use super::{
-    super::{Mesh, Pipeline, TgtColorFmt, TgtDepthFmt, Tri},
+    super::{Mesh, Pipeline, Tri, WinColorFmt, WinDepthFmt},
     Globals,
 };
 
@@ -31,10 +31,10 @@ gfx_defines! {
         locals: gfx::ConstantBuffer<Locals> = "u_locals",
         globals: gfx::ConstantBuffer<Globals> = "u_globals",
 
-        src_sampler: gfx::TextureSampler<<TgtColorFmt as gfx::format::Formatted>::View> = "src_color",
+        src_sampler: gfx::TextureSampler<<WinColorFmt as gfx::format::Formatted>::View> = "src_color",
 
-        tgt_color: gfx::RenderTarget<TgtColorFmt> = "tgt_color",
-        tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::PASS_TEST,
+        tgt_color: gfx::RenderTarget<WinColorFmt> = "tgt_color",
+        tgt_depth: gfx::DepthTarget<WinDepthFmt> = gfx::preset::depth::PASS_TEST,
     }
 }
 
diff --git a/voxygen/src/render/pipelines/ui.rs b/voxygen/src/render/pipelines/ui.rs
index 54bde26431..2ebbcc3bcf 100644
--- a/voxygen/src/render/pipelines/ui.rs
+++ b/voxygen/src/render/pipelines/ui.rs
@@ -1,4 +1,4 @@
-use super::super::{Pipeline, Quad, TgtColorFmt, TgtDepthFmt, Tri};
+use super::super::{Pipeline, Quad, Tri, WinColorFmt, WinDepthFmt};
 use gfx::{
     self,
     // Macros
@@ -25,8 +25,8 @@ gfx_defines! {
 
         scissor: gfx::Scissor = (),
 
-        tgt_color: gfx::BlendTarget<TgtColorFmt> = ("tgt_color", gfx::state::ColorMask::all(), gfx::preset::blend::ALPHA),
-        tgt_depth: gfx::DepthTarget<TgtDepthFmt> = gfx::preset::depth::PASS_TEST,
+        tgt_color: gfx::BlendTarget<WinColorFmt> = ("tgt_color", gfx::state::ColorMask::all(), gfx::preset::blend::ALPHA),
+        tgt_depth: gfx::DepthTarget<WinDepthFmt> = gfx::preset::depth::PASS_TEST,
     }
 }
 
diff --git a/voxygen/src/render/renderer.rs b/voxygen/src/render/renderer.rs
index f3645326d7..bc553ae536 100644
--- a/voxygen/src/render/renderer.rs
+++ b/voxygen/src/render/renderer.rs
@@ -15,16 +15,26 @@ use gfx::{
 use image;
 use vek::*;
 
-/// Represents the format of the window's color target.
-pub type TgtColorFmt = gfx::format::Rgba8;
-/// Represents the format of the window's depth target.
+/// Represents the format of the pre-processed color target.
+pub type TgtColorFmt = gfx::format::Rgba16F;
+/// Represents the format of the pre-processed depth target.
 pub type TgtDepthFmt = gfx::format::DepthStencil;
 
-/// A handle to a window color target.
+/// Represents the format of the window's color target.
+pub type WinColorFmt = gfx::format::Rgba8;
+/// Represents the format of the window's depth target.
+pub type WinDepthFmt = gfx::format::DepthStencil;
+
+/// A handle to a pre-processed color target.
 pub type TgtColorView = gfx::handle::RenderTargetView<gfx_backend::Resources, TgtColorFmt>;
-/// A handle to a window depth target.
+/// A handle to a pre-processed depth target.
 pub type TgtDepthView = gfx::handle::DepthStencilView<gfx_backend::Resources, TgtDepthFmt>;
 
+/// A handle to a window color target.
+pub type WinColorView = gfx::handle::RenderTargetView<gfx_backend::Resources, WinColorFmt>;
+/// A handle to a window depth target.
+pub type WinDepthView = gfx::handle::DepthStencilView<gfx_backend::Resources, WinDepthFmt>;
+
 /// A handle to a render color target as a resource.
 pub type TgtColorRes = gfx::handle::ShaderResourceView<
     gfx_backend::Resources,
@@ -39,8 +49,8 @@ pub struct Renderer {
     encoder: gfx::Encoder<gfx_backend::Resources, gfx_backend::CommandBuffer>,
     factory: gfx_backend::Factory,
 
-    win_color_view: TgtColorView,
-    win_depth_view: TgtDepthView,
+    win_color_view: WinColorView,
+    win_depth_view: WinDepthView,
 
     tgt_color_view: TgtColorView,
     tgt_depth_view: TgtDepthView,
@@ -62,8 +72,8 @@ impl Renderer {
     pub fn new(
         device: gfx_backend::Device,
         mut factory: gfx_backend::Factory,
-        win_color_view: TgtColorView,
-        win_depth_view: TgtDepthView,
+        win_color_view: WinColorView,
+        win_depth_view: WinDepthView,
     ) -> Result<Self, RenderError> {
         // Construct a pipeline for rendering skyboxes
         let skybox_pipeline = create_pipeline(
@@ -139,13 +149,27 @@ impl Renderer {
         })
     }
 
+    /// Get references to the internal render target views that get rendered to before post-processing.
+    #[allow(dead_code)]
+    pub fn tgt_views(&self) -> (&TgtColorView, &TgtDepthView) {
+        (&self.tgt_color_view, &self.tgt_depth_view)
+    }
+
     /// Get references to the internal render target views that get displayed directly by the window.
-    pub fn target_views(&self) -> (&TgtColorView, &TgtDepthView) {
+    #[allow(dead_code)]
+    pub fn win_views(&self) -> (&WinColorView, &WinDepthView) {
         (&self.win_color_view, &self.win_depth_view)
     }
 
+    /// Get mutable references to the internal render target views that get rendered to before post-processing.
+    #[allow(dead_code)]
+    pub fn tgt_views_mut(&mut self) -> (&mut TgtColorView, &mut TgtDepthView) {
+        (&mut self.tgt_color_view, &mut self.tgt_depth_view)
+    }
+
     /// Get mutable references to the internal render target views that get displayed directly by the window.
-    pub fn target_views_mut(&mut self) -> (&mut TgtColorView, &mut TgtDepthView) {
+    #[allow(dead_code)]
+    pub fn win_views_mut(&mut self) -> (&mut WinColorView, &mut WinDepthView) {
         (&mut self.win_color_view, &mut self.win_depth_view)
     }
 
@@ -178,8 +202,8 @@ impl Renderer {
     /// Get the resolution of the render target.
     pub fn get_resolution(&self) -> Vec2<u16> {
         Vec2::new(
-            self.tgt_color_view.get_dimensions().0,
-            self.tgt_color_view.get_dimensions().1,
+            self.win_color_view.get_dimensions().0,
+            self.win_color_view.get_dimensions().1,
         )
     }
 
diff --git a/voxygen/src/scene/camera.rs b/voxygen/src/scene/camera.rs
index 7dae0f5a52..c72da5ec54 100644
--- a/voxygen/src/scene/camera.rs
+++ b/voxygen/src/scene/camera.rs
@@ -11,7 +11,7 @@ use vek::*;
 const NEAR_PLANE: f32 = 0.1;
 const FAR_PLANE: f32 = 10000.0;
 
-const INTERP_TIME: f32 = 0.2;
+const INTERP_TIME: f32 = 0.1;
 
 pub struct Camera {
     tgt_focus: Vec3<f32>,
diff --git a/voxygen/src/scene/figure.rs b/voxygen/src/scene/figure.rs
index af37bb5388..b9763f6731 100644
--- a/voxygen/src/scene/figure.rs
+++ b/voxygen/src/scene/figure.rs
@@ -1,6 +1,6 @@
 use crate::{
     anim::{
-        character::{CharacterSkeleton, IdleAnimation, RunAnimation},
+        character::{CharacterSkeleton, IdleAnimation, JumpAnimation, RunAnimation},
         Animation, Skeleton,
     },
     mesh::Meshable,
@@ -110,7 +110,7 @@ impl FigureCache {
             match head {
                 Head::DefaultHead => "head.vox",
             },
-            Vec3::new(-7.5, -8.0, 0.0),
+            Vec3::new(-7.0, -5.5, -6.0),
         )
     }
 
@@ -119,7 +119,7 @@ impl FigureCache {
             match chest {
                 Chest::DefaultChest => "chest.vox",
             },
-            Vec3::new(-2.5, -6.0, 0.0),
+            Vec3::new(-6.0, -3.5, 0.0),
         )
     }
 
@@ -128,7 +128,7 @@ impl FigureCache {
             match belt {
                 Belt::DefaultBelt => "belt.vox",
             },
-            Vec3::new(-2.5, -5.0, 0.0),
+            Vec3::new(-5.0, -3.5, 0.0),
         )
     }
 
@@ -137,7 +137,7 @@ impl FigureCache {
             match pants {
                 Pants::DefaultPants => "pants.vox",
             },
-            Vec3::new(-2.5, -5.0, 0.0),
+            Vec3::new(-5.0, -3.5, 0.0),
         )
     }
 
@@ -146,7 +146,7 @@ impl FigureCache {
             match hand {
                 Hand::DefaultHand => "hand.vox",
             },
-            Vec3::new(0.0, -2.0, -7.0),
+            Vec3::new(3.5, 0.0, -7.0),
         )
     }
 
@@ -155,7 +155,7 @@ impl FigureCache {
             match hand {
                 Hand::DefaultHand => "hand.vox",
             },
-            Vec3::new(0.0, -2.0, -7.0),
+            Vec3::new(3.5, 0.0, -7.0),
         )
     }
 
@@ -164,7 +164,7 @@ impl FigureCache {
             match foot {
                 Foot::DefaultFoot => "foot.vox",
             },
-            Vec3::new(-3.5, -2.5, -8.0),
+            Vec3::new(2.5, -3.5, -9.0),
         )
     }
 
@@ -173,7 +173,7 @@ impl FigureCache {
             match foot {
                 Foot::DefaultFoot => "foot.vox",
             },
-            Vec3::new(-3.5, -2.5, -8.0),
+            Vec3::new(2.5, -3.5, -9.0),
         )
     }
 
@@ -191,9 +191,10 @@ impl FigureCache {
     pub fn maintain(&mut self, renderer: &mut Renderer, client: &mut Client) {
         let time = client.state().get_time();
         let ecs = client.state_mut().ecs_mut();
-        for (entity, pos, dir, character, animation_history) in (
+        for (entity, pos, vel, dir, character, animation_history) in (
             &ecs.entities(),
             &ecs.read_storage::<comp::phys::Pos>(),
+            &ecs.read_storage::<comp::phys::Vel>(),
             &ecs.read_storage::<comp::phys::Dir>(),
             &ecs.read_storage::<comp::Character>(),
             &ecs.read_storage::<comp::AnimationHistory>(),
@@ -206,12 +207,21 @@ impl FigureCache {
                 .or_insert_with(|| FigureState::new(renderer, CharacterSkeleton::new()));
 
             let target_skeleton = match animation_history.current {
-                comp::character::Animation::Idle => {
-                    IdleAnimation::update_skeleton(&mut state.skeleton, time)
-                }
-                comp::character::Animation::Run => {
-                    RunAnimation::update_skeleton(&mut state.skeleton, time)
-                }
+                comp::character::Animation::Idle => IdleAnimation::update_skeleton(
+                    &mut state.skeleton,
+                    time,
+                    animation_history.time,
+                ),
+                comp::character::Animation::Run => RunAnimation::update_skeleton(
+                    &mut state.skeleton,
+                    (vel.0.magnitude(), time),
+                    animation_history.time,
+                ),
+                comp::character::Animation::Jump => JumpAnimation::update_skeleton(
+                    &mut state.skeleton,
+                    time,
+                    animation_history.time,
+                ),
             };
 
             state.skeleton.interpolate(&target_skeleton);
@@ -262,7 +272,7 @@ impl<S: Skeleton> FigureState<S> {
     fn update(&mut self, renderer: &mut Renderer, pos: Vec3<f32>, dir: Vec3<f32>) {
         let mat = Mat4::<f32>::identity()
             * Mat4::translation_3d(pos)
-            * Mat4::rotation_z(-dir.x.atan2(dir.y) + f32::consts::PI / 2.0);
+            * Mat4::rotation_z(-dir.x.atan2(dir.y)); // + f32::consts::PI / 2.0);
 
         let locals = FigureLocals::new(mat);
         renderer.update_consts(&mut self.locals, &[locals]).unwrap();
diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs
index 0c5c2d9376..e445495cf3 100644
--- a/voxygen/src/scene/mod.rs
+++ b/voxygen/src/scene/mod.rs
@@ -115,7 +115,7 @@ impl Scene {
             .unwrap_or(Vec3::zero());
 
         // Alter camera position to match player
-        self.camera.set_focus_pos(player_pos + Vec3::unit_z() * 3.5);
+        self.camera.set_focus_pos(player_pos + Vec3::unit_z() * 2.1);
 
         // Tick camera for interpolation
         self.camera.update(client.state().get_time());
@@ -135,6 +135,7 @@ impl Scene {
                     10.0,
                     client.state().get_time_of_day(),
                     client.state().get_time(),
+                    renderer.get_resolution(),
                 )],
             )
             .expect("Failed to update global constants");
diff --git a/voxygen/src/session.rs b/voxygen/src/session.rs
index d1b9de0361..b66d036118 100644
--- a/voxygen/src/session.rs
+++ b/voxygen/src/session.rs
@@ -7,9 +7,9 @@ use crate::{
     window::{Event, Key, Window},
     Direction, Error, GlobalState, PlayState, PlayStateResult,
 };
-use client::{self, Client};
+use client::{self, Client, Input, InputEvent};
 use common::clock::Clock;
-use std::{cell::RefCell, rc::Rc, time::Duration};
+use std::{cell::RefCell, mem, rc::Rc, time::Duration};
 use vek::*;
 
 const FPS: u64 = 60;
@@ -18,6 +18,7 @@ pub struct SessionState {
     scene: Scene,
     client: Rc<RefCell<Client>>,
     key_state: KeyState,
+    input_events: Vec<InputEvent>,
     hud: Hud,
 }
 
@@ -32,6 +33,7 @@ impl SessionState {
             client,
             key_state: KeyState::new(),
             hud: Hud::new(window, settings),
+            input_events: Vec::new(),
         }
     }
 }
@@ -56,11 +58,18 @@ impl SessionState {
         let dir_vec = self.key_state.dir_vec();
         let move_dir = unit_vecs.0 * dir_vec[0] + unit_vecs.1 * dir_vec[1];
 
-        for event in self
-            .client
-            .borrow_mut()
-            .tick(client::Input { move_dir }, dt)?
-        {
+        // Take the input events
+        let mut input_events = Vec::new();
+        mem::swap(&mut self.input_events, &mut input_events);
+
+        for event in self.client.borrow_mut().tick(
+            Input {
+                move_dir,
+                jumping: self.key_state.jump,
+                events: input_events,
+            },
+            dt,
+        )? {
             match event {
                 client::Event::Chat(msg) => {
                     self.hud.new_message(msg);
@@ -132,11 +141,16 @@ impl PlayState for SessionState {
                     Event::KeyDown(Key::MoveBack) => self.key_state.down = true,
                     Event::KeyDown(Key::MoveLeft) => self.key_state.left = true,
                     Event::KeyDown(Key::MoveRight) => self.key_state.right = true,
+                    Event::KeyDown(Key::Jump) => {
+                        self.input_events.push(InputEvent::Jump);
+                        self.key_state.jump = true;
+                    }
                     // Movement Key Released
                     Event::KeyUp(Key::MoveForward) => self.key_state.up = false,
                     Event::KeyUp(Key::MoveBack) => self.key_state.down = false,
                     Event::KeyUp(Key::MoveLeft) => self.key_state.left = false,
                     Event::KeyUp(Key::MoveRight) => self.key_state.right = false,
+                    Event::KeyUp(Key::Jump) => self.key_state.jump = false,
                     // Pass all other events to the scene
                     event => {
                         self.scene.handle_input_event(event);
diff --git a/voxygen/src/settings.rs b/voxygen/src/settings.rs
index e911498c76..5a22ee9936 100644
--- a/voxygen/src/settings.rs
+++ b/voxygen/src/settings.rs
@@ -24,6 +24,7 @@ pub struct ControlSettings {
     pub move_left: VirtualKeyCode,
     pub move_back: VirtualKeyCode,
     pub move_right: VirtualKeyCode,
+    pub jump: VirtualKeyCode,
     pub map: VirtualKeyCode,
     pub bag: VirtualKeyCode,
     pub quest_log: VirtualKeyCode,
@@ -58,6 +59,7 @@ impl Default for Settings {
                 move_left: VirtualKeyCode::A,
                 move_back: VirtualKeyCode::S,
                 move_right: VirtualKeyCode::D,
+                jump: VirtualKeyCode::Space,
                 map: VirtualKeyCode::M,
                 bag: VirtualKeyCode::B,
                 quest_log: VirtualKeyCode::L,
diff --git a/voxygen/src/singleplayer.rs b/voxygen/src/singleplayer.rs
index c4ad5f6eb9..bb56791f65 100644
--- a/voxygen/src/singleplayer.rs
+++ b/voxygen/src/singleplayer.rs
@@ -1,9 +1,13 @@
 use common::clock::Clock;
 use log::info;
+use portpicker::pick_unused_port;
 use server::{Event, Input, Server};
-use std::sync::mpsc::{channel, Receiver, Sender, TryRecvError};
-use std::time::Duration;
-use std::{thread, thread::JoinHandle};
+use std::{
+    net::SocketAddr,
+    sync::mpsc::{channel, Receiver, Sender, TryRecvError},
+    thread::{self, JoinHandle},
+    time::Duration,
+};
 
 const TPS: u64 = 30;
 
@@ -19,15 +23,26 @@ pub struct Singleplayer {
 }
 
 impl Singleplayer {
-    pub fn new() -> Self {
+    pub fn new() -> (Self, SocketAddr) {
         let (sender, reciever) = channel();
+
+        let sock = SocketAddr::from((
+            [127, 0, 0, 1],
+            pick_unused_port().expect("Failed to find unused port"),
+        ));
+
+        let sock2 = sock.clone();
         let thread = thread::spawn(move || {
-            run_server(reciever);
+            run_server(sock2, reciever);
         });
-        Singleplayer {
-            server_thread: thread,
-            sender,
-        }
+
+        (
+            Singleplayer {
+                server_thread: thread,
+                sender,
+            },
+            sock,
+        )
     }
 }
 
@@ -37,14 +52,14 @@ impl Drop for Singleplayer {
     }
 }
 
-fn run_server(rec: Receiver<Msg>) {
+fn run_server(sock: SocketAddr, rec: Receiver<Msg>) {
     info!("Starting server-cli...");
 
     // Set up an fps clock
     let mut clock = Clock::new();
 
     // Create server
-    let mut server = Server::new().expect("Failed to create server instance");
+    let mut server = Server::bind(sock).expect("Failed to create server instance");
 
     loop {
         let events = server
diff --git a/voxygen/src/window.rs b/voxygen/src/window.rs
index 824b679d0b..9f5cdd44fb 100644
--- a/voxygen/src/window.rs
+++ b/voxygen/src/window.rs
@@ -1,5 +1,5 @@
 use crate::{
-    render::{Renderer, TgtColorFmt, TgtDepthFmt},
+    render::{Renderer, WinColorFmt, WinDepthFmt},
     settings::Settings,
     ui, Error,
 };
@@ -29,8 +29,8 @@ impl Window {
             .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGl, (3, 2)))
             .with_vsync(false);
 
-        let (window, device, factory, tgt_color_view, tgt_depth_view) =
-            gfx_window_glutin::init::<TgtColorFmt, TgtDepthFmt>(
+        let (window, device, factory, win_color_view, win_depth_view) =
+            gfx_window_glutin::init::<WinColorFmt, WinDepthFmt>(
                 win_builder,
                 ctx_builder,
                 &events_loop,
@@ -45,6 +45,7 @@ impl Window {
         key_map.insert(settings.controls.move_left, Key::MoveLeft);
         key_map.insert(settings.controls.move_back, Key::MoveBack);
         key_map.insert(settings.controls.move_right, Key::MoveRight);
+        key_map.insert(settings.controls.jump, Key::Jump);
         key_map.insert(settings.controls.map, Key::Map);
         key_map.insert(settings.controls.bag, Key::Bag);
         key_map.insert(settings.controls.quest_log, Key::QuestLog);
@@ -57,7 +58,7 @@ impl Window {
 
         let tmp = Ok(Self {
             events_loop,
-            renderer: Renderer::new(device, factory, tgt_color_view, tgt_depth_view)?,
+            renderer: Renderer::new(device, factory, win_color_view, win_depth_view)?,
             window,
             cursor_grabbed: false,
             needs_refresh_resize: false,
@@ -100,7 +101,7 @@ impl Window {
                 glutin::Event::WindowEvent { event, .. } => match event {
                     glutin::WindowEvent::CloseRequested => events.push(Event::Close),
                     glutin::WindowEvent::Resized(glutin::dpi::LogicalSize { width, height }) => {
-                        let (mut color_view, mut depth_view) = renderer.target_views_mut();
+                        let (mut color_view, mut depth_view) = renderer.win_views_mut();
                         gfx_window_glutin::update_views(&window, &mut color_view, &mut depth_view);
                         renderer.on_resize().unwrap();
                         events.push(Event::Resize(Vec2::new(width as u32, height as u32)));
@@ -180,6 +181,7 @@ pub enum Key {
     MoveBack,
     MoveLeft,
     MoveRight,
+    Jump,
     Enter,
     Escape,
     Map,
diff --git a/world/src/lib.rs b/world/src/lib.rs
index 7a29dc2f2f..98242c847c 100644
--- a/world/src/lib.rs
+++ b/world/src/lib.rs
@@ -1,5 +1,5 @@
 // Library
-use noise::{NoiseFn, Perlin};
+use noise::{NoiseFn, Perlin, Seedable};
 use vek::*;
 
 // Project
@@ -32,30 +32,43 @@ impl World {
         let dirt = Block::new(3, Rgb::new(128, 90, 0));
         let sand = Block::new(4, Rgb::new(180, 150, 50));
 
-        let perlin_nz = Perlin::new();
+        let perlin_nz = Perlin::new().set_seed(1);
+        let temp_nz = Perlin::new().set_seed(2);
+        let chaos_nz = Perlin::new().set_seed(3);
 
         for lpos in chunk.iter_positions() {
             let wpos = lpos + chunk_pos * chunk.get_size().map(|e| e as i32);
             let wposf = wpos.map(|e| e as f64);
 
+            let chaos_freq = 1.0 / 100.0;
             let freq = 1.0 / 128.0;
             let ampl = 32.0;
             let small_freq = 1.0 / 32.0;
             let small_ampl = 6.0;
             let offs = 32.0;
-            let height = perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl
-                + perlin_nz.get(Vec2::from(wposf * small_freq).into_array()) * small_ampl
+
+            let chaos = chaos_nz
+                .get(Vec2::from(wposf * chaos_freq).into_array())
+                .max(0.0)
+                + 0.5;
+
+            let height = perlin_nz.get(Vec2::from(wposf * freq).into_array()) * ampl * chaos
+                + perlin_nz.get((wposf * small_freq).into_array())
+                    * small_ampl
+                    * 2.0
+                    * chaos.powf(2.0)
                 + offs;
+            let temp = (temp_nz.get(Vec2::from(wposf * (1.0 / 64.0)).into_array()) + 1.0) * 0.5;
 
             chunk
                 .set(
                     lpos,
                     if wposf.z < height - 4.0 {
                         stone
-                    } else if wposf.z < height - 1.0 {
+                    } else if wposf.z < height - 2.0 {
                         dirt
                     } else if wposf.z < height {
-                        grass
+                        Block::new(2, Rgb::new(10 + (150.0 * temp) as u8, 150, 0))
                     } else {
                         air
                     },